]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/YQWizard.cc
the ui compiles
[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() == fromUTF8( 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( fromUTF8( 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 = fromUTF8( 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     //FIXME
833 //     _tree->addColumn( "" );
834 //     _tree->header()->hide();
835
836     _tree->setRootIsDecorated( true );
837     _tree->setSortByInsertionSequence( true );
838
839     connect( _tree,     SIGNAL( selectionChanged     ( void ) ),
840              this,      SLOT  ( treeSelectionChanged ( void ) ) );
841
842     connect( _tree,     SIGNAL( spacePressed  ( QTreeWidgetItem * ) ),
843              this,      SLOT  ( sendTreeEvent ( QTreeWidgetItem * ) ) );
844
845     connect( _tree,     SIGNAL( doubleClicked ( QTreeWidgetItem * ) ),
846              this,      SLOT  ( sendTreeEvent ( QTreeWidgetItem * ) ) );
847
848
849     // Bottom gradient
850
851     QLabel * buttonBox = new QLabel( vbox );
852     YUI_CHECK_NEW( buttonBox );
853
854
855     // "Help" button - intentionally without keyboard shortcut
856     QPushButton * button = new QPushButton( _( "Help" ), buttonBox );
857     YUI_CHECK_NEW( button );
858
859 #if USE_ICON_ON_HELP_BUTTON
860     QPixmap pixmap( PIXMAP_DIR "help-button.png" );
861
862     if ( ! pixmap.isNull() )
863         button->setPixmap( pixmap );
864 #endif
865
866     layoutSideBarButtonBox( buttonBox, button );
867
868     connect( button, SIGNAL( clicked()  ),
869              this,   SLOT  ( showHelp() ) );
870
871
872     // Right margin (with gradients)
873     addGradientColumn( _treePanel );
874 }
875
876
877
878 void YQWizard::addTreeItem( const string & parentID, const string & text, const string & id )
879 {
880     QString qId = fromUTF8( id );
881
882     if ( ! _tree )
883     {
884         y2error( "YQWizard widget not created with `opt(`treeEnabled) !" );
885         return;
886     }
887
888     YQWizard::TreeItem * item   = 0;
889     YQWizard::TreeItem * parent = 0;
890
891     if ( ! parentID.empty() )
892     {
893         parent = findTreeItem( parentID );
894     }
895
896     if ( parent )
897     {
898         item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId );
899         YUI_CHECK_NEW( item );
900     }
901     else
902     {
903         item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId );
904         YUI_CHECK_NEW( item );
905     }
906
907     if ( ! qId.isEmpty() )
908         _treeIDs.insert( qId, item );
909 }
910
911
912
913 void YQWizard::deleteTreeItems()
914 {
915     if ( _tree )
916         _tree->clear();
917
918     _treeIDs.clear();
919 }
920
921
922
923 YQWizard::TreeItem * YQWizard::findTreeItem( const string & id )
924 {
925     if ( id.empty() )
926         return 0;
927
928     return _treeIDs[ fromUTF8( id ) ];
929 }
930
931
932 void YQWizard::selectTreeItem( const string & id )
933 {
934     if ( _tree )
935     {
936         YQWizard::TreeItem * item = findTreeItem( id );
937
938         if ( item )
939         {
940             YQSignalBlocker sigBlocker( _tree );
941
942       _tree->setCurrentItem(item);
943             _tree->scrollToItem(item);
944         }
945     }
946 }
947
948
949 void YQWizard::sendTreeEvent( QTreeWidgetItem * listViewItem )
950 {
951     if ( listViewItem )
952     {
953         YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem );
954
955         if ( item && ! item->id().isEmpty() )
956             sendEvent( toUTF8( item->id() ) );
957     }
958 }
959
960
961 void YQWizard::treeSelectionChanged()
962 { //FIXME is currentItem correct or selected.first
963     if ( _tree )
964         sendTreeEvent( _tree->currentItem() );
965 }
966
967
968 string YQWizard::currentTreeSelection()
969 {
970     if ( _tree )
971     {
972         QTreeWidgetItem * sel = _tree->currentItem();
973
974         if ( sel )
975         {
976             YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel);
977
978             if ( item && ! item->id().isEmpty() )
979                 return toUTF8( item->id() );
980         }
981     }
982
983     return string();
984 }
985
986
987
988 void YQWizard::layoutWorkArea( QFrame * parentHBox )
989 {
990     Q3VBox * workAreaVBox = new Q3VBox( parentHBox );
991     YUI_CHECK_NEW( workAreaVBox );
992
993     // An extra QVBox inside the workAreaVBox is needed for frame and margin
994
995     Q3VBox * workArea = new Q3VBox( workAreaVBox );
996     YUI_CHECK_NEW( workArea );
997
998 #if ENABLE_GRADIENTS
999     workArea->setFrameStyle( QFrame::Box | QFrame::Plain );
1000     workArea->setMargin( 4 );
1001 #else
1002     workArea->setFrameStyle( QFrame::Box | QFrame::Sunken );
1003     // workArea->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Sunken );
1004 #endif
1005
1006
1007     //
1008     // Menu bar
1009     //
1010
1011     // Placed directly inside workArea the menu bar positions itself at (0,0)
1012     // and so obscures any kind of frame there might be.
1013     _menuBarBox = new Q3VBox( workArea );
1014     YUI_CHECK_NEW( _menuBarBox );
1015
1016     _menuBar = new QMenuBar( _menuBarBox );
1017     YUI_CHECK_NEW( _menuBar );
1018
1019     _menuBarBox->hide(); // will be made visible when menus are added
1020
1021
1022     //
1023     // Dialog icon and heading
1024     //
1025
1026     Q3HBox * headingHBox = new Q3HBox( workArea );
1027     YUI_CHECK_NEW( headingHBox );
1028     headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1029
1030     addHSpacing( headingHBox, SEPARATOR_MARGIN );
1031
1032     _dialogIcon = new QLabel( headingHBox );
1033     YUI_CHECK_NEW( _dialogIcon );
1034     _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert
1035
1036     addHSpacing( headingHBox );
1037
1038     _dialogHeading = new QLabel( headingHBox );
1039     YUI_CHECK_NEW( _dialogHeading );
1040     _dialogHeading->setFont( YQUI::yqApp()->headingFont() );
1041     _dialogHeading->setAlignment( Qt::AlignLeft | Qt::WordBreak );
1042     _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1043
1044 #if 0
1045     addHStretch( headingHBox );
1046 #endif
1047     addVSpacing( workArea );
1048
1049 #if USE_SEPARATOR
1050
1051     Q3HBox * hbox = new Q3HBox( workArea );
1052
1053     addHSpacing( hbox, SEPARATOR_MARGIN );
1054
1055     QFrame * separator = new QFrame( hbox );
1056     YUI_CHECK_NEW( separator );
1057     separator->setFrameStyle( QFrame::HLine | QFrame::Sunken );
1058
1059     addHSpacing( hbox, SEPARATOR_MARGIN );
1060     addVSpacing( workArea );
1061 #endif
1062
1063     //
1064     // Client area (the part that belongs to the YCP application)
1065     //
1066
1067     layoutClientArea( workArea );
1068
1069
1070     //
1071     // Button box
1072     //
1073
1074     layoutButtonBox( workAreaVBox );
1075
1076
1077     //
1078     // Spacer (purely decorative) at the right of the client area
1079     //
1080
1081     addGradientColumn( parentHBox, WORK_AREA_RIGHT_MARGIN );
1082 }
1083
1084
1085
1086 void YQWizard::layoutClientArea( QWidget * parent )
1087 {
1088     _clientArea = new Q3VBox( parent );
1089     YUI_CHECK_NEW( _clientArea );
1090     _clientArea->setMargin( 4 );
1091
1092 #if 0
1093     _clientArea->setPaletteBackgroundColor( QColor( 0x60, 0x60, 0x60 ) );
1094 #endif
1095
1096
1097     //
1098     // HVCenter for wizard contents
1099     //
1100
1101     _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
1102     YUI_CHECK_NEW( _contents );
1103
1104     _contents->setStretchable( YD_HORIZ, true );
1105     _contents->setStretchable( YD_VERT,  true );
1106     _contents->installEventFilter( this );
1107     _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
1108
1109
1110     //
1111     // Replace point for wizard contents
1112     //
1113
1114     _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
1115
1116     //
1117     // Initial YEmpty widget contents of replace point
1118     //
1119
1120     YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
1121     _contentsReplacePoint->showChild();
1122 }
1123
1124
1125
1126 void YQWizard::layoutButtonBox( QWidget * parent )
1127 {
1128     //
1129     // Button box and layout
1130     //
1131
1132     QWidget * buttonBox = new QWidget( parent );
1133     YUI_CHECK_NEW( buttonBox );
1134
1135     // Using old-style layouts to enable a seamless background with the
1136     // gradient pixmap: Any sub-widgets (Q3VBox, QHBox) would have to get yet
1137     // another portion of that gradient as their backround pixmap, and it would
1138     // be very hard to cover all cases - resizing, hiding individual buttons, etc.
1139
1140     QVBoxLayout * vbox = new QVBoxLayout( buttonBox, 0, 0 );    // parent, margin, spacing
1141     YUI_CHECK_NEW( vbox );
1142
1143     vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
1144
1145
1146     //
1147     // QHBoxLayout for the buttons
1148     //
1149
1150     QHBoxLayout * hbox = new QHBoxLayout( vbox, 2 );            // parent, spacing
1151     YUI_CHECK_NEW( hbox );
1152
1153
1154     //
1155     // "Back" button
1156     //
1157
1158     _backButton  = new YQWizardButton( this, buttonBox, _backButtonLabel );
1159     YUI_CHECK_NEW( _backButton );
1160
1161     hbox->addWidget( (QWidget *) _backButton->widgetRep() );
1162     connect( _backButton,       SIGNAL( clicked()               ),
1163              this,              SLOT  ( slotBackClicked()       ) );
1164
1165     _backButtonSpacer = new QSpacerItem( 0, 0,                          // width, height
1166                                          QSizePolicy::Expanding,        // horizontal
1167                                          QSizePolicy::Minimum );        // vertical
1168     YUI_CHECK_NEW( _backButtonSpacer );
1169     hbox->addItem( _backButtonSpacer );
1170
1171
1172     if ( _backButton->text().isEmpty() )
1173     {
1174         _backButton->hide();
1175
1176         // Minimize _backButtonSpacer
1177         _backButtonSpacer->changeSize( 0, 0,                            // width, height
1178                                        QSizePolicy::Minimum,            // horizontal
1179                                        QSizePolicy::Minimum );          // vertical
1180     }
1181
1182
1183     //
1184     // "Abort" button
1185     //
1186
1187     _abortButton = new YQWizardButton( this, buttonBox, _abortButtonLabel );
1188     YUI_CHECK_NEW( _abortButton );
1189
1190     hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
1191     connect( _abortButton,      SIGNAL( clicked()               ),
1192              this,              SLOT  ( slotAbortClicked()      ) );
1193
1194
1195     // Using spacer rather than addSpacing() since the default stretchability
1196     // of a QSpacerItem is undefined, i.e. centering the middle button could
1197     // not be guaranteed.
1198
1199     QSpacerItem * spacer = new QSpacerItem( 0, 0,                       // width, height
1200                                             QSizePolicy::Expanding,     // horizontal
1201                                             QSizePolicy::Minimum );     // vertical
1202     YUI_CHECK_NEW( spacer );
1203     hbox->addItem( spacer );
1204
1205
1206     //
1207     // "Next" button
1208     //
1209
1210     _nextButton  = new YQWizardButton( this, buttonBox, _nextButtonLabel );
1211     YUI_CHECK_NEW( _nextButton );
1212
1213     hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
1214     connect( _nextButton,       SIGNAL( clicked()               ),
1215              this,              SLOT  ( slotNextClicked()       ) );
1216
1217
1218     //
1219     // Bottom margin and gradient
1220     //
1221
1222     vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
1223
1224 #if ENABLE_GRADIENTS
1225     setBottomCroppedGradient( buttonBox, _bottomGradientPixmap, buttonBox->sizeHint().height() );
1226 #endif
1227
1228     buttonBox->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); // hor/vert
1229 }
1230
1231
1232
1233 void YQWizard::loadGradientPixmaps()
1234 {
1235 #if ENABLE_GRADIENTS
1236     if ( highColorDisplay() )
1237     {
1238         _topGradientPixmap      = QPixmap( PIXMAP_DIR "top-gradient.png"        );
1239         _bottomGradientPixmap   = QPixmap( PIXMAP_DIR "bottom-gradient.png"     );
1240         _titleBarGradientPixmap = QPixmap( PIXMAP_DIR "title-bar-gradient.png"  );
1241         _gradientCenterColor    = pixelColor( _bottomGradientPixmap, 0, 0, paletteBackgroundColor() );
1242         _gradientTopColor       = pixelColor( _topGradientPixmap, 0, 0 , paletteBackgroundColor() );
1243     }
1244     else // 8 bit display or worse - don't use gradients
1245     {
1246         // Gradient pixmaps remain empty. The respecive widgets will retain the
1247         // default widget background (grey, depending on the widget theme).
1248
1249         // Use deault widget background (some shade of grey) for the center
1250         // stretchable part of the side bar.
1251         _gradientCenterColor = paletteBackgroundColor();
1252         _gradientTopColor = paletteBackgroundColor();
1253     }
1254 #endif
1255 }
1256
1257
1258 void YQWizard::loadStepsIcons()
1259 {
1260     _stepCurrentIcon    = YQIconPool::stepCurrent();
1261     _stepToDoIcon       = YQIconPool::stepToDo();
1262     _stepDoneIcon       = YQIconPool::stepDone();
1263
1264     if ( highColorDisplay() )
1265     {
1266         _stepCurrentColor       = pixelColor( QPixmap( PIXMAP_DIR "color-step-current.png" ), 0, 0, paletteForegroundColor() );
1267         _stepToDoColor          = pixelColor( QPixmap( PIXMAP_DIR "color-step-todo.png"    ), 0, 0, paletteForegroundColor() );
1268         _stepDoneColor          = pixelColor( QPixmap( PIXMAP_DIR "color-step-done.png"    ), 0, 0, paletteForegroundColor() );
1269     }
1270     else
1271     {
1272         _stepCurrentColor       = paletteForegroundColor();
1273         _stepToDoColor          = paletteForegroundColor();
1274         _stepDoneColor          = paletteForegroundColor();
1275     }
1276 }
1277
1278
1279
1280 void YQWizard::setGradient( QWidget * widget, const QPixmap & pixmap )
1281 {
1282 #if ENABLE_GRADIENTS
1283     if ( widget && ! pixmap.isNull() )
1284     {
1285         widget->setFixedHeight( pixmap.height() );
1286         widget->setPaletteBackgroundPixmap( pixmap );
1287     }
1288 #endif
1289 }
1290
1291
1292
1293 void YQWizard::setBottomCroppedGradient( QWidget * widget, const QPixmap & pixmap, int croppedHeight )
1294 {
1295 #if ENABLE_GRADIENTS
1296     setGradient( widget, bottomCropPixmap( pixmap, croppedHeight ) );
1297 #endif
1298 }
1299
1300
1301
1302 QPixmap YQWizard::bottomCropPixmap( const QPixmap & full, int croppedHeight )
1303 {
1304     QPixmap pixmap;
1305
1306 #if ENABLE_GRADIENTS
1307
1308     if ( full.height() > croppedHeight )
1309     {
1310         pixmap = QPixmap( full.width(), croppedHeight );
1311
1312         bitBlt( &pixmap, 0, 0,                                  // dest, dest_x, dest_y
1313                 &full,   0, full.height() - croppedHeight - 1,  // src, src_x, src_y
1314                 full.width(), croppedHeight );                  // src_width, src_height
1315     }
1316     else
1317     {
1318         pixmap = full;
1319     }
1320 #endif
1321
1322     return pixmap;
1323 }
1324
1325
1326
1327 QColor YQWizard::pixelColor( const QPixmap & pixmap, int x, int y, const QColor & defaultColor )
1328 {
1329     if ( pixmap.isNull() )
1330         return defaultColor;
1331
1332     // QPixmap doesn't allow direct access to pixel values (which makes some
1333     // sense since this requires a round-trip to the X server - pixmaps are X
1334     // server resources), so we need to convert the QPixmap to a QImage to get
1335     // that information. But since this conversion is expensive, we might save
1336     // some performance if we only convert the part we really need - so let's
1337     // cut out a tiny portion of the original pixmap and convert only that tiny
1338     // portion.
1339
1340
1341     QPixmap tiny( 1, 1 );
1342
1343     bitBlt( &tiny, 0, 0,        // dest, dest_x, dest_y
1344             &pixmap, x, y,      // src, src_x, src_y
1345             1, 1 );             // src_width, src_height
1346
1347     QImage image = tiny.convertToImage();
1348
1349
1350     return QColor( image.pixel( 0, 0 ) );
1351 }
1352
1353
1354
1355 void YQWizard::addGradientColumn( QWidget * parent, int width )
1356 {
1357     if ( ! parent )
1358         return;
1359
1360     Q3VBox * vbox = new Q3VBox( parent );
1361     YUI_CHECK_NEW( vbox );
1362
1363 #if ENABLE_GRADIENTS
1364     QWidget * topGradient = addHSpacing( vbox, width );
1365     YUI_CHECK_NEW( topGradient );
1366     setGradient( topGradient, _topGradientPixmap );
1367
1368     QWidget * centerStretch = new QWidget( vbox );
1369     YUI_CHECK_NEW( centerStretch );
1370     centerStretch->setPaletteBackgroundColor( _gradientCenterColor );
1371
1372
1373     QWidget * bottomGradient = new QWidget( vbox );
1374     YUI_CHECK_NEW( bottomGradient );
1375     setGradient( bottomGradient, _bottomGradientPixmap );
1376 #else
1377     vbox->setFixedWidth( width );
1378 #endif
1379
1380 }
1381
1382
1383 void YQWizard::destroyButtons()
1384 {
1385     if ( _backButton  )
1386     {
1387         delete _backButton;
1388         _backButton = 0;
1389     }
1390
1391     if ( _abortButton )
1392     {
1393         delete _abortButton;
1394         _abortButton = 0;
1395     }
1396
1397     if ( _nextButton  )
1398     {
1399         delete _nextButton;
1400         _nextButton = 0;
1401     }
1402 }
1403
1404
1405
1406 bool YQWizard::highColorDisplay() const
1407 {
1408     return depth() > 8;
1409 }
1410
1411
1412 void YQWizard::connectNotify ( const char * signal )
1413 {
1414     if ( QString( signal ).contains( "nextClicked()" ) )
1415     {
1416         y2debug( "nextClicked connected, no longer directly sending button events" );
1417         _sendButtonEvents = false;
1418     }
1419 }
1420
1421
1422 void YQWizard::disconnectNotify ( const char * signal )
1423 {
1424     if ( QString( signal ).contains( "nextClicked()" ) )
1425     {
1426         y2debug( "nextClicked disconnected, directly sending button events again" );
1427         _sendButtonEvents = true;
1428     }
1429 }
1430
1431
1432 void YQWizard::setDialogIcon( const string & iconName )
1433 {
1434     if ( _dialogIcon )
1435     {
1436         if ( ! iconName.empty() )
1437         {
1438             QPixmap icon( iconName.c_str() );
1439
1440             if ( icon.isNull() )
1441                 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
1442             else
1443             {
1444                 _dialogIcon->setPixmap( icon );
1445                 topLevelWidget()->setIcon( icon );
1446             }
1447         }
1448         else
1449         {
1450             _dialogIcon->clear();
1451             topLevelWidget()->setIcon( QPixmap() );
1452         }
1453     }
1454 }
1455
1456
1457 void YQWizard::setDialogHeading( const string & headingText )
1458 {
1459     if ( _dialogHeading )
1460     {
1461         if ( ! headingText.empty() )
1462             _dialogHeading->setText( fromUTF8( headingText ) );
1463         else
1464             _dialogHeading->clear();
1465     }
1466 }
1467
1468 string YQWizard::debugLabel()
1469 {
1470     if ( _dialogHeading )
1471     {
1472         QString label = _dialogHeading->text();
1473         label.simplifyWhiteSpace(); // Replace any embedded newline with a single blank
1474
1475         if ( ! label.isEmpty() )
1476         {
1477             label.prepend( "YQWizard \"" );
1478             label.append( "\"" );
1479
1480             return toUTF8( label );
1481         }
1482     }
1483
1484     return "untitled YQWizard";
1485 }
1486
1487 void YQWizard::setHelpText( const string & helpText )
1488 {
1489     if ( _helpBrowser )
1490     {
1491         if ( ! helpText.empty() )
1492         {
1493             QString qHelpText = fromUTF8( helpText );
1494             qHelpText.replace( "&product;", YQUI::ui()->productName() );
1495             _helpBrowser->setText( qHelpText );
1496         }
1497         else
1498             _helpBrowser->clear();
1499     }
1500 }
1501
1502
1503 void YQWizard::slotBackClicked()
1504 {
1505     emit backClicked();
1506
1507     if ( _sendButtonEvents )
1508         YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
1509
1510     _direction = YQWizard::Backward;
1511 }
1512
1513
1514 void YQWizard::slotAbortClicked()
1515 {
1516     emit abortClicked();
1517
1518     if ( _sendButtonEvents )
1519         YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
1520 }
1521
1522
1523 void YQWizard::slotNextClicked()
1524 {
1525     emit nextClicked();
1526
1527     if ( _sendButtonEvents )
1528         YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1529
1530     _direction = YQWizard::Forward;
1531 }
1532
1533
1534 void YQWizard::showHelp()
1535 {
1536     if ( _sideBar && _helpPanel )
1537     {
1538         _sideBar->raiseWidget( _helpPanel );
1539     }
1540 }
1541
1542
1543 void YQWizard::releaseNotesClicked()
1544 {
1545     YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1546
1547     if ( ! _releaseNotesButtonId.empty() )
1548     {
1549         y2milestone( "Release Notes button clicked" );
1550         sendEvent( _releaseNotesButtonId );
1551     }
1552 }
1553
1554
1555 void YQWizard::showSteps()
1556 {
1557     if ( _sideBar && _stepsPanel )
1558     {
1559         _sideBar->raiseWidget( _stepsPanel );
1560     }
1561 }
1562
1563
1564 void YQWizard::showTree()
1565 {
1566     if ( _sideBar && _treePanel )
1567     {
1568         _sideBar->raiseWidget( _treePanel );
1569     }
1570 }
1571
1572
1573
1574 void YQWizard::addMenu( const string & text,
1575                         const string & id )
1576 {
1577     if ( _menuBar )
1578     {
1579         Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1580         YUI_CHECK_NEW( menu );
1581
1582         _menuIDs.insert( fromUTF8( id ), menu );
1583         _menuBar->insertItem( fromUTF8( text ), menu );
1584
1585         connect( menu, SIGNAL( activated    ( int ) ),
1586                  this, SLOT  ( sendMenuEvent( int ) ) );
1587
1588         if ( _menuBarBox && _menuBarBox->isHidden() )
1589         {
1590             _menuBarBox->show();
1591             _menuBarBox->setFixedHeight( _menuBar->sizeHint().height() + MENU_BAR_MARGIN );
1592         }
1593     }
1594 }
1595
1596
1597 void YQWizard::addSubMenu( const string & parentMenuID,
1598                            const string & text,
1599                            const string & id )
1600 {
1601     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1602
1603     if ( parentMenu )
1604     {
1605         Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1606         YUI_CHECK_NEW( menu );
1607
1608         _menuIDs.insert( fromUTF8( id ), menu );
1609         parentMenu->insertItem( fromUTF8( text ), menu );
1610
1611         connect( menu, SIGNAL( activated    ( int ) ),
1612                  this, SLOT  ( sendMenuEvent( int ) ) );
1613     }
1614     else
1615     {
1616         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1617     }
1618 }
1619
1620
1621 void YQWizard::addMenuEntry( const string & parentMenuID,
1622                              const string & text,
1623                              const string & idString )
1624 {
1625     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1626
1627     if ( parentMenu )
1628     {
1629         int id = _menuEntryIDs.size();
1630         _menuEntryIDs.push_back( idString );
1631         parentMenu->insertItem( fromUTF8( text ), id );
1632     }
1633     else
1634     {
1635         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1636     }
1637 }
1638
1639
1640 void YQWizard::addMenuSeparator( const string & parentMenuID )
1641 {
1642     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1643
1644     if ( parentMenu )
1645     {
1646         parentMenu->insertSeparator();
1647     }
1648     else
1649     {
1650         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1651     }
1652 }
1653
1654
1655 void YQWizard::deleteMenus()
1656 {
1657     if ( _menuBar )
1658     {
1659         _menuBarBox->hide();
1660         _menuBar->clear();
1661         _menuIDs.clear();
1662         _menuEntryIDs.clear();
1663     }
1664 }
1665
1666
1667 void YQWizard::sendMenuEvent( int numID )
1668 {
1669     if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
1670     {
1671         sendEvent( _menuEntryIDs[ numID ] );
1672     }
1673     else
1674     {
1675         y2error( "Invalid menu ID: %d", numID );
1676     }
1677 }
1678
1679
1680 void YQWizard::sendEvent( const string & id )
1681 {
1682     YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1683 }
1684
1685
1686 int YQWizard::preferredWidth()
1687 {
1688     return sizeHint().width();
1689 }
1690
1691
1692 int YQWizard::preferredHeight()
1693 {
1694     return sizeHint().height();
1695 }
1696
1697
1698 void YQWizard::setSize( int newWidth, int newHeight )
1699 {
1700     resize( newWidth, newHeight );
1701     resizeClientArea();
1702 }
1703
1704
1705
1706 void YQWizard::resizeClientArea()
1707 {
1708     // y2debug( "resizing client area" );
1709     QRect contentsRect = _clientArea->contentsRect();
1710     _contents->setSize( contentsRect.width(), contentsRect.height() );
1711 }
1712
1713
1714
1715 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1716 {
1717     if ( ev->type() == QEvent::Resize && obj == _contents )
1718     {
1719         resizeClientArea();
1720         return true;            // Event handled
1721     }
1722
1723     return QWidget::eventFilter( obj, ev );
1724 }
1725
1726
1727 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1728 {
1729     button->setLabel( newLabel );
1730     YDialog::currentDialog()->checkShortcuts();
1731
1732     YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1733
1734     if ( wizardButton )
1735     {
1736         if ( newLabel.empty() )
1737         {
1738             wizardButton->hide();
1739
1740             if ( wizardButton == _backButton && _backButtonSpacer )
1741             {
1742                 // Minimize _backButtonSpacer
1743
1744                 _backButtonSpacer->changeSize( 0, 0,                            // width, height
1745                                                QSizePolicy::Minimum,            // horizontal
1746                                                QSizePolicy::Minimum );          // vertical
1747             }
1748         }
1749         else
1750         {
1751             wizardButton->show();
1752
1753             if ( button == _backButton && _backButtonSpacer )
1754             {
1755                 // Restore _backButtonSpacer to normal size
1756
1757                 _backButtonSpacer->changeSize( 0, 0,                            // width, height
1758                                                QSizePolicy::Expanding,          // horizontal
1759                                                QSizePolicy::Minimum );          // vertical
1760             }
1761         }
1762     }
1763 }
1764
1765
1766 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1767 {
1768     if ( ! _releaseNotesButton )
1769     {
1770         y2error( "NULL Release Notes button" );
1771
1772         if ( ! _stepsBox )
1773             y2error( "This works only if there is a \"steps\" panel!" );
1774
1775         return;
1776     }
1777
1778     // no way to check the shortcut, so strip it
1779     _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1780     _releaseNotesButtonId = id;
1781
1782     if ( _releaseNotesButton->isHidden() )
1783         _releaseNotesButton->show();
1784
1785 }
1786
1787
1788 void YQWizard::hideReleaseNotesButton()
1789 {
1790     if ( _releaseNotesButton && _releaseNotesButton->isShown() )
1791         _releaseNotesButton->hide();
1792 }
1793
1794
1795 void YQWizard::retranslateInternalButtons()
1796 {
1797     YQUI::setTextdomain( TEXTDOMAIN );
1798
1799     if ( _helpButton )
1800         // "Help" button - intentionally without keyboard shortcut
1801         _helpButton->setText( _( "Help" ) );
1802
1803     if ( _stepsButton )
1804         // "Steps" button - intentionally without keyboard shortcut
1805         _stepsButton->setText( _( "Steps" ) );
1806
1807     if ( _treeButton )
1808         // "Tree" button - intentionally without keyboard shortcut
1809         _treeButton->setText( _( "Tree" ) );
1810 }
1811
1812 #include "YQWizard.moc"