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