1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
15 Author: Stefan Hundhammer <sh@suse.de>
17 Textdomain "packages-qt"
24 #define y2log_component "qt-wizard"
25 #include <ycp/y2log.h>
27 // For the command parser
30 #include <YShortcut.h>
38 #include <qmenudata.h>
41 #include <q3popupmenu.h>
42 #include <qpushbutton.h>
44 #include <qtabwidget.h>
45 #include <q3textbrowser.h>
46 #include <qtoolbutton.h>
47 #include <q3widgetstack.h>
49 #include "QY2ListView.h"
51 #include <q3boxlayout.h>
52 #include <QGridLayout>
55 #include <q3boxlayout.h>
60 #include "YQApplication.h"
62 #include "YQAlignment.h"
63 #include "YQReplacePoint.h"
66 #include "YQWizardButton.h"
67 #include "YQIconPool.h"
68 #include "YQWidgetFactory.h"
69 #include "YQSignalBlocker.h"
70 #include "QY2LayoutUtils.h"
76 #define PIXMAP_DIR THEMEDIR "/wizard/"
82 #define TEXTDOMAIN "packages-qt"
84 #define ENABLE_GRADIENTS 1
86 #define USE_SEPARATOR 1
88 #define WORK_AREA_TOP_MARGIN 10
91 # define WORK_AREA_BOTTOM_MARGIN 8
92 # define WORK_AREA_RIGHT_MARGIN 8
94 # define WORK_AREA_BOTTOM_MARGIN 8
95 # define WORK_AREA_RIGHT_MARGIN 6
98 #define BUTTON_BOX_TOP_MARGIN 10
100 #define SEPARATOR_MARGIN 6
101 #define STEPS_MARGIN 10
102 #define STEPS_SPACING 2
103 #define STEPS_HEADING_SPACING 8
104 #define MENU_BAR_MARGIN 8
106 #define USE_FIXED_STEP_FONTS 0
107 #define STEPS_FONT_FAMILY "Sans Serif"
108 #define STEPS_FONT_SIZE 11
109 #define STEPS_HEADING_FONT_SIZE 11
111 #define USE_ICON_ON_HELP_BUTTON 0
114 YQWizard::YQWizard( YWidget * parent,
115 const string & backButtonLabel,
116 const string & abortButtonLabel,
117 const string & nextButtonLabel,
118 YWizardMode wizardMode )
119 : QFrame( (QWidget *) parent->widgetRep() )
125 , _backButtonLabel( backButtonLabel )
126 , _abortButtonLabel( abortButtonLabel )
127 , _nextButtonLabel( nextButtonLabel )
129 QVBoxLayout* layout = new QVBoxLayout( this );
130 layout->setSpacing( 0 );
131 layout->setMargin( 0 );
134 setWidgetRep( this );
136 _stepsEnabled = (wizardMode == YWizardMode_Steps);
137 _treeEnabled = (wizardMode == YWizardMode_Tree);
140 _direction = YQWizard::Forward;
149 _releaseNotesButton = 0;
161 _backButtonSpacer = 0;
164 _sendButtonEvents = true;
165 _contentsReplacePoint = 0;
167 _stepsList.setAutoDelete( true );
168 _stepsIDs.setAutoDelete( false ); // Only for one of both!
170 YQUI::setTextdomain( TEXTDOMAIN );
178 loadGradientPixmaps();
190 if ( ! _titleBarGradientPixmap.isNull() )
192 layoutTitleBar( this );
196 QWidget * spacer = addVSpacing( this, WORK_AREA_TOP_MARGIN );
197 Q_CHECK_PTR( spacer );
199 # if ENABLE_GRADIENTS
200 spacer->setPaletteBackgroundColor( _gradientTopColor );
204 Q3HBox * hBox = new Q3HBox( this );
205 YUI_CHECK_NEW( hBox );
206 layout->addWidget( hBox );
208 layoutSideBar( hBox );
209 layoutWorkArea( hBox );
211 y2debug( "Constructor finished." );
216 YQWizard::~YQWizard()
223 void YQWizard::layoutTitleBar( QWidget * parent )
225 if ( ! highColorDisplay() ) // 8 bit display or worse?
227 // No colorful title bar, just a spacing to match the one at the bottom.
228 addVSpacing( parent, WORK_AREA_BOTTOM_MARGIN );
234 Q3HBox * titleBar = new Q3HBox( parent );
235 YUI_CHECK_NEW( titleBar );
238 setGradient( titleBar, _titleBarGradientPixmap );
241 titleBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); // hor/vert
247 QLabel * left = new QLabel( titleBar );
248 left->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
250 QPixmap leftLogo( PIXMAP_DIR "title-bar-left.png" );
252 if ( ! leftLogo.isNull() )
254 left->setPixmap( leftLogo );
255 left->setFixedSize( leftLogo.size() );
256 left->setBackgroundOrigin( QWidget::ParentOrigin );
261 // Center stretch space
264 addHStretch( titleBar );
271 QLabel * right = new QLabel( titleBar );
272 YUI_CHECK_NEW( right );
274 QPixmap rightLogo( PIXMAP_DIR "title-bar-right.png" );
276 if ( ! rightLogo.isNull() )
278 right->setPixmap( rightLogo );
279 right->setFixedSize( rightLogo.size() );
280 right->setBackgroundOrigin( QWidget::ParentOrigin );
286 void YQWizard::layoutSideBar( QWidget * parent )
288 _sideBar = new Q3WidgetStack( parent );
289 YUI_CHECK_NEW( _sideBar );
290 _sideBar->setMinimumWidth( YQUI::ui()->defaultSize( YD_HORIZ ) / 5 );
291 _sideBar->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ) ); // hor/vert
292 _sideBar->setMargin( 0 );
302 else if ( _stepsEnabled )
311 void YQWizard::layoutStepsPanel()
313 _stepsPanel = new Q3VBox( _sideBar );
314 YUI_CHECK_NEW( _stepsPanel );
318 if ( ! _titleBarGradientPixmap.isNull() )
322 QLabel * topGradient = new QLabel( _stepsPanel );
323 Q_CHECK_PTR( topGradient );
324 setGradient( topGradient, _topGradientPixmap );
331 _sideBar->addWidget( _stepsPanel );
333 _stepsBox = new Q3VBox( _stepsPanel );
334 YUI_CHECK_NEW( _stepsBox );
336 _stepsBox->setPaletteBackgroundColor( _gradientCenterColor );
338 _stepsBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) ); // hor/vert
340 QWidget * stretch = addVStretch( _stepsPanel );
341 YUI_CHECK_NEW( stretch );
343 stretch->setPaletteBackgroundColor( _gradientCenterColor );
347 // Steps panel bottom buttons ("Help", "Release Notes")
349 QLabel * helpButtonBox = new QLabel( _stepsPanel );
352 YUI_CHECK_NEW( helpButtonBox );
353 setGradient( helpButtonBox, _bottomGradientPixmap );
358 // Layouts for the buttons
360 QVBoxLayout * vbox = new QVBoxLayout( helpButtonBox, 0, 0 ); // parent, margin, spacing
361 YUI_CHECK_NEW( vbox );
362 vbox->addStretch( 99 );
365 QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 ); // parent, spacing
366 hbox->addStretch( 99 );
368 _releaseNotesButton = new QPushButton( _( "Release Notes..." ), helpButtonBox );
369 hbox->addWidget( _releaseNotesButton );
372 connect( _releaseNotesButton, SIGNAL( clicked() ),
373 this, SLOT ( releaseNotesClicked() ) );
375 _releaseNotesButton->hide(); // hidden until showReleaseNotesButton() is called
377 hbox->addStretch( 99 );
378 vbox->addStretch( 99 );
380 hbox = new QHBoxLayout( vbox, 0 ); // parent, spacing
381 hbox->addStretch( 99 );
383 // Help button - intentionally without keyboard shortcut
384 _helpButton = new QPushButton( _( "Help" ), helpButtonBox );
385 YUI_CHECK_NEW( _helpButton );
387 hbox->addWidget( _helpButton );
388 hbox->addStretch( 99 );
390 connect( _helpButton, SIGNAL( clicked() ),
391 this, SLOT ( showHelp() ) );
393 #if USE_ICON_ON_HELP_BUTTON
394 QPixmap pixmap = QPixmap( PIXMAP_DIR "help-button.png" );
396 if ( ! pixmap.isNull() )
397 _helpButton->setPixmap( pixmap );
401 vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
406 void YQWizard::addStep( const string & text, const string & id )
408 QString qId = fromUTF8( id );
410 if ( _stepsIDs[ qId ] )
412 y2error( "Step ID \"%s\" (\"%s\") already used for \"%s\"",
415 (const char *) _stepsIDs[ qId ]->name() );
419 if ( _stepsList.last() && _stepsList.last()->name() == fromUTF8( text ) )
421 // Consecutive steps with the same name will be shown as one single step.
423 // Since steps are always added at the end of the list, it is
424 // sufficient to check the last step of the list. If the texts are the
425 // same, the other with the same text needs to get another (additional)
426 // ID to make sure setCurrentStep() works as it should.
427 _stepsList.last()->addID( qId );
431 _stepsList.append( new YQWizard::Step( fromUTF8( text ), qId ) );
435 _stepsIDs.insert( qId, _stepsList.last() );
440 void YQWizard::addStepHeading( const string & text )
442 _stepsList.append( new YQWizard::StepHeading( fromUTF8( text ) ) );
448 void YQWizard::updateSteps()
454 // Delete any previous step widgets
459 delete _stepsGrid->mainWidget();
465 // Create a new parent widget for the steps
468 QWidget * stepsParent = new QWidget( _stepsBox );
469 YUI_CHECK_NEW( stepsParent );
470 stepsParent->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) ); // hor/vert
472 stepsParent->setPaletteBackgroundColor( _gradientCenterColor );
475 // Create a grid layout for the steps
477 _stepsGrid = new QGridLayout(stepsParent);
478 //_stepsList.count(), 4, // rows, cols
479 _stepsGrid->setMargin(0);
480 _stepsGrid->setSpacing(STEPS_SPACING);
481 YUI_CHECK_NEW( _stepsGrid );
483 const int statusCol = 1;
484 const int nameCol = 2;
486 _stepsGrid->setColStretch( 0, 99 ); // Left margin column - stretch
487 _stepsGrid->setColStretch( statusCol, 0 ); // Status column - don't stretch
488 _stepsGrid->setColStretch( nameCol, 0 ); // Name column - don't stretch
489 _stepsGrid->setColStretch( 3, 99 ); // Left margin column - stretch
492 // Work around Qt bug: Grid layout only works right if the parent widget isn't visible.
496 // Add left and right (but not top and bottom) margins
501 QWidget * leftSpacer = addHSpacing( stepsParent, STEPS_MARGIN );
502 YUI_CHECK_NEW( leftSpacer );
503 _stepsGrid->addWidget( leftSpacer, row, 0 );
505 QWidget * rightSpacer = addHSpacing( stepsParent, STEPS_MARGIN );
506 YUI_CHECK_NEW( rightSpacer );
507 _stepsGrid->addWidget( rightSpacer, row, 3 );
511 // Create widgets for all steps and step headings in the internal list
514 YQWizard::Step * step = _stepsList.first();
518 if ( step->isHeading() )
524 QWidget * spacer = addVSpacing( stepsParent, STEPS_HEADING_SPACING );
525 YUI_CHECK_NEW( spacer );
526 _stepsGrid->addWidget( spacer, row++, nameCol );
533 QLabel * label = new QLabel( step->name(), stepsParent );
534 YUI_CHECK_NEW( label );
535 label->setAlignment( Qt::AlignLeft | Qt::AlignTop );
537 #if USE_FIXED_STEP_FONTS
538 QFont font( STEPS_FONT_FAMILY, STEPS_HEADING_FONT_SIZE );
539 font.setWeight( QFont::Bold );
540 label->setFont( font );
542 QFont font = YQUI::yqApp()->currentFont();
544 int size = font.pointSize();
547 font.setPointSize( size + 2 );
549 font.setBold( true );
550 label->setFont( font );
553 step->setNameLabel( label );
554 _stepsGrid->addMultiCellWidget( label,
555 row, row, // from_row, to_row
556 statusCol, nameCol ); // from_col, to_col
558 else // No heading - ordinary step
564 QLabel * statusLabel = new QLabel( stepsParent );
565 YUI_CHECK_NEW( statusLabel );
567 step->setStatusLabel( statusLabel );
568 _stepsGrid->addWidget( statusLabel, row, statusCol );
575 QLabel * nameLabel = new QLabel( step->name(), stepsParent );
576 YUI_CHECK_NEW( nameLabel );
577 nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop );
579 #if USE_FIXED_STEP_FONTS
580 nameLabel->setFont( QFont( STEPS_FONT_FAMILY, STEPS_FONT_SIZE ) );
582 nameLabel->setFont( YQUI::yqApp()->currentFont() );
585 step->setNameLabel( nameLabel );
586 _stepsGrid->addWidget( nameLabel, row, nameCol );
589 step = _stepsList.next();
593 _stepsGrid->activate();
599 void YQWizard::updateStepStates()
604 YQWizard::Step * currentStep = findStep( _currentStepID );
605 YQWizard::Step * step = _stepsList.first();
609 // Set status icon and color for the current step
610 setStepStatus( currentStep, _stepCurrentIcon, _stepCurrentColor );
614 // Set all steps before the current to "done"
617 while ( step && step != currentStep )
619 setStepStatus( step, _stepDoneIcon, _stepDoneColor );
620 step = _stepsList.next();
623 // Skip the current step - continue with the step after it
626 step = _stepsList.next();
630 // Set all steps after the current to "to do"
635 setStepStatus( step, _stepToDoIcon, _stepToDoColor );
636 step = _stepsList.next();
641 void YQWizard::setStepStatus( YQWizard::Step * step, const QPixmap & icon, const QColor & color )
645 if ( step->nameLabel() )
646 step->nameLabel()->setPaletteForegroundColor( color );
648 if ( step->statusLabel() )
649 step->statusLabel()->setPixmap( icon );
654 void YQWizard::setCurrentStep( const string & id )
656 _currentStepID = fromUTF8( id );
661 void YQWizard::deleteSteps()
668 YQWizard::Step * YQWizard::findStep( const QString & id )
673 return _stepsIDs[ id ];
677 void YQWizard::layoutHelpPanel()
679 _helpPanel = new Q3HBox( _sideBar );
680 YUI_CHECK_NEW( _helpPanel );
681 _sideBar->addWidget( _helpPanel );
683 addGradientColumn( _helpPanel );
685 Q3VBox * vbox = new Q3VBox( _helpPanel );
686 YUI_CHECK_NEW( vbox );
691 _helpBrowser = new Q3TextBrowser( vbox );
692 YUI_CHECK_NEW( _helpBrowser );
694 _helpBrowser->setMimeSourceFactory( 0 );
695 _helpBrowser->installEventFilter( this );
696 _helpBrowser->setTextFormat( Qt::RichText );
697 _helpBrowser->setMargin( 4 );
698 _helpBrowser->setResizePolicy( Q3ScrollView::Manual );
701 // Set help browser text color
702 QPixmap fgPixmap = QPixmap( PIXMAP_DIR "help-text-color.png" );
703 if (! fgPixmap.isNull() )
704 _helpBrowser->setPaletteForegroundColor( pixelColor( fgPixmap, 0, 0, paletteForegroundColor() ) );
707 if ( highColorDisplay() )
709 // Set fancy help browser background pixmap
711 QPixmap bgPixmap( PIXMAP_DIR "help-background.png" );
713 if ( ! bgPixmap.isNull() )
714 _helpBrowser->setPaletteBackgroundPixmap( bgPixmap );
720 // Button box with bottom gradient
724 QLabel * buttonBox = new QLabel( vbox );
725 YUI_CHECK_NEW( buttonBox );
727 QPushButton * button;
732 // "Tree" button - intentionally without keyboard shortcut
733 button = new QPushButton( _( "Tree" ), buttonBox );
734 YUI_CHECK_NEW( button );
735 _treeButton = button;
737 #if USE_ICON_ON_HELP_BUTTON
738 pixmap = QPixmap( PIXMAP_DIR "tree-button.png" );
744 // "Steps" button - intentionally without keyboard shortcut
745 button = new QPushButton( _( "Steps" ), buttonBox );
746 YUI_CHECK_NEW( button );
747 _stepsButton = button;
749 #if USE_ICON_ON_HELP_BUTTON
750 pixmap = QPixmap( PIXMAP_DIR "steps-button.png" );
755 // Create a dummy button just to find out how high it would become
756 button = new QPushButton( "Dummy", buttonBox );
757 YUI_CHECK_NEW( button );
761 if ( ! pixmap.isNull() )
762 button->setPixmap( pixmap );
764 layoutSideBarButtonBox( buttonBox, button );
768 connect( button, SIGNAL( clicked() ),
769 this, SLOT ( showTree() ) );
771 else if ( _stepsEnabled )
773 connect( button, SIGNAL( clicked() ),
774 this, SLOT ( showSteps() ) );
778 // Hide the dummy button - the button box height is fixed now.
782 addGradientColumn( _helpPanel );
787 void YQWizard::layoutSideBarButtonBox( QWidget * parent, QPushButton * button )
789 QVBoxLayout * vbox = new QVBoxLayout( parent, 0, 0 ); // parent, margin, spacing
790 YUI_CHECK_NEW( vbox );
791 vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
793 QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 ); // parent, spacing
794 YUI_CHECK_NEW( hbox );
796 hbox->addStretch( 99 );
797 hbox->addWidget( button );
798 hbox->addStretch( 99 );
800 vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
802 // For whatever strange reason, parent->sizeHint() does not return anything
803 // meaningful yet - not even after vbox->activate() or parent->adjustSize()
804 int height = button->sizeHint().height() + BUTTON_BOX_TOP_MARGIN + WORK_AREA_BOTTOM_MARGIN;
807 if ( ! _bottomGradientPixmap.isNull() )
808 setBottomCroppedGradient( parent, _bottomGradientPixmap, height );
811 parent->setFixedHeight( height );
816 void YQWizard::layoutTreePanel()
818 _treePanel = new Q3HBox( _sideBar );
819 YUI_CHECK_NEW( _treePanel );
820 _sideBar->addWidget( _treePanel );
822 // Left margin (with gradients)
823 addGradientColumn( _treePanel );
825 Q3VBox * vbox = new Q3VBox( _treePanel );
826 YUI_CHECK_NEW( vbox );
831 _tree = new QY2ListView( vbox );
832 YUI_CHECK_NEW( _tree );
835 // _tree->addColumn( "" );
836 // _tree->header()->hide();
838 _tree->setRootIsDecorated( true );
839 _tree->setSortByInsertionSequence( true );
841 connect( _tree, SIGNAL( selectionChanged ( void ) ),
842 this, SLOT ( treeSelectionChanged ( void ) ) );
844 connect( _tree, SIGNAL( spacePressed ( QTreeWidgetItem * ) ),
845 this, SLOT ( sendTreeEvent ( QTreeWidgetItem * ) ) );
847 connect( _tree, SIGNAL( doubleClicked ( QTreeWidgetItem * ) ),
848 this, SLOT ( sendTreeEvent ( QTreeWidgetItem * ) ) );
853 QLabel * buttonBox = new QLabel( vbox );
854 YUI_CHECK_NEW( buttonBox );
857 // "Help" button - intentionally without keyboard shortcut
858 QPushButton * button = new QPushButton( _( "Help" ), buttonBox );
859 YUI_CHECK_NEW( button );
861 #if USE_ICON_ON_HELP_BUTTON
862 QPixmap pixmap( PIXMAP_DIR "help-button.png" );
864 if ( ! pixmap.isNull() )
865 button->setPixmap( pixmap );
868 layoutSideBarButtonBox( buttonBox, button );
870 connect( button, SIGNAL( clicked() ),
871 this, SLOT ( showHelp() ) );
874 // Right margin (with gradients)
875 addGradientColumn( _treePanel );
880 void YQWizard::addTreeItem( const string & parentID, const string & text, const string & id )
882 QString qId = fromUTF8( id );
886 y2error( "YQWizard widget not created with `opt(`treeEnabled) !" );
890 YQWizard::TreeItem * item = 0;
891 YQWizard::TreeItem * parent = 0;
893 if ( ! parentID.empty() )
895 parent = findTreeItem( parentID );
900 item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId );
901 YUI_CHECK_NEW( item );
905 item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId );
906 YUI_CHECK_NEW( item );
909 if ( ! qId.isEmpty() )
910 _treeIDs.insert( qId, item );
915 void YQWizard::deleteTreeItems()
925 YQWizard::TreeItem * YQWizard::findTreeItem( const string & id )
930 return _treeIDs[ fromUTF8( id ) ];
934 void YQWizard::selectTreeItem( const string & id )
938 YQWizard::TreeItem * item = findTreeItem( id );
942 YQSignalBlocker sigBlocker( _tree );
944 _tree->setCurrentItem(item);
945 _tree->scrollToItem(item);
951 void YQWizard::sendTreeEvent( QTreeWidgetItem * listViewItem )
955 YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem );
957 if ( item && ! item->id().isEmpty() )
958 sendEvent( toUTF8( item->id() ) );
963 void YQWizard::treeSelectionChanged()
964 { //FIXME is currentItem correct or selected.first
966 sendTreeEvent( _tree->currentItem() );
970 string YQWizard::currentTreeSelection()
974 QTreeWidgetItem * sel = _tree->currentItem();
978 YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel);
980 if ( item && ! item->id().isEmpty() )
981 return toUTF8( item->id() );
990 void YQWizard::layoutWorkArea( QFrame * parentHBox )
992 Q3VBox * workAreaVBox = new Q3VBox( parentHBox );
993 YUI_CHECK_NEW( workAreaVBox );
995 // An extra QVBox inside the workAreaVBox is needed for frame and margin
997 Q3VBox * workArea = new Q3VBox( workAreaVBox );
998 YUI_CHECK_NEW( workArea );
1000 #if ENABLE_GRADIENTS
1001 workArea->setFrameStyle( QFrame::Box | QFrame::Plain );
1002 workArea->setMargin( 4 );
1004 workArea->setFrameStyle( QFrame::Box | QFrame::Sunken );
1005 // workArea->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Sunken );
1013 // Placed directly inside workArea the menu bar positions itself at (0,0)
1014 // and so obscures any kind of frame there might be.
1015 _menuBarBox = new Q3VBox( workArea );
1016 YUI_CHECK_NEW( _menuBarBox );
1018 _menuBar = new QMenuBar( _menuBarBox );
1019 YUI_CHECK_NEW( _menuBar );
1021 _menuBarBox->hide(); // will be made visible when menus are added
1025 // Dialog icon and heading
1028 Q3HBox * headingHBox = new Q3HBox( workArea );
1029 YUI_CHECK_NEW( headingHBox );
1030 headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1032 addHSpacing( headingHBox, SEPARATOR_MARGIN );
1034 _dialogIcon = new QLabel( headingHBox );
1035 YUI_CHECK_NEW( _dialogIcon );
1036 _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert
1038 addHSpacing( headingHBox );
1040 _dialogHeading = new QLabel( headingHBox );
1041 YUI_CHECK_NEW( _dialogHeading );
1042 _dialogHeading->setFont( YQUI::yqApp()->headingFont() );
1043 _dialogHeading->setAlignment( Qt::AlignLeft | Qt::WordBreak );
1044 _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1047 addHStretch( headingHBox );
1049 addVSpacing( workArea );
1053 Q3HBox * hbox = new Q3HBox( workArea );
1055 addHSpacing( hbox, SEPARATOR_MARGIN );
1057 QFrame * separator = new QFrame( hbox );
1058 YUI_CHECK_NEW( separator );
1059 separator->setFrameStyle( QFrame::HLine | QFrame::Sunken );
1061 addHSpacing( hbox, SEPARATOR_MARGIN );
1062 addVSpacing( workArea );
1066 // Client area (the part that belongs to the YCP application)
1069 layoutClientArea( workArea );
1076 layoutButtonBox( workAreaVBox );
1080 // Spacer (purely decorative) at the right of the client area
1083 addGradientColumn( parentHBox, WORK_AREA_RIGHT_MARGIN );
1088 void YQWizard::layoutClientArea( QWidget * parent )
1090 _clientArea = new Q3VBox( parent );
1091 YUI_CHECK_NEW( _clientArea );
1092 _clientArea->setMargin( 4 );
1095 _clientArea->setPaletteBackgroundColor( QColor( 0x60, 0x60, 0x60 ) );
1100 // HVCenter for wizard contents
1103 _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
1104 YUI_CHECK_NEW( _contents );
1106 _contents->setStretchable( YD_HORIZ, true );
1107 _contents->setStretchable( YD_VERT, true );
1108 _contents->installEventFilter( this );
1109 _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
1113 // Replace point for wizard contents
1116 _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
1119 // Initial YEmpty widget contents of replace point
1122 YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
1123 _contentsReplacePoint->showChild();
1128 void YQWizard::layoutButtonBox( QWidget * parent )
1131 // Button box and layout
1134 QWidget * buttonBox = new QWidget( parent );
1135 YUI_CHECK_NEW( buttonBox );
1137 // Using old-style layouts to enable a seamless background with the
1138 // gradient pixmap: Any sub-widgets (Q3VBox, QHBox) would have to get yet
1139 // another portion of that gradient as their backround pixmap, and it would
1140 // be very hard to cover all cases - resizing, hiding individual buttons, etc.
1142 QVBoxLayout * vbox = new QVBoxLayout( buttonBox, 0, 0 ); // parent, margin, spacing
1143 YUI_CHECK_NEW( vbox );
1145 vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
1149 // QHBoxLayout for the buttons
1152 QHBoxLayout * hbox = new QHBoxLayout( vbox, 2 ); // parent, spacing
1153 YUI_CHECK_NEW( hbox );
1160 _backButton = new YQWizardButton( this, buttonBox, _backButtonLabel );
1161 YUI_CHECK_NEW( _backButton );
1163 hbox->addWidget( (QWidget *) _backButton->widgetRep() );
1164 connect( _backButton, SIGNAL( clicked() ),
1165 this, SLOT ( slotBackClicked() ) );
1167 _backButtonSpacer = new QSpacerItem( 0, 0, // width, height
1168 QSizePolicy::Expanding, // horizontal
1169 QSizePolicy::Minimum ); // vertical
1170 YUI_CHECK_NEW( _backButtonSpacer );
1171 hbox->addItem( _backButtonSpacer );
1174 if ( _backButton->text().isEmpty() )
1176 _backButton->hide();
1178 // Minimize _backButtonSpacer
1179 _backButtonSpacer->changeSize( 0, 0, // width, height
1180 QSizePolicy::Minimum, // horizontal
1181 QSizePolicy::Minimum ); // vertical
1189 _abortButton = new YQWizardButton( this, buttonBox, _abortButtonLabel );
1190 YUI_CHECK_NEW( _abortButton );
1192 hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
1193 connect( _abortButton, SIGNAL( clicked() ),
1194 this, SLOT ( slotAbortClicked() ) );
1197 // Using spacer rather than addSpacing() since the default stretchability
1198 // of a QSpacerItem is undefined, i.e. centering the middle button could
1199 // not be guaranteed.
1201 QSpacerItem * spacer = new QSpacerItem( 0, 0, // width, height
1202 QSizePolicy::Expanding, // horizontal
1203 QSizePolicy::Minimum ); // vertical
1204 YUI_CHECK_NEW( spacer );
1205 hbox->addItem( spacer );
1212 _nextButton = new YQWizardButton( this, buttonBox, _nextButtonLabel );
1213 YUI_CHECK_NEW( _nextButton );
1215 hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
1216 connect( _nextButton, SIGNAL( clicked() ),
1217 this, SLOT ( slotNextClicked() ) );
1221 // Bottom margin and gradient
1224 vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
1226 #if ENABLE_GRADIENTS
1227 setBottomCroppedGradient( buttonBox, _bottomGradientPixmap, buttonBox->sizeHint().height() );
1230 buttonBox->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); // hor/vert
1235 void YQWizard::loadGradientPixmaps()
1237 #if ENABLE_GRADIENTS
1238 if ( highColorDisplay() )
1240 _topGradientPixmap = QPixmap( PIXMAP_DIR "top-gradient.png" );
1241 _bottomGradientPixmap = QPixmap( PIXMAP_DIR "bottom-gradient.png" );
1242 _titleBarGradientPixmap = QPixmap( PIXMAP_DIR "title-bar-gradient.png" );
1243 _gradientCenterColor = pixelColor( _bottomGradientPixmap, 0, 0, paletteBackgroundColor() );
1244 _gradientTopColor = pixelColor( _topGradientPixmap, 0, 0 , paletteBackgroundColor() );
1246 else // 8 bit display or worse - don't use gradients
1248 // Gradient pixmaps remain empty. The respecive widgets will retain the
1249 // default widget background (grey, depending on the widget theme).
1251 // Use deault widget background (some shade of grey) for the center
1252 // stretchable part of the side bar.
1253 _gradientCenterColor = paletteBackgroundColor();
1254 _gradientTopColor = paletteBackgroundColor();
1260 void YQWizard::loadStepsIcons()
1262 _stepCurrentIcon = YQIconPool::stepCurrent();
1263 _stepToDoIcon = YQIconPool::stepToDo();
1264 _stepDoneIcon = YQIconPool::stepDone();
1266 if ( highColorDisplay() )
1268 _stepCurrentColor = pixelColor( QPixmap( PIXMAP_DIR "color-step-current.png" ), 0, 0, paletteForegroundColor() );
1269 _stepToDoColor = pixelColor( QPixmap( PIXMAP_DIR "color-step-todo.png" ), 0, 0, paletteForegroundColor() );
1270 _stepDoneColor = pixelColor( QPixmap( PIXMAP_DIR "color-step-done.png" ), 0, 0, paletteForegroundColor() );
1274 _stepCurrentColor = paletteForegroundColor();
1275 _stepToDoColor = paletteForegroundColor();
1276 _stepDoneColor = paletteForegroundColor();
1282 void YQWizard::setGradient( QWidget * widget, const QPixmap & pixmap )
1284 #if ENABLE_GRADIENTS
1285 if ( widget && ! pixmap.isNull() )
1287 widget->setFixedHeight( pixmap.height() );
1288 widget->setPaletteBackgroundPixmap( pixmap );
1295 void YQWizard::setBottomCroppedGradient( QWidget * widget, const QPixmap & pixmap, int croppedHeight )
1297 #if ENABLE_GRADIENTS
1298 setGradient( widget, bottomCropPixmap( pixmap, croppedHeight ) );
1304 QPixmap YQWizard::bottomCropPixmap( const QPixmap & full, int croppedHeight )
1308 #if ENABLE_GRADIENTS
1310 if ( full.height() > croppedHeight )
1312 pixmap = QPixmap( full.width(), croppedHeight );
1314 bitBlt( &pixmap, 0, 0, // dest, dest_x, dest_y
1315 &full, 0, full.height() - croppedHeight - 1, // src, src_x, src_y
1316 full.width(), croppedHeight ); // src_width, src_height
1329 QColor YQWizard::pixelColor( const QPixmap & pixmap, int x, int y, const QColor & defaultColor )
1331 if ( pixmap.isNull() )
1332 return defaultColor;
1334 // QPixmap doesn't allow direct access to pixel values (which makes some
1335 // sense since this requires a round-trip to the X server - pixmaps are X
1336 // server resources), so we need to convert the QPixmap to a QImage to get
1337 // that information. But since this conversion is expensive, we might save
1338 // some performance if we only convert the part we really need - so let's
1339 // cut out a tiny portion of the original pixmap and convert only that tiny
1343 QPixmap tiny( 1, 1 );
1345 bitBlt( &tiny, 0, 0, // dest, dest_x, dest_y
1346 &pixmap, x, y, // src, src_x, src_y
1347 1, 1 ); // src_width, src_height
1349 QImage image = tiny.convertToImage();
1352 return QColor( image.pixel( 0, 0 ) );
1357 void YQWizard::addGradientColumn( QWidget * parent, int width )
1362 Q3VBox * vbox = new Q3VBox( parent );
1363 YUI_CHECK_NEW( vbox );
1365 #if ENABLE_GRADIENTS
1366 QWidget * topGradient = addHSpacing( vbox, width );
1367 YUI_CHECK_NEW( topGradient );
1368 setGradient( topGradient, _topGradientPixmap );
1370 QWidget * centerStretch = new QWidget( vbox );
1371 YUI_CHECK_NEW( centerStretch );
1372 centerStretch->setPaletteBackgroundColor( _gradientCenterColor );
1375 QWidget * bottomGradient = new QWidget( vbox );
1376 YUI_CHECK_NEW( bottomGradient );
1377 setGradient( bottomGradient, _bottomGradientPixmap );
1379 vbox->setFixedWidth( width );
1385 void YQWizard::destroyButtons()
1395 delete _abortButton;
1408 bool YQWizard::highColorDisplay() const
1414 void YQWizard::connectNotify ( const char * signal )
1416 if ( QString( signal ).contains( "nextClicked()" ) )
1418 y2debug( "nextClicked connected, no longer directly sending button events" );
1419 _sendButtonEvents = false;
1424 void YQWizard::disconnectNotify ( const char * signal )
1426 if ( QString( signal ).contains( "nextClicked()" ) )
1428 y2debug( "nextClicked disconnected, directly sending button events again" );
1429 _sendButtonEvents = true;
1434 void YQWizard::setDialogIcon( const string & iconName )
1438 if ( ! iconName.empty() )
1440 QPixmap icon( iconName.c_str() );
1442 if ( icon.isNull() )
1443 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
1446 _dialogIcon->setPixmap( icon );
1447 topLevelWidget()->setIcon( icon );
1452 _dialogIcon->clear();
1453 topLevelWidget()->setIcon( QPixmap() );
1459 void YQWizard::setDialogHeading( const string & headingText )
1461 if ( _dialogHeading )
1463 if ( ! headingText.empty() )
1464 _dialogHeading->setText( fromUTF8( headingText ) );
1466 _dialogHeading->clear();
1470 string YQWizard::debugLabel()
1472 if ( _dialogHeading )
1474 QString label = _dialogHeading->text();
1475 label.simplifyWhiteSpace(); // Replace any embedded newline with a single blank
1477 if ( ! label.isEmpty() )
1479 label.prepend( "YQWizard \"" );
1480 label.append( "\"" );
1482 return toUTF8( label );
1486 return "untitled YQWizard";
1489 void YQWizard::setHelpText( const string & helpText )
1493 if ( ! helpText.empty() )
1495 QString qHelpText = fromUTF8( helpText );
1496 qHelpText.replace( "&product;", YQUI::ui()->productName() );
1497 _helpBrowser->setText( qHelpText );
1500 _helpBrowser->clear();
1505 void YQWizard::slotBackClicked()
1509 if ( _sendButtonEvents )
1510 YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
1512 _direction = YQWizard::Backward;
1516 void YQWizard::slotAbortClicked()
1518 emit abortClicked();
1520 if ( _sendButtonEvents )
1521 YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
1525 void YQWizard::slotNextClicked()
1529 if ( _sendButtonEvents )
1530 YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1532 _direction = YQWizard::Forward;
1536 void YQWizard::showHelp()
1538 if ( _sideBar && _helpPanel )
1540 _sideBar->raiseWidget( _helpPanel );
1545 void YQWizard::releaseNotesClicked()
1547 YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1549 if ( ! _releaseNotesButtonId.empty() )
1551 y2milestone( "Release Notes button clicked" );
1552 sendEvent( _releaseNotesButtonId );
1557 void YQWizard::showSteps()
1559 if ( _sideBar && _stepsPanel )
1561 _sideBar->raiseWidget( _stepsPanel );
1566 void YQWizard::showTree()
1568 if ( _sideBar && _treePanel )
1570 _sideBar->raiseWidget( _treePanel );
1576 void YQWizard::addMenu( const string & text,
1581 Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1582 YUI_CHECK_NEW( menu );
1584 _menuIDs.insert( fromUTF8( id ), menu );
1585 _menuBar->insertItem( fromUTF8( text ), menu );
1587 connect( menu, SIGNAL( activated ( int ) ),
1588 this, SLOT ( sendMenuEvent( int ) ) );
1590 if ( _menuBarBox && _menuBarBox->isHidden() )
1592 _menuBarBox->show();
1593 _menuBarBox->setFixedHeight( _menuBar->sizeHint().height() + MENU_BAR_MARGIN );
1599 void YQWizard::addSubMenu( const string & parentMenuID,
1600 const string & text,
1603 Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1607 Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1608 YUI_CHECK_NEW( menu );
1610 _menuIDs.insert( fromUTF8( id ), menu );
1611 parentMenu->insertItem( fromUTF8( text ), menu );
1613 connect( menu, SIGNAL( activated ( int ) ),
1614 this, SLOT ( sendMenuEvent( int ) ) );
1618 y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1623 void YQWizard::addMenuEntry( const string & parentMenuID,
1624 const string & text,
1625 const string & idString )
1627 Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1631 int id = _menuEntryIDs.size();
1632 _menuEntryIDs.push_back( idString );
1633 parentMenu->insertItem( fromUTF8( text ), id );
1637 y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1642 void YQWizard::addMenuSeparator( const string & parentMenuID )
1644 Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1648 parentMenu->insertSeparator();
1652 y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1657 void YQWizard::deleteMenus()
1661 _menuBarBox->hide();
1664 _menuEntryIDs.clear();
1669 void YQWizard::sendMenuEvent( int numID )
1671 if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
1673 sendEvent( _menuEntryIDs[ numID ] );
1677 y2error( "Invalid menu ID: %d", numID );
1682 void YQWizard::sendEvent( const string & id )
1684 YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1688 int YQWizard::preferredWidth()
1690 return sizeHint().width();
1694 int YQWizard::preferredHeight()
1696 return sizeHint().height();
1700 void YQWizard::setSize( int newWidth, int newHeight )
1702 resize( newWidth, newHeight );
1708 void YQWizard::resizeClientArea()
1710 // y2debug( "resizing client area" );
1711 QRect contentsRect = _clientArea->contentsRect();
1712 _contents->setSize( contentsRect.width(), contentsRect.height() );
1717 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1719 if ( ev->type() == QEvent::Resize && obj == _contents )
1722 return true; // Event handled
1725 return QWidget::eventFilter( obj, ev );
1729 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1731 button->setLabel( newLabel );
1732 YDialog::currentDialog()->checkShortcuts();
1734 YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1738 if ( newLabel.empty() )
1740 wizardButton->hide();
1742 if ( wizardButton == _backButton && _backButtonSpacer )
1744 // Minimize _backButtonSpacer
1746 _backButtonSpacer->changeSize( 0, 0, // width, height
1747 QSizePolicy::Minimum, // horizontal
1748 QSizePolicy::Minimum ); // vertical
1753 wizardButton->show();
1755 if ( button == _backButton && _backButtonSpacer )
1757 // Restore _backButtonSpacer to normal size
1759 _backButtonSpacer->changeSize( 0, 0, // width, height
1760 QSizePolicy::Expanding, // horizontal
1761 QSizePolicy::Minimum ); // vertical
1768 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1770 if ( ! _releaseNotesButton )
1772 y2error( "NULL Release Notes button" );
1775 y2error( "This works only if there is a \"steps\" panel!" );
1780 // no way to check the shortcut, so strip it
1781 _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1782 _releaseNotesButtonId = id;
1784 if ( _releaseNotesButton->isHidden() )
1785 _releaseNotesButton->show();
1790 void YQWizard::hideReleaseNotesButton()
1792 if ( _releaseNotesButton && !_releaseNotesButton->isHidden() )
1793 _releaseNotesButton->hide();
1797 void YQWizard::retranslateInternalButtons()
1799 YQUI::setTextdomain( TEXTDOMAIN );
1802 // "Help" button - intentionally without keyboard shortcut
1803 _helpButton->setText( _( "Help" ) );
1806 // "Steps" button - intentionally without keyboard shortcut
1807 _stepsButton->setText( _( "Steps" ) );
1810 // "Tree" button - intentionally without keyboard shortcut
1811 _treeButton->setText( _( "Tree" ) );
1814 #include "YQWizard.moc"