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