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