merging mod-ui changes from trunk
[duncan/yast2-qt4.git] / src / YQWizard.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                    (c) SuSE Linux AG |
11 \----------------------------------------------------------------------/
12
13   File:         YQWizard.cc
14
15   Author:       Stefan Hundhammer <sh@suse.de>
16
17   Textdomain    "packages-qt"
18
19 /-*/
20
21
22 #include "YQWizard.h"
23 #define y2log_component "qt-wizard"
24 #include <ycp/y2log.h>
25
26 // For the command parser
27
28 #include <string>
29 #include <YShortcut.h>
30
31 #include <q3hbox.h>
32 #include <q3header.h>
33 #include <qimage.h>
34 #include <qlabel.h>
35 #include <qlayout.h>
36 #include <qmenubar.h>
37 #include <qmenudata.h>
38 #include <qobject.h>
39 #include <qpixmap.h>
40 #include <q3popupmenu.h>
41 #include <qpushbutton.h>
42 #include <qregexp.h>
43 #include <qtabwidget.h>
44 #include <q3textbrowser.h>
45 #include <qtoolbutton.h>
46 #include <q3widgetstack.h>
47
48 #include "QY2ListView.h"
49 //Added by qt3to4:
50 #include <q3boxlayout.h>
51 #include <q3gridlayout.h>
52 #include <q3frame.h>
53 #include <qevent.h>
54 #include <q3boxlayout.h>
55
56 #include "utf8.h"
57 #include "YQi18n.h"
58 #include "YQUI.h"
59 #include "YQApplication.h"
60 #include "YQDialog.h"
61 #include "YQAlignment.h"
62 #include "YQReplacePoint.h"
63 #include "YQEmpty.h"
64 #include "YQLabel.h"
65 #include "YQWizardButton.h"
66 #include "YQIconPool.h"
67 #include "YQWidgetFactory.h"
68 #include "YQSignalBlocker.h"
69 #include "QY2LayoutUtils.h"
70 #include "YEvent.h"
71
72 using std::string;
73
74
75 #define PIXMAP_DIR THEMEDIR "/wizard/"
76
77 #ifdef TEXTDOMAIN
78 #    undef TEXTDOMAIN
79 #endif
80
81 #define TEXTDOMAIN "packages-qt"
82
83 #define ENABLE_GRADIENTS                1
84
85 #define USE_SEPARATOR                   1
86
87 #define WORK_AREA_TOP_MARGIN            10
88
89 #if ENABLE_GRADIENTS
90 #  define WORK_AREA_BOTTOM_MARGIN       8
91 #  define WORK_AREA_RIGHT_MARGIN        8
92 #else
93 #  define WORK_AREA_BOTTOM_MARGIN       8
94 #  define WORK_AREA_RIGHT_MARGIN        6
95 #endif
96
97 #define BUTTON_BOX_TOP_MARGIN           10
98
99 #define SEPARATOR_MARGIN                6
100 #define STEPS_MARGIN                    10
101 #define STEPS_SPACING                   2
102 #define STEPS_HEADING_SPACING           8
103 #define MENU_BAR_MARGIN                 8
104
105 #define USE_FIXED_STEP_FONTS            0
106 #define STEPS_FONT_FAMILY               "Sans Serif"
107 #define STEPS_FONT_SIZE                 11
108 #define STEPS_HEADING_FONT_SIZE         11
109
110 #define USE_ICON_ON_HELP_BUTTON         0
111
112
113 YQWizard::YQWizard( YWidget *           parent,
114                     const string &      backButtonLabel,
115                     const string &      abortButtonLabel,
116                     const string &      nextButtonLabel,
117                     YWizardMode         wizardMode )
118     : QFrame( (QWidget *) parent->widgetRep() )
119     , YWizard( parent,
120                backButtonLabel,
121                abortButtonLabel,
122                nextButtonLabel,
123                wizardMode )
124     , _backButtonLabel( backButtonLabel )
125     , _abortButtonLabel( abortButtonLabel )
126     , _nextButtonLabel( nextButtonLabel )
127 {
128     QVBoxLayout* layout = new QVBoxLayout( this );
129     layout->setSpacing( 0 );
130     layout->setMargin( 0 );
131     setLayout( layout );
132
133     setWidgetRep( this );
134
135     _stepsEnabled = (wizardMode == YWizardMode_Steps);
136     _treeEnabled  = (wizardMode == YWizardMode_Tree);
137
138     _stepsDirty         = false;
139     _direction          = YQWizard::Forward;
140
141     _sideBar            = 0;
142     _stepsPanel         = 0;
143     _stepsBox           = 0;
144     _stepsGrid          = 0;
145     _helpButton         = 0;
146     _stepsButton        = 0;
147     _treeButton         = 0;
148     _releaseNotesButton = 0;
149     _treePanel          = 0;
150     _tree               = 0;
151     _helpPanel          = 0;
152     _helpBrowser        = 0;
153     _clientArea         = 0;
154     _menuBarBox         = 0;
155     _menuBar            = 0;
156     _dialogIcon         = 0;
157     _dialogHeading      = 0;
158     _contents           = 0;
159     _backButton         = 0;
160     _backButtonSpacer   = 0;
161     _abortButton        = 0;
162     _nextButton         = 0;
163     _sendButtonEvents   = true;
164     _contentsReplacePoint = 0;
165
166     _stepsList.setAutoDelete( true );
167     _stepsIDs.setAutoDelete( false );   // Only for one of both!
168
169     YQUI::setTextdomain( TEXTDOMAIN );
170
171
172     //
173     // Load graphics
174     //
175
176 #if ENABLE_GRADIENTS
177     loadGradientPixmaps();
178 #endif
179
180     if ( _stepsEnabled )
181         loadStepsIcons();
182
183
184     //
185     // Create widgets
186     //
187
188
189     if ( ! _titleBarGradientPixmap.isNull() )
190     {
191         layoutTitleBar( this );
192     }
193     else
194     {
195         QWidget * spacer = addVSpacing( this, WORK_AREA_TOP_MARGIN );
196         Q_CHECK_PTR( spacer );
197
198 #       if ENABLE_GRADIENTS
199             spacer->setPaletteBackgroundColor( _gradientTopColor );
200 #       endif
201     }
202
203     Q3HBox * hBox = new Q3HBox( this );
204     YUI_CHECK_NEW( hBox );
205     layout->addWidget( hBox );
206
207     layoutSideBar( hBox );
208     layoutWorkArea( hBox );
209
210     y2debug( "Constructor finished." );
211 }
212
213
214
215 YQWizard::~YQWizard()
216 {
217     deleteSteps();
218 }
219
220
221
222 void YQWizard::layoutTitleBar( QWidget * parent )
223 {
224     if ( ! highColorDisplay() )         // 8 bit display or worse?
225     {
226         // No colorful title bar, just a spacing to match the one at the bottom.
227         addVSpacing( parent, WORK_AREA_BOTTOM_MARGIN );
228
229         return;
230     }
231
232
233     Q3HBox * titleBar = new Q3HBox( parent );
234     YUI_CHECK_NEW( titleBar );
235
236 #if ENABLE_GRADIENTS
237     setGradient( titleBar, _titleBarGradientPixmap );
238 #endif
239
240     titleBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); // hor/vert
241
242     //
243     // Left logo
244     //
245
246     QLabel * left = new QLabel( titleBar );
247     left->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
248
249     QPixmap leftLogo( PIXMAP_DIR "title-bar-left.png" );
250
251     if ( ! leftLogo.isNull() )
252     {
253         left->setPixmap( leftLogo );
254         left->setFixedSize( leftLogo.size() );
255         left->setBackgroundOrigin( QWidget::ParentOrigin );
256     }
257
258
259     //
260     // Center stretch space
261     //
262
263     addHStretch( titleBar );
264
265
266     //
267     // Right logo
268     //
269
270     QLabel * right = new QLabel( titleBar );
271     YUI_CHECK_NEW( right );
272
273     QPixmap rightLogo( PIXMAP_DIR "title-bar-right.png" );
274
275     if ( ! rightLogo.isNull() )
276     {
277         right->setPixmap( rightLogo );
278         right->setFixedSize( rightLogo.size() );
279         right->setBackgroundOrigin( QWidget::ParentOrigin );
280     }
281 }
282
283
284
285 void YQWizard::layoutSideBar( QWidget * parent )
286 {
287     _sideBar = new Q3WidgetStack( parent );
288     YUI_CHECK_NEW( _sideBar );
289     _sideBar->setMinimumWidth( YQUI::ui()->defaultSize( YD_HORIZ ) / 5 );
290     _sideBar->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ) ); // hor/vert
291     _sideBar->setMargin( 0 );
292
293
294     layoutHelpPanel();
295
296     if ( _treeEnabled )
297     {
298         layoutTreePanel();
299         showTree();
300     }
301     else if ( _stepsEnabled )
302     {
303         layoutStepsPanel();
304         showSteps();
305     }
306 }
307
308
309
310 void YQWizard::layoutStepsPanel()
311 {
312     _stepsPanel = new Q3VBox( _sideBar );
313     YUI_CHECK_NEW( _stepsPanel );
314
315
316 #if ENABLE_GRADIENTS
317     if ( ! _titleBarGradientPixmap.isNull() )
318     {
319         // Top gradient
320
321         QLabel * topGradient = new QLabel( _stepsPanel );
322         Q_CHECK_PTR( topGradient );
323         setGradient( topGradient, _topGradientPixmap );
324     }
325 #endif
326
327
328     // Steps
329
330     _sideBar->addWidget( _stepsPanel );
331
332     _stepsBox = new Q3VBox( _stepsPanel );
333     YUI_CHECK_NEW( _stepsBox );
334 #if ENABLE_GRADIENTS
335     _stepsBox->setPaletteBackgroundColor( _gradientCenterColor );
336 #endif
337     _stepsBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) ); // hor/vert
338
339     QWidget * stretch = addVStretch( _stepsPanel );
340     YUI_CHECK_NEW( stretch );
341 #if ENABLE_GRADIENTS
342     stretch->setPaletteBackgroundColor( _gradientCenterColor );
343 #endif
344
345
346     // Steps panel bottom buttons ("Help", "Release Notes")
347
348     QLabel * helpButtonBox = new QLabel( _stepsPanel );
349
350 #if ENABLE_GRADIENTS
351     YUI_CHECK_NEW( helpButtonBox );
352     setGradient( helpButtonBox, _bottomGradientPixmap );
353 #endif
354
355
356
357     // Layouts for the buttons
358
359     QVBoxLayout * vbox = new QVBoxLayout( helpButtonBox, 0, 0 ); // parent, margin, spacing
360     YUI_CHECK_NEW( vbox );
361     vbox->addStretch( 99 );
362
363
364     QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 );    // parent, spacing
365     hbox->addStretch( 99 );
366
367     _releaseNotesButton = new QPushButton( _( "Release Notes..." ), helpButtonBox );
368     hbox->addWidget( _releaseNotesButton );
369
370
371     connect( _releaseNotesButton,       SIGNAL( clicked()  ),
372              this,                      SLOT  ( releaseNotesClicked() ) );
373
374     _releaseNotesButton->hide();        // hidden until showReleaseNotesButton() is called
375
376     hbox->addStretch( 99 );
377     vbox->addStretch( 99 );
378
379     hbox = new QHBoxLayout( vbox, 0 );  // parent, spacing
380     hbox->addStretch( 99 );
381
382     // Help button - intentionally without keyboard shortcut
383     _helpButton = new QPushButton( _( "Help" ), helpButtonBox );
384     YUI_CHECK_NEW( _helpButton );
385
386     hbox->addWidget( _helpButton );
387     hbox->addStretch( 99 );
388
389     connect( _helpButton, SIGNAL( clicked()  ),
390              this,       SLOT  ( showHelp() ) );
391
392 #if USE_ICON_ON_HELP_BUTTON
393     QPixmap pixmap = QPixmap( PIXMAP_DIR "help-button.png" );
394
395     if ( ! pixmap.isNull() )
396         _helpButton->setPixmap( pixmap );
397 #endif
398
399
400     vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
401 }
402
403
404
405 void YQWizard::addStep( const string & text, const string & id )
406 {
407     QString qId = fromUTF8( id );
408
409     if ( _stepsIDs[ qId ] )
410     {
411         y2error( "Step ID \"%s\" (\"%s\") already used for \"%s\"",
412                  id.c_str(),
413                  text.c_str(),
414                  (const char *) _stepsIDs[ qId ]->name() );
415         return;
416     }
417
418     if ( _stepsList.last() && _stepsList.last()->name() == text )
419     {
420         // Consecutive steps with the same name will be shown as one single step.
421         //
422         // Since steps are always added at the end of the list, it is
423         // sufficient to check the last step of the list. If the texts are the
424         // same, the other with the same text needs to get another (additional)
425         // ID to make sure setCurrentStep() works as it should.
426         _stepsList.last()->addID( qId );
427     }
428     else
429     {
430         _stepsList.append( new YQWizard::Step( fromUTF8( text ), qId ) );
431         _stepsDirty = true;
432     }
433
434     _stepsIDs.insert( qId, _stepsList.last() );
435 }
436
437
438
439 void YQWizard::addStepHeading( const string & text )
440 {
441     _stepsList.append( new YQWizard::StepHeading( text ) );
442     _stepsDirty = true;
443 }
444
445
446
447 void YQWizard::updateSteps()
448 {
449     if ( ! _stepsBox )
450         return;
451
452     //
453     // Delete any previous step widgets
454     //
455
456     if ( _stepsGrid )
457     {
458         delete _stepsGrid->mainWidget();
459         _stepsGrid = 0;
460     }
461
462
463     //
464     // Create a new parent widget for the steps
465     //
466
467     QWidget * stepsParent = new QWidget( _stepsBox );
468     YUI_CHECK_NEW( stepsParent );
469     stepsParent->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) ); // hor/vert
470 #if ENABLE_GRADIENTS
471     stepsParent->setPaletteBackgroundColor( _gradientCenterColor );
472 #endif
473
474     // Create a grid layout for the steps
475
476     _stepsGrid = new Q3GridLayout( stepsParent,                 // parent
477                                   _stepsList.count(), 4,        // rows, cols
478                                   0, STEPS_SPACING );           // margin, spacing
479     YUI_CHECK_NEW( _stepsGrid );
480
481     const int statusCol = 1;
482     const int nameCol   = 2;
483
484     _stepsGrid->setColStretch( 0, 99 );         // Left margin column - stretch
485     _stepsGrid->setColStretch( statusCol, 0 );  // Status column - don't stretch
486     _stepsGrid->setColStretch( nameCol,   0 );  // Name column - don't stretch
487     _stepsGrid->setColStretch( 3, 99  );        // Left margin column - stretch
488
489
490     // Work around Qt bug: Grid layout only works right if the parent widget isn't visible.
491     stepsParent->hide();
492
493     //
494     // Add left and right (but not top and bottom) margins
495     //
496
497     int row = 0;
498
499     QWidget * leftSpacer  = addHSpacing( stepsParent, STEPS_MARGIN );
500     YUI_CHECK_NEW( leftSpacer );
501     _stepsGrid->addWidget( leftSpacer, row, 0 );
502
503     QWidget * rightSpacer = addHSpacing( stepsParent, STEPS_MARGIN );
504     YUI_CHECK_NEW( rightSpacer );
505     _stepsGrid->addWidget( rightSpacer, row, 3 );
506
507
508     //
509     // Create widgets for all steps and step headings in the internal list
510     //
511
512     YQWizard::Step * step = _stepsList.first();
513
514     while ( step )
515     {
516         if ( step->isHeading() )
517         {
518             if ( row > 0 )
519             {
520                 // Spacing
521
522                 QWidget * spacer = addVSpacing( stepsParent, STEPS_HEADING_SPACING );
523                 YUI_CHECK_NEW( spacer );
524                 _stepsGrid->addWidget( spacer, row++, nameCol );
525             }
526
527             //
528             // Heading
529             //
530
531             QLabel * label = new QLabel( step->name(), stepsParent );
532             YUI_CHECK_NEW( label );
533             label->setAlignment( Qt::AlignLeft | Qt::AlignTop );
534
535 #if USE_FIXED_STEP_FONTS
536             QFont font( STEPS_FONT_FAMILY, STEPS_HEADING_FONT_SIZE );
537             font.setWeight( QFont::Bold );
538             label->setFont( font );
539 #else
540             QFont font = YQUI::yqApp()->currentFont();
541
542             int size = font.pointSize();
543
544             if ( size > 1 )
545                 font.setPointSize( size + 2 );
546
547             font.setBold( true );
548             label->setFont( font );
549 #endif
550
551             step->setNameLabel( label );
552             _stepsGrid->addMultiCellWidget( label,
553                                             row, row,                   // from_row, to_row
554                                             statusCol, nameCol );       // from_col, to_col
555         }
556         else    // No heading - ordinary step
557         {
558             //
559             // Step status
560             //
561
562             QLabel * statusLabel = new QLabel( stepsParent );
563             YUI_CHECK_NEW( statusLabel );
564
565             step->setStatusLabel( statusLabel );
566             _stepsGrid->addWidget( statusLabel, row, statusCol );
567
568
569             //
570             // Step name
571             //
572
573             QLabel * nameLabel = new QLabel( step->name(), stepsParent );
574             YUI_CHECK_NEW( nameLabel );
575             nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop );
576
577 #if USE_FIXED_STEP_FONTS
578             nameLabel->setFont( QFont( STEPS_FONT_FAMILY, STEPS_FONT_SIZE ) );
579 #else
580             nameLabel->setFont( YQUI::yqApp()->currentFont() );
581 #endif
582
583             step->setNameLabel( nameLabel );
584             _stepsGrid->addWidget( nameLabel, row, nameCol );
585         }
586
587         step = _stepsList.next();
588         row++;
589     }
590
591     _stepsGrid->activate();
592     stepsParent->show();
593     _stepsDirty = false;
594 }
595
596
597 void YQWizard::updateStepStates()
598 {
599     if ( _stepsDirty )
600         updateSteps();
601
602     YQWizard::Step * currentStep = findStep( _currentStepID );
603     YQWizard::Step * step = _stepsList.first();
604
605     if ( currentStep )
606     {
607         // Set status icon and color for the current step
608         setStepStatus( currentStep, _stepCurrentIcon, _stepCurrentColor );
609
610
611         //
612         // Set all steps before the current to "done"
613         //
614
615         while ( step && step != currentStep )
616         {
617             setStepStatus( step, _stepDoneIcon, _stepDoneColor );
618             step = _stepsList.next();
619         }
620
621         // Skip the current step - continue with the step after it
622
623         if ( step )
624             step = _stepsList.next();
625     }
626
627     //
628     // Set all steps after the current to "to do"
629     //
630
631     while ( step )
632     {
633         setStepStatus( step, _stepToDoIcon, _stepToDoColor );
634         step = _stepsList.next();
635     }
636 }
637
638
639 void YQWizard::setStepStatus( YQWizard::Step * step, const QPixmap & icon, const QColor & color )
640 {
641     if ( step )
642     {
643         if ( step->nameLabel() )
644             step->nameLabel()->setPaletteForegroundColor( color );
645
646         if ( step->statusLabel() )
647             step->statusLabel()->setPixmap( icon );
648     }
649 }
650
651
652 void YQWizard::setCurrentStep( const string & id )
653 {
654     _currentStepID = id;
655     updateStepStates();
656 }
657
658
659 void YQWizard::deleteSteps()
660 {
661     _stepsList.clear();
662     _stepsIDs.clear();
663 }
664
665
666 YQWizard::Step * YQWizard::findStep( const QString & id )
667 {
668     if ( id.isEmpty() )
669         return 0;
670
671     return _stepsIDs[ id ];
672 }
673
674
675 void YQWizard::layoutHelpPanel()
676 {
677     _helpPanel = new Q3HBox( _sideBar );
678     YUI_CHECK_NEW( _helpPanel );
679     _sideBar->addWidget( _helpPanel );
680
681     addGradientColumn( _helpPanel );
682
683     Q3VBox * vbox = new Q3VBox( _helpPanel );
684     YUI_CHECK_NEW( vbox );
685
686
687     // Help browser
688
689     _helpBrowser = new Q3TextBrowser( vbox );
690     YUI_CHECK_NEW( _helpBrowser );
691
692     _helpBrowser->setMimeSourceFactory( 0 );
693     _helpBrowser->installEventFilter( this );
694     _helpBrowser->setTextFormat( Qt::RichText );
695     _helpBrowser->setMargin( 4 );
696     _helpBrowser->setResizePolicy( Q3ScrollView::Manual );
697
698
699     // Set help browser text color
700     QPixmap fgPixmap = QPixmap( PIXMAP_DIR "help-text-color.png" );
701     if (! fgPixmap.isNull() )
702         _helpBrowser->setPaletteForegroundColor( pixelColor( fgPixmap, 0, 0, paletteForegroundColor() ) );
703
704
705     if ( highColorDisplay() )
706     {
707         // Set fancy help browser background pixmap
708
709         QPixmap bgPixmap( PIXMAP_DIR "help-background.png" );
710
711         if ( ! bgPixmap.isNull() )
712             _helpBrowser->setPaletteBackgroundPixmap( bgPixmap );
713     }
714
715
716
717     //
718     // Button box with bottom gradient
719     //
720
721
722     QLabel * buttonBox = new QLabel( vbox );
723     YUI_CHECK_NEW( buttonBox );
724
725     QPushButton * button;
726     QPixmap pixmap;
727
728     if ( _treeEnabled )
729     {
730         // "Tree" button - intentionally without keyboard shortcut
731         button = new QPushButton( _( "Tree" ), buttonBox );
732         YUI_CHECK_NEW( button );
733         _treeButton = button;
734
735 #if USE_ICON_ON_HELP_BUTTON
736         pixmap = QPixmap( PIXMAP_DIR "tree-button.png" );
737 #endif
738     }
739     else
740         if ( _stepsEnabled )
741     {
742         // "Steps" button - intentionally without keyboard shortcut
743         button = new QPushButton( _( "Steps" ), buttonBox );
744         YUI_CHECK_NEW( button );
745         _stepsButton = button;
746
747 #if USE_ICON_ON_HELP_BUTTON
748         pixmap = QPixmap( PIXMAP_DIR "steps-button.png" );
749 #endif
750     }
751     else
752     {
753         // Create a dummy button just to find out how high it would become
754         button = new QPushButton( "Dummy", buttonBox );
755         YUI_CHECK_NEW( button );
756     }
757
758
759     if ( ! pixmap.isNull() )
760         button->setPixmap( pixmap );
761
762     layoutSideBarButtonBox( buttonBox, button );
763
764     if ( _treeEnabled )
765     {
766         connect( button, SIGNAL( clicked()  ),
767                  this,   SLOT  ( showTree() ) );
768     }
769     else if ( _stepsEnabled )
770     {
771         connect( button, SIGNAL( clicked()   ),
772                  this,   SLOT  ( showSteps() ) );
773     }
774     else
775     {
776         // Hide the dummy button - the button box height is fixed now.
777         button->hide();
778     }
779
780     addGradientColumn( _helpPanel );
781 }
782
783
784
785 void YQWizard::layoutSideBarButtonBox( QWidget * parent, QPushButton * button )
786 {
787     QVBoxLayout * vbox = new QVBoxLayout( parent, 0, 0 );       // parent, margin, spacing
788     YUI_CHECK_NEW( vbox );
789     vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
790
791     QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 );            // parent, spacing
792     YUI_CHECK_NEW( hbox );
793
794     hbox->addStretch( 99 );
795     hbox->addWidget( button );
796     hbox->addStretch( 99 );
797
798     vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
799
800     // For whatever strange reason, parent->sizeHint() does not return anything
801     // meaningful yet - not even after vbox->activate() or parent->adjustSize()
802     int height = button->sizeHint().height() + BUTTON_BOX_TOP_MARGIN + WORK_AREA_BOTTOM_MARGIN;
803
804 #if ENABLE_GRADIENTS
805     if ( ! _bottomGradientPixmap.isNull() )
806         setBottomCroppedGradient( parent, _bottomGradientPixmap, height );
807 #endif
808
809     parent->setFixedHeight( height );
810 }
811
812
813
814 void YQWizard::layoutTreePanel()
815 {
816     _treePanel = new Q3HBox( _sideBar );
817     YUI_CHECK_NEW( _treePanel );
818     _sideBar->addWidget( _treePanel );
819
820     // Left margin (with gradients)
821     addGradientColumn( _treePanel );
822
823     Q3VBox * vbox = new Q3VBox( _treePanel );
824     YUI_CHECK_NEW( vbox );
825
826
827     // Selection tree
828
829     _tree = new QY2ListView( vbox );
830     YUI_CHECK_NEW( _tree );
831
832     _tree->addColumn( "" );
833     _tree->header()->hide();
834     _tree->setRootIsDecorated( true );
835     _tree->setSortByInsertionSequence( true );
836
837     connect( _tree,     SIGNAL( selectionChanged     ( void ) ),
838              this,      SLOT  ( treeSelectionChanged ( void ) ) );
839
840     connect( _tree,     SIGNAL( spacePressed  ( Q3ListViewItem * ) ),
841              this,      SLOT  ( sendTreeEvent ( Q3ListViewItem * ) ) );
842
843     connect( _tree,     SIGNAL( doubleClicked ( Q3ListViewItem * ) ),
844              this,      SLOT  ( sendTreeEvent ( Q3ListViewItem * ) ) );
845
846
847     // Bottom gradient
848
849     QLabel * buttonBox = new QLabel( vbox );
850     YUI_CHECK_NEW( buttonBox );
851
852
853     // "Help" button - intentionally without keyboard shortcut
854     QPushButton * button = new QPushButton( _( "Help" ), buttonBox );
855     YUI_CHECK_NEW( button );
856
857 #if USE_ICON_ON_HELP_BUTTON
858     QPixmap pixmap( PIXMAP_DIR "help-button.png" );
859
860     if ( ! pixmap.isNull() )
861         button->setPixmap( pixmap );
862 #endif
863
864     layoutSideBarButtonBox( buttonBox, button );
865
866     connect( button, SIGNAL( clicked()  ),
867              this,   SLOT  ( showHelp() ) );
868
869
870     // Right margin (with gradients)
871     addGradientColumn( _treePanel );
872 }
873
874
875
876 void YQWizard::addTreeItem( const string & parentID, const string & text, const string & id )
877 {
878     QString qId = fromUTF8( id );
879
880     if ( ! _tree )
881     {
882         y2error( "YQWizard widget not created with `opt(`treeEnabled) !" );
883         return;
884     }
885
886     YQWizard::TreeItem * item   = 0;
887     YQWizard::TreeItem * parent = 0;
888
889     if ( ! parentID.empty() )
890     {
891         parent = findTreeItem( parentID );
892     }
893
894     if ( parent )
895     {
896         item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId );
897         YUI_CHECK_NEW( item );
898     }
899     else
900     {
901         item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId );
902         YUI_CHECK_NEW( item );
903     }
904
905     if ( ! qId.isEmpty() )
906         _treeIDs.insert( qId, item );
907 }
908
909
910
911 void YQWizard::deleteTreeItems()
912 {
913     if ( _tree )
914         _tree->clear();
915
916     _treeIDs.clear();
917 }
918
919
920
921 YQWizard::TreeItem * YQWizard::findTreeItem( const string & id )
922 {
923     if ( id.empty() )
924         return 0;
925
926     return _treeIDs[ fromUTF8( id ) ];
927 }
928
929
930 void YQWizard::selectTreeItem( const string & id )
931 {
932     if ( _tree )
933     {
934         YQWizard::TreeItem * item = findTreeItem( id );
935
936         if ( item )
937         {
938             YQSignalBlocker sigBlocker( _tree );
939
940             _tree->setSelected( item, true );
941             _tree->ensureItemVisible( item );
942         }
943     }
944 }
945
946
947 void YQWizard::sendTreeEvent( Q3ListViewItem * listViewItem )
948 {
949     if ( listViewItem )
950     {
951         YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem );
952
953         if ( item && ! item->id().isEmpty() )
954             sendEvent( toUTF8( item->id() ) );
955     }
956 }
957
958
959 void YQWizard::treeSelectionChanged()
960 {
961     if ( _tree )
962         sendTreeEvent( _tree->selectedItem() );
963 }
964
965
966 string YQWizard::currentTreeSelection()
967 {
968     if ( _tree )
969     {
970         Q3ListViewItem * sel = _tree->selectedItem();
971
972         if ( sel )
973         {
974             YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel);
975
976             if ( item && ! item->id().isEmpty() )
977                 return toUTF8( item->id() );
978         }
979     }
980
981     return string();
982 }
983
984
985
986 void YQWizard::layoutWorkArea( QFrame * parentHBox )
987 {
988     Q3VBox * workAreaVBox = new Q3VBox( parentHBox );
989     YUI_CHECK_NEW( workAreaVBox );
990
991     // An extra QVBox inside the workAreaVBox is needed for frame and margin
992
993     Q3VBox * workArea = new Q3VBox( workAreaVBox );
994     YUI_CHECK_NEW( workArea );
995
996 #if ENABLE_GRADIENTS
997     workArea->setFrameStyle( QFrame::Box | QFrame::Plain );
998     workArea->setMargin( 4 );
999 #else
1000     workArea->setFrameStyle( QFrame::Box | QFrame::Sunken );
1001     // workArea->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Sunken );
1002 #endif
1003
1004
1005     //
1006     // Menu bar
1007     //
1008
1009     // Placed directly inside workArea the menu bar positions itself at (0,0)
1010     // and so obscures any kind of frame there might be.
1011     _menuBarBox = new Q3VBox( workArea );
1012     YUI_CHECK_NEW( _menuBarBox );
1013
1014     _menuBar = new QMenuBar( _menuBarBox );
1015     YUI_CHECK_NEW( _menuBar );
1016
1017     _menuBarBox->hide(); // will be made visible when menus are added
1018
1019
1020     //
1021     // Dialog icon and heading
1022     //
1023
1024     Q3HBox * headingHBox = new Q3HBox( workArea );
1025     YUI_CHECK_NEW( headingHBox );
1026     headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1027
1028     addHSpacing( headingHBox, SEPARATOR_MARGIN );
1029
1030     _dialogIcon = new QLabel( headingHBox );
1031     YUI_CHECK_NEW( _dialogIcon );
1032     _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert
1033
1034     addHSpacing( headingHBox );
1035
1036     _dialogHeading = new QLabel( headingHBox );
1037     YUI_CHECK_NEW( _dialogHeading );
1038     _dialogHeading->setFont( YQUI::yqApp()->headingFont() );
1039     _dialogHeading->setAlignment( Qt::AlignLeft | Qt::WordBreak );
1040     _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1041
1042 #if 0
1043     addHStretch( headingHBox );
1044 #endif
1045     addVSpacing( workArea );
1046
1047 #if USE_SEPARATOR
1048
1049     Q3HBox * hbox = new Q3HBox( workArea );
1050
1051     addHSpacing( hbox, SEPARATOR_MARGIN );
1052
1053     QFrame * separator = new QFrame( hbox );
1054     YUI_CHECK_NEW( separator );
1055     separator->setFrameStyle( QFrame::HLine | QFrame::Sunken );
1056
1057     addHSpacing( hbox, SEPARATOR_MARGIN );
1058     addVSpacing( workArea );
1059 #endif
1060
1061     //
1062     // Client area (the part that belongs to the YCP application)
1063     //
1064
1065     layoutClientArea( workArea );
1066
1067
1068     //
1069     // Button box
1070     //
1071
1072     layoutButtonBox( workAreaVBox );
1073
1074
1075     //
1076     // Spacer (purely decorative) at the right of the client area
1077     //
1078
1079     addGradientColumn( parentHBox, WORK_AREA_RIGHT_MARGIN );
1080 }
1081
1082
1083
1084 void YQWizard::layoutClientArea( QWidget * parent )
1085 {
1086     _clientArea = new Q3VBox( parent );
1087     YUI_CHECK_NEW( _clientArea );
1088     _clientArea->setMargin( 4 );
1089
1090 #if 0
1091     _clientArea->setPaletteBackgroundColor( QColor( 0x60, 0x60, 0x60 ) );
1092 #endif
1093
1094
1095     //
1096     // HVCenter for wizard contents
1097     //
1098
1099     _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
1100     YUI_CHECK_NEW( _contents );
1101
1102     _contents->setStretchable( YD_HORIZ, true );
1103     _contents->setStretchable( YD_VERT,  true );
1104     _contents->installEventFilter( this );
1105     _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
1106
1107
1108     //
1109     // Replace point for wizard contents
1110     //
1111
1112     _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
1113
1114     //
1115     // Initial YEmpty widget contents of replace point
1116     //
1117
1118     YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
1119     _contentsReplacePoint->showChild();
1120 }
1121
1122
1123
1124 void YQWizard::layoutButtonBox( QWidget * parent )
1125 {
1126     //
1127     // Button box and layout
1128     //
1129
1130     QWidget * buttonBox = new QWidget( parent );
1131     YUI_CHECK_NEW( buttonBox );
1132
1133     // Using old-style layouts to enable a seamless background with the
1134     // gradient pixmap: Any sub-widgets (Q3VBox, QHBox) would have to get yet
1135     // another portion of that gradient as their backround pixmap, and it would
1136     // be very hard to cover all cases - resizing, hiding individual buttons, etc.
1137
1138     QVBoxLayout * vbox = new QVBoxLayout( buttonBox, 0, 0 );    // parent, margin, spacing
1139     YUI_CHECK_NEW( vbox );
1140
1141     vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
1142
1143
1144     //
1145     // QHBoxLayout for the buttons
1146     //
1147
1148     QHBoxLayout * hbox = new QHBoxLayout( vbox, 2 );            // parent, spacing
1149     YUI_CHECK_NEW( hbox );
1150
1151
1152     //
1153     // "Back" button
1154     //
1155
1156     _backButton  = new YQWizardButton( this, buttonBox, _backButtonLabel );
1157     YUI_CHECK_NEW( _backButton );
1158
1159     hbox->addWidget( (QWidget *) _backButton->widgetRep() );
1160     connect( _backButton,       SIGNAL( clicked()               ),
1161              this,              SLOT  ( slotBackClicked()       ) );
1162
1163     _backButtonSpacer = new QSpacerItem( 0, 0,                          // width, height
1164                                          QSizePolicy::Expanding,        // horizontal
1165                                          QSizePolicy::Minimum );        // vertical
1166     YUI_CHECK_NEW( _backButtonSpacer );
1167     hbox->addItem( _backButtonSpacer );
1168
1169
1170     if ( _backButton->text().isEmpty() )
1171     {
1172         _backButton->hide();
1173
1174         // Minimize _backButtonSpacer
1175         _backButtonSpacer->changeSize( 0, 0,                            // width, height
1176                                        QSizePolicy::Minimum,            // horizontal
1177                                        QSizePolicy::Minimum );          // vertical
1178     }
1179
1180
1181     //
1182     // "Abort" button
1183     //
1184
1185     _abortButton = new YQWizardButton( this, buttonBox, _abortButtonLabel );
1186     YUI_CHECK_NEW( _abortButton );
1187
1188     hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
1189     connect( _abortButton,      SIGNAL( clicked()               ),
1190              this,              SLOT  ( slotAbortClicked()      ) );
1191
1192
1193     // Using spacer rather than addSpacing() since the default stretchability
1194     // of a QSpacerItem is undefined, i.e. centering the middle button could
1195     // not be guaranteed.
1196
1197     QSpacerItem * spacer = new QSpacerItem( 0, 0,                       // width, height
1198                                             QSizePolicy::Expanding,     // horizontal
1199                                             QSizePolicy::Minimum );     // vertical
1200     YUI_CHECK_NEW( spacer );
1201     hbox->addItem( spacer );
1202
1203
1204     //
1205     // "Next" button
1206     //
1207
1208     _nextButton  = new YQWizardButton( this, buttonBox, _nextButtonLabel );
1209     YUI_CHECK_NEW( _nextButton );
1210
1211     hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
1212     connect( _nextButton,       SIGNAL( clicked()               ),
1213              this,              SLOT  ( slotNextClicked()       ) );
1214
1215
1216     //
1217     // Bottom margin and gradient
1218     //
1219
1220     vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
1221
1222 #if ENABLE_GRADIENTS
1223     setBottomCroppedGradient( buttonBox, _bottomGradientPixmap, buttonBox->sizeHint().height() );
1224 #endif
1225
1226     buttonBox->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); // hor/vert
1227 }
1228
1229
1230
1231 void YQWizard::loadGradientPixmaps()
1232 {
1233 #if ENABLE_GRADIENTS
1234     if ( highColorDisplay() )
1235     {
1236         _topGradientPixmap      = QPixmap( PIXMAP_DIR "top-gradient.png"        );
1237         _bottomGradientPixmap   = QPixmap( PIXMAP_DIR "bottom-gradient.png"     );
1238         _titleBarGradientPixmap = QPixmap( PIXMAP_DIR "title-bar-gradient.png"  );
1239         _gradientCenterColor    = pixelColor( _bottomGradientPixmap, 0, 0, paletteBackgroundColor() );
1240         _gradientTopColor       = pixelColor( _topGradientPixmap, 0, 0 , paletteBackgroundColor() );
1241     }
1242     else // 8 bit display or worse - don't use gradients
1243     {
1244         // Gradient pixmaps remain empty. The respecive widgets will retain the
1245         // default widget background (grey, depending on the widget theme).
1246
1247         // Use deault widget background (some shade of grey) for the center
1248         // stretchable part of the side bar.
1249         _gradientCenterColor = paletteBackgroundColor();
1250         _gradientTopColor = paletteBackgroundColor();
1251     }
1252 #endif
1253 }
1254
1255
1256 void YQWizard::loadStepsIcons()
1257 {
1258     _stepCurrentIcon    = YQIconPool::stepCurrent();
1259     _stepToDoIcon       = YQIconPool::stepToDo();
1260     _stepDoneIcon       = YQIconPool::stepDone();
1261
1262     if ( highColorDisplay() )
1263     {
1264         _stepCurrentColor       = pixelColor( QPixmap( PIXMAP_DIR "color-step-current.png" ), 0, 0, paletteForegroundColor() );
1265         _stepToDoColor          = pixelColor( QPixmap( PIXMAP_DIR "color-step-todo.png"    ), 0, 0, paletteForegroundColor() );
1266         _stepDoneColor          = pixelColor( QPixmap( PIXMAP_DIR "color-step-done.png"    ), 0, 0, paletteForegroundColor() );
1267     }
1268     else
1269     {
1270         _stepCurrentColor       = paletteForegroundColor();
1271         _stepToDoColor          = paletteForegroundColor();
1272         _stepDoneColor          = paletteForegroundColor();
1273     }
1274 }
1275
1276
1277
1278 void YQWizard::setGradient( QWidget * widget, const QPixmap & pixmap )
1279 {
1280 #if ENABLE_GRADIENTS
1281     if ( widget && ! pixmap.isNull() )
1282     {
1283         widget->setFixedHeight( pixmap.height() );
1284         widget->setPaletteBackgroundPixmap( pixmap );
1285     }
1286 #endif
1287 }
1288
1289
1290
1291 void YQWizard::setBottomCroppedGradient( QWidget * widget, const QPixmap & pixmap, int croppedHeight )
1292 {
1293 #if ENABLE_GRADIENTS
1294     setGradient( widget, bottomCropPixmap( pixmap, croppedHeight ) );
1295 #endif
1296 }
1297
1298
1299
1300 QPixmap YQWizard::bottomCropPixmap( const QPixmap & full, int croppedHeight )
1301 {
1302     QPixmap pixmap;
1303
1304 #if ENABLE_GRADIENTS
1305
1306     if ( full.height() > croppedHeight )
1307     {
1308         pixmap = QPixmap( full.width(), croppedHeight );
1309
1310         bitBlt( &pixmap, 0, 0,                                  // dest, dest_x, dest_y
1311                 &full,   0, full.height() - croppedHeight - 1,  // src, src_x, src_y
1312                 full.width(), croppedHeight );                  // src_width, src_height
1313     }
1314     else
1315     {
1316         pixmap = full;
1317     }
1318 #endif
1319
1320     return pixmap;
1321 }
1322
1323
1324
1325 QColor YQWizard::pixelColor( const QPixmap & pixmap, int x, int y, const QColor & defaultColor )
1326 {
1327     if ( pixmap.isNull() )
1328         return defaultColor;
1329
1330     // QPixmap doesn't allow direct access to pixel values (which makes some
1331     // sense since this requires a round-trip to the X server - pixmaps are X
1332     // server resources), so we need to convert the QPixmap to a QImage to get
1333     // that information. But since this conversion is expensive, we might save
1334     // some performance if we only convert the part we really need - so let's
1335     // cut out a tiny portion of the original pixmap and convert only that tiny
1336     // portion.
1337
1338
1339     QPixmap tiny( 1, 1 );
1340
1341     bitBlt( &tiny, 0, 0,        // dest, dest_x, dest_y
1342             &pixmap, x, y,      // src, src_x, src_y
1343             1, 1 );             // src_width, src_height
1344
1345     QImage image = tiny.convertToImage();
1346
1347
1348     return QColor( image.pixel( 0, 0 ) );
1349 }
1350
1351
1352
1353 void YQWizard::addGradientColumn( QWidget * parent, int width )
1354 {
1355     if ( ! parent )
1356         return;
1357
1358     Q3VBox * vbox = new Q3VBox( parent );
1359     YUI_CHECK_NEW( vbox );
1360
1361 #if ENABLE_GRADIENTS
1362     QWidget * topGradient = addHSpacing( vbox, width );
1363     YUI_CHECK_NEW( topGradient );
1364     setGradient( topGradient, _topGradientPixmap );
1365
1366     QWidget * centerStretch = new QWidget( vbox );
1367     YUI_CHECK_NEW( centerStretch );
1368     centerStretch->setPaletteBackgroundColor( _gradientCenterColor );
1369
1370
1371     QWidget * bottomGradient = new QWidget( vbox );
1372     YUI_CHECK_NEW( bottomGradient );
1373     setGradient( bottomGradient, _bottomGradientPixmap );
1374 #else
1375     vbox->setFixedWidth( width );
1376 #endif
1377
1378 }
1379
1380
1381 void YQWizard::destroyButtons()
1382 {
1383     if ( _backButton  )
1384     {
1385         delete _backButton;
1386         _backButton = 0;
1387     }
1388
1389     if ( _abortButton )
1390     {
1391         delete _abortButton;
1392         _abortButton = 0;
1393     }
1394
1395     if ( _nextButton  )
1396     {
1397         delete _nextButton;
1398         _nextButton = 0;
1399     }
1400 }
1401
1402
1403
1404 bool YQWizard::highColorDisplay() const
1405 {
1406     return depth() > 8;
1407 }
1408
1409
1410 void YQWizard::connectNotify ( const char * signal )
1411 {
1412     if ( QString( signal ).contains( "nextClicked()" ) )
1413     {
1414         y2debug( "nextClicked connected, no longer directly sending button events" );
1415         _sendButtonEvents = false;
1416     }
1417 }
1418
1419
1420 void YQWizard::disconnectNotify ( const char * signal )
1421 {
1422     if ( QString( signal ).contains( "nextClicked()" ) )
1423     {
1424         y2debug( "nextClicked disconnected, directly sending button events again" );
1425         _sendButtonEvents = true;
1426     }
1427 }
1428
1429
1430 void YQWizard::setDialogIcon( const string & iconName )
1431 {
1432     if ( _dialogIcon )
1433     {
1434         if ( ! iconName.empty() )
1435         {
1436             QPixmap icon( iconName.c_str() );
1437
1438             if ( icon.isNull() )
1439                 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
1440             else
1441             {
1442                 _dialogIcon->setPixmap( icon );
1443                 topLevelWidget()->setIcon( icon );
1444             }
1445         }
1446         else
1447         {
1448             _dialogIcon->clear();
1449             topLevelWidget()->setIcon( QPixmap() );
1450         }
1451     }
1452 }
1453
1454
1455 void YQWizard::setDialogHeading( const string & headingText )
1456 {
1457     if ( _dialogHeading )
1458     {
1459         if ( ! headingText.empty() )
1460             _dialogHeading->setText( fromUTF8( headingText ) );
1461         else
1462             _dialogHeading->clear();
1463     }
1464 }
1465
1466 string YQWizard::debugLabel()
1467 {
1468     if ( _dialogHeading )
1469     {
1470         QString label = _dialogHeading->text();
1471         label.simplifyWhiteSpace(); // Replace any embedded newline with a single blank
1472
1473         if ( ! label.isEmpty() )
1474         {
1475             label.prepend( "YQWizard \"" );
1476             label.append( "\"" );
1477
1478             return toUTF8( label );
1479         }
1480     }
1481
1482     return "untitled YQWizard";
1483 }
1484
1485 void YQWizard::setHelpText( const string & helpText )
1486 {
1487     if ( _helpBrowser )
1488     {
1489         if ( ! helpText.empty() )
1490         {
1491             QString qHelpText = fromUTF8( helpText );
1492             qHelpText.replace( "&product;", YQUI::ui()->productName() );
1493             _helpBrowser->setText( qHelpText );
1494         }
1495         else
1496             _helpBrowser->clear();
1497     }
1498 }
1499
1500
1501 void YQWizard::slotBackClicked()
1502 {
1503     emit backClicked();
1504
1505     if ( _sendButtonEvents )
1506         YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
1507
1508     _direction = YQWizard::Backward;
1509 }
1510
1511
1512 void YQWizard::slotAbortClicked()
1513 {
1514     emit abortClicked();
1515
1516     if ( _sendButtonEvents )
1517         YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
1518 }
1519
1520
1521 void YQWizard::slotNextClicked()
1522 {
1523     emit nextClicked();
1524
1525     if ( _sendButtonEvents )
1526         YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1527
1528     _direction = YQWizard::Forward;
1529 }
1530
1531
1532 void YQWizard::showHelp()
1533 {
1534     if ( _sideBar && _helpPanel )
1535     {
1536         _sideBar->raiseWidget( _helpPanel );
1537     }
1538 }
1539
1540
1541 void YQWizard::releaseNotesClicked()
1542 {
1543     YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1544
1545     if ( ! _releaseNotesButtonId.empty() )
1546     {
1547         y2milestone( "Release Notes button clicked" );
1548         sendEvent( _releaseNotesButtonId );
1549     }
1550 }
1551
1552
1553 void YQWizard::showSteps()
1554 {
1555     if ( _sideBar && _stepsPanel )
1556     {
1557         _sideBar->raiseWidget( _stepsPanel );
1558     }
1559 }
1560
1561
1562 void YQWizard::showTree()
1563 {
1564     if ( _sideBar && _treePanel )
1565     {
1566         _sideBar->raiseWidget( _treePanel );
1567     }
1568 }
1569
1570
1571
1572 void YQWizard::addMenu( const string & text,
1573                         const string & id )
1574 {
1575     if ( _menuBar )
1576     {
1577         Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1578         YUI_CHECK_NEW( menu );
1579
1580         _menuIDs.insert( fromUTF8( id ), menu );
1581         _menuBar->insertItem( fromUTF8( text ), menu );
1582
1583         connect( menu, SIGNAL( activated    ( int ) ),
1584                  this, SLOT  ( sendMenuEvent( int ) ) );
1585
1586         if ( _menuBarBox && _menuBarBox->isHidden() )
1587         {
1588             _menuBarBox->show();
1589             _menuBarBox->setFixedHeight( _menuBar->sizeHint().height() + MENU_BAR_MARGIN );
1590         }
1591     }
1592 }
1593
1594
1595 void YQWizard::addSubMenu( const string & parentMenuID,
1596                            const string & text,
1597                            const string & id )
1598 {
1599     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1600
1601     if ( parentMenu )
1602     {
1603         Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1604         YUI_CHECK_NEW( menu );
1605
1606         _menuIDs.insert( fromUTF8( id ), menu );
1607         parentMenu->insertItem( fromUTF8( text ), menu );
1608
1609         connect( menu, SIGNAL( activated    ( int ) ),
1610                  this, SLOT  ( sendMenuEvent( int ) ) );
1611     }
1612     else
1613     {
1614         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1615     }
1616 }
1617
1618
1619 void YQWizard::addMenuEntry( const string & parentMenuID,
1620                              const string & text,
1621                              const string & idString )
1622 {
1623     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1624
1625     if ( parentMenu )
1626     {
1627         int id = _menuEntryIDs.size();
1628         _menuEntryIDs.push_back( idString );
1629         parentMenu->insertItem( text, id );
1630     }
1631     else
1632     {
1633         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1634     }
1635 }
1636
1637
1638 void YQWizard::addMenuSeparator( const string & parentMenuID )
1639 {
1640     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1641
1642     if ( parentMenu )
1643     {
1644         parentMenu->insertSeparator();
1645     }
1646     else
1647     {
1648         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1649     }
1650 }
1651
1652
1653 void YQWizard::deleteMenus()
1654 {
1655     if ( _menuBar )
1656     {
1657         _menuBarBox->hide();
1658         _menuBar->clear();
1659         _menuIDs.clear();
1660         _menuEntryIDs.clear();
1661     }
1662 }
1663
1664
1665 void YQWizard::sendMenuEvent( int numID )
1666 {
1667     if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
1668     {
1669         sendEvent( toUTF8( _menuEntryIDs[ numID ] ) );
1670     }
1671     else
1672     {
1673         y2error( "Invalid menu ID: %d", numID );
1674     }
1675 }
1676
1677
1678 void YQWizard::sendEvent( const string & id )
1679 {
1680     YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1681 }
1682
1683
1684 int YQWizard::preferredWidth()
1685 {
1686     return sizeHint().width();
1687 }
1688
1689
1690 int YQWizard::preferredHeight()
1691 {
1692     return sizeHint().height();
1693 }
1694
1695
1696 void YQWizard::setSize( int newWidth, int newHeight )
1697 {
1698     resize( newWidth, newHeight );
1699     resizeClientArea();
1700 }
1701
1702
1703
1704 void YQWizard::resizeClientArea()
1705 {
1706     // y2debug( "resizing client area" );
1707     QRect contentsRect = _clientArea->contentsRect();
1708     _contents->setSize( contentsRect.width(), contentsRect.height() );
1709 }
1710
1711
1712
1713 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1714 {
1715     if ( ev->type() == QEvent::Resize && obj == _contents )
1716     {
1717         resizeClientArea();
1718         return true;            // Event handled
1719     }
1720
1721     return QWidget::eventFilter( obj, ev );
1722 }
1723
1724
1725 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1726 {
1727     button->setLabel( newLabel );
1728     YDialog::currentDialog()->checkShortcuts();
1729
1730     YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1731
1732     if ( wizardButton )
1733     {
1734         if ( newLabel.empty() )
1735         {
1736             wizardButton->hide();
1737
1738             if ( wizardButton == _backButton && _backButtonSpacer )
1739             {
1740                 // Minimize _backButtonSpacer
1741
1742                 _backButtonSpacer->changeSize( 0, 0,                            // width, height
1743                                                QSizePolicy::Minimum,            // horizontal
1744                                                QSizePolicy::Minimum );          // vertical
1745             }
1746         }
1747         else
1748         {
1749             wizardButton->show();
1750
1751             if ( button == _backButton && _backButtonSpacer )
1752             {
1753                 // Restore _backButtonSpacer to normal size
1754
1755                 _backButtonSpacer->changeSize( 0, 0,                            // width, height
1756                                                QSizePolicy::Expanding,          // horizontal
1757                                                QSizePolicy::Minimum );          // vertical
1758             }
1759         }
1760     }
1761 }
1762
1763
1764 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1765 {
1766     if ( ! _releaseNotesButton )
1767     {
1768         y2error( "NULL Release Notes button" );
1769
1770         if ( ! _stepsBox )
1771             y2error( "This works only if there is a \"steps\" panel!" );
1772
1773         return;
1774     }
1775
1776     // no way to check the shortcut, so strip it
1777     _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1778     _releaseNotesButtonId = id;
1779
1780     if ( _releaseNotesButton->isHidden() )
1781         _releaseNotesButton->show();
1782
1783 }
1784
1785
1786 void YQWizard::hideReleaseNotesButton()
1787 {
1788     if ( _releaseNotesButton && _releaseNotesButton->isShown() )
1789         _releaseNotesButton->hide();
1790 }
1791
1792
1793 void YQWizard::retranslateInternalButtons()
1794 {
1795     YQUI::setTextdomain( TEXTDOMAIN );
1796
1797     if ( _helpButton )
1798         // "Help" button - intentionally without keyboard shortcut
1799         _helpButton->setText( _( "Help" ) );
1800
1801     if ( _stepsButton )
1802         // "Steps" button - intentionally without keyboard shortcut
1803         _stepsButton->setText( _( "Steps" ) );
1804
1805     if ( _treeButton )
1806         // "Tree" button - intentionally without keyboard shortcut
1807         _treeButton->setText( _( "Tree" ) );
1808 }
1809
1810 #include "YQWizard.moc"