the help panel should be gone now
[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     if ( _treeEnabled )
193     {
194         layoutTreePanel();
195         showTree();
196     }
197     else if ( _stepsEnabled )
198     {
199         layoutStepsPanel();
200         showSteps();
201     } else
202         _sideBar->hide();
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     qDeleteAll(_stepsList);
408     _stepsList.clear();
409     _stepsIDs.clear();
410 }
411
412
413 YQWizard::Step * YQWizard::findStep( const QString & id )
414 {
415     if ( id.isEmpty() )
416         return 0;
417
418     return _stepsIDs[ id ];
419 }
420
421
422 void YQWizard::layoutTreePanel()
423 {
424     _treePanel = new QFrame( _sideBar );
425     YUI_CHECK_NEW( _treePanel );
426     QHBoxLayout *layout = new QHBoxLayout( _treePanel );
427     _sideBar->addWidget( _treePanel );
428
429     QVBoxLayout * vbox = new QVBoxLayout();
430     YUI_CHECK_NEW( vbox );
431     layout->addLayout( vbox );
432
433     // Selection tree
434
435     _tree = new QY2ListView( _treePanel );
436     YUI_CHECK_NEW( _tree );
437     vbox->addWidget( _tree );
438
439     //FIXME
440 //     _tree->addColumn( "" );
441 //     _tree->header()->hide();
442
443     _tree->setRootIsDecorated( true );
444     _tree->setSortByInsertionSequence( true );
445
446     connect( _tree,     SIGNAL( itemSelectionChanged     ( void ) ),
447              this,      SLOT  ( treeSelectionChanged ( void ) ) );
448
449     connect( _tree,     SIGNAL( spacePressed  ( QTreeWidgetItem * ) ),
450              this,      SLOT  ( sendTreeEvent ( QTreeWidgetItem * ) ) );
451
452     connect( _tree,     SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int ) ),
453              this,      SLOT  ( sendTreeEvent ( QTreeWidgetItem * ) ) );
454
455 }
456
457
458 void YQWizard::addTreeItem( const string & parentID, const string & text, const string & id )
459 {
460     QString qId = fromUTF8( id );
461
462     if ( ! _tree )
463     {
464         y2error( "YQWizard widget not created with `opt(`treeEnabled) !" );
465         return;
466     }
467
468     YQWizard::TreeItem * item   = 0;
469     YQWizard::TreeItem * parent = 0;
470
471     if ( ! parentID.empty() )
472     {
473         parent = findTreeItem( parentID );
474     }
475
476     if ( parent )
477     {
478         item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId );
479         YUI_CHECK_NEW( item );
480     }
481     else
482     {
483         item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId );
484         YUI_CHECK_NEW( item );
485     }
486
487     if ( ! qId.isEmpty() )
488         _treeIDs.insert( qId, item );
489 }
490
491
492
493 void YQWizard::deleteTreeItems()
494 {
495     if ( _tree )
496         _tree->clear();
497
498     _treeIDs.clear();
499 }
500
501
502
503 YQWizard::TreeItem * YQWizard::findTreeItem( const string & id )
504 {
505     if ( id.empty() )
506         return 0;
507
508     return _treeIDs[ fromUTF8( id ) ];
509 }
510
511
512 void YQWizard::selectTreeItem( const string & id )
513 {
514     if ( _tree )
515     {
516         YQWizard::TreeItem * item = findTreeItem( id );
517
518         if ( item )
519         {
520             YQSignalBlocker sigBlocker( _tree );
521
522       _tree->setCurrentItem(item);
523             _tree->scrollToItem(item);
524         }
525     }
526 }
527
528
529 void YQWizard::sendTreeEvent( QTreeWidgetItem * listViewItem )
530 {
531     if ( listViewItem )
532     {
533         YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem );
534
535         if ( item && ! item->id().isEmpty() )
536             sendEvent( toUTF8( item->id() ) );
537     }
538 }
539
540
541 void YQWizard::treeSelectionChanged()
542 { //FIXME is currentItem correct or selected.first
543     if ( _tree )
544         sendTreeEvent( _tree->currentItem() );
545 }
546
547
548 string YQWizard::currentTreeSelection()
549 {
550     if ( _tree )
551     {
552         QTreeWidgetItem * sel = _tree->currentItem();
553
554         if ( sel )
555         {
556             YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel);
557
558             if ( item && ! item->id().isEmpty() )
559                 return toUTF8( item->id() );
560         }
561     }
562
563     return string();
564 }
565
566
567
568 QWidget *YQWizard::layoutWorkArea( QWidget * parent )
569 {
570     QFrame *workArea = new QFrame( parent );
571     workArea->setObjectName( "work_area" );
572
573     QY2Styler::self()->registerWidget( workArea );
574
575     QVBoxLayout *vbox = new QVBoxLayout( workArea );
576
577     _menuBar = new QMenuBar( workArea );
578     YUI_CHECK_NEW( _menuBar );
579
580     _menuBar->hide(); // will be made visible when menus are added
581     vbox->addWidget( _menuBar );
582
583     //
584     // Dialog icon and heading
585     //
586
587     QHBoxLayout * headingHBox = new QHBoxLayout();
588     YUI_CHECK_NEW( headingHBox );
589     //headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
590     vbox->addLayout( headingHBox );
591
592     _dialogIcon = new QLabel( workArea );
593     YUI_CHECK_NEW( _dialogIcon );
594     headingHBox->addWidget( _dialogIcon );
595     _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert
596     _dialogIcon->setObjectName( "DialogIcon" );
597
598     _dialogHeading = new QLabel( workArea );
599     YUI_CHECK_NEW( _dialogHeading );
600     headingHBox->addWidget( _dialogHeading );
601     _dialogHeading->setAlignment( Qt::AlignLeft );
602     _dialogHeading->setWordWrap( true );
603     _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
604     _dialogHeading->setObjectName( "DialogHeading" );
605
606     //
607     // Client area (the part that belongs to the YCP application)
608     //
609
610     layoutClientArea( workArea );
611     vbox->addWidget( _clientArea );
612
613     //
614     // Button box
615     //
616
617     QLayout *bb = layoutButtonBox( workArea );
618     vbox->addLayout( bb );
619
620     return workArea;
621 }
622
623
624
625 void YQWizard::layoutClientArea( QWidget * parent )
626 {
627     _clientArea = new QFrame( parent );
628     YUI_CHECK_NEW( _clientArea );
629     QVBoxLayout *layout = new QVBoxLayout( _clientArea );
630     // _clientArea->layout()->setMargin( 4 );
631
632     //
633     // HVCenter for wizard contents
634     //
635
636     _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
637     YUI_CHECK_NEW( _contents );
638     layout->addWidget( _contents );
639     _contents->QObject::setProperty( "class", "Contents" );
640
641     _contents->setStretchable( YD_HORIZ, true );
642     _contents->setStretchable( YD_VERT,  true );
643     _contents->installEventFilter( this );
644     _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
645
646     //
647     // Replace point for wizard contents
648     //
649
650     _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
651
652     //
653     // Initial YEmpty widget contents of replace point
654     //
655
656     YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
657     _contentsReplacePoint->showChild();
658
659 }
660
661
662
663 QLayout *YQWizard::layoutButtonBox( QWidget * parent )
664 {
665     //
666     // QHBoxLayout for the buttons
667     //
668
669     QHBoxLayout * hbox = new QHBoxLayout();             // parent, spacing
670     YUI_CHECK_NEW( hbox );
671
672     hbox->setSpacing( 0 );
673     hbox->setMargin( 0 );
674
675     // Help button - intentionally without keyboard shortcut
676     _helpButton = new QPushButton( _( "Help" ), parent );
677     YUI_CHECK_NEW( _helpButton );
678
679     connect( _helpButton, SIGNAL( clicked()  ),
680              this,       SLOT  ( showHelp() ) );
681
682     hbox->addWidget( _helpButton );
683
684     hbox->addStretch( 10 );
685
686     //
687     // "Abort" button
688     //
689
690     _abortButton = new YQWizardButton( this, parent, _abortButtonLabel );
691     YUI_CHECK_NEW( _abortButton );
692
693     hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
694     connect( _abortButton,      SIGNAL( clicked()               ),
695              this,              SLOT  ( slotAbortClicked()      ) );
696
697     hbox->addSpacing( 10 );
698
699     //
700     // "Back" button
701     //
702
703     _backButton  = new YQWizardButton( this, parent, _backButtonLabel );
704     YUI_CHECK_NEW( _backButton );
705
706     hbox->addWidget( (QWidget *) _backButton->widgetRep() );
707     connect( _backButton,       SIGNAL( clicked()               ),
708              this,              SLOT  ( slotBackClicked()       ) );
709
710     if ( _backButton->text().isEmpty() )
711         _backButton->hide();
712
713     //
714     // "Next" button
715     //
716
717     hbox->addSpacing( 5 );
718
719     _nextButton  = new YQWizardButton( this, parent, _nextButtonLabel );
720     YUI_CHECK_NEW( _nextButton );
721
722     hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
723     connect( _nextButton,       SIGNAL( clicked()               ),
724              this,              SLOT  ( slotNextClicked()       ) );
725
726     return hbox;
727 }
728
729 void YQWizard::destroyButtons()
730 {
731     delete _backButton;
732     _backButton = 0;
733
734     delete _abortButton;
735     _abortButton = 0;
736
737     delete _nextButton;
738     _nextButton = 0;
739 }
740
741
742 void YQWizard::connectNotify ( const char * signal )
743 {
744     if ( QString( signal ).contains( "nextClicked()" ) )
745     {
746         y2debug( "nextClicked connected, no longer directly sending button events" );
747         _sendButtonEvents = false;
748     }
749 }
750
751
752 void YQWizard::disconnectNotify ( const char * signal )
753 {
754     if ( QString( signal ).contains( "nextClicked()" ) )
755     {
756         y2debug( "nextClicked disconnected, directly sending button events again" );
757         _sendButtonEvents = true;
758     }
759 }
760
761
762 void YQWizard::setDialogIcon( const string & iconName )
763 {
764     if ( _dialogIcon )
765     {
766         if ( ! iconName.empty() )
767         {
768             QPixmap icon( iconName.c_str() );
769
770             if ( icon.isNull() )
771                 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
772             else
773             {
774                 _dialogIcon->setPixmap( icon );
775                 topLevelWidget()->setWindowIcon( icon );
776             }
777         }
778         else
779         {
780             _dialogIcon->clear();
781             topLevelWidget()->setWindowIcon( QIcon() );
782         }
783     }
784 }
785
786
787 void YQWizard::setDialogHeading( const string & headingText )
788 {
789     if ( _dialogHeading )
790     {
791         if ( ! headingText.empty() )
792             _dialogHeading->setText( fromUTF8( headingText ) );
793         else
794             _dialogHeading->clear();
795     }
796 }
797
798 string YQWizard::debugLabel()
799 {
800     if ( _dialogHeading )
801     {
802         QString label = _dialogHeading->text();
803         label = label.simplified(); // Replace any embedded newline with a single blank
804
805         if ( ! label.isEmpty() )
806         {
807             label.prepend( "YQWizard \"" );
808             label.append( "\"" );
809
810             return toUTF8( label );
811         }
812     }
813
814     return "untitled YQWizard";
815 }
816
817 void YQWizard::setHelpText( const string & helpText )
818 {
819     _qHelpText = fromUTF8( helpText );
820     _qHelpText.replace( "&product;", YQUI::ui()->productName() );
821 }
822
823
824 void YQWizard::slotBackClicked()
825 {
826     emit backClicked();
827
828     if ( _sendButtonEvents )
829         YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
830
831     _direction = YQWizard::Backward;
832 }
833
834
835 void YQWizard::slotAbortClicked()
836 {
837     emit abortClicked();
838
839     if ( _sendButtonEvents )
840         YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
841 }
842
843
844 void YQWizard::slotNextClicked()
845 {
846     emit nextClicked();
847
848     if ( _sendButtonEvents )
849         YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
850
851     _direction = YQWizard::Forward;
852 }
853
854
855 void YQWizard::showHelp()
856 {
857     QDialog helpDlg( this );
858     Ui_QHelpDialog ui;
859     ui.setupUi( &helpDlg );
860     ui.textBrowser->setText( _qHelpText );
861     helpDlg.exec();
862 }
863
864
865 void YQWizard::releaseNotesClicked()
866 {
867     YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
868
869     if ( ! _releaseNotesButtonId.empty() )
870     {
871         y2milestone( "Release Notes button clicked" );
872         sendEvent( _releaseNotesButtonId );
873     }
874 }
875
876
877 void YQWizard::showSteps()
878 {
879     if ( _sideBar && _stepsPanel )
880     {
881         _sideBar->setCurrentWidget( _stepsPanel );
882     }
883 }
884
885
886 void YQWizard::showTree()
887 {
888     if ( _sideBar && _treePanel )
889     {
890         _sideBar->setCurrentWidget( _treePanel );
891     }
892 }
893
894
895
896 void YQWizard::addMenu( const string & text,
897                         const string & id )
898 {
899     if ( _menuBar )
900     {
901         QMenu * menu = new QMenu( _menuBar );
902         YUI_CHECK_NEW( menu );
903
904         _menuIDs.insert( fromUTF8( id ), menu );
905         //FIXME _menuBar->insertItem( fromUTF8( text ), menu );
906
907         connect( menu, SIGNAL( activated    ( int ) ),
908                  this, SLOT  ( sendMenuEvent( int ) ) );
909
910         _menuBar->show();
911     }
912 }
913
914
915 void YQWizard::addSubMenu( const string & parentMenuID,
916                            const string & text,
917                            const string & id )
918 {
919     QMenu* parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
920
921     if ( parentMenu )
922     {
923         QMenu * menu = new QMenu( _menuBar );
924         YUI_CHECK_NEW( menu );
925
926         _menuIDs.insert( fromUTF8( id ), menu );
927         //FIXME parentMenu->insertItem( fromUTF8( text ), menu );
928
929         connect( menu, SIGNAL( activated    ( int ) ),
930                  this, SLOT  ( sendMenuEvent( int ) ) );
931     }
932     else
933     {
934         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
935     }
936 }
937
938
939 void YQWizard::addMenuEntry( const string & parentMenuID,
940                              const string & text,
941                              const string & idString )
942 {
943     QMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
944
945     if ( parentMenu )
946     {
947         int id = _menuEntryIDs.size();
948         _menuEntryIDs.push_back( idString );
949         //FIXME parentMenu->insertItem( fromUTF8( text ), id );
950     }
951     else
952     {
953         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
954     }
955 }
956
957
958 void YQWizard::addMenuSeparator( const string & parentMenuID )
959 {
960     QMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
961
962     if ( parentMenu )
963     {
964         parentMenu->addSeparator();
965     }
966     else
967     {
968         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
969     }
970 }
971
972
973 void YQWizard::deleteMenus()
974 {
975     if ( _menuBar )
976     {
977         _menuBar->hide();
978         _menuBar->clear();
979         _menuIDs.clear();
980         _menuEntryIDs.clear();
981     }
982 }
983
984
985 void YQWizard::sendMenuEvent( int numID )
986 {
987     if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
988     {
989         sendEvent( _menuEntryIDs[ numID ] );
990     }
991     else
992     {
993         y2error( "Invalid menu ID: %d", numID );
994     }
995 }
996
997
998 void YQWizard::sendEvent( const string & id )
999 {
1000     YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1001 }
1002
1003
1004 int YQWizard::preferredWidth()
1005 {
1006     return sizeHint().width();
1007 }
1008
1009
1010 int YQWizard::preferredHeight()
1011 {
1012     return sizeHint().height();
1013 }
1014
1015
1016 void YQWizard::setSize( int newWidth, int newHeight )
1017 {
1018     resize( newWidth, newHeight );
1019     resizeClientArea();
1020 }
1021
1022
1023
1024 void YQWizard::resizeClientArea()
1025 {
1026     y2debug( "resizing client area" );
1027     QRect contentsRect = _clientArea->contentsRect();
1028     _contents->setSize( contentsRect.width(), contentsRect.height() );
1029 }
1030
1031 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1032 {
1033     if ( ev->type() == QEvent::Resize && obj == _contents )
1034     {
1035         resizeClientArea();
1036         return true;            // Event handled
1037     }
1038
1039     return QWidget::eventFilter( obj, ev );
1040 }
1041
1042
1043 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1044 {
1045     button->setLabel( newLabel );
1046     YDialog::currentDialog()->checkShortcuts();
1047
1048     YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1049
1050     if ( wizardButton )
1051         wizardButton->setVisible( !newLabel.empty() );
1052 }
1053
1054
1055 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1056 {
1057     return; // no longer supported!
1058
1059     if ( ! _releaseNotesButton )
1060     {
1061         y2error( "NULL Release Notes button" );
1062
1063         if ( ! _stepsPanel )
1064             y2error( "This works only if there is a \"steps\" panel!" );
1065
1066         return;
1067     }
1068
1069     // no way to check the shortcut, so strip it
1070     _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1071     _releaseNotesButtonId = id;
1072
1073     _releaseNotesButton->show();
1074 }
1075
1076
1077 void YQWizard::hideReleaseNotesButton()
1078 {
1079     if ( _releaseNotesButton && !_releaseNotesButton->isHidden() )
1080         _releaseNotesButton->hide();
1081 }
1082
1083
1084 void YQWizard::retranslateInternalButtons()
1085 {
1086     YQUI::setTextdomain( TEXTDOMAIN );
1087
1088     if ( _helpButton )
1089         // "Help" button - intentionally without keyboard shortcut
1090         _helpButton->setText( _( "Help" ) );
1091
1092     if ( _stepsButton )
1093         // "Steps" button - intentionally without keyboard shortcut
1094         _stepsButton->setText( _( "Steps" ) );
1095
1096     if ( _treeButton )
1097         // "Tree" button - intentionally without keyboard shortcut
1098         _treeButton->setText( _( "Tree" ) );
1099 }
1100
1101 void YQWizard::Step::setStatus( Status s )
1102 {
1103     if ( !_statusLabel || !_nameLabel || _status == s )
1104         return;
1105
1106     _status = s;
1107
1108     if ( s == Todo )
1109     {
1110         _statusLabel->setProperty( "class", "todo-step-status QLabel" );
1111         _nameLabel->setProperty( "class", "todo-step-name QLabel" );
1112     }
1113
1114     if ( s == Done )
1115     {
1116         _statusLabel->setProperty( "class", "done-step-status QLabel" );
1117         _nameLabel->setProperty( "class", "done-step-name QLabel" );
1118     }
1119
1120     if ( s == Current )
1121     {
1122         _statusLabel->setProperty( "class", "current-step-status QLabel" );
1123         _nameLabel->setProperty( "class", "current-step-name QLabel" );
1124     }
1125
1126     qApp->style()->polish( _statusLabel );
1127     qApp->style()->polish( _nameLabel );
1128 }
1129
1130 #include "YQWizard.moc"