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