]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/YQWizard.cc
fix margins
[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( itemActivated  ( QTreeWidgetItem *, int ) ),
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     _clientArea->setObjectName("_clientArea");
630     QVBoxLayout *layout = new QVBoxLayout( _clientArea );
631     layout->setMargin( 0 );
632
633     //
634     // HVCenter for wizard contents
635     //
636
637     _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
638     YUI_CHECK_NEW( _contents );
639     layout->addWidget( _contents );
640     _contents->QObject::setProperty( "class", "Contents" );
641
642     _contents->setStretchable( YD_HORIZ, true );
643     _contents->setStretchable( YD_VERT,  true );
644     _contents->installEventFilter( this );
645     _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
646
647     //
648     // Replace point for wizard contents
649     //
650
651     _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
652
653     //
654     // Initial YEmpty widget contents of replace point
655     //
656
657     YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
658     _contentsReplacePoint->showChild();
659
660 }
661
662
663
664 QLayout *YQWizard::layoutButtonBox( QWidget * parent )
665 {
666     //
667     // QHBoxLayout for the buttons
668     //
669
670     QHBoxLayout * hbox = new QHBoxLayout();             // parent, spacing
671     YUI_CHECK_NEW( hbox );
672
673     hbox->setSpacing( 0 );
674     hbox->setMargin( 0 );
675
676     // Help button - intentionally without keyboard shortcut
677     _helpButton = new QPushButton( _( "Help" ), parent );
678     YUI_CHECK_NEW( _helpButton );
679
680     connect( _helpButton, SIGNAL( clicked()  ),
681              this,       SLOT  ( showHelp() ) );
682
683     hbox->addWidget( _helpButton );
684
685     hbox->addStretch( 10 );
686
687     //
688     // "Abort" button
689     //
690
691     _abortButton = new YQWizardButton( this, parent, _abortButtonLabel );
692     YUI_CHECK_NEW( _abortButton );
693
694     hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
695     connect( _abortButton,      SIGNAL( clicked()               ),
696              this,              SLOT  ( slotAbortClicked()      ) );
697
698     hbox->addSpacing( 10 );
699
700     //
701     // "Back" button
702     //
703
704     _backButton  = new YQWizardButton( this, parent, _backButtonLabel );
705     YUI_CHECK_NEW( _backButton );
706
707     hbox->addWidget( (QWidget *) _backButton->widgetRep() );
708     connect( _backButton,       SIGNAL( clicked()               ),
709              this,              SLOT  ( slotBackClicked()       ) );
710
711     if ( _backButton->text().isEmpty() )
712         _backButton->hide();
713
714     //
715     // "Next" button
716     //
717
718     hbox->addSpacing( 5 );
719
720     _nextButton  = new YQWizardButton( this, parent, _nextButtonLabel );
721     YUI_CHECK_NEW( _nextButton );
722
723     hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
724     connect( _nextButton,       SIGNAL( clicked()               ),
725              this,              SLOT  ( slotNextClicked()       ) );
726
727     return hbox;
728 }
729
730 void YQWizard::destroyButtons()
731 {
732     delete _backButton;
733     _backButton = 0;
734
735     delete _abortButton;
736     _abortButton = 0;
737
738     delete _nextButton;
739     _nextButton = 0;
740 }
741
742
743 void YQWizard::connectNotify ( const char * signal )
744 {
745     if ( QString( signal ).contains( "nextClicked()" ) )
746     {
747         y2debug( "nextClicked connected, no longer directly sending button events" );
748         _sendButtonEvents = false;
749     }
750 }
751
752
753 void YQWizard::disconnectNotify ( const char * signal )
754 {
755     if ( QString( signal ).contains( "nextClicked()" ) )
756     {
757         y2debug( "nextClicked disconnected, directly sending button events again" );
758         _sendButtonEvents = true;
759     }
760 }
761
762
763 void YQWizard::setDialogIcon( const string & iconName )
764 {
765     if ( _dialogIcon )
766     {
767         if ( ! iconName.empty() )
768         {
769             QPixmap icon( iconName.c_str() );
770
771             if ( icon.isNull() )
772                 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
773             else
774             {
775                 _dialogIcon->setPixmap( icon );
776                 topLevelWidget()->setWindowIcon( icon );
777             }
778         }
779         else
780         {
781             _dialogIcon->clear();
782             topLevelWidget()->setWindowIcon( QIcon() );
783         }
784     }
785 }
786
787
788 void YQWizard::setDialogHeading( const string & headingText )
789 {
790     if ( _dialogHeading )
791     {
792         if ( ! headingText.empty() )
793             _dialogHeading->setText( fromUTF8( headingText ) );
794         else
795             _dialogHeading->clear();
796     }
797 }
798
799 string YQWizard::debugLabel()
800 {
801     if ( _dialogHeading )
802     {
803         QString label = _dialogHeading->text();
804         label = label.simplified(); // Replace any embedded newline with a single blank
805
806         if ( ! label.isEmpty() )
807         {
808             label.prepend( "YQWizard \"" );
809             label.append( "\"" );
810
811             return toUTF8( label );
812         }
813     }
814
815     return "untitled YQWizard";
816 }
817
818 void YQWizard::setHelpText( const string & helpText )
819 {
820     _qHelpText = fromUTF8( helpText );
821     _qHelpText.replace( "&product;", YQUI::ui()->productName() );
822 }
823
824
825 void YQWizard::slotBackClicked()
826 {
827     emit backClicked();
828
829     if ( _sendButtonEvents )
830         YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
831
832     _direction = YQWizard::Backward;
833 }
834
835
836 void YQWizard::slotAbortClicked()
837 {
838     emit abortClicked();
839
840     if ( _sendButtonEvents )
841         YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
842 }
843
844
845 void YQWizard::slotNextClicked()
846 {
847     emit nextClicked();
848
849     if ( _sendButtonEvents )
850         YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
851
852     _direction = YQWizard::Forward;
853 }
854
855
856 void YQWizard::showHelp()
857 {
858     QDialog helpDlg( this );
859     Ui_QHelpDialog ui;
860     ui.setupUi( &helpDlg );
861     ui.textBrowser->setText( _qHelpText );
862     helpDlg.exec();
863 }
864
865
866 void YQWizard::releaseNotesClicked()
867 {
868     YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
869
870     if ( ! _releaseNotesButtonId.empty() )
871     {
872         y2milestone( "Release Notes button clicked" );
873         sendEvent( _releaseNotesButtonId );
874     }
875 }
876
877
878 void YQWizard::showSteps()
879 {
880     if ( _sideBar && _stepsPanel )
881     {
882         _sideBar->setCurrentWidget( _stepsPanel );
883     }
884 }
885
886
887 void YQWizard::showTree()
888 {
889     if ( _sideBar && _treePanel )
890     {
891         _sideBar->setCurrentWidget( _treePanel );
892     }
893 }
894
895
896
897 void YQWizard::addMenu( const string & text,
898                         const string & id )
899 {
900     if ( _menuBar )
901     {
902         QMenu * menu = new QMenu( _menuBar );
903         YUI_CHECK_NEW( menu );
904
905         _menuIDs.insert( fromUTF8( id ), menu );
906         //FIXME _menuBar->insertItem( fromUTF8( text ), menu );
907
908         connect( menu, SIGNAL( activated    ( int ) ),
909                  this, SLOT  ( sendMenuEvent( int ) ) );
910
911         _menuBar->show();
912     }
913 }
914
915
916 void YQWizard::addSubMenu( const string & parentMenuID,
917                            const string & text,
918                            const string & id )
919 {
920     QMenu* parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
921
922     if ( parentMenu )
923     {
924         QMenu * menu = new QMenu( _menuBar );
925         YUI_CHECK_NEW( menu );
926
927         _menuIDs.insert( fromUTF8( id ), menu );
928         //FIXME parentMenu->insertItem( fromUTF8( text ), menu );
929
930         connect( menu, SIGNAL( activated    ( int ) ),
931                  this, SLOT  ( sendMenuEvent( int ) ) );
932     }
933     else
934     {
935         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
936     }
937 }
938
939
940 void YQWizard::addMenuEntry( const string & parentMenuID,
941                              const string & text,
942                              const string & idString )
943 {
944     QMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
945
946     if ( parentMenu )
947     {
948         int id = _menuEntryIDs.size();
949         _menuEntryIDs.push_back( idString );
950         //FIXME parentMenu->insertItem( fromUTF8( text ), id );
951     }
952     else
953     {
954         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
955     }
956 }
957
958
959 void YQWizard::addMenuSeparator( const string & parentMenuID )
960 {
961     QMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
962
963     if ( parentMenu )
964     {
965         parentMenu->addSeparator();
966     }
967     else
968     {
969         y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
970     }
971 }
972
973
974 void YQWizard::deleteMenus()
975 {
976     if ( _menuBar )
977     {
978         _menuBar->hide();
979         _menuBar->clear();
980         _menuIDs.clear();
981         _menuEntryIDs.clear();
982     }
983 }
984
985
986 void YQWizard::sendMenuEvent( int numID )
987 {
988     if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
989     {
990         sendEvent( _menuEntryIDs[ numID ] );
991     }
992     else
993     {
994         y2error( "Invalid menu ID: %d", numID );
995     }
996 }
997
998
999 void YQWizard::sendEvent( const string & id )
1000 {
1001     YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1002 }
1003
1004
1005 int YQWizard::preferredWidth()
1006 {
1007     return sizeHint().width();
1008 }
1009
1010
1011 int YQWizard::preferredHeight()
1012 {
1013     return sizeHint().height();
1014 }
1015
1016
1017 void YQWizard::setSize( int newWidth, int newHeight )
1018 {
1019     resize( newWidth, newHeight );
1020     resizeClientArea();
1021 }
1022
1023
1024
1025 void YQWizard::resizeClientArea()
1026 {
1027     y2debug( "resizing client area" );
1028     QRect contentsRect = _clientArea->contentsRect();
1029     _contents->setSize( contentsRect.width(), contentsRect.height() );
1030 }
1031
1032 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1033 {
1034     if ( ev->type() == QEvent::Resize && obj == _contents )
1035     {
1036         resizeClientArea();
1037         return true;            // Event handled
1038     }
1039
1040     return QWidget::eventFilter( obj, ev );
1041 }
1042
1043
1044 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1045 {
1046     button->setLabel( newLabel );
1047     YDialog::currentDialog()->checkShortcuts();
1048
1049     YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1050
1051     if ( wizardButton )
1052         wizardButton->setVisible( !newLabel.empty() );
1053 }
1054
1055
1056 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1057 {
1058     return; // no longer supported!
1059
1060     if ( ! _releaseNotesButton )
1061     {
1062         y2error( "NULL Release Notes button" );
1063
1064         if ( ! _stepsPanel )
1065             y2error( "This works only if there is a \"steps\" panel!" );
1066
1067         return;
1068     }
1069
1070     // no way to check the shortcut, so strip it
1071     _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1072     _releaseNotesButtonId = id;
1073
1074     _releaseNotesButton->show();
1075 }
1076
1077
1078 void YQWizard::hideReleaseNotesButton()
1079 {
1080     if ( _releaseNotesButton && !_releaseNotesButton->isHidden() )
1081         _releaseNotesButton->hide();
1082 }
1083
1084
1085 void YQWizard::retranslateInternalButtons()
1086 {
1087     YQUI::setTextdomain( TEXTDOMAIN );
1088
1089     if ( _helpButton )
1090         // "Help" button - intentionally without keyboard shortcut
1091         _helpButton->setText( _( "Help" ) );
1092
1093     if ( _stepsButton )
1094         // "Steps" button - intentionally without keyboard shortcut
1095         _stepsButton->setText( _( "Steps" ) );
1096
1097     if ( _treeButton )
1098         // "Tree" button - intentionally without keyboard shortcut
1099         _treeButton->setText( _( "Tree" ) );
1100 }
1101
1102 void YQWizard::Step::setStatus( Status s )
1103 {
1104     if ( !_statusLabel || !_nameLabel || _status == s )
1105         return;
1106
1107     _status = s;
1108
1109     if ( s == Todo )
1110     {
1111         _statusLabel->setProperty( "class", "todo-step-status QLabel" );
1112         _nameLabel->setProperty( "class", "todo-step-name QLabel" );
1113     }
1114
1115     if ( s == Done )
1116     {
1117         _statusLabel->setProperty( "class", "done-step-status QLabel" );
1118         _nameLabel->setProperty( "class", "done-step-name QLabel" );
1119     }
1120
1121     if ( s == Current )
1122     {
1123         _statusLabel->setProperty( "class", "current-step-status QLabel" );
1124         _nameLabel->setProperty( "class", "current-step-name QLabel" );
1125     }
1126
1127     qApp->style()->polish( _statusLabel );
1128     qApp->style()->polish( _nameLabel );
1129 }
1130
1131 #include "YQWizard.moc"