1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
15 Author: Stefan Hundhammer <sh@suse.de>
17 Textdomain "packages-qt"
23 #define y2log_component "qt-wizard"
24 #include <ycp/y2log.h>
26 // For the command parser
29 #include <YShortcut.h>
37 #include <qmenudata.h>
40 #include <q3popupmenu.h>
41 #include <qpushbutton.h>
43 #include <qtabwidget.h>
44 #include <q3textbrowser.h>
45 #include <qtoolbutton.h>
46 #include <q3widgetstack.h>
48 #include "QY2ListView.h"
50 #include <q3boxlayout.h>
51 #include <q3gridlayout.h>
54 #include <q3boxlayout.h>
59 #include "YQApplication.h"
61 #include "YQAlignment.h"
62 #include "YQReplacePoint.h"
65 #include "YQWizardButton.h"
66 #include "YQIconPool.h"
67 #include "YQWidgetFactory.h"
68 #include "YQSignalBlocker.h"
69 #include "QY2LayoutUtils.h"
75 #define PIXMAP_DIR THEMEDIR "/wizard/"
81 #define TEXTDOMAIN "packages-qt"
83 #define ENABLE_GRADIENTS 1
85 #define USE_SEPARATOR 1
87 #define WORK_AREA_TOP_MARGIN 10
90 # define WORK_AREA_BOTTOM_MARGIN 8
91 # define WORK_AREA_RIGHT_MARGIN 8
93 # define WORK_AREA_BOTTOM_MARGIN 8
94 # define WORK_AREA_RIGHT_MARGIN 6
97 #define BUTTON_BOX_TOP_MARGIN 10
99 #define SEPARATOR_MARGIN 6
100 #define STEPS_MARGIN 10
101 #define STEPS_SPACING 2
102 #define STEPS_HEADING_SPACING 8
103 #define MENU_BAR_MARGIN 8
105 #define USE_FIXED_STEP_FONTS 0
106 #define STEPS_FONT_FAMILY "Sans Serif"
107 #define STEPS_FONT_SIZE 11
108 #define STEPS_HEADING_FONT_SIZE 11
110 #define USE_ICON_ON_HELP_BUTTON 0
113 YQWizard::YQWizard( YWidget * parent,
114 const string & backButtonLabel,
115 const string & abortButtonLabel,
116 const string & nextButtonLabel,
117 YWizardMode wizardMode )
118 : QFrame( (QWidget *) parent->widgetRep() )
124 , _backButtonLabel( backButtonLabel )
125 , _abortButtonLabel( abortButtonLabel )
126 , _nextButtonLabel( nextButtonLabel )
128 QVBoxLayout* layout = new QVBoxLayout( this );
129 layout->setSpacing( 0 );
130 layout->setMargin( 0 );
133 setWidgetRep( this );
135 _stepsEnabled = (wizardMode == YWizardMode_Steps);
136 _treeEnabled = (wizardMode == YWizardMode_Tree);
139 _direction = YQWizard::Forward;
148 _releaseNotesButton = 0;
160 _backButtonSpacer = 0;
163 _sendButtonEvents = true;
164 _contentsReplacePoint = 0;
166 _stepsList.setAutoDelete( true );
167 _stepsIDs.setAutoDelete( false ); // Only for one of both!
169 YQUI::setTextdomain( TEXTDOMAIN );
177 loadGradientPixmaps();
189 if ( ! _titleBarGradientPixmap.isNull() )
191 layoutTitleBar( this );
195 QWidget * spacer = addVSpacing( this, WORK_AREA_TOP_MARGIN );
196 Q_CHECK_PTR( spacer );
198 # if ENABLE_GRADIENTS
199 spacer->setPaletteBackgroundColor( _gradientTopColor );
203 Q3HBox * hBox = new Q3HBox( this );
204 YUI_CHECK_NEW( hBox );
205 layout->addWidget( hBox );
207 layoutSideBar( hBox );
208 layoutWorkArea( hBox );
210 y2debug( "Constructor finished." );
215 YQWizard::~YQWizard()
222 void YQWizard::layoutTitleBar( QWidget * parent )
224 if ( ! highColorDisplay() ) // 8 bit display or worse?
226 // No colorful title bar, just a spacing to match the one at the bottom.
227 addVSpacing( parent, WORK_AREA_BOTTOM_MARGIN );
233 Q3HBox * titleBar = new Q3HBox( parent );
234 YUI_CHECK_NEW( titleBar );
237 setGradient( titleBar, _titleBarGradientPixmap );
240 titleBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); // hor/vert
246 QLabel * left = new QLabel( titleBar );
247 left->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert
249 QPixmap leftLogo( PIXMAP_DIR "title-bar-left.png" );
251 if ( ! leftLogo.isNull() )
253 left->setPixmap( leftLogo );
254 left->setFixedSize( leftLogo.size() );
255 left->setBackgroundOrigin( QWidget::ParentOrigin );
260 // Center stretch space
263 addHStretch( titleBar );
270 QLabel * right = new QLabel( titleBar );
271 YUI_CHECK_NEW( right );
273 QPixmap rightLogo( PIXMAP_DIR "title-bar-right.png" );
275 if ( ! rightLogo.isNull() )
277 right->setPixmap( rightLogo );
278 right->setFixedSize( rightLogo.size() );
279 right->setBackgroundOrigin( QWidget::ParentOrigin );
285 void YQWizard::layoutSideBar( QWidget * parent )
287 _sideBar = new Q3WidgetStack( parent );
288 YUI_CHECK_NEW( _sideBar );
289 _sideBar->setMinimumWidth( YQUI::ui()->defaultSize( YD_HORIZ ) / 5 );
290 _sideBar->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ) ); // hor/vert
291 _sideBar->setMargin( 0 );
301 else if ( _stepsEnabled )
310 void YQWizard::layoutStepsPanel()
312 _stepsPanel = new Q3VBox( _sideBar );
313 YUI_CHECK_NEW( _stepsPanel );
317 if ( ! _titleBarGradientPixmap.isNull() )
321 QLabel * topGradient = new QLabel( _stepsPanel );
322 Q_CHECK_PTR( topGradient );
323 setGradient( topGradient, _topGradientPixmap );
330 _sideBar->addWidget( _stepsPanel );
332 _stepsBox = new Q3VBox( _stepsPanel );
333 YUI_CHECK_NEW( _stepsBox );
335 _stepsBox->setPaletteBackgroundColor( _gradientCenterColor );
337 _stepsBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) ); // hor/vert
339 QWidget * stretch = addVStretch( _stepsPanel );
340 YUI_CHECK_NEW( stretch );
342 stretch->setPaletteBackgroundColor( _gradientCenterColor );
346 // Steps panel bottom buttons ("Help", "Release Notes")
348 QLabel * helpButtonBox = new QLabel( _stepsPanel );
351 YUI_CHECK_NEW( helpButtonBox );
352 setGradient( helpButtonBox, _bottomGradientPixmap );
357 // Layouts for the buttons
359 QVBoxLayout * vbox = new QVBoxLayout( helpButtonBox, 0, 0 ); // parent, margin, spacing
360 YUI_CHECK_NEW( vbox );
361 vbox->addStretch( 99 );
364 QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 ); // parent, spacing
365 hbox->addStretch( 99 );
367 _releaseNotesButton = new QPushButton( _( "Release Notes..." ), helpButtonBox );
368 hbox->addWidget( _releaseNotesButton );
371 connect( _releaseNotesButton, SIGNAL( clicked() ),
372 this, SLOT ( releaseNotesClicked() ) );
374 _releaseNotesButton->hide(); // hidden until showReleaseNotesButton() is called
376 hbox->addStretch( 99 );
377 vbox->addStretch( 99 );
379 hbox = new QHBoxLayout( vbox, 0 ); // parent, spacing
380 hbox->addStretch( 99 );
382 // Help button - intentionally without keyboard shortcut
383 _helpButton = new QPushButton( _( "Help" ), helpButtonBox );
384 YUI_CHECK_NEW( _helpButton );
386 hbox->addWidget( _helpButton );
387 hbox->addStretch( 99 );
389 connect( _helpButton, SIGNAL( clicked() ),
390 this, SLOT ( showHelp() ) );
392 #if USE_ICON_ON_HELP_BUTTON
393 QPixmap pixmap = QPixmap( PIXMAP_DIR "help-button.png" );
395 if ( ! pixmap.isNull() )
396 _helpButton->setPixmap( pixmap );
400 vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
405 void YQWizard::addStep( const string & text, const string & id )
407 QString qId = fromUTF8( id );
409 if ( _stepsIDs[ qId ] )
411 y2error( "Step ID \"%s\" (\"%s\") already used for \"%s\"",
414 (const char *) _stepsIDs[ qId ]->name() );
418 if ( _stepsList.last() && _stepsList.last()->name() == fromUTF8( text ) )
420 // Consecutive steps with the same name will be shown as one single step.
422 // Since steps are always added at the end of the list, it is
423 // sufficient to check the last step of the list. If the texts are the
424 // same, the other with the same text needs to get another (additional)
425 // ID to make sure setCurrentStep() works as it should.
426 _stepsList.last()->addID( qId );
430 _stepsList.append( new YQWizard::Step( fromUTF8( text ), qId ) );
434 _stepsIDs.insert( qId, _stepsList.last() );
439 void YQWizard::addStepHeading( const string & text )
441 _stepsList.append( new YQWizard::StepHeading( fromUTF8( text ) ) );
447 void YQWizard::updateSteps()
453 // Delete any previous step widgets
458 delete _stepsGrid->mainWidget();
464 // Create a new parent widget for the steps
467 QWidget * stepsParent = new QWidget( _stepsBox );
468 YUI_CHECK_NEW( stepsParent );
469 stepsParent->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) ); // hor/vert
471 stepsParent->setPaletteBackgroundColor( _gradientCenterColor );
474 // Create a grid layout for the steps
476 _stepsGrid = new Q3GridLayout( stepsParent, // parent
477 _stepsList.count(), 4, // rows, cols
478 0, STEPS_SPACING ); // margin, spacing
479 YUI_CHECK_NEW( _stepsGrid );
481 const int statusCol = 1;
482 const int nameCol = 2;
484 _stepsGrid->setColStretch( 0, 99 ); // Left margin column - stretch
485 _stepsGrid->setColStretch( statusCol, 0 ); // Status column - don't stretch
486 _stepsGrid->setColStretch( nameCol, 0 ); // Name column - don't stretch
487 _stepsGrid->setColStretch( 3, 99 ); // Left margin column - stretch
490 // Work around Qt bug: Grid layout only works right if the parent widget isn't visible.
494 // Add left and right (but not top and bottom) margins
499 QWidget * leftSpacer = addHSpacing( stepsParent, STEPS_MARGIN );
500 YUI_CHECK_NEW( leftSpacer );
501 _stepsGrid->addWidget( leftSpacer, row, 0 );
503 QWidget * rightSpacer = addHSpacing( stepsParent, STEPS_MARGIN );
504 YUI_CHECK_NEW( rightSpacer );
505 _stepsGrid->addWidget( rightSpacer, row, 3 );
509 // Create widgets for all steps and step headings in the internal list
512 YQWizard::Step * step = _stepsList.first();
516 if ( step->isHeading() )
522 QWidget * spacer = addVSpacing( stepsParent, STEPS_HEADING_SPACING );
523 YUI_CHECK_NEW( spacer );
524 _stepsGrid->addWidget( spacer, row++, nameCol );
531 QLabel * label = new QLabel( step->name(), stepsParent );
532 YUI_CHECK_NEW( label );
533 label->setAlignment( Qt::AlignLeft | Qt::AlignTop );
535 #if USE_FIXED_STEP_FONTS
536 QFont font( STEPS_FONT_FAMILY, STEPS_HEADING_FONT_SIZE );
537 font.setWeight( QFont::Bold );
538 label->setFont( font );
540 QFont font = YQUI::yqApp()->currentFont();
542 int size = font.pointSize();
545 font.setPointSize( size + 2 );
547 font.setBold( true );
548 label->setFont( font );
551 step->setNameLabel( label );
552 _stepsGrid->addMultiCellWidget( label,
553 row, row, // from_row, to_row
554 statusCol, nameCol ); // from_col, to_col
556 else // No heading - ordinary step
562 QLabel * statusLabel = new QLabel( stepsParent );
563 YUI_CHECK_NEW( statusLabel );
565 step->setStatusLabel( statusLabel );
566 _stepsGrid->addWidget( statusLabel, row, statusCol );
573 QLabel * nameLabel = new QLabel( step->name(), stepsParent );
574 YUI_CHECK_NEW( nameLabel );
575 nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop );
577 #if USE_FIXED_STEP_FONTS
578 nameLabel->setFont( QFont( STEPS_FONT_FAMILY, STEPS_FONT_SIZE ) );
580 nameLabel->setFont( YQUI::yqApp()->currentFont() );
583 step->setNameLabel( nameLabel );
584 _stepsGrid->addWidget( nameLabel, row, nameCol );
587 step = _stepsList.next();
591 _stepsGrid->activate();
597 void YQWizard::updateStepStates()
602 YQWizard::Step * currentStep = findStep( _currentStepID );
603 YQWizard::Step * step = _stepsList.first();
607 // Set status icon and color for the current step
608 setStepStatus( currentStep, _stepCurrentIcon, _stepCurrentColor );
612 // Set all steps before the current to "done"
615 while ( step && step != currentStep )
617 setStepStatus( step, _stepDoneIcon, _stepDoneColor );
618 step = _stepsList.next();
621 // Skip the current step - continue with the step after it
624 step = _stepsList.next();
628 // Set all steps after the current to "to do"
633 setStepStatus( step, _stepToDoIcon, _stepToDoColor );
634 step = _stepsList.next();
639 void YQWizard::setStepStatus( YQWizard::Step * step, const QPixmap & icon, const QColor & color )
643 if ( step->nameLabel() )
644 step->nameLabel()->setPaletteForegroundColor( color );
646 if ( step->statusLabel() )
647 step->statusLabel()->setPixmap( icon );
652 void YQWizard::setCurrentStep( const string & id )
654 _currentStepID = fromUTF8( id );
659 void YQWizard::deleteSteps()
666 YQWizard::Step * YQWizard::findStep( const QString & id )
671 return _stepsIDs[ id ];
675 void YQWizard::layoutHelpPanel()
677 _helpPanel = new Q3HBox( _sideBar );
678 YUI_CHECK_NEW( _helpPanel );
679 _sideBar->addWidget( _helpPanel );
681 addGradientColumn( _helpPanel );
683 Q3VBox * vbox = new Q3VBox( _helpPanel );
684 YUI_CHECK_NEW( vbox );
689 _helpBrowser = new Q3TextBrowser( vbox );
690 YUI_CHECK_NEW( _helpBrowser );
692 _helpBrowser->setMimeSourceFactory( 0 );
693 _helpBrowser->installEventFilter( this );
694 _helpBrowser->setTextFormat( Qt::RichText );
695 _helpBrowser->setMargin( 4 );
696 _helpBrowser->setResizePolicy( Q3ScrollView::Manual );
699 // Set help browser text color
700 QPixmap fgPixmap = QPixmap( PIXMAP_DIR "help-text-color.png" );
701 if (! fgPixmap.isNull() )
702 _helpBrowser->setPaletteForegroundColor( pixelColor( fgPixmap, 0, 0, paletteForegroundColor() ) );
705 if ( highColorDisplay() )
707 // Set fancy help browser background pixmap
709 QPixmap bgPixmap( PIXMAP_DIR "help-background.png" );
711 if ( ! bgPixmap.isNull() )
712 _helpBrowser->setPaletteBackgroundPixmap( bgPixmap );
718 // Button box with bottom gradient
722 QLabel * buttonBox = new QLabel( vbox );
723 YUI_CHECK_NEW( buttonBox );
725 QPushButton * button;
730 // "Tree" button - intentionally without keyboard shortcut
731 button = new QPushButton( _( "Tree" ), buttonBox );
732 YUI_CHECK_NEW( button );
733 _treeButton = button;
735 #if USE_ICON_ON_HELP_BUTTON
736 pixmap = QPixmap( PIXMAP_DIR "tree-button.png" );
742 // "Steps" button - intentionally without keyboard shortcut
743 button = new QPushButton( _( "Steps" ), buttonBox );
744 YUI_CHECK_NEW( button );
745 _stepsButton = button;
747 #if USE_ICON_ON_HELP_BUTTON
748 pixmap = QPixmap( PIXMAP_DIR "steps-button.png" );
753 // Create a dummy button just to find out how high it would become
754 button = new QPushButton( "Dummy", buttonBox );
755 YUI_CHECK_NEW( button );
759 if ( ! pixmap.isNull() )
760 button->setPixmap( pixmap );
762 layoutSideBarButtonBox( buttonBox, button );
766 connect( button, SIGNAL( clicked() ),
767 this, SLOT ( showTree() ) );
769 else if ( _stepsEnabled )
771 connect( button, SIGNAL( clicked() ),
772 this, SLOT ( showSteps() ) );
776 // Hide the dummy button - the button box height is fixed now.
780 addGradientColumn( _helpPanel );
785 void YQWizard::layoutSideBarButtonBox( QWidget * parent, QPushButton * button )
787 QVBoxLayout * vbox = new QVBoxLayout( parent, 0, 0 ); // parent, margin, spacing
788 YUI_CHECK_NEW( vbox );
789 vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
791 QHBoxLayout * hbox = new QHBoxLayout( vbox, 0 ); // parent, spacing
792 YUI_CHECK_NEW( hbox );
794 hbox->addStretch( 99 );
795 hbox->addWidget( button );
796 hbox->addStretch( 99 );
798 vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
800 // For whatever strange reason, parent->sizeHint() does not return anything
801 // meaningful yet - not even after vbox->activate() or parent->adjustSize()
802 int height = button->sizeHint().height() + BUTTON_BOX_TOP_MARGIN + WORK_AREA_BOTTOM_MARGIN;
805 if ( ! _bottomGradientPixmap.isNull() )
806 setBottomCroppedGradient( parent, _bottomGradientPixmap, height );
809 parent->setFixedHeight( height );
814 void YQWizard::layoutTreePanel()
816 _treePanel = new Q3HBox( _sideBar );
817 YUI_CHECK_NEW( _treePanel );
818 _sideBar->addWidget( _treePanel );
820 // Left margin (with gradients)
821 addGradientColumn( _treePanel );
823 Q3VBox * vbox = new Q3VBox( _treePanel );
824 YUI_CHECK_NEW( vbox );
829 _tree = new QY2ListView( vbox );
830 YUI_CHECK_NEW( _tree );
832 _tree->addColumn( "" );
833 _tree->header()->hide();
834 _tree->setRootIsDecorated( true );
835 _tree->setSortByInsertionSequence( true );
837 connect( _tree, SIGNAL( selectionChanged ( void ) ),
838 this, SLOT ( treeSelectionChanged ( void ) ) );
840 connect( _tree, SIGNAL( spacePressed ( Q3ListViewItem * ) ),
841 this, SLOT ( sendTreeEvent ( Q3ListViewItem * ) ) );
843 connect( _tree, SIGNAL( doubleClicked ( Q3ListViewItem * ) ),
844 this, SLOT ( sendTreeEvent ( Q3ListViewItem * ) ) );
849 QLabel * buttonBox = new QLabel( vbox );
850 YUI_CHECK_NEW( buttonBox );
853 // "Help" button - intentionally without keyboard shortcut
854 QPushButton * button = new QPushButton( _( "Help" ), buttonBox );
855 YUI_CHECK_NEW( button );
857 #if USE_ICON_ON_HELP_BUTTON
858 QPixmap pixmap( PIXMAP_DIR "help-button.png" );
860 if ( ! pixmap.isNull() )
861 button->setPixmap( pixmap );
864 layoutSideBarButtonBox( buttonBox, button );
866 connect( button, SIGNAL( clicked() ),
867 this, SLOT ( showHelp() ) );
870 // Right margin (with gradients)
871 addGradientColumn( _treePanel );
876 void YQWizard::addTreeItem( const string & parentID, const string & text, const string & id )
878 QString qId = fromUTF8( id );
882 y2error( "YQWizard widget not created with `opt(`treeEnabled) !" );
886 YQWizard::TreeItem * item = 0;
887 YQWizard::TreeItem * parent = 0;
889 if ( ! parentID.empty() )
891 parent = findTreeItem( parentID );
896 item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId );
897 YUI_CHECK_NEW( item );
901 item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId );
902 YUI_CHECK_NEW( item );
905 if ( ! qId.isEmpty() )
906 _treeIDs.insert( qId, item );
911 void YQWizard::deleteTreeItems()
921 YQWizard::TreeItem * YQWizard::findTreeItem( const string & id )
926 return _treeIDs[ fromUTF8( id ) ];
930 void YQWizard::selectTreeItem( const string & id )
934 YQWizard::TreeItem * item = findTreeItem( id );
938 YQSignalBlocker sigBlocker( _tree );
940 _tree->setSelected( item, true );
941 _tree->ensureItemVisible( item );
947 void YQWizard::sendTreeEvent( Q3ListViewItem * listViewItem )
951 YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem );
953 if ( item && ! item->id().isEmpty() )
954 sendEvent( toUTF8( item->id() ) );
959 void YQWizard::treeSelectionChanged()
962 sendTreeEvent( _tree->selectedItem() );
966 string YQWizard::currentTreeSelection()
970 Q3ListViewItem * sel = _tree->selectedItem();
974 YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel);
976 if ( item && ! item->id().isEmpty() )
977 return toUTF8( item->id() );
986 void YQWizard::layoutWorkArea( QFrame * parentHBox )
988 Q3VBox * workAreaVBox = new Q3VBox( parentHBox );
989 YUI_CHECK_NEW( workAreaVBox );
991 // An extra QVBox inside the workAreaVBox is needed for frame and margin
993 Q3VBox * workArea = new Q3VBox( workAreaVBox );
994 YUI_CHECK_NEW( workArea );
997 workArea->setFrameStyle( QFrame::Box | QFrame::Plain );
998 workArea->setMargin( 4 );
1000 workArea->setFrameStyle( QFrame::Box | QFrame::Sunken );
1001 // workArea->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Sunken );
1009 // Placed directly inside workArea the menu bar positions itself at (0,0)
1010 // and so obscures any kind of frame there might be.
1011 _menuBarBox = new Q3VBox( workArea );
1012 YUI_CHECK_NEW( _menuBarBox );
1014 _menuBar = new QMenuBar( _menuBarBox );
1015 YUI_CHECK_NEW( _menuBar );
1017 _menuBarBox->hide(); // will be made visible when menus are added
1021 // Dialog icon and heading
1024 Q3HBox * headingHBox = new Q3HBox( workArea );
1025 YUI_CHECK_NEW( headingHBox );
1026 headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1028 addHSpacing( headingHBox, SEPARATOR_MARGIN );
1030 _dialogIcon = new QLabel( headingHBox );
1031 YUI_CHECK_NEW( _dialogIcon );
1032 _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert
1034 addHSpacing( headingHBox );
1036 _dialogHeading = new QLabel( headingHBox );
1037 YUI_CHECK_NEW( _dialogHeading );
1038 _dialogHeading->setFont( YQUI::yqApp()->headingFont() );
1039 _dialogHeading->setAlignment( Qt::AlignLeft | Qt::WordBreak );
1040 _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert
1043 addHStretch( headingHBox );
1045 addVSpacing( workArea );
1049 Q3HBox * hbox = new Q3HBox( workArea );
1051 addHSpacing( hbox, SEPARATOR_MARGIN );
1053 QFrame * separator = new QFrame( hbox );
1054 YUI_CHECK_NEW( separator );
1055 separator->setFrameStyle( QFrame::HLine | QFrame::Sunken );
1057 addHSpacing( hbox, SEPARATOR_MARGIN );
1058 addVSpacing( workArea );
1062 // Client area (the part that belongs to the YCP application)
1065 layoutClientArea( workArea );
1072 layoutButtonBox( workAreaVBox );
1076 // Spacer (purely decorative) at the right of the client area
1079 addGradientColumn( parentHBox, WORK_AREA_RIGHT_MARGIN );
1084 void YQWizard::layoutClientArea( QWidget * parent )
1086 _clientArea = new Q3VBox( parent );
1087 YUI_CHECK_NEW( _clientArea );
1088 _clientArea->setMargin( 4 );
1091 _clientArea->setPaletteBackgroundColor( QColor( 0x60, 0x60, 0x60 ) );
1096 // HVCenter for wizard contents
1099 _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter );
1100 YUI_CHECK_NEW( _contents );
1102 _contents->setStretchable( YD_HORIZ, true );
1103 _contents->setStretchable( YD_VERT, true );
1104 _contents->installEventFilter( this );
1105 _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert
1109 // Replace point for wizard contents
1112 _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents );
1115 // Initial YEmpty widget contents of replace point
1118 YUI::widgetFactory()->createEmpty( _contentsReplacePoint );
1119 _contentsReplacePoint->showChild();
1124 void YQWizard::layoutButtonBox( QWidget * parent )
1127 // Button box and layout
1130 QWidget * buttonBox = new QWidget( parent );
1131 YUI_CHECK_NEW( buttonBox );
1133 // Using old-style layouts to enable a seamless background with the
1134 // gradient pixmap: Any sub-widgets (Q3VBox, QHBox) would have to get yet
1135 // another portion of that gradient as their backround pixmap, and it would
1136 // be very hard to cover all cases - resizing, hiding individual buttons, etc.
1138 QVBoxLayout * vbox = new QVBoxLayout( buttonBox, 0, 0 ); // parent, margin, spacing
1139 YUI_CHECK_NEW( vbox );
1141 vbox->addSpacing( BUTTON_BOX_TOP_MARGIN );
1145 // QHBoxLayout for the buttons
1148 QHBoxLayout * hbox = new QHBoxLayout( vbox, 2 ); // parent, spacing
1149 YUI_CHECK_NEW( hbox );
1156 _backButton = new YQWizardButton( this, buttonBox, _backButtonLabel );
1157 YUI_CHECK_NEW( _backButton );
1159 hbox->addWidget( (QWidget *) _backButton->widgetRep() );
1160 connect( _backButton, SIGNAL( clicked() ),
1161 this, SLOT ( slotBackClicked() ) );
1163 _backButtonSpacer = new QSpacerItem( 0, 0, // width, height
1164 QSizePolicy::Expanding, // horizontal
1165 QSizePolicy::Minimum ); // vertical
1166 YUI_CHECK_NEW( _backButtonSpacer );
1167 hbox->addItem( _backButtonSpacer );
1170 if ( _backButton->text().isEmpty() )
1172 _backButton->hide();
1174 // Minimize _backButtonSpacer
1175 _backButtonSpacer->changeSize( 0, 0, // width, height
1176 QSizePolicy::Minimum, // horizontal
1177 QSizePolicy::Minimum ); // vertical
1185 _abortButton = new YQWizardButton( this, buttonBox, _abortButtonLabel );
1186 YUI_CHECK_NEW( _abortButton );
1188 hbox->addWidget( (QWidget *) _abortButton->widgetRep() );
1189 connect( _abortButton, SIGNAL( clicked() ),
1190 this, SLOT ( slotAbortClicked() ) );
1193 // Using spacer rather than addSpacing() since the default stretchability
1194 // of a QSpacerItem is undefined, i.e. centering the middle button could
1195 // not be guaranteed.
1197 QSpacerItem * spacer = new QSpacerItem( 0, 0, // width, height
1198 QSizePolicy::Expanding, // horizontal
1199 QSizePolicy::Minimum ); // vertical
1200 YUI_CHECK_NEW( spacer );
1201 hbox->addItem( spacer );
1208 _nextButton = new YQWizardButton( this, buttonBox, _nextButtonLabel );
1209 YUI_CHECK_NEW( _nextButton );
1211 hbox->addWidget( (QWidget *) _nextButton->widgetRep() );
1212 connect( _nextButton, SIGNAL( clicked() ),
1213 this, SLOT ( slotNextClicked() ) );
1217 // Bottom margin and gradient
1220 vbox->addSpacing( WORK_AREA_BOTTOM_MARGIN );
1222 #if ENABLE_GRADIENTS
1223 setBottomCroppedGradient( buttonBox, _bottomGradientPixmap, buttonBox->sizeHint().height() );
1226 buttonBox->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); // hor/vert
1231 void YQWizard::loadGradientPixmaps()
1233 #if ENABLE_GRADIENTS
1234 if ( highColorDisplay() )
1236 _topGradientPixmap = QPixmap( PIXMAP_DIR "top-gradient.png" );
1237 _bottomGradientPixmap = QPixmap( PIXMAP_DIR "bottom-gradient.png" );
1238 _titleBarGradientPixmap = QPixmap( PIXMAP_DIR "title-bar-gradient.png" );
1239 _gradientCenterColor = pixelColor( _bottomGradientPixmap, 0, 0, paletteBackgroundColor() );
1240 _gradientTopColor = pixelColor( _topGradientPixmap, 0, 0 , paletteBackgroundColor() );
1242 else // 8 bit display or worse - don't use gradients
1244 // Gradient pixmaps remain empty. The respecive widgets will retain the
1245 // default widget background (grey, depending on the widget theme).
1247 // Use deault widget background (some shade of grey) for the center
1248 // stretchable part of the side bar.
1249 _gradientCenterColor = paletteBackgroundColor();
1250 _gradientTopColor = paletteBackgroundColor();
1256 void YQWizard::loadStepsIcons()
1258 _stepCurrentIcon = YQIconPool::stepCurrent();
1259 _stepToDoIcon = YQIconPool::stepToDo();
1260 _stepDoneIcon = YQIconPool::stepDone();
1262 if ( highColorDisplay() )
1264 _stepCurrentColor = pixelColor( QPixmap( PIXMAP_DIR "color-step-current.png" ), 0, 0, paletteForegroundColor() );
1265 _stepToDoColor = pixelColor( QPixmap( PIXMAP_DIR "color-step-todo.png" ), 0, 0, paletteForegroundColor() );
1266 _stepDoneColor = pixelColor( QPixmap( PIXMAP_DIR "color-step-done.png" ), 0, 0, paletteForegroundColor() );
1270 _stepCurrentColor = paletteForegroundColor();
1271 _stepToDoColor = paletteForegroundColor();
1272 _stepDoneColor = paletteForegroundColor();
1278 void YQWizard::setGradient( QWidget * widget, const QPixmap & pixmap )
1280 #if ENABLE_GRADIENTS
1281 if ( widget && ! pixmap.isNull() )
1283 widget->setFixedHeight( pixmap.height() );
1284 widget->setPaletteBackgroundPixmap( pixmap );
1291 void YQWizard::setBottomCroppedGradient( QWidget * widget, const QPixmap & pixmap, int croppedHeight )
1293 #if ENABLE_GRADIENTS
1294 setGradient( widget, bottomCropPixmap( pixmap, croppedHeight ) );
1300 QPixmap YQWizard::bottomCropPixmap( const QPixmap & full, int croppedHeight )
1304 #if ENABLE_GRADIENTS
1306 if ( full.height() > croppedHeight )
1308 pixmap = QPixmap( full.width(), croppedHeight );
1310 bitBlt( &pixmap, 0, 0, // dest, dest_x, dest_y
1311 &full, 0, full.height() - croppedHeight - 1, // src, src_x, src_y
1312 full.width(), croppedHeight ); // src_width, src_height
1325 QColor YQWizard::pixelColor( const QPixmap & pixmap, int x, int y, const QColor & defaultColor )
1327 if ( pixmap.isNull() )
1328 return defaultColor;
1330 // QPixmap doesn't allow direct access to pixel values (which makes some
1331 // sense since this requires a round-trip to the X server - pixmaps are X
1332 // server resources), so we need to convert the QPixmap to a QImage to get
1333 // that information. But since this conversion is expensive, we might save
1334 // some performance if we only convert the part we really need - so let's
1335 // cut out a tiny portion of the original pixmap and convert only that tiny
1339 QPixmap tiny( 1, 1 );
1341 bitBlt( &tiny, 0, 0, // dest, dest_x, dest_y
1342 &pixmap, x, y, // src, src_x, src_y
1343 1, 1 ); // src_width, src_height
1345 QImage image = tiny.convertToImage();
1348 return QColor( image.pixel( 0, 0 ) );
1353 void YQWizard::addGradientColumn( QWidget * parent, int width )
1358 Q3VBox * vbox = new Q3VBox( parent );
1359 YUI_CHECK_NEW( vbox );
1361 #if ENABLE_GRADIENTS
1362 QWidget * topGradient = addHSpacing( vbox, width );
1363 YUI_CHECK_NEW( topGradient );
1364 setGradient( topGradient, _topGradientPixmap );
1366 QWidget * centerStretch = new QWidget( vbox );
1367 YUI_CHECK_NEW( centerStretch );
1368 centerStretch->setPaletteBackgroundColor( _gradientCenterColor );
1371 QWidget * bottomGradient = new QWidget( vbox );
1372 YUI_CHECK_NEW( bottomGradient );
1373 setGradient( bottomGradient, _bottomGradientPixmap );
1375 vbox->setFixedWidth( width );
1381 void YQWizard::destroyButtons()
1391 delete _abortButton;
1404 bool YQWizard::highColorDisplay() const
1410 void YQWizard::connectNotify ( const char * signal )
1412 if ( QString( signal ).contains( "nextClicked()" ) )
1414 y2debug( "nextClicked connected, no longer directly sending button events" );
1415 _sendButtonEvents = false;
1420 void YQWizard::disconnectNotify ( const char * signal )
1422 if ( QString( signal ).contains( "nextClicked()" ) )
1424 y2debug( "nextClicked disconnected, directly sending button events again" );
1425 _sendButtonEvents = true;
1430 void YQWizard::setDialogIcon( const string & iconName )
1434 if ( ! iconName.empty() )
1436 QPixmap icon( iconName.c_str() );
1438 if ( icon.isNull() )
1439 y2warning( "Couldn't load dialog icon \"%s\"", iconName.c_str() );
1442 _dialogIcon->setPixmap( icon );
1443 topLevelWidget()->setIcon( icon );
1448 _dialogIcon->clear();
1449 topLevelWidget()->setIcon( QPixmap() );
1455 void YQWizard::setDialogHeading( const string & headingText )
1457 if ( _dialogHeading )
1459 if ( ! headingText.empty() )
1460 _dialogHeading->setText( fromUTF8( headingText ) );
1462 _dialogHeading->clear();
1466 string YQWizard::debugLabel()
1468 if ( _dialogHeading )
1470 QString label = _dialogHeading->text();
1471 label.simplifyWhiteSpace(); // Replace any embedded newline with a single blank
1473 if ( ! label.isEmpty() )
1475 label.prepend( "YQWizard \"" );
1476 label.append( "\"" );
1478 return toUTF8( label );
1482 return "untitled YQWizard";
1485 void YQWizard::setHelpText( const string & helpText )
1489 if ( ! helpText.empty() )
1491 QString qHelpText = fromUTF8( helpText );
1492 qHelpText.replace( "&product;", YQUI::ui()->productName() );
1493 _helpBrowser->setText( qHelpText );
1496 _helpBrowser->clear();
1501 void YQWizard::slotBackClicked()
1505 if ( _sendButtonEvents )
1506 YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) );
1508 _direction = YQWizard::Backward;
1512 void YQWizard::slotAbortClicked()
1514 emit abortClicked();
1516 if ( _sendButtonEvents )
1517 YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) );
1521 void YQWizard::slotNextClicked()
1525 if ( _sendButtonEvents )
1526 YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1528 _direction = YQWizard::Forward;
1532 void YQWizard::showHelp()
1534 if ( _sideBar && _helpPanel )
1536 _sideBar->raiseWidget( _helpPanel );
1541 void YQWizard::releaseNotesClicked()
1543 YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) );
1545 if ( ! _releaseNotesButtonId.empty() )
1547 y2milestone( "Release Notes button clicked" );
1548 sendEvent( _releaseNotesButtonId );
1553 void YQWizard::showSteps()
1555 if ( _sideBar && _stepsPanel )
1557 _sideBar->raiseWidget( _stepsPanel );
1562 void YQWizard::showTree()
1564 if ( _sideBar && _treePanel )
1566 _sideBar->raiseWidget( _treePanel );
1572 void YQWizard::addMenu( const string & text,
1577 Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1578 YUI_CHECK_NEW( menu );
1580 _menuIDs.insert( fromUTF8( id ), menu );
1581 _menuBar->insertItem( fromUTF8( text ), menu );
1583 connect( menu, SIGNAL( activated ( int ) ),
1584 this, SLOT ( sendMenuEvent( int ) ) );
1586 if ( _menuBarBox && _menuBarBox->isHidden() )
1588 _menuBarBox->show();
1589 _menuBarBox->setFixedHeight( _menuBar->sizeHint().height() + MENU_BAR_MARGIN );
1595 void YQWizard::addSubMenu( const string & parentMenuID,
1596 const string & text,
1599 Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1603 Q3PopupMenu * menu = new Q3PopupMenu( _menuBar );
1604 YUI_CHECK_NEW( menu );
1606 _menuIDs.insert( fromUTF8( id ), menu );
1607 parentMenu->insertItem( fromUTF8( text ), menu );
1609 connect( menu, SIGNAL( activated ( int ) ),
1610 this, SLOT ( sendMenuEvent( int ) ) );
1614 y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1619 void YQWizard::addMenuEntry( const string & parentMenuID,
1620 const string & text,
1621 const string & idString )
1623 Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1627 int id = _menuEntryIDs.size();
1628 _menuEntryIDs.push_back( idString );
1629 parentMenu->insertItem( fromUTF8( text ), id );
1633 y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1638 void YQWizard::addMenuSeparator( const string & parentMenuID )
1640 Q3PopupMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ];
1644 parentMenu->insertSeparator();
1648 y2error( "Can't find menu with ID %s", parentMenuID.c_str() );
1653 void YQWizard::deleteMenus()
1657 _menuBarBox->hide();
1660 _menuEntryIDs.clear();
1665 void YQWizard::sendMenuEvent( int numID )
1667 if ( numID >= 0 && numID < (int) _menuEntryIDs.size() )
1669 sendEvent( _menuEntryIDs[ numID ] );
1673 y2error( "Invalid menu ID: %d", numID );
1678 void YQWizard::sendEvent( const string & id )
1680 YQUI::ui()->sendEvent( new YMenuEvent( id ) );
1684 int YQWizard::preferredWidth()
1686 return sizeHint().width();
1690 int YQWizard::preferredHeight()
1692 return sizeHint().height();
1696 void YQWizard::setSize( int newWidth, int newHeight )
1698 resize( newWidth, newHeight );
1704 void YQWizard::resizeClientArea()
1706 // y2debug( "resizing client area" );
1707 QRect contentsRect = _clientArea->contentsRect();
1708 _contents->setSize( contentsRect.width(), contentsRect.height() );
1713 bool YQWizard::eventFilter( QObject * obj, QEvent * ev )
1715 if ( ev->type() == QEvent::Resize && obj == _contents )
1718 return true; // Event handled
1721 return QWidget::eventFilter( obj, ev );
1725 void YQWizard::setButtonLabel( YPushButton * button, const string & newLabel )
1727 button->setLabel( newLabel );
1728 YDialog::currentDialog()->checkShortcuts();
1730 YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button);
1734 if ( newLabel.empty() )
1736 wizardButton->hide();
1738 if ( wizardButton == _backButton && _backButtonSpacer )
1740 // Minimize _backButtonSpacer
1742 _backButtonSpacer->changeSize( 0, 0, // width, height
1743 QSizePolicy::Minimum, // horizontal
1744 QSizePolicy::Minimum ); // vertical
1749 wizardButton->show();
1751 if ( button == _backButton && _backButtonSpacer )
1753 // Restore _backButtonSpacer to normal size
1755 _backButtonSpacer->changeSize( 0, 0, // width, height
1756 QSizePolicy::Expanding, // horizontal
1757 QSizePolicy::Minimum ); // vertical
1764 void YQWizard::showReleaseNotesButton( const string & label, const string & id )
1766 if ( ! _releaseNotesButton )
1768 y2error( "NULL Release Notes button" );
1771 y2error( "This works only if there is a \"steps\" panel!" );
1776 // no way to check the shortcut, so strip it
1777 _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) );
1778 _releaseNotesButtonId = id;
1780 if ( _releaseNotesButton->isHidden() )
1781 _releaseNotesButton->show();
1786 void YQWizard::hideReleaseNotesButton()
1788 if ( _releaseNotesButton && _releaseNotesButton->isShown() )
1789 _releaseNotesButton->hide();
1793 void YQWizard::retranslateInternalButtons()
1795 YQUI::setTextdomain( TEXTDOMAIN );
1798 // "Help" button - intentionally without keyboard shortcut
1799 _helpButton->setText( _( "Help" ) );
1802 // "Steps" button - intentionally without keyboard shortcut
1803 _stepsButton->setText( _( "Steps" ) );
1806 // "Tree" button - intentionally without keyboard shortcut
1807 _treeButton->setText( _( "Tree" ) );
1810 #include "YQWizard.moc"