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