]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/YQWizard.cc
merge in changes from wizard-rework. Still work in progress,
[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 <QDialog>
33 #include <QSvgRenderer>
34 #include <QPainter>
35 #include <QStackedWidget>
36 #include "ui_QHelpDialog.h"
37 #include <q3hbox.h>
38 #include <q3header.h>
39 #include <qimage.h>
40 #include <qlabel.h>
41 #include <qlayout.h>
42 #include <qmenubar.h>
43 #include <qmenudata.h>
44 #include <qobject.h>
45 #include <qpixmap.h>
46 #include <q3popupmenu.h>
47 #include <qpushbutton.h>
48 #include <qregexp.h>
49 #include <qtabwidget.h>
50 #include <q3textbrowser.h>
51 #include <qtoolbutton.h>
52 #include <q3widgetstack.h>
53
54 #include "QY2ListView.h"
55 //Added by qt3to4:
56 #include <q3boxlayout.h>
57 #include <QGridLayout>
58 #include <q3frame.h>
59 #include <qevent.h>
60 #include <q3boxlayout.h>
61
62 #include "utf8.h"
63 #include "YQi18n.h"
64 #include "YQUI.h"
65 #include "YQApplication.h"
66 #include "YQDialog.h"
67 #include "YQAlignment.h"
68 #include "YQReplacePoint.h"
69 #include "YQEmpty.h"
70 #include "YQLabel.h"
71 #include "YQWizardButton.h"
72 #include "YQIconPool.h"
73 #include "YQWidgetFactory.h"
74 #include "YQSignalBlocker.h"
75 #include "QY2LayoutUtils.h"
76 #include "YEvent.h"
77
78 using std::string;
79
80
81 #define PIXMAP_DIR THEMEDIR "/wizard/"
82
83 #ifdef TEXTDOMAIN
84 #    undef TEXTDOMAIN
85 #endif
86
87 #define TEXTDOMAIN "packages-qt"
88
89 #define USE_ICON_ON_HELP_BUTTON         0
90
91
92 YQWizard::YQWizard( YWidget *           parent,
93                     const string &      backButtonLabel,
94                     const string &      abortButtonLabel,
95                     const string &      nextButtonLabel,
96                     YWizardMode         wizardMode )
97     : QFrame( (QWidget *) parent->widgetRep() )
98     , YWizard( parent,
99                backButtonLabel,
100                abortButtonLabel,
101                nextButtonLabel,
102                wizardMode )
103     , _backButtonLabel( backButtonLabel )
104     , _abortButtonLabel( abortButtonLabel )
105     , _nextButtonLabel( nextButtonLabel )
106 {
107     QHBoxLayout* layout = new QHBoxLayout( this );
108     layout->setSpacing( 0 );
109     layout->setMargin( 0 );
110
111     setWidgetRep( this );
112
113     _stepsEnabled = (wizardMode == YWizardMode_Steps);
114     _treeEnabled  = (wizardMode == YWizardMode_Tree);
115
116     _stepsDirty         = false;
117     _direction          = YQWizard::Forward;
118
119     _sideBar            = 0;
120     _stepsPanel         = 0;
121     _helpButton         = 0;
122     _stepsButton        = 0;
123     _treeButton         = 0;
124     _releaseNotesButton = 0;
125     _treePanel          = 0;
126     _tree               = 0;
127     _clientArea         = 0;
128     _menuBar            = 0;
129     _dialogIcon         = 0;
130     _dialogHeading      = 0;
131     _contents           = 0;
132     _backButton         = 0;
133     _abortButton        = 0;
134     _nextButton         = 0;
135     _sendButtonEvents   = true;
136     _contentsReplacePoint = 0;
137
138     _stepsList.setAutoDelete( true );
139     _stepsIDs.setAutoDelete( false );   // Only for one of both!
140
141     YQUI::setTextdomain( TEXTDOMAIN );
142
143     //layoutTitleBar( this );
144
145     layout->addLayout( layoutSideBar( this ) );
146     layout->addWidget( layoutWorkArea( this ) );
147 }
148
149
150
151 YQWizard::~YQWizard()
152 {
153     deleteSteps();
154 }
155
156
157
158 void YQWizard::layoutTitleBar( QWidget * parent )
159 {
160     Q3HBox * titleBar = new Q3HBox( parent );
161     YUI_CHECK_NEW( titleBar );
162
163     titleBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); // hor/vert
164
165     //
166     // Left logo
167     //
168
169     QLabel * left = new QLabel( titleBar );
170     left->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
171
172     QPixmap leftLogo( PIXMAP_DIR "title-bar-left.png" );
173
174     if ( ! leftLogo.isNull() )
175     {
176         left->setPixmap( leftLogo );
177         left->setFixedSize( leftLogo.size() );
178         left->setBackgroundOrigin( QWidget::ParentOrigin );
179     }
180
181
182     //
183     // Center stretch space
184     //
185
186     addHStretch( titleBar );
187
188
189     //
190     // Right logo
191     //
192
193     QLabel * right = new QLabel( titleBar );
194     YUI_CHECK_NEW( right );
195
196     QPixmap rightLogo( PIXMAP_DIR "title-bar-right.png" );
197
198     if ( ! rightLogo.isNull() )
199     {
200         right->setPixmap( rightLogo );
201         right->setFixedSize( rightLogo.size() );
202         right->setBackgroundOrigin( QWidget::ParentOrigin );
203     }
204 }
205
206
207
208 QLayout *YQWizard::layoutSideBar( QWidget * parent )
209 {
210     _sideBar = new QStackedWidget( parent );
211     YUI_CHECK_NEW( _sideBar );
212     _sideBar->setMinimumWidth( YQUI::ui()->defaultSize( YD_HORIZ ) / 5 );
213     _sideBar->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ) ); // hor/vert
214
215     QVBoxLayout *vbox = new QVBoxLayout( );
216     vbox->addWidget( _sideBar );
217
218     layoutHelpPanel();
219
220     if ( _treeEnabled )
221     {
222         layoutTreePanel();
223         showTree();
224     }
225     else if ( _stepsEnabled )
226     {
227         layoutStepsPanel();
228         showSteps();
229     }
230
231     return vbox;
232 }
233
234 void YQWizard::layoutStepsPanel()
235 {
236     // Steps
237     _stepsPanel = new QFrame( _sideBar );
238     _sideBar->addWidget( _stepsPanel );
239     _sideBar->setObjectName( "steps" );
240     _stepsPanel->setProperty( "class", "steps QFrame" );
241
242     // Steps panel bottom buttons ("Help", "Release Notes")
243
244     // Layouts for the buttons
245
246     _releaseNotesButton = new QPushButton( _( "Release Notes..." ), _stepsPanel );
247     _releaseNotesButton->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum ) ); // hor/vert
248
249     connect( _releaseNotesButton,       SIGNAL( clicked()  ),
250              this,                      SLOT  ( releaseNotesClicked() ) );
251
252     _releaseNotesButton->hide();        // hidden until showReleaseNotesButton() is called
253
254     _stepsDirty = true; // no layout yet
255 }
256
257
258
259 void YQWizard::addStep( const string & text, const string & id )
260 {
261     QString qId = fromUTF8( id );
262
263     if ( _stepsIDs[ qId ] )
264     {
265         y2error( "Step ID \"%s\" (\"%s\") already used for \"%s\"",
266                  id.c_str(),
267                  text.c_str(),
268                  (const char *) _stepsIDs[ qId ]->name() );
269         return;
270     }
271
272     if ( _stepsList.last() && _stepsList.last()->name() == fromUTF8( text ) )
273     {
274         // Consecutive steps with the same name will be shown as one single step.
275         //
276         // Since steps are always added at the end of the list, it is
277         // sufficient to check the last step of the list. If the texts are the
278         // same, the other with the same text needs to get another (additional)
279         // ID to make sure setCurrentStep() works as it should.
280         _stepsList.last()->addID( qId );
281     }
282     else
283     {
284         _stepsList.append( new YQWizard::Step( fromUTF8( text ), qId ) );
285         _stepsDirty = true;
286     }
287
288     _stepsIDs.insert( qId, _stepsList.last() );
289 }
290
291
292
293 void YQWizard::addStepHeading( const string & text )
294 {
295     _stepsList.append( new YQWizard::StepHeading( fromUTF8( text ) ) );
296     _stepsDirty = true;
297 }
298
299
300
301 void YQWizard::updateSteps()
302 {
303     if ( ! _stepsPanel )
304         return;
305
306     // Create a grid layout for the steps
307     QVBoxLayout *_stepsVBox = new QVBoxLayout( _stepsPanel );
308
309     QGridLayout *_stepsGrid = new QGridLayout( );
310     YUI_CHECK_NEW( _stepsGrid );
311     _stepsVBox->addLayout( _stepsGrid );
312     _stepsGrid->setColumnMinimumWidth( 0, 10 );
313     _stepsGrid->setRowStretch( 0, 1 );
314     _stepsGrid->setRowStretch( 1, 1 );
315     _stepsGrid->setRowStretch( 2, 99 );
316
317     const int statusCol = 1;
318     const int nameCol   = 2;
319
320     int row = 0;
321
322     //
323     // Create widgets for all steps and step headings in the internal list
324     //
325
326     YQWizard::Step * step = _stepsList.first();
327
328     while ( step )
329     {
330         if ( step->isHeading() )
331         {
332             //
333             // Heading
334             //
335
336             QLabel * label = new QLabel( step->name(), _stepsPanel );
337             YUI_CHECK_NEW( label );
338             label->setAlignment( Qt::AlignLeft | Qt::AlignTop );
339             label->setProperty( "class", "steps_heading" );
340
341             step->setNameLabel( label );
342             _stepsGrid->addMultiCellWidget( label,
343                                             row, row,                   // from_row, to_row
344                                             statusCol, nameCol );       // from_col, to_col
345         }
346         else    // No heading - ordinary step
347         {
348             //
349             // Step status
350             //
351
352             QLabel * statusLabel = new QLabel( _stepsPanel );
353             YUI_CHECK_NEW( statusLabel );
354
355             step->setStatusLabel( statusLabel );
356             statusLabel->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
357             _stepsGrid->addWidget( statusLabel, row, statusCol );
358
359             //
360             // Step name
361             //
362
363             QLabel * nameLabel = new QLabel( step->name(), _stepsPanel );
364             YUI_CHECK_NEW( nameLabel );
365             nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop );
366
367             step->setNameLabel( nameLabel );
368             _stepsGrid->addWidget( nameLabel, row, nameCol );
369         }
370
371         step = _stepsList.next();
372         row++;
373     }
374
375     _stepsVBox->addStretch( 99 );
376     QVBoxLayout *rbl = new QVBoxLayout();
377     rbl->addWidget( _releaseNotesButton, 0, Qt::AlignCenter );
378
379     _stepsVBox->addLayout( rbl );
380     _stepsVBox->addStretch( 29 );
381
382     _stepsDirty = false;
383 }
384
385
386 void YQWizard::updateStepStates()
387 {
388     if ( _stepsDirty )
389         updateSteps();
390
391     YQWizard::Step * currentStep = findStep( _currentStepID );
392     YQWizard::Step * step = _stepsList.first();
393
394     if ( currentStep )
395     {
396         // Set status icon and color for the current step
397         currentStep->setStatus( Step::Current );
398
399         //
400         // Set all steps before the current to "done"
401         //
402
403         while ( step && step != currentStep )
404         {
405             step->setStatus( Step::Done );
406             step = _stepsList.next();
407         }
408
409         // Skip the current step - continue with the step after it
410
411         if ( step )
412             step = _stepsList.next();
413     }
414
415     //
416     // Set all steps after the current to "to do"
417     //
418
419     while ( step )
420     {
421         step->setStatus( Step::Todo );
422         step = _stepsList.next();
423     }
424 }
425
426 void YQWizard::setCurrentStep( const string & id )
427 {
428     _currentStepID = fromUTF8( id );
429     updateStepStates();
430 }
431
432
433 void YQWizard::deleteSteps()
434 {
435     _stepsList.clear();
436     _stepsIDs.clear();
437 }
438
439
440 YQWizard::Step * YQWizard::findStep( const QString & id )
441 {
442     if ( id.isEmpty() )
443         return 0;
444
445     return _stepsIDs[ id ];
446 }
447
448
449 void YQWizard::layoutHelpPanel()
450 {
451     return;
452
453     //
454     // Button box with bottom gradient
455     //
456
457     QLabel * buttonBox = new QLabel( _sideBar );
458     YUI_CHECK_NEW( buttonBox );
459
460     QPushButton * button;
461     QPixmap pixmap;
462
463     if ( _treeEnabled )
464     {
465         // "Tree" button - intentionally without keyboard shortcut
466         button = new QPushButton( _( "Tree" ), buttonBox );
467         YUI_CHECK_NEW( button );
468         _treeButton = button;
469
470         pixmap = QPixmap( PIXMAP_DIR "tree-button.png" );
471     }
472     else
473         if ( _stepsEnabled )
474     {
475         // "Steps" button - intentionally without keyboard shortcut
476         button = new QPushButton( _( "Steps" ), buttonBox );
477         YUI_CHECK_NEW( button );
478         _stepsButton = button;
479         _stepsButton->hide();
480
481         pixmap = QPixmap( PIXMAP_DIR "steps-button.png" );
482     }
483     else
484     {
485         // Create a dummy button just to find out how high it would become
486         button = new QPushButton( "Dummy", buttonBox );
487         YUI_CHECK_NEW( button );
488     }
489
490
491 #if USE_ICON_ON_HELP_BUTTON
492     if ( ! pixmap.isNull() )
493         button->setPixmap( pixmap );
494 #endif
495
496     layoutSideBarButtonBox( buttonBox, button );
497
498     if ( _treeEnabled )
499     {
500         connect( button, SIGNAL( clicked()  ),
501                  this,   SLOT  ( showTree() ) );
502     }
503     else if ( _stepsEnabled )
504     {
505         connect( button, SIGNAL( clicked()   ),
506                  this,   SLOT  ( showSteps() ) );
507     }
508     else
509     {
510         // Hide the dummy button - the button box height is fixed now.
511         button->hide();
512     }
513 }
514
515
516
517 void YQWizard::layoutSideBarButtonBox( QWidget * parent, QPushButton * button )
518 {
519     QVBoxLayout * vbox = new QVBoxLayout( parent, 0, 0 );       // parent, margin, spacing
520     YUI_CHECK_NEW( vbox );
521
522     QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 );            // parent, spacing
523     YUI_CHECK_NEW( hbox );
524
525     hbox->addStretch( 99 );
526     hbox->addWidget( button );
527     hbox->addStretch( 99 );
528 }
529
530
531
532 void YQWizard::layoutTreePanel()
533 {
534     _treePanel = new Q3HBox( _sideBar );
535     YUI_CHECK_NEW( _treePanel );
536     _sideBar->addWidget( _treePanel );
537
538     Q3VBox * vbox = new Q3VBox( _treePanel );
539     YUI_CHECK_NEW( vbox );
540
541
542     // Selection tree
543
544     _tree = new QY2ListView( vbox );
545     YUI_CHECK_NEW( _tree );
546
547     //FIXME
548 //     _tree->addColumn( "" );
549 //     _tree->header()->hide();
550
551     _tree->setRootIsDecorated( true );
552     _tree->setSortByInsertionSequence( true );
553
554     connect( _tree,     SIGNAL( selectionChanged     ( void ) ),
555              this,      SLOT  ( treeSelectionChanged ( void ) ) );
556
557     connect( _tree,     SIGNAL( spacePressed  ( QTreeWidgetItem * ) ),
558              this,      SLOT  ( sendTreeEvent ( QTreeWidgetItem * ) ) );
559
560     connect( _tree,     SIGNAL( doubleClicked ( QTreeWidgetItem * ) ),
561              this,      SLOT  ( sendTreeEvent ( QTreeWidgetItem * ) ) );
562
563
564     // Bottom gradient
565
566     QLabel * buttonBox = new QLabel( vbox );
567     YUI_CHECK_NEW( buttonBox );
568
569
570     // "Help" button - intentionally without keyboard shortcut
571     QPushButton * button = new QPushButton( _( "Help" ), buttonBox );
572     YUI_CHECK_NEW( button );
573
574 #if USE_ICON_ON_HELP_BUTTON
575     QPixmap pixmap( PIXMAP_DIR "help-button.png" );
576
577     if ( ! pixmap.isNull() )
578         button->setPixmap( pixmap );
579 #endif
580
581     layoutSideBarButtonBox( buttonBox, button );
582
583     connect( button, SIGNAL( clicked()  ),
584              this,   SLOT  ( showHelp() ) );
585
586 }
587
588
589
590 void YQWizard::addTreeItem( const string & parentID, const string & text, const string & id )
591 {
592     QString qId = fromUTF8( id );
593
594     if ( ! _tree )
595     {
596         y2error( "YQWizard widget not created with `opt(`treeEnabled) !" );
597         return;
598     }
599
600     YQWizard::TreeItem * item   = 0;
601     YQWizard::TreeItem * parent = 0;
602
603     if ( ! parentID.empty() )
604     {
605         parent = findTreeItem( parentID );
606     }
607
608     if ( parent )
609     {
610         item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId );
611         YUI_CHECK_NEW( item );
612     }
613     else
614     {
615         item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId );
616         YUI_CHECK_NEW( item );
617     }
618
619     if ( ! qId.isEmpty() )
620         _treeIDs.insert( qId, item );
621 }
622
623
624
625 void YQWizard::deleteTreeItems()
626 {
627     if ( _tree )
628         _tree->clear();
629
630     _treeIDs.clear();
631 }
632
633
634
635 YQWizard::TreeItem * YQWizard::findTreeItem( const string & id )
636 {
637     if ( id.empty() )
638         return 0;
639
640     return _treeIDs[ fromUTF8( id ) ];
641 }
642
643
644 void YQWizard::selectTreeItem( const string & id )
645 {
646     if ( _tree )
647     {
648         YQWizard::TreeItem * item = findTreeItem( id );
649
650         if ( item )
651         {
652             YQSignalBlocker sigBlocker( _tree );
653
654       _tree->setCurrentItem(item);
655             _tree->scrollToItem(item);
656         }
657     }
658 }
659
660
661 void YQWizard::sendTreeEvent( QTreeWidgetItem * listViewItem )
662 {
663     if ( listViewItem )
664     {
665         YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem );
666
667         if ( item && ! item->id().isEmpty() )
668             sendEvent( toUTF8( item->id() ) );
669     }
670 }
671
672
673 void YQWizard::treeSelectionChanged()
674 { //FIXME is currentItem correct or selected.first
675     if ( _tree )
676         sendTreeEvent( _tree->currentItem() );
677 }
678
679
680 string YQWizard::currentTreeSelection()
681 {
682     if ( _tree )
683     {
684         QTreeWidgetItem * sel = _tree->currentItem();
685
686         if ( sel )
687         {
688             YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel);
689
690             if ( item && ! item->id().isEmpty() )
691                 return toUTF8( item->id() );
692         }
693     }
694
695     return string();
696 }
697
698
699
700 QWidget *YQWizard::layoutWorkArea( QWidget * parent )
701 {
702     QFrame *workArea = new QFrame( parent );
703     workArea->setObjectName( "work_area" );
704
705     QVBoxLayout *vbox = new QVBoxLayout( workArea );
706
707     _menuBar = new QMenuBar( workArea );
708     YUI_CHECK_NEW( _menuBar );
709
710     _menuBar->hide(); // will be made visible when menus are added
711     vbox->addWidget( _menuBar );
712
713     //
714     // Dialog icon and heading
715     //
716
717     QHBoxLayout * headingHBox = new QHBoxLayout();
718     YUI_CHECK_NEW( headingHBox );
719     //headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
720     vbox->addLayout( headingHBox );
721
722     _dialogIcon = new QLabel( workArea );
723     YUI_CHECK_NEW( _dialogIcon );
724     headingHBox->addWidget( _dialogIcon );
725     _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert
726     _dialogIcon->setObjectName( "DialogIcon" );
727
728     _dialogHeading = new QLabel( workArea );
729     YUI_CHECK_NEW( _dialogHeading );
730     headingHBox->addWidget( _dialogHeading );
731     _dialogHeading->setAlignment( Qt::AlignLeft | Qt::WordBreak );
732     _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
733     _dialogHeading->setObjectName( "DialogHeading" );
734
735     //
736     // Client area (the part that belongs to the YCP application)
737     //
738
739     layoutClientArea( workArea );
740     vbox->addWidget( _clientArea );
741
742     //
743     // Button box
744     //
745
746     QLayout *bb = layoutButtonBox( workArea );
747     vbox->addLayout( bb );
748
749     return workArea;
750 }
751
752
753
754 void YQWizard::layoutClientArea( QWidget * parent )
755 {
756     _clientArea = new Q3VBox( parent );
757     YUI_CHECK_NEW( _clientArea );
758     // _clientArea->layout()->setMargin( 4 );
759
760     //
761     // HVCenter for wizard contents
762     //
763
764     _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
765     YUI_CHECK_NEW( _contents );
766     _contents->QObject::setProperty( "class", "Contents" );
767
768     _contents->setStretchable( YD_HORIZ, true );
769     _contents->setStretchable( YD_VERT,  true );
770     _contents->installEventFilter( this );
771     _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
772
773     //
774     // Replace point for wizard contents
775     //
776
777     _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
778
779     //
780     // Initial YEmpty widget contents of replace point
781     //
782
783     YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
784     _contentsReplacePoint->showChild();
785
786 }
787
788
789
790 QLayout *YQWizard::layoutButtonBox( QWidget * parent )
791 {
792     //
793     // QHBoxLayout for the buttons
794     //
795
796     QHBoxLayout * hbox = new QHBoxLayout();             // parent, spacing
797     YUI_CHECK_NEW( hbox );
798
799     hbox->setSpacing( 0 );
800     hbox->setMargin( 0 );
801
802     // Help button - intentionally without keyboard shortcut
803     _helpButton = new QPushButton( _( "Help" ), parent );
804     YUI_CHECK_NEW( _helpButton );
805
806     connect( _helpButton, SIGNAL( clicked()  ),
807              this,       SLOT  ( showHelp() ) );
808
809 #if USE_ICON_ON_HELP_BUTTON
810     QPixmap pixmap = QPixmap( PIXMAP_DIR "help-button.png" );
811
812     if ( ! pixmap.isNull() )
813         _helpButton->setPixmap( pixmap );
814 #endif
815     hbox->addWidget( _helpButton );
816
817     hbox->addStretch( 10 );
818
819     //
820     // "Abort" button
821     //
822
823     _abortButton = new YQWizardButton( this, parent, _abortButtonLabel );
824     YUI_CHECK_NEW( _abortButton );
825
826     hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
827     connect( _abortButton,      SIGNAL( clicked()               ),
828              this,              SLOT  ( slotAbortClicked()      ) );
829
830     hbox->addSpacing( 10 );
831
832     //
833     // "Back" button
834     //
835
836     _backButton  = new YQWizardButton( this, parent, _backButtonLabel );
837     YUI_CHECK_NEW( _backButton );
838
839     hbox->addWidget( (QWidget *) _backButton->widgetRep() );
840     connect( _backButton,       SIGNAL( clicked()               ),
841              this,              SLOT  ( slotBackClicked()       ) );
842
843     if ( _backButton->text().isEmpty() )
844         _backButton->hide();
845
846     //
847     // "Next" button
848     //
849
850     hbox->addSpacing( 5 );
851
852     _nextButton  = new YQWizardButton( this, parent, _nextButtonLabel );
853     YUI_CHECK_NEW( _nextButton );
854
855     hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
856     connect( _nextButton,       SIGNAL( clicked()               ),
857              this,              SLOT  ( slotNextClicked()       ) );
858
859     return hbox;
860 }
861
862 void YQWizard::destroyButtons()
863 {
864     delete _backButton;
865     _backButton = 0;
866
867     delete _abortButton;
868     _abortButton = 0;
869
870     delete _nextButton;
871     _nextButton = 0;
872 }
873
874
875 void YQWizard::connectNotify ( const char * signal )
876 {
877     if ( QString( signal ).contains( "nextClicked()" ) )
878     {
879         y2debug( "nextClicked connected, no longer directly sending button events" );
880         _sendButtonEvents = false;
881     }
882 }
883
884
885 void YQWizard::disconnectNotify ( const char * signal )
886 {
887     if ( QString( signal ).contains( "nextClicked()" ) )
888     {
889         y2debug( "nextClicked disconnected, directly sending button events again" );
890         _sendButtonEvents = true;
891     }
892 }
893
894
895 void YQWizard::setDialogIcon( const string & iconName )
896 {
897     if ( _dialogIcon )
898     {
899         if ( ! iconName.empty() )
900         {
901             QPixmap icon( iconName.c_str() );
902
903             if ( icon.isNull() )
904                 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
905             else
906             {
907                 _dialogIcon->setPixmap( icon );
908                 topLevelWidget()->setIcon( icon );
909             }
910         }
911         else
912         {
913             _dialogIcon->clear();
914             topLevelWidget()->setIcon( QPixmap() );
915         }
916     }
917 }
918
919
920 void YQWizard::setDialogHeading( const string & headingText )
921 {
922     if ( _dialogHeading )
923     {
924         if ( ! headingText.empty() )
925             _dialogHeading->setText( fromUTF8( headingText ) );
926         else
927             _dialogHeading->clear();
928     }
929 }
930
931 string YQWizard::debugLabel()
932 {
933     if ( _dialogHeading )
934     {
935         QString label = _dialogHeading->text();
936         label.simplifyWhiteSpace(); // Replace any embedded newline with a single blank
937
938         if ( ! label.isEmpty() )
939         {
940             label.prepend( "YQWizard \"" );
941             label.append( "\"" );
942
943             return toUTF8( label );
944         }
945     }
946
947     return "untitled YQWizard";
948 }
949
950 void YQWizard::setHelpText( const string & helpText )
951 {
952     _qHelpText = fromUTF8( helpText );
953     _qHelpText.replace( "&product;", YQUI::ui()->productName() );
954 }
955
956
957 void YQWizard::slotBackClicked()
958 {
959     emit backClicked();
960
961     if ( _sendButtonEvents )
962         YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
963
964     _direction = YQWizard::Backward;
965 }
966
967
968 void YQWizard::slotAbortClicked()
969 {
970     emit abortClicked();
971
972     if ( _sendButtonEvents )
973         YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
974 }
975
976
977 void YQWizard::slotNextClicked()
978 {
979     emit nextClicked();
980
981     if ( _sendButtonEvents )
982         YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
983
984     _direction = YQWizard::Forward;
985 }
986
987
988 void YQWizard::showHelp()
989 {
990     QDialog helpDlg( this );
991     Ui_QHelpDialog ui;
992     ui.setupUi( &helpDlg );
993     ui.textBrowser->setText( _qHelpText );
994     helpDlg.exec();
995 }
996
997
998 void YQWizard::releaseNotesClicked()
999 {
1000     YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1001
1002     if ( ! _releaseNotesButtonId.empty() )
1003     {
1004         y2milestone( "Release Notes button clicked" );
1005         sendEvent( _releaseNotesButtonId );
1006     }
1007 }
1008
1009
1010 void YQWizard::showSteps()
1011 {
1012     if ( _sideBar && _stepsPanel )
1013     {
1014         _sideBar->setCurrentWidget( _stepsPanel );
1015     }
1016 }
1017
1018
1019 void YQWizard::showTree()
1020 {
1021     if ( _sideBar && _treePanel )
1022     {
1023         _sideBar->setCurrentWidget( _treePanel );
1024     }
1025 }
1026
1027
1028
1029 void YQWizard::addMenu( const string & text,
1030                         const string & id )
1031 {
1032     if ( _menuBar )
1033     {
1034         Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1035         YUI_CHECK_NEW( menu );
1036
1037         _menuIDs.insert( fromUTF8( id ), menu );
1038         _menuBar->insertItem( fromUTF8( text ), menu );
1039
1040         connect( menu, SIGNAL( activated    ( int ) ),
1041                  this, SLOT  ( sendMenuEvent( int ) ) );
1042
1043         _menuBar->show();
1044     }
1045 }
1046
1047
1048 void YQWizard::addSubMenu( const string & parentMenuID,
1049                            const string & text,
1050                            const string & id )
1051 {
1052     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1053
1054     if ( parentMenu )
1055     {
1056         Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1057         YUI_CHECK_NEW( menu );
1058
1059         _menuIDs.insert( fromUTF8( id ), menu );
1060         parentMenu->insertItem( fromUTF8( text ), menu );
1061
1062         connect( menu, SIGNAL( activated    ( int ) ),
1063                  this, SLOT  ( sendMenuEvent( int ) ) );
1064     }
1065     else
1066     {
1067         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1068     }
1069 }
1070
1071
1072 void YQWizard::addMenuEntry( const string & parentMenuID,
1073                              const string & text,
1074                              const string & idString )
1075 {
1076     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1077
1078     if ( parentMenu )
1079     {
1080         int id = _menuEntryIDs.size();
1081         _menuEntryIDs.push_back( idString );
1082         parentMenu->insertItem( fromUTF8( text ), id );
1083     }
1084     else
1085     {
1086         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1087     }
1088 }
1089
1090
1091 void YQWizard::addMenuSeparator( const string & parentMenuID )
1092 {
1093     Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1094
1095     if ( parentMenu )
1096     {
1097         parentMenu->insertSeparator();
1098     }
1099     else
1100     {
1101         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1102     }
1103 }
1104
1105
1106 void YQWizard::deleteMenus()
1107 {
1108     if ( _menuBar )
1109     {
1110         _menuBar->hide();
1111         _menuBar->clear();
1112         _menuIDs.clear();
1113         _menuEntryIDs.clear();
1114     }
1115 }
1116
1117
1118 void YQWizard::sendMenuEvent( int numID )
1119 {
1120     if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
1121     {
1122         sendEvent( _menuEntryIDs[ numID ] );
1123     }
1124     else
1125     {
1126         y2error( "Invalid menu ID: %d", numID );
1127     }
1128 }
1129
1130
1131 void YQWizard::sendEvent( const string & id )
1132 {
1133     YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1134 }
1135
1136
1137 int YQWizard::preferredWidth()
1138 {
1139     return sizeHint().width();
1140 }
1141
1142
1143 int YQWizard::preferredHeight()
1144 {
1145     return sizeHint().height();
1146 }
1147
1148
1149 void YQWizard::setSize( int newWidth, int newHeight )
1150 {
1151     resize( newWidth, newHeight );
1152     resizeClientArea();
1153 }
1154
1155
1156
1157 void YQWizard::resizeClientArea()
1158 {
1159     y2debug( "resizing client area" );
1160     QRect contentsRect = _clientArea->contentsRect();
1161     _contents->setSize( contentsRect.width(), contentsRect.height() );
1162 }
1163
1164 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1165 {
1166     if ( ev->type() == QEvent::Resize && obj == _contents )
1167     {
1168         resizeClientArea();
1169         return true;            // Event handled
1170     }
1171
1172     return QWidget::eventFilter( obj, ev );
1173 }
1174
1175
1176 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1177 {
1178     button->setLabel( newLabel );
1179     YDialog::currentDialog()->checkShortcuts();
1180
1181     YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1182
1183     if ( wizardButton )
1184         wizardButton->setVisible( !newLabel.empty() );
1185 }
1186
1187
1188 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1189 {
1190     return; // no longer supported!
1191
1192     if ( ! _releaseNotesButton )
1193     {
1194         y2error( "NULL Release Notes button" );
1195
1196         if ( ! _stepsPanel )
1197             y2error( "This works only if there is a \"steps\" panel!" );
1198
1199         return;
1200     }
1201
1202     // no way to check the shortcut, so strip it
1203     _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1204     _releaseNotesButtonId = id;
1205
1206     _releaseNotesButton->show();
1207 }
1208
1209
1210 void YQWizard::hideReleaseNotesButton()
1211 {
1212     if ( _releaseNotesButton && !_releaseNotesButton->isHidden() )
1213         _releaseNotesButton->hide();
1214 }
1215
1216
1217 void YQWizard::retranslateInternalButtons()
1218 {
1219     YQUI::setTextdomain( TEXTDOMAIN );
1220
1221     if ( _helpButton )
1222         // "Help" button - intentionally without keyboard shortcut
1223         _helpButton->setText( _( "Help" ) );
1224
1225     if ( _stepsButton )
1226         // "Steps" button - intentionally without keyboard shortcut
1227         _stepsButton->setText( _( "Steps" ) );
1228
1229     if ( _treeButton )
1230         // "Tree" button - intentionally without keyboard shortcut
1231         _treeButton->setText( _( "Tree" ) );
1232 }
1233
1234 void YQWizard::Step::setStatus( Status s )
1235 {
1236     if ( !_statusLabel || !_nameLabel || _status == s )
1237         return;
1238
1239     _status = s;
1240
1241     if ( s == Todo )
1242     {
1243         _statusLabel->setProperty( "class", "todo-step-status QLabel" );
1244         _nameLabel->setProperty( "class", "todo-step-name QLabel" );
1245     }
1246
1247     if ( s == Done )
1248     {
1249         _statusLabel->setProperty( "class", "done-step-status QLabel" );
1250         _nameLabel->setProperty( "class", "done-step-name QLabel" );
1251     }
1252
1253     if ( s == Current )
1254     {
1255         _statusLabel->setProperty( "class", "current-step-status QLabel" );
1256         _nameLabel->setProperty( "class", "current-step-name QLabel" );
1257     }
1258
1259     qApp->style()->polish( _statusLabel );
1260     qApp->style()->polish( _nameLabel );
1261 }
1262
1263 #include "YQWizard.moc"