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