libyui-qt
2.43.5
|
00001 /* 00002 Copyright (C) 2000-2012 Novell, Inc 00003 This library is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU Lesser General Public License as 00005 published by the Free Software Foundation; either version 2.1 of the 00006 License, or (at your option) version 3.0 of the License. This library 00007 is distributed in the hope that it will be useful, but WITHOUT ANY 00008 WARRANTY; without even the implied warranty of MERCHANTABILITY or 00009 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00010 License for more details. You should have received a copy of the GNU 00011 Lesser General Public License along with this library; if not, write 00012 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth 00013 Floor, Boston, MA 02110-1301 USA 00014 */ 00015 00016 00017 /*-/ 00018 00019 File: YQWizard.cc 00020 00021 Author: Stefan Hundhammer <sh@suse.de> 00022 00023 Textdomain "qt" 00024 00025 /-*/ 00026 00027 #include "YQWizard.h" 00028 #define YUILogComponent "qt-wizard" 00029 #include <yui/YUILog.h> 00030 00031 #include <string> 00032 #include <yui/YShortcut.h> 00033 00034 #include <QDialog> 00035 #include <QSvgRenderer> 00036 #include <QPainter> 00037 #include <QStackedWidget> 00038 #include <qimage.h> 00039 #include <qlabel.h> 00040 #include <qlayout.h> 00041 #include <qmenubar.h> 00042 #include <qmenudata.h> 00043 #include <qobject.h> 00044 #include <qpixmap.h> 00045 #include <qpushbutton.h> 00046 #include <qregexp.h> 00047 #include <qtabwidget.h> 00048 #include <qtoolbutton.h> 00049 #include <QGraphicsDropShadowEffect> 00050 00051 #include "QY2ListView.h" 00052 #include "QY2Styler.h" 00053 #include "QY2HelpDialog.h" 00054 #include <QGridLayout> 00055 #include <QHeaderView> 00056 #include <qevent.h> 00057 00058 #include "utf8.h" 00059 #include "YQi18n.h" 00060 #include "YQUI.h" 00061 #include "YQApplication.h" 00062 #include "YQDialog.h" 00063 #include "YQAlignment.h" 00064 #include "YQReplacePoint.h" 00065 #include "YQEmpty.h" 00066 #include "YQLabel.h" 00067 #include "YQWizardButton.h" 00068 #include "YQWidgetFactory.h" 00069 #include "YQSignalBlocker.h" 00070 #include <yui/YEvent.h> 00071 #include "YQMainWinDock.h" 00072 00073 00074 using std::string; 00075 00076 #ifdef TEXTDOMAIN 00077 # undef TEXTDOMAIN 00078 #endif 00079 00080 #define TEXTDOMAIN "qt" 00081 00082 #define USE_ICON_ON_HELP_BUTTON 0 00083 00084 YQWizard *YQWizard::main_wizard = 0; 00085 00086 YQWizard::YQWizard( YWidget * parent, 00087 const std::string & backButtonLabel, 00088 const std::string & abortButtonLabel, 00089 const std::string & nextButtonLabel, 00090 YWizardMode wizardMode ) 00091 : QSplitter( Qt::Horizontal, (QWidget *) parent->widgetRep() ) 00092 00093 , YWizard( parent, 00094 backButtonLabel, 00095 abortButtonLabel, 00096 nextButtonLabel, 00097 wizardMode ) 00098 , _backButtonLabel( backButtonLabel ) 00099 , _abortButtonLabel( abortButtonLabel ) 00100 , _nextButtonLabel( nextButtonLabel ) 00101 , _helpDlg ( NULL ) 00102 { 00103 setObjectName( "wizard" ); 00104 setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); 00105 00106 QHBoxLayout* layout = new QHBoxLayout( this ); 00107 layout->setSpacing( 0 ); 00108 layout->setMargin( 0 ); 00109 00110 setWidgetRep( this ); 00111 00112 //either main wizard with `opt(`stepsEnabled), or sub-wizard of steps-enabled wizard 00113 _stepsEnabled = ( (wizardMode == YWizardMode_Steps) || main_wizard ); 00114 _treeEnabled = (wizardMode == YWizardMode_Tree); 00115 00116 _stepsRegistered = false; 00117 _stepsDirty = false; 00118 _direction = YQWizard::Forward; 00119 00120 _sideBar = 0; 00121 _stepsPanel = 0; 00122 _helpButton = 0; 00123 _stepsButton = 0; 00124 _treeButton = 0; 00125 _releaseNotesButton = 0; 00126 _treePanel = 0; 00127 _tree = 0; 00128 _workArea = 0; 00129 _clientArea = 0; 00130 _menuBar = 0; 00131 _dialogIcon = 0; 00132 _dialogHeading = 0; 00133 _contents = 0; 00134 _backButton = 0; 00135 _abortButton = 0; 00136 _nextButton = 0; 00137 _sendButtonEvents = true; 00138 _contentsReplacePoint = 0; 00139 00140 _previousWindowIcon = topLevelWidget()->windowIcon(); 00141 00142 YQUI::setTextdomain( TEXTDOMAIN ); 00143 00144 //layoutTitleBar( this ); 00145 00146 if( topLevelWidget()->windowTitle().isEmpty() ) 00147 { 00148 topLevelWidget()->setWindowTitle ( YQUI::ui()->applicationTitle() ); 00149 QPixmap pixmap ( YUI::app()->applicationIcon().c_str() ); 00150 if ( !pixmap.isNull() ) 00151 setWindowIcon ( QIcon ( pixmap ) ); 00152 } 00153 00154 layout->addLayout( layoutSideBar( this ) ); 00155 layout->addWidget( layoutWorkArea( this ) ); 00156 00157 setStretchFactor(indexOf(_sideBar),0); 00158 setStretchFactor(indexOf(_workArea),1); 00159 00160 /* If steps are enabled, we want to delay 00161 the registering for after we have steps registered */ 00162 if ( !_stepsEnabled ) 00163 QY2Styler::styler()->registerWidget( this ); 00164 00165 if ( !main_wizard && _stepsEnabled ) 00166 { 00167 main_wizard = this; 00168 } 00169 else if ( main_wizard ) 00170 { 00171 copySteps( main_wizard ); 00172 YQMainWinDock::mainWinDock()->resizeVisibleChild(); 00173 } 00174 00175 } 00176 00177 00178 YQWizard::~YQWizard() 00179 { 00180 deleteSteps(); 00181 if ( this == main_wizard ) 00182 { 00183 main_wizard = 0; 00184 } 00185 else if ( main_wizard ) 00186 { 00187 //transfer the widget ratio to the main wizard 00188 main_wizard->setSizes( sizes() ); 00189 } 00190 00191 delete _helpDlg; 00192 00193 QY2Styler::styler()->unregisterWidget( this ); 00194 topLevelWidget()->setWindowIcon( _previousWindowIcon ); 00195 } 00196 00197 00198 bool YQWizard::isSecondary() const 00199 { 00200 return this != main_wizard; 00201 } 00202 00203 00204 void YQWizard::layoutTitleBar( QWidget * parent ) 00205 { 00206 QFrame * titleBar = new QFrame( parent ); 00207 YUI_CHECK_NEW( titleBar ); 00208 00209 QHBoxLayout *layout = new QHBoxLayout( titleBar ); 00210 titleBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); // hor/vert 00211 00212 // 00213 // Left logo 00214 // 00215 00216 QLabel * left = new QLabel( titleBar ); 00217 layout->addWidget( left ); 00218 left->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); // hor/vert 00219 left->setObjectName( "titleBar-left" ); 00220 00221 // 00222 // Center stretch space 00223 // 00224 00225 layout->addStretch( 10 ); 00226 00227 00228 // 00229 // Right logo 00230 // 00231 00232 QLabel * right = new QLabel( titleBar ); 00233 YUI_CHECK_NEW( right ); 00234 00235 layout->addWidget( right ); 00236 right->setObjectName( "titleBar-right" ); 00237 } 00238 00239 00240 QLayout *YQWizard::layoutSideBar( QWidget * parent ) 00241 { 00242 _sideBar = new QStackedWidget( parent ); 00243 YUI_CHECK_NEW( _sideBar ); 00244 // _sideBar->setMinimumWidth( YQUI::ui()->defaultSize( YD_HORIZ ) / 5 ); 00245 _sideBar->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ) ); // hor/vert 00246 _sideBar->setObjectName( QString( "_sideBar-%1" ).arg( long( this ) ) ); 00247 _sideBar->installEventFilter( this ); 00248 00249 QVBoxLayout *vbox = new QVBoxLayout( ); 00250 vbox->addWidget( _sideBar ); 00251 00252 if ( _treeEnabled ) 00253 { 00254 layoutTreePanel(); 00255 showTree(); 00256 } 00257 else if ( _stepsEnabled ) 00258 { 00259 layoutStepsPanel(); 00260 showSteps(); 00261 } else { 00262 _sideBar->hide(); 00263 } 00264 00265 return vbox; 00266 } 00267 00268 00269 void YQWizard::layoutStepsPanel() 00270 { 00271 // Steps 00272 _stepsPanel = new QFrame( _sideBar ); 00273 _sideBar->addWidget( _stepsPanel ); 00274 _stepsPanel->setObjectName( "steps" ); 00275 QY2Styler::styler()->registerChildWidget( this, _stepsPanel ); 00276 _stepsPanel->setProperty( "class", "steps QFrame" ); 00277 00278 // Steps panel bottom buttons ("Help", "Release Notes") 00279 00280 // Layouts for the buttons 00281 00282 _releaseNotesButton = new QPushButton( _( "Release Notes..." ), _stepsPanel ); 00283 _releaseNotesButton->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum ) ); // hor/vert 00284 00285 connect( _releaseNotesButton, SIGNAL( clicked() ), 00286 this, SLOT ( releaseNotesClicked() ) ); 00287 00288 _releaseNotesButton->hide(); // hidden until showReleaseNotesButton() is called 00289 00290 _stepsDirty = true; // no layout yet 00291 } 00292 00293 00294 void YQWizard::addStep( const std::string & text, const std::string & id ) 00295 { 00296 QString qId = fromUTF8( id ); 00297 00298 if ( _stepsIDs[ qId ] ) 00299 { 00300 yuiError() << "Step ID \"" << id << "\" (\"" << text 00301 <<"\") already used for \"" << _stepsIDs[ qId ]->name() <<"\"" 00302 << std::endl; 00303 return; 00304 } 00305 00306 if ( !_stepsList.empty() && _stepsList.last()->name() == fromUTF8( text ) ) 00307 { 00308 // Consecutive steps with the same name will be shown as one single step. 00309 // 00310 // Since steps are always added at the end of the list, it is 00311 // sufficient to check the last step of the list. If the texts are the 00312 // same, the other with the same text needs to get another (additional) 00313 // ID to make sure setCurrentStep() works as it should. 00314 _stepsList.last()->addID( qId ); 00315 } 00316 else 00317 { 00318 _stepsList.append( new YQWizard::Step( fromUTF8( text ), qId ) ); 00319 _stepsDirty = true; 00320 } 00321 00322 _stepsIDs.insert( qId, _stepsList.last() ); 00323 00324 // make sure we always have a current step if we have steps 00325 if ( _currentStepID.isNull() ) 00326 _currentStepID = qId; 00327 } 00328 00329 00330 void YQWizard::addStepHeading( const std::string & text ) 00331 { 00332 _stepsList.append( new YQWizard::StepHeading( fromUTF8( text ) ) ); 00333 _stepsDirty = true; 00334 } 00335 00336 00337 void YQWizard::updateSteps() 00338 { 00339 if ( ! _stepsPanel ) 00340 return; 00341 00342 yuiDebug() << "updateSteps" << std::endl; 00343 00344 if ( !_stepsRegistered ) 00345 setUpdatesEnabled(false); 00346 00347 // Create a grid layout for the steps 00348 delete _stepsPanel->layout(); 00349 _stepsPanel->setMaximumWidth( 65000 ); 00350 00351 QVBoxLayout *_stepsVBox = new QVBoxLayout( _stepsPanel ); 00352 00353 QGridLayout *_stepsGrid = new QGridLayout( ); 00354 _stepsGrid->setObjectName( QString( "_stepsGrid_%1" ).arg( long( this ) ) ); 00355 YUI_CHECK_NEW( _stepsGrid ); 00356 _stepsVBox->addLayout( _stepsGrid ); 00357 _stepsGrid->setColumnMinimumWidth( 0, 10 ); 00358 _stepsGrid->setRowStretch( 0, 1 ); 00359 _stepsGrid->setRowStretch( 1, 1 ); 00360 _stepsGrid->setRowStretch( 2, 99 ); 00361 00362 const int statusCol = 1; 00363 const int nameCol = 2; 00364 00365 int row = 0; 00366 00367 // 00368 // Create widgets for all steps and step headings in the internal list 00369 // 00370 00371 for ( QList<Step*>::iterator i = _stepsList.begin(); i != _stepsList.end(); ++i) 00372 { 00373 YQWizard::Step * step = *i; 00374 00375 step->deleteLabels(); 00376 00377 if ( step->isHeading() ) 00378 { 00379 // 00380 // Heading 00381 // 00382 00383 yuiDebug() << "Adding StepHeading \"" << step->name() << "\"" << std::endl; 00384 QLabel * label = new QLabel( step->name(), _stepsPanel ); 00385 YUI_CHECK_NEW( label ); 00386 label->setObjectName( step->name() ); 00387 label->setAlignment( Qt::AlignLeft | Qt::AlignTop ); 00388 label->setProperty( "class", "steps_heading" ); 00389 00390 step->setNameLabel( label ); 00391 _stepsGrid->addWidget( label, 00392 row, statusCol, 00393 1, nameCol - statusCol + 1); 00394 } 00395 else // No heading - ordinary step 00396 { 00397 // 00398 // Step status 00399 // 00400 00401 yuiDebug() << "Adding Step \"" << step->name() << "\"" << std::endl; 00402 00403 QLabel * statusLabel = new QLabel( _stepsPanel ); 00404 YUI_CHECK_NEW( statusLabel ); 00405 00406 step->setStatusLabel( statusLabel ); 00407 statusLabel->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); 00408 _stepsGrid->addWidget( statusLabel, row, statusCol ); 00409 00410 // 00411 // Step name 00412 // 00413 00414 QLabel * nameLabel = new QLabel( step->name(), _stepsPanel ); 00415 YUI_CHECK_NEW( nameLabel ); 00416 nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignTop ); 00417 nameLabel->setObjectName( step->name() ); 00418 00419 step->setNameLabel( nameLabel ); 00420 _stepsGrid->addWidget( nameLabel, row, nameCol ); 00421 } 00422 00423 step->setStatus( Step::Todo ); 00424 row++; 00425 } 00426 00427 _stepsVBox->addStretch( 99 ); 00428 QVBoxLayout *rbl = new QVBoxLayout(); 00429 rbl->addWidget( _releaseNotesButton, 0, Qt::AlignCenter ); 00430 00431 _stepsVBox->addLayout( rbl ); 00432 _stepsVBox->addStretch( 29 ); 00433 00434 _stepsDirty = false; 00435 00436 if ( !_stepsRegistered ) 00437 { 00438 QY2Styler::styler()->registerWidget( this ); 00439 setUpdatesEnabled( true ); 00440 QY2Styler::styler()->updateRendering( this ); 00441 _stepsRegistered = true; 00442 } 00443 } 00444 00445 00446 void YQWizard::updateStepStates() 00447 { 00448 yuiDebug() << "steps dirty: " << _stepsDirty << std::endl; 00449 00450 if ( _stepsDirty ) 00451 updateSteps(); 00452 00453 YQWizard::Step * currentStep = findStep( _currentStepID ); 00454 QList<YQWizard::Step*>::iterator step = _stepsList.begin(); 00455 00456 if ( currentStep ) 00457 { 00458 // Set status icon and color for the current step 00459 currentStep->setStatus( Step::Current ); 00460 00461 // 00462 // Set all steps before the current to "done" 00463 // 00464 00465 while ( step != _stepsList.end() && *step != currentStep ) 00466 { 00467 ( *step )->setStatus( Step::Done ); 00468 step++; 00469 } 00470 00471 // Skip the current step - continue with the step after it 00472 00473 if ( step != _stepsList.end() ) 00474 step++; 00475 } 00476 00477 // 00478 // Set all steps after the current to "to do" 00479 // 00480 00481 while ( step != _stepsList.end() ) 00482 { 00483 ( *step )->setStatus( Step::Todo ); 00484 step++; 00485 } 00486 } 00487 00488 00489 void YQWizard::setCurrentStep( const std::string & id ) 00490 { 00491 yuiDebug() << "Setting current step to \"" << id << "\"" << std::endl; 00492 00493 _currentStepID = fromUTF8( id ); 00494 updateStepStates(); 00495 } 00496 00497 void YQWizard::copySteps( YQWizard *wizard) 00498 { 00499 QList<Step*> _oldSteps = wizard->stepsList(); 00500 00501 if (_oldSteps.empty()) 00502 return; 00503 00504 foreach( Step *oldStep, _oldSteps) 00505 { 00506 Step *newStep; 00507 00508 if( !oldStep->isHeading() ) 00509 newStep = new Step( oldStep->name()); 00510 else 00511 newStep = new StepHeading( oldStep->name()); 00512 00513 foreach( QString oneId, oldStep->id()) 00514 { 00515 newStep->addID( oneId); 00516 _stepsIDs.insert( oneId, newStep ); 00517 } 00518 00519 newStep->setEnabled( oldStep->isEnabled()); 00520 _stepsList.append(newStep); 00521 00522 } 00523 00524 setCurrentStep( wizard->currentStep().toStdString() ); 00525 setSizes( main_wizard->sizes()); 00526 } 00527 00528 00529 void YQWizard::deleteSteps() 00530 { 00531 yuiDebug() << "Deleting steps" << std::endl; 00532 00533 if ( _stepsPanel ) 00534 _stepsPanel->setFixedWidth( _stepsPanel->width() ); 00535 00536 qDeleteAll(_stepsList); 00537 _stepsList.clear(); 00538 _stepsIDs.clear(); 00539 _currentStepID = QString::null; 00540 _stepsDirty = true; 00541 } 00542 00543 00544 YQWizard::Step * YQWizard::findStep( const QString & id ) 00545 { 00546 if ( id.isEmpty() ) 00547 return 0; 00548 00549 return _stepsIDs[ id ]; 00550 } 00551 00552 00553 void YQWizard::layoutTreePanel() 00554 { 00555 _treePanel = new QFrame( _sideBar ); 00556 YUI_CHECK_NEW( _treePanel ); 00557 QHBoxLayout *layout = new QHBoxLayout( _treePanel ); 00558 _sideBar->addWidget( _treePanel ); 00559 00560 QVBoxLayout * vbox = new QVBoxLayout(); 00561 YUI_CHECK_NEW( vbox ); 00562 layout->addLayout( vbox ); 00563 00564 // Selection tree 00565 00566 _tree = new QY2ListView( _treePanel ); 00567 YUI_CHECK_NEW( _tree ); 00568 vbox->addWidget( _tree ); 00569 00570 _tree->header()->hide(); 00571 _tree->header()->setResizeMode( 0, QHeaderView::Stretch ); 00572 00573 _tree->setRootIsDecorated( true ); 00574 _tree->setSortByInsertionSequence( true ); 00575 00576 connect( _tree, SIGNAL( itemSelectionChanged ( void ) ), 00577 this, SLOT ( treeSelectionChanged ( void ) ) ); 00578 00579 connect( _tree, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int ) ), 00580 this, SLOT ( sendTreeEvent ( QTreeWidgetItem * ) ) ); 00581 00582 } 00583 00584 00585 void YQWizard::addTreeItem( const std::string & parentID, const std::string & text, const std::string & id ) 00586 { 00587 QString qId = fromUTF8( id ); 00588 00589 if ( ! _tree ) 00590 { 00591 yuiError() << "YQWizard widget not created with `opt(`treeEnabled) !" << std::endl; 00592 return; 00593 } 00594 00595 YQWizard::TreeItem * item = 0; 00596 YQWizard::TreeItem * parent = 0; 00597 00598 if ( ! parentID.empty() ) 00599 { 00600 parent = findTreeItem( parentID ); 00601 } 00602 00603 if ( parent ) 00604 { 00605 item = new YQWizard::TreeItem( parent, fromUTF8( text ), qId ); 00606 YUI_CHECK_NEW( item ); 00607 } 00608 else 00609 { 00610 item = new YQWizard::TreeItem( _tree, fromUTF8( text ), qId ); 00611 YUI_CHECK_NEW( item ); 00612 } 00613 00614 if ( ! qId.isEmpty() ) 00615 _treeIDs.insert( qId, item ); 00616 } 00617 00618 00619 00620 void YQWizard::deleteTreeItems() 00621 { 00622 if ( _tree ) 00623 _tree->clear(); 00624 00625 _treeIDs.clear(); 00626 } 00627 00628 00629 00630 YQWizard::TreeItem * YQWizard::findTreeItem( const std::string & id ) 00631 { 00632 if ( id.empty() ) 00633 return 0; 00634 00635 return _treeIDs[ fromUTF8( id ) ]; 00636 } 00637 00638 00639 void YQWizard::selectTreeItem( const std::string & id ) 00640 { 00641 if ( _tree ) 00642 { 00643 YQWizard::TreeItem * item = findTreeItem( id ); 00644 00645 if ( item ) 00646 { 00647 YQSignalBlocker sigBlocker( _tree ); 00648 00649 _tree->setCurrentItem(item); 00650 _tree->scrollToItem(item); 00651 } 00652 } 00653 } 00654 00655 00656 void YQWizard::sendTreeEvent( QTreeWidgetItem * listViewItem ) 00657 { 00658 if ( listViewItem ) 00659 { 00660 YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> ( listViewItem ); 00661 00662 if ( item && ! item->id().isEmpty() ) 00663 sendEvent( toUTF8( item->id() ) ); 00664 } 00665 } 00666 00667 00668 void YQWizard::treeSelectionChanged() 00669 { //FIXME is currentItem correct or selected.first 00670 if ( _tree ) 00671 sendTreeEvent( _tree->currentItem() ); 00672 } 00673 00674 00675 string YQWizard::currentTreeSelection() 00676 { 00677 if ( _tree ) 00678 { 00679 QTreeWidgetItem * sel = _tree->currentItem(); 00680 00681 if ( sel ) 00682 { 00683 YQWizard::TreeItem * item = dynamic_cast<YQWizard::TreeItem *> (sel); 00684 00685 if ( item && ! item->id().isEmpty() ) 00686 return toUTF8( item->id() ); 00687 } 00688 } 00689 00690 return std::string(); 00691 } 00692 00693 00694 00695 QWidget *YQWizard::layoutWorkArea( QWidget * parent ) 00696 { 00697 _workArea = new QFrame( parent ); 00698 _workArea->setObjectName( "work_area" ); 00699 00700 QY2Styler::styler()->registerChildWidget( this, _workArea ); 00701 00702 QVBoxLayout *vbox = new QVBoxLayout( _workArea ); 00703 YUI_CHECK_NEW( vbox ); 00704 00705 // 00706 // Menu bar 00707 // 00708 00709 _menuBar = new QMenuBar( _workArea ); 00710 YUI_CHECK_NEW( _menuBar ); 00711 00712 _menuBar->hide(); // will be made visible when menus are added 00713 vbox->addWidget( _menuBar ); 00714 00715 00716 QVBoxLayout *innerbox = new QVBoxLayout( _workArea ); 00717 YUI_CHECK_NEW( innerbox ); 00718 00719 innerbox->setMargin ( YQWidgetMargin ); 00720 00721 vbox->addLayout(innerbox); 00722 vbox->setMargin( 0 ); 00723 00724 00725 // 00726 // Dialog icon and heading 00727 // 00728 00729 QHBoxLayout * headingHBox = new QHBoxLayout(); 00730 YUI_CHECK_NEW( headingHBox ); 00731 //headingHBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert 00732 innerbox->addLayout( headingHBox ); 00733 00734 _dialogIcon = new QLabel( _workArea ); 00735 YUI_CHECK_NEW( _dialogIcon ); 00736 headingHBox->addWidget( _dialogIcon ); 00737 _dialogIcon->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); // hor/vert 00738 _dialogIcon->setObjectName( "DialogIcon" ); 00739 00740 _dialogHeading = new QLabel( _workArea ); 00741 YUI_CHECK_NEW( _dialogHeading ); 00742 headingHBox->addWidget( _dialogHeading ); 00743 _dialogHeading->setAlignment( Qt::AlignLeft ); 00744 _dialogHeading->setWordWrap( true ); 00745 _dialogHeading->setTextFormat( Qt::PlainText ); 00746 _dialogHeading->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); // hor/vert 00747 _dialogHeading->setObjectName( "DialogHeading" ); 00748 00749 00750 // 00751 // Client area (the part that belongs to the YCP application) 00752 // 00753 00754 layoutClientArea( _workArea ); 00755 innerbox->addWidget( _clientArea ); 00756 00757 // 00758 // Button box 00759 // 00760 00761 QLayout *bb = layoutButtonBox( _workArea ); 00762 innerbox->addLayout( bb ); 00763 00764 return _workArea; 00765 } 00766 00767 00768 00769 void YQWizard::layoutClientArea( QWidget * parent ) 00770 { 00771 _clientArea = new QFrame( parent ); 00772 YUI_CHECK_NEW( _clientArea ); 00773 _clientArea->setObjectName("_clientArea"); 00774 QVBoxLayout *layout = new QVBoxLayout( _clientArea ); 00775 layout->setMargin( 0 ); 00776 00777 // 00778 // HVCenter for wizard contents 00779 // 00780 00781 _contents = new YQAlignment( this, _clientArea, YAlignCenter, YAlignCenter ); 00782 YUI_CHECK_NEW( _contents ); 00783 layout->addWidget( _contents ); 00784 _contents->QObject::setProperty( "class", "Contents" ); 00785 00786 _contents->setStretchable( YD_HORIZ, true ); 00787 _contents->setStretchable( YD_VERT, true ); 00788 _contents->installEventFilter( this ); 00789 _contents->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); // hor/vert 00790 00791 // 00792 // Replace point for wizard contents 00793 // 00794 00795 _contentsReplacePoint = YUI::widgetFactory()->createReplacePoint( _contents ); 00796 00797 // 00798 // Initial YEmpty widget contents of replace point 00799 // 00800 00801 YUI::widgetFactory()->createEmpty( _contentsReplacePoint ); 00802 _contentsReplacePoint->showChild(); 00803 00804 } 00805 00806 00807 00808 QLayout *YQWizard::layoutButtonBox( QWidget * parent ) 00809 { 00810 // 00811 // QHBoxLayout for the buttons 00812 // 00813 00814 QHBoxLayout * hbox = new QHBoxLayout(); // parent, spacing 00815 YUI_CHECK_NEW( hbox ); 00816 00817 hbox->setSpacing( 0 ); 00818 hbox->setMargin( 0 ); 00819 00820 // Help button - intentionally without keyboard shortcut 00821 _helpButton = new QPushButton( _( "Help" ), parent ); 00822 YUI_CHECK_NEW( _helpButton ); 00823 _helpButton->setShortcut( Qt::Key_F1 ); 00824 00825 connect( _helpButton, SIGNAL( clicked() ), 00826 this, SLOT ( showHelp() ) ); 00827 00828 hbox->addWidget( _helpButton ); 00829 00830 hbox->addStretch( 10 ); 00831 00832 // 00833 // "Abort" button 00834 // 00835 00836 _abortButton = new YQWizardButton( this, parent, _abortButtonLabel ); 00837 YUI_CHECK_NEW( _abortButton ); 00838 00839 hbox->addWidget( (QWidget *) _abortButton->widgetRep() ); 00840 connect( _abortButton, SIGNAL( clicked() ), 00841 this, SLOT ( slotAbortClicked() ) ); 00842 00843 hbox->addSpacing( 10 ); 00844 00845 // 00846 // "Back" button 00847 // 00848 00849 _backButton = new YQWizardButton( this, parent, _backButtonLabel ); 00850 YUI_CHECK_NEW( _backButton ); 00851 00852 hbox->addWidget( (QWidget *) _backButton->widgetRep() ); 00853 connect( _backButton, SIGNAL( clicked() ), 00854 this, SLOT ( slotBackClicked() ) ); 00855 00856 if ( _backButton->text().isEmpty() ) 00857 _backButton->hide(); 00858 00859 // 00860 // "Next" button 00861 // 00862 00863 hbox->addSpacing( 5 ); 00864 00865 _nextButton = new YQWizardButton( this, parent, _nextButtonLabel ); 00866 YUI_CHECK_NEW( _nextButton ); 00867 00868 hbox->addWidget( (QWidget *) _nextButton->widgetRep() ); 00869 connect( _nextButton, SIGNAL( clicked() ), 00870 this, SLOT ( slotNextClicked() ) ); 00871 00872 return hbox; 00873 } 00874 00875 00876 void YQWizard::destroyButtons() 00877 { 00878 delete _backButton; 00879 _backButton = 0; 00880 00881 delete _abortButton; 00882 _abortButton = 0; 00883 00884 delete _nextButton; 00885 _nextButton = 0; 00886 } 00887 00888 00889 void YQWizard::connectNotify ( const char * signal ) 00890 { 00891 if ( QString( signal ).contains( "nextClicked()" ) ) 00892 { 00893 yuiDebug() << "nextClicked connected, no longer directly sending button events" << std::endl; 00894 _sendButtonEvents = false; 00895 } 00896 } 00897 00898 00899 void YQWizard::disconnectNotify ( const char * signal ) 00900 { 00901 if ( QString( signal ).contains( "nextClicked()" ) ) 00902 { 00903 yuiDebug() << "nextClicked disconnected, directly sending button events again" << std::endl; 00904 _sendButtonEvents = true; 00905 } 00906 } 00907 00908 00909 void YQWizard::setDialogIcon( const std::string & iconName ) 00910 { 00911 if ( _dialogIcon ) 00912 { 00913 if ( ! iconName.empty() ) 00914 { 00915 QPixmap icon( iconName.c_str() ); 00916 00917 if ( icon.isNull() ) 00918 yuiWarning() << "Couldn't load dialog icon \"" << iconName << "\"" << std::endl; 00919 else 00920 { 00921 _dialogIcon->setPixmap( icon ); 00922 topLevelWidget()->setWindowIcon( icon ); 00923 } 00924 } 00925 else 00926 { 00927 _dialogIcon->clear(); 00928 topLevelWidget()->setWindowIcon( QIcon() ); 00929 } 00930 } 00931 } 00932 00933 00934 void YQWizard::setDialogTitle( const std::string & titleText ) 00935 { 00936 QString title = fromUTF8( titleText.c_str() ); 00937 00938 if ( !title.isEmpty() ) 00939 topLevelWidget()->setWindowTitle( YQUI::ui()->applicationTitle() + QString(" - ") + title ); 00940 else 00941 topLevelWidget()->setWindowTitle( YQUI::ui()->applicationTitle() ); 00942 } 00943 00944 00945 void YQWizard::setDialogHeading( const std::string & headingText ) 00946 { 00947 if ( _dialogHeading ) 00948 { 00949 if ( ! headingText.empty() ) 00950 _dialogHeading->setText( fromUTF8( headingText ) ); 00951 else 00952 _dialogHeading->clear(); 00953 } 00954 } 00955 00956 string YQWizard::debugLabel() const 00957 { 00958 if ( _dialogHeading ) 00959 { 00960 QString label = _dialogHeading->text(); 00961 label = label.simplified(); // Replace any embedded newline with a single blank 00962 00963 if ( ! label.isEmpty() ) 00964 return toUTF8( label ); 00965 } 00966 00967 return "untitled YQWizard"; 00968 } 00969 00970 00971 void YQWizard::setHelpText( const std::string & helpText ) 00972 { 00973 _qHelpText = fromUTF8( helpText ); 00974 _qHelpText.replace( "&product;", fromUTF8( YUI::app()->productName() ) ); 00975 } 00976 00977 00978 void YQWizard::slotBackClicked() 00979 { 00980 emit backClicked(); 00981 00982 if ( _sendButtonEvents ) 00983 YQUI::ui()->sendEvent( new YWidgetEvent( _backButton, YEvent::Activated ) ); 00984 00985 _direction = YQWizard::Backward; 00986 } 00987 00988 00989 void YQWizard::slotAbortClicked() 00990 { 00991 emit abortClicked(); 00992 00993 if ( _sendButtonEvents ) 00994 YQUI::ui()->sendEvent( new YWidgetEvent( _abortButton, YEvent::Activated ) ); 00995 } 00996 00997 00998 void YQWizard::slotNextClicked() 00999 { 01000 emit nextClicked(); 01001 01002 if ( _sendButtonEvents ) 01003 YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) ); 01004 01005 _direction = YQWizard::Forward; 01006 } 01007 01008 01009 void YQWizard::showHelp() 01010 { 01011 01012 if (!_helpDlg) 01013 _helpDlg = new QY2HelpDialog ( _qHelpText, NULL ); 01014 else 01015 { 01016 _helpDlg->setHelpText( _qHelpText ); 01017 _helpDlg->hide(); // workaround for icewm (see: bnc #397083) 01018 } 01019 01020 _helpDlg->show(); 01021 _helpDlg->raise(); 01022 _helpDlg->activateWindow(); 01023 } 01024 01025 01026 void YQWizard::releaseNotesClicked() 01027 { 01028 YQUI::ui()->sendEvent( new YWidgetEvent( _nextButton, YEvent::Activated ) ); 01029 01030 if ( ! _releaseNotesButtonId.empty() ) 01031 { 01032 yuiMilestone() << "Release Notes button clicked" << std::endl; 01033 sendEvent( _releaseNotesButtonId ); 01034 } 01035 } 01036 01037 01038 void YQWizard::showSteps() 01039 { 01040 if ( _sideBar && _stepsPanel ) 01041 { 01042 _sideBar->setCurrentWidget( _stepsPanel ); 01043 } 01044 } 01045 01046 01047 void YQWizard::showTree() 01048 { 01049 if ( _sideBar && _treePanel ) 01050 { 01051 _sideBar->setCurrentWidget( _treePanel ); 01052 } 01053 } 01054 01055 01056 void YQWizard::addMenu( const std::string & text, 01057 const std::string & id ) 01058 { 01059 if ( _menuBar ) 01060 { 01061 QMenu * menu = new QMenu( _menuBar ); 01062 YUI_CHECK_NEW( menu ); 01063 01064 _menuIDs.insert( fromUTF8( id ), menu ); 01065 _menuBar->addMenu( menu ); 01066 menu->setTitle( fromUTF8( text ) ); 01067 01068 connect( menu, SIGNAL( triggered ( QAction * ) ), 01069 this, SLOT ( sendMenuEvent( QAction * ) ) ); 01070 01071 _menuBar->show(); 01072 } 01073 } 01074 01075 01076 void YQWizard::addSubMenu( const std::string & parentMenuID, 01077 const std::string & text, 01078 const std::string & id ) 01079 { 01080 QMenu* parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ]; 01081 01082 if ( parentMenu ) 01083 { 01084 QMenu * menu = new QMenu( _menuBar ); 01085 YUI_CHECK_NEW( menu ); 01086 01087 _menuIDs.insert( fromUTF8( id ), menu ); 01088 //FIXME parentMenu->insertItem( fromUTF8( text ), menu ); 01089 01090 connect( menu, SIGNAL( triggered ( QAction * ) ), 01091 this, SLOT ( sendMenuEvent( QAction * ) ) ); 01092 } 01093 else 01094 { 01095 yuiError() << "Can't find menu with ID " << parentMenuID << std::endl; 01096 } 01097 } 01098 01099 01100 void YQWizard::addMenuEntry( const std::string & parentMenuID, 01101 const std::string & text, 01102 const std::string & idString ) 01103 { 01104 QMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ]; 01105 01106 if ( parentMenu ) 01107 { 01108 #if 0 01109 int id = _menuEntryIDs.size(); 01110 #endif 01111 QAction *action; 01112 action = parentMenu->addAction( fromUTF8( text ) ); 01113 _menuEntryIDs[ action ] = idString ; 01114 01115 } 01116 else 01117 { 01118 yuiError() << "Can't find menu with ID " << parentMenuID << std::endl; 01119 } 01120 } 01121 01122 01123 void YQWizard::addMenuSeparator( const std::string & parentMenuID ) 01124 { 01125 QMenu * parentMenu = _menuIDs[ fromUTF8( parentMenuID ) ]; 01126 01127 if ( parentMenu ) 01128 { 01129 parentMenu->addSeparator(); 01130 } 01131 else 01132 { 01133 yuiError() << "Can't find menu with ID " << parentMenuID << std::endl; 01134 } 01135 } 01136 01137 01138 void YQWizard::deleteMenus() 01139 { 01140 if ( _menuBar ) 01141 { 01142 _menuBar->hide(); 01143 _menuBar->clear(); 01144 _menuIDs.clear(); 01145 _menuEntryIDs.clear(); 01146 } 01147 } 01148 01149 01150 void YQWizard::sendMenuEvent( QAction *action ) 01151 { 01152 if ( _menuEntryIDs.contains( action ) ) 01153 { 01154 sendEvent( _menuEntryIDs[ action ] ); 01155 } 01156 else 01157 { 01158 yuiError() << "Invalid menu ID " << std::endl; 01159 } 01160 } 01161 01162 01163 void YQWizard::sendEvent( const std::string & id ) 01164 { 01165 YQUI::ui()->sendEvent( new YMenuEvent( id ) ); 01166 } 01167 01168 01169 int YQWizard::preferredWidth() 01170 { 01171 return sizeHint().width(); 01172 } 01173 01174 01175 int YQWizard::preferredHeight() 01176 { 01177 return sizeHint().height(); 01178 } 01179 01180 01181 void YQWizard::setSize( int newWidth, int newHeight ) 01182 { 01183 resize( newWidth, newHeight ); 01184 resizeClientArea(); 01185 } 01186 01187 void YQWizard::resizeClientArea() 01188 { 01189 QSize contentsRect = _clientArea->contentsRect().size(); 01190 _contents->setSize( contentsRect.width(), contentsRect.height() ); 01191 } 01192 01193 bool YQWizard::eventFilter( QObject * obj, QEvent * ev ) 01194 { 01195 if ( ev->type() == QEvent::Resize && obj == _contents ) 01196 { 01197 resizeClientArea(); 01198 return true; // Event handled 01199 } 01200 01201 if ( ev->type() == QEvent::Resize && obj == _sideBar && main_wizard == this && _stepsPanel ) 01202 { 01203 YQMainWinDock::mainWinDock()->setSideBarWidth( _sideBar->width() ); 01204 return true; // Event handled 01205 } 01206 01207 return QWidget::eventFilter( obj, ev ); 01208 } 01209 01210 01211 void YQWizard::setButtonLabel( YPushButton * button, const std::string & newLabel ) 01212 { 01213 button->setLabel( newLabel ); 01214 YDialog::currentDialog()->checkShortcuts(); 01215 01216 YQWizardButton * wizardButton = dynamic_cast<YQWizardButton *> (button); 01217 01218 if ( wizardButton ) { 01219 // QWizardButton only implements hide and show, not setVisible 01220 if ( newLabel.empty() ) 01221 wizardButton->hide(); 01222 else 01223 wizardButton->show(); 01224 } 01225 } 01226 01227 01228 void YQWizard::showReleaseNotesButton( const std::string & label, const std::string & id ) 01229 { 01230 return; // no longer supported! 01231 01232 if ( ! _releaseNotesButton ) 01233 { 01234 yuiError() << "NULL Release Notes button" << std::endl; 01235 01236 if ( ! _stepsPanel ) 01237 yuiError() << "This works only if there is a \"steps\" panel!" << std::endl; 01238 01239 return; 01240 } 01241 01242 // no way to check the shortcut, so strip it 01243 _releaseNotesButton->setText( fromUTF8( YShortcut::cleanShortcutString( label ) ) ); 01244 _releaseNotesButtonId = id; 01245 01246 _releaseNotesButton->show(); 01247 } 01248 01249 01250 void YQWizard::hideReleaseNotesButton() 01251 { 01252 if ( _releaseNotesButton && !_releaseNotesButton->isHidden() ) 01253 _releaseNotesButton->hide(); 01254 } 01255 01256 01257 void YQWizard::retranslateInternalButtons() 01258 { 01259 YQUI::setTextdomain( TEXTDOMAIN ); 01260 01261 if ( _helpButton ) 01262 // "Help" button - intentionally without keyboard shortcut 01263 _helpButton->setText( _( "Help" ) ); 01264 01265 if ( _stepsButton ) 01266 // "Steps" button - intentionally without keyboard shortcut 01267 _stepsButton->setText( _( "Steps" ) ); 01268 01269 if ( _treeButton ) 01270 // "Tree" button - intentionally without keyboard shortcut 01271 _treeButton->setText( _( "Tree" ) ); 01272 01273 if ( _helpDlg ) 01274 _helpDlg->retranslate(); 01275 01276 } 01277 01278 01279 void YQWizard::Step::deleteLabels() 01280 { 01281 delete _statusLabel; 01282 _statusLabel = 0; 01283 delete _nameLabel; 01284 _nameLabel = 0; 01285 } 01286 01287 01288 YQWizard::Step::~Step() 01289 { 01290 deleteLabels(); 01291 } 01292 01293 01294 void YQWizard::Step::setStatus( Status s ) 01295 { 01296 if ( !_statusLabel || !_nameLabel || _status == s ) 01297 return; 01298 01299 _status = s; 01300 01301 if ( s == Todo ) 01302 { 01303 _statusLabel->setProperty( "class", "todo-step-status QLabel" ); 01304 _nameLabel->setProperty ( "class", "todo-step-name QLabel" ); 01305 } 01306 01307 if ( s == Done ) 01308 { 01309 _statusLabel->setProperty( "class", "done-step-status QLabel" ); 01310 _nameLabel->setProperty ( "class", "done-step-name QLabel" ); 01311 } 01312 01313 if ( s == Current ) 01314 { 01315 _statusLabel->setProperty( "class", "current-step-status QLabel" ); 01316 _nameLabel->setProperty ( "class", "current-step-name QLabel" ); 01317 } 01318 01319 _statusLabel->style()->unpolish( _statusLabel ); 01320 _statusLabel->style()->polish( _statusLabel ); 01321 _nameLabel->style()->unpolish( _nameLabel ); 01322 _nameLabel->style()->polish( _nameLabel ); 01323 } 01324 01325 #include "YQWizard.moc"