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