Changeset 22948 in vbox
- Timestamp:
- Sep 11, 2009 10:10:35 AM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 52214
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 3 edited
- 8 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r22904 r22948 5 5 6 6 # 7 # Copyright (C) 2006-200 7Sun Microsystems, Inc.7 # Copyright (C) 2006-2009 Sun Microsystems, Inc. 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 257 257 include/QIStatusBar.h \ 258 258 include/QIStateIndicator.h \ 259 include/QIRichToolButton.h \ 260 include/QIArrowButtonPress.h \ 261 include/QIArrowButtonSwitch.h \ 262 include/QIArrowSplitter.h \ 259 263 include/QIMessageBox.h \ 260 264 include/QILabel.h \ … … 332 336 # Sources containing local definitions of classes that use the Q_OBJECT macro. 333 337 VirtualBox_QT_MOCSRCS = \ 334 src/QIMessageBox.cpp \335 338 src/VBoxSelectorWnd.cpp \ 336 339 src/VBoxConsoleWnd.cpp \ … … 352 355 src/QIStateIndicator.cpp \ 353 356 src/QIStatusBar.cpp \ 357 src/QIRichToolButton.cpp \ 358 src/QIArrowButtonSwitch.cpp \ 359 src/QIArrowButtonPress.cpp \ 360 src/QIArrowSplitter.cpp \ 354 361 src/QIMessageBox.cpp \ 355 362 src/QILabel.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/include/QIArrowButtonPress.h
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBox class implementation4 * VirtualBox Qt extensions: QIArrowButtonPress class declaration 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 */ 22 22 23 #ifndef __QIArrowButtonPress_h__ 24 #define __QIArrowButtonPress_h__ 25 23 26 /* VBox includes */ 24 #include "VBoxDefs.h" 25 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 27 #include "QIRichToolButton.h" 32 28 33 /* Qt includes */ 34 #include <QHBoxLayout> 35 #include <QLabel> 36 #include <QPushButton> 37 #include <QStyleOptionFocusRect> 38 #include <QStylePainter> 39 #include <QToolButton> 40 #include <QKeyEvent> 41 42 /** @class QIRichToolButton 43 * 44 * The QIRichToolButton class is a tool-botton with separate text-label. 45 * It is declared here until moved into separate file in case 46 * of it will be used somewhere except problem-reporter dialog. 47 */ 48 class QIRichToolButton : public QWidget 49 { 50 Q_OBJECT; 51 52 public: 53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0) 55 : QWidget (aParent) 56 , mButton (new QToolButton()) 57 , mLabel (new QLabel (aName)) 58 { 59 /* Setup itself */ 60 setFocusPolicy (Qt::StrongFocus); 61 62 /* Setup tool-button */ 63 mButton->setAutoRaise (true); 64 mButton->setFixedSize (17, 16); 65 mButton->setFocusPolicy (Qt::NoFocus); 66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}"); 67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked())); 68 69 /* Setup text-label */ 70 mLabel->setBuddy (mButton); 71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}"); 72 73 /* Setup main-layout */ 74 QHBoxLayout *mainLayout = new QHBoxLayout (this); 75 VBoxGlobal::setLayoutMargin (mainLayout, 0); 76 mainLayout->setSpacing (0); 77 mainLayout->addWidget (mButton); 78 mainLayout->addWidget (mLabel); 79 80 /* Install event-filter */ 81 qApp->installEventFilter (this); 82 } 83 84 void animateClick() { mButton->animateClick(); } 85 86 void setText (const QString &aName) { mLabel->setText (aName); } 87 88 signals: 89 90 void clicked(); 91 92 protected slots: 93 94 virtual void buttonClicked() 95 { 96 emit clicked(); 97 } 98 99 protected: 100 101 bool eventFilter (QObject *aObject, QEvent *aEvent) 102 { 103 /* Process only QIRichToolButton or children */ 104 if (!(aObject == this || children().contains (aObject))) 105 return QWidget::eventFilter (aObject, aEvent); 106 107 /* Process keyboard events */ 108 if (aEvent->type() == QEvent::KeyPress) 109 { 110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 111 if (kEvent->key() == Qt::Key_Space) 112 animateClick(); 113 } 114 115 /* Process mouse events */ 116 if ((aEvent->type() == QEvent::MouseButtonPress || 117 aEvent->type() == QEvent::MouseButtonDblClick) 118 && aObject == mLabel) 119 { 120 /* Label click as toggle */ 121 animateClick(); 122 } 123 124 /* Default one handler */ 125 return QWidget::eventFilter (aObject, aEvent); 126 } 127 128 void paintEvent (QPaintEvent *aEvent) 129 { 130 /* Draw focus around mLabel if focused */ 131 if (hasFocus()) 132 { 133 QStylePainter painter (this); 134 QStyleOptionFocusRect option; 135 option.initFrom (this); 136 option.rect = mLabel->frameGeometry(); 137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option); 138 } 139 QWidget::paintEvent (aEvent); 140 } 141 142 QToolButton *mButton; 143 QLabel *mLabel; 144 }; 145 146 /** @class QIArrowButtonSwitch 147 * 148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 152 */ 153 class QIArrowButtonSwitch : public QIRichToolButton 154 { 155 Q_OBJECT; 156 157 public: 158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 162 { 163 updateIcon(); 164 } 165 166 bool isExpanded() const { return mIsExpanded; } 167 168 private slots: 169 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 176 177 private: 178 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 203 204 bool mIsExpanded; 205 }; 29 /* VBox forwards */ 30 class QIRichToolButton; 206 31 207 32 /** @class QIArrowButtonPress … … 209 34 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 35 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 36 * 213 37 */ 214 38 class QIArrowButtonPress : public QIRichToolButton … … 218 42 public: 219 43 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 44 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0); 226 45 227 46 private: 228 47 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 48 void updateIcon(); 49 bool eventFilter (QObject *aObject, QEvent *aEvent); 253 50 254 51 bool mNext; 255 52 }; 256 53 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 549 } 550 551 /** 552 * Returns the text of the given message box button. 553 * See QMessageBox::buttonText() for details. 554 * 555 * @param aButton Button index (0, 1 or 2). 556 */ 557 QString QIMessageBox::buttonText (int aButton) const 558 { 559 switch (aButton) 560 { 561 case 0: if (mButton0PB) return mButton0PB->text(); break; 562 case 1: if (mButton1PB) return mButton1PB->text(); break; 563 case 2: if (mButton2PB) return mButton2PB->text(); break; 564 default: break; 565 } 566 567 return QString::null; 568 } 569 570 /** 571 * Sets the text of the given message box button. 572 * See QMessageBox::setButtonText() for details. 573 * 574 * @param aButton Button index (0, 1 or 2). 575 * @param aText New button text. 576 */ 577 void QIMessageBox::setButtonText (int aButton, const QString &aText) 578 { 579 switch (aButton) 580 { 581 case 0: if (mButton0PB) mButton0PB->setText (aText); break; 582 case 1: if (mButton1PB) mButton1PB->setText (aText); break; 583 case 2: if (mButton2PB) mButton2PB->setText (aText); break; 584 default: break; 585 } 586 } 587 588 /** @fn QIMessageBox::flagText() const 589 * 590 * Returns the text of the optional message box flag. If the flag is hidden 591 * (by default) a null string is returned. 592 * 593 * @see #setFlagText() 594 */ 595 596 /** 597 * Sets the text for the optional message box flag (check box) that is 598 * displayed under the message text. Passing the null string as the argument 599 * will hide the flag. By default, the flag is hidden. 600 */ 601 void QIMessageBox::setFlagText (const QString &aText) 602 { 603 if (aText.isNull()) 604 { 605 mFlagCB->hide(); 606 } 607 else 608 { 609 mFlagCB->setText (aText); 610 mFlagCB->show(); 611 mFlagCB->setFocus(); 612 } 613 } 614 615 /** @fn QIMessageBox::isFlagChecked() const 616 * 617 * Returns true if the optional message box flag is checked and false 618 * otherwise. By default, the flag is not checked. 619 * 620 * @see #setFlagChecked() 621 * @see #setFlagText() 622 */ 623 624 /** @fn QIMessageBox::setFlagChecked (bool) 625 * 626 * Sets the state of the optional message box flag to a value of the argument. 627 * 628 * @see #isFlagChecked() 629 * @see #setFlagText() 630 */ 631 632 QPushButton *QIMessageBox::createButton (int aButton) 633 { 634 if (aButton == 0) 635 return 0; 636 637 QString text; 638 QDialogButtonBox::ButtonRole role; 639 switch (aButton & ButtonMask) 640 { 641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break; 642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break; 643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break; 644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break; 645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break; 646 default: 647 AssertMsgFailed (("Type %d is not implemented", aButton)); 648 return NULL; 649 } 650 651 QPushButton *b = mButtonBox->addButton (text, role); 652 653 if (aButton & Default) 654 { 655 b->setDefault (true); 656 b->setFocus(); 657 } 658 659 if (aButton & Escape) 660 mButtonEsc = aButton & ButtonMask; 661 662 return b; 663 } 664 665 /** @fn QIMessageBox::detailsText() const 666 * 667 * Returns the text of the optional details box. The details box is empty 668 * by default, so QString::null will be returned. 669 * 670 * @see #setDetailsText() 671 */ 672 673 /** 674 * Sets the text for the optional details box. Note that the details box 675 * is hidden by default, call #setDetailsShown(true) to make it visible. 676 * 677 * @see #detailsText() 678 * @see #setDetailsShown() 679 */ 680 void QIMessageBox::setDetailsText (const QString &aText) 681 { 682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty.")); 683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts)); 685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph.")); 686 687 foreach (QString paragraph, paragraphs) 688 { 689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts)); 690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts.")); 691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]); 692 } 693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1); 695 mDetailsIndex = 0; 696 refreshDetails(); 697 } 698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon) 700 { 701 QIcon icon; 702 switch (aIcon) 703 { 704 case QIMessageBox::Information: 705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this); 706 break; 707 case QMessageBox::Warning: 708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this); 709 break; 710 case QIMessageBox::Critical: 711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this); 712 break; 713 case QIMessageBox::Question: 714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this); 715 break; 716 case QIMessageBox::GuruMeditation: 717 icon = QIcon (":/meditation_32px.png"); 718 break; 719 default: 720 break; 721 } 722 if (!icon.isNull()) 723 { 724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this); 725 return icon.pixmap (size, size); 726 }else 727 return QPixmap(); 728 } 729 730 void QIMessageBox::closeEvent (QCloseEvent *e) 731 { 732 if (mWasDone) 733 e->accept(); 734 else 735 e->ignore(); 736 } 737 738 void QIMessageBox::showEvent (QShowEvent *e) 739 { 740 if (!mWasPolished) 741 { 742 /* Polishing sub-widgets */ 743 resize (minimumSizeHint()); 744 qApp->processEvents(); 745 mTextLabel->setMinimumWidth (mTextLabel->width()); 746 mTextLabel->updateSizeHint(); 747 qApp->processEvents(); 748 setFixedWidth (width()); 749 mDetailsSplitter->toggleWidget(); 750 mWasPolished = true; 751 } 752 753 QIDialog::showEvent (e); 754 } 755 756 void QIMessageBox::refreshDetails() 757 { 758 /* Update message text iteself */ 759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first); 760 mTextLabel->updateSizeHint(); 761 /* Update details table */ 762 mDetailsText->setText (mDetailsList [mDetailsIndex].second); 763 setDetailsShown (!mDetailsText->toPlainText().isEmpty()); 764 765 /* Update multi-paging system */ 766 if (mDetailsList.size() > 1) 767 { 768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1); 769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0); 770 } 771 772 /* Update details label */ 773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") : 774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size())); 775 } 776 777 /** 778 * Sets the visibility state of the optional details box 779 * to a value of the argument. 780 * 781 * @see #isDetailsShown() 782 * @see #setDetailsText() 783 */ 784 void QIMessageBox::setDetailsShown (bool aShown) 785 { 786 if (aShown) 787 { 788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible()); 789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked()); 790 mFlagCB_Details->setText (mFlagCB_Main->text()); 791 if (mFlagCB_Main->hasFocus()) 792 mFlagCB_Details->setFocus(); 793 mFlagCB_Main->setVisible (false); 794 mFlagCB = mFlagCB_Details; 795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum); 796 } 797 798 mDetailsVBox->setVisible (aShown); 799 800 if (!aShown) 801 { 802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible()); 803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked()); 804 mFlagCB_Main->setText (mFlagCB_Details->text()); 805 if (mFlagCB_Details->hasFocus()) 806 mFlagCB_Main->setFocus(); 807 mFlagCB = mFlagCB_Main; 808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); 809 } 810 } 811 812 void QIMessageBox::detailsBack() 813 { 814 if (mDetailsIndex > 0) 815 { 816 -- mDetailsIndex; 817 refreshDetails(); 818 } 819 } 820 821 void QIMessageBox::detailsNext() 822 { 823 if (mDetailsIndex < mDetailsList.size() - 1) 824 { 825 ++ mDetailsIndex; 826 refreshDetails(); 827 } 828 } 829 830 void QIMessageBox::reject() 831 { 832 if (mButtonEsc) 833 { 834 QDialog::reject(); 835 setResult (mButtonEsc & ButtonMask); 836 } 837 } 838 839 #include "QIMessageBox.moc" 840 54 #endif -
trunk/src/VBox/Frontends/VirtualBox/include/QIArrowButtonSwitch.h
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBox class implementation4 * VirtualBox Qt extensions: QIArrowButtonSwitch class declaration 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 */ 22 22 23 #ifndef __QIArrowButtonSwitch_h__ 24 #define __QIArrowButtonSwitch_h__ 25 23 26 /* VBox includes */ 24 #include "VBoxDefs.h" 25 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 27 #include "QIRichToolButton.h" 32 28 33 /* Qt includes */ 34 #include <QHBoxLayout> 35 #include <QLabel> 36 #include <QPushButton> 37 #include <QStyleOptionFocusRect> 38 #include <QStylePainter> 39 #include <QToolButton> 40 #include <QKeyEvent> 29 /* VBox forwards */ 30 class QIRichToolButton; 41 31 42 /** @class QIRichToolButton43 *44 * The QIRichToolButton class is a tool-botton with separate text-label.45 * It is declared here until moved into separate file in case46 * of it will be used somewhere except problem-reporter dialog.47 */48 class QIRichToolButton : public QWidget49 {50 Q_OBJECT;51 52 public:53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0)55 : QWidget (aParent)56 , mButton (new QToolButton())57 , mLabel (new QLabel (aName))58 {59 /* Setup itself */60 setFocusPolicy (Qt::StrongFocus);61 62 /* Setup tool-button */63 mButton->setAutoRaise (true);64 mButton->setFixedSize (17, 16);65 mButton->setFocusPolicy (Qt::NoFocus);66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}");67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked()));68 69 /* Setup text-label */70 mLabel->setBuddy (mButton);71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}");72 73 /* Setup main-layout */74 QHBoxLayout *mainLayout = new QHBoxLayout (this);75 VBoxGlobal::setLayoutMargin (mainLayout, 0);76 mainLayout->setSpacing (0);77 mainLayout->addWidget (mButton);78 mainLayout->addWidget (mLabel);79 80 /* Install event-filter */81 qApp->installEventFilter (this);82 }83 84 void animateClick() { mButton->animateClick(); }85 86 void setText (const QString &aName) { mLabel->setText (aName); }87 88 signals:89 90 void clicked();91 92 protected slots:93 94 virtual void buttonClicked()95 {96 emit clicked();97 }98 99 protected:100 101 bool eventFilter (QObject *aObject, QEvent *aEvent)102 {103 /* Process only QIRichToolButton or children */104 if (!(aObject == this || children().contains (aObject)))105 return QWidget::eventFilter (aObject, aEvent);106 107 /* Process keyboard events */108 if (aEvent->type() == QEvent::KeyPress)109 {110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);111 if (kEvent->key() == Qt::Key_Space)112 animateClick();113 }114 115 /* Process mouse events */116 if ((aEvent->type() == QEvent::MouseButtonPress ||117 aEvent->type() == QEvent::MouseButtonDblClick)118 && aObject == mLabel)119 {120 /* Label click as toggle */121 animateClick();122 }123 124 /* Default one handler */125 return QWidget::eventFilter (aObject, aEvent);126 }127 128 void paintEvent (QPaintEvent *aEvent)129 {130 /* Draw focus around mLabel if focused */131 if (hasFocus())132 {133 QStylePainter painter (this);134 QStyleOptionFocusRect option;135 option.initFrom (this);136 option.rect = mLabel->frameGeometry();137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option);138 }139 QWidget::paintEvent (aEvent);140 }141 142 QToolButton *mButton;143 QLabel *mLabel;144 };145 32 146 33 /** @class QIArrowButtonSwitch … … 148 35 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 36 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 37 * 152 38 */ 153 39 class QIArrowButtonSwitch : public QIRichToolButton … … 157 43 public: 158 44 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 162 { 163 updateIcon(); 164 } 165 45 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0); 166 46 bool isExpanded() const { return mIsExpanded; } 167 47 168 48 private slots: 169 49 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 50 void buttonClicked(); 176 51 177 52 private: 178 53 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 54 void updateIcon(); 55 bool eventFilter (QObject *aObject, QEvent *aEvent); 203 56 204 57 bool mIsExpanded; 205 58 }; 206 59 207 /** @class QIArrowButtonPress 208 * 209 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 213 */ 214 class QIArrowButtonPress : public QIRichToolButton 215 { 216 Q_OBJECT; 217 218 public: 219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 226 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 256 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 549 } 550 551 /** 552 * Returns the text of the given message box button. 553 * See QMessageBox::buttonText() for details. 554 * 555 * @param aButton Button index (0, 1 or 2). 556 */ 557 QString QIMessageBox::buttonText (int aButton) const 558 { 559 switch (aButton) 560 { 561 case 0: if (mButton0PB) return mButton0PB->text(); break; 562 case 1: if (mButton1PB) return mButton1PB->text(); break; 563 case 2: if (mButton2PB) return mButton2PB->text(); break; 564 default: break; 565 } 566 567 return QString::null; 568 } 569 570 /** 571 * Sets the text of the given message box button. 572 * See QMessageBox::setButtonText() for details. 573 * 574 * @param aButton Button index (0, 1 or 2). 575 * @param aText New button text. 576 */ 577 void QIMessageBox::setButtonText (int aButton, const QString &aText) 578 { 579 switch (aButton) 580 { 581 case 0: if (mButton0PB) mButton0PB->setText (aText); break; 582 case 1: if (mButton1PB) mButton1PB->setText (aText); break; 583 case 2: if (mButton2PB) mButton2PB->setText (aText); break; 584 default: break; 585 } 586 } 587 588 /** @fn QIMessageBox::flagText() const 589 * 590 * Returns the text of the optional message box flag. If the flag is hidden 591 * (by default) a null string is returned. 592 * 593 * @see #setFlagText() 594 */ 595 596 /** 597 * Sets the text for the optional message box flag (check box) that is 598 * displayed under the message text. Passing the null string as the argument 599 * will hide the flag. By default, the flag is hidden. 600 */ 601 void QIMessageBox::setFlagText (const QString &aText) 602 { 603 if (aText.isNull()) 604 { 605 mFlagCB->hide(); 606 } 607 else 608 { 609 mFlagCB->setText (aText); 610 mFlagCB->show(); 611 mFlagCB->setFocus(); 612 } 613 } 614 615 /** @fn QIMessageBox::isFlagChecked() const 616 * 617 * Returns true if the optional message box flag is checked and false 618 * otherwise. By default, the flag is not checked. 619 * 620 * @see #setFlagChecked() 621 * @see #setFlagText() 622 */ 623 624 /** @fn QIMessageBox::setFlagChecked (bool) 625 * 626 * Sets the state of the optional message box flag to a value of the argument. 627 * 628 * @see #isFlagChecked() 629 * @see #setFlagText() 630 */ 631 632 QPushButton *QIMessageBox::createButton (int aButton) 633 { 634 if (aButton == 0) 635 return 0; 636 637 QString text; 638 QDialogButtonBox::ButtonRole role; 639 switch (aButton & ButtonMask) 640 { 641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break; 642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break; 643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break; 644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break; 645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break; 646 default: 647 AssertMsgFailed (("Type %d is not implemented", aButton)); 648 return NULL; 649 } 650 651 QPushButton *b = mButtonBox->addButton (text, role); 652 653 if (aButton & Default) 654 { 655 b->setDefault (true); 656 b->setFocus(); 657 } 658 659 if (aButton & Escape) 660 mButtonEsc = aButton & ButtonMask; 661 662 return b; 663 } 664 665 /** @fn QIMessageBox::detailsText() const 666 * 667 * Returns the text of the optional details box. The details box is empty 668 * by default, so QString::null will be returned. 669 * 670 * @see #setDetailsText() 671 */ 672 673 /** 674 * Sets the text for the optional details box. Note that the details box 675 * is hidden by default, call #setDetailsShown(true) to make it visible. 676 * 677 * @see #detailsText() 678 * @see #setDetailsShown() 679 */ 680 void QIMessageBox::setDetailsText (const QString &aText) 681 { 682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty.")); 683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts)); 685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph.")); 686 687 foreach (QString paragraph, paragraphs) 688 { 689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts)); 690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts.")); 691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]); 692 } 693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1); 695 mDetailsIndex = 0; 696 refreshDetails(); 697 } 698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon) 700 { 701 QIcon icon; 702 switch (aIcon) 703 { 704 case QIMessageBox::Information: 705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this); 706 break; 707 case QMessageBox::Warning: 708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this); 709 break; 710 case QIMessageBox::Critical: 711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this); 712 break; 713 case QIMessageBox::Question: 714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this); 715 break; 716 case QIMessageBox::GuruMeditation: 717 icon = QIcon (":/meditation_32px.png"); 718 break; 719 default: 720 break; 721 } 722 if (!icon.isNull()) 723 { 724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this); 725 return icon.pixmap (size, size); 726 }else 727 return QPixmap(); 728 } 729 730 void QIMessageBox::closeEvent (QCloseEvent *e) 731 { 732 if (mWasDone) 733 e->accept(); 734 else 735 e->ignore(); 736 } 737 738 void QIMessageBox::showEvent (QShowEvent *e) 739 { 740 if (!mWasPolished) 741 { 742 /* Polishing sub-widgets */ 743 resize (minimumSizeHint()); 744 qApp->processEvents(); 745 mTextLabel->setMinimumWidth (mTextLabel->width()); 746 mTextLabel->updateSizeHint(); 747 qApp->processEvents(); 748 setFixedWidth (width()); 749 mDetailsSplitter->toggleWidget(); 750 mWasPolished = true; 751 } 752 753 QIDialog::showEvent (e); 754 } 755 756 void QIMessageBox::refreshDetails() 757 { 758 /* Update message text iteself */ 759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first); 760 mTextLabel->updateSizeHint(); 761 /* Update details table */ 762 mDetailsText->setText (mDetailsList [mDetailsIndex].second); 763 setDetailsShown (!mDetailsText->toPlainText().isEmpty()); 764 765 /* Update multi-paging system */ 766 if (mDetailsList.size() > 1) 767 { 768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1); 769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0); 770 } 771 772 /* Update details label */ 773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") : 774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size())); 775 } 776 777 /** 778 * Sets the visibility state of the optional details box 779 * to a value of the argument. 780 * 781 * @see #isDetailsShown() 782 * @see #setDetailsText() 783 */ 784 void QIMessageBox::setDetailsShown (bool aShown) 785 { 786 if (aShown) 787 { 788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible()); 789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked()); 790 mFlagCB_Details->setText (mFlagCB_Main->text()); 791 if (mFlagCB_Main->hasFocus()) 792 mFlagCB_Details->setFocus(); 793 mFlagCB_Main->setVisible (false); 794 mFlagCB = mFlagCB_Details; 795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum); 796 } 797 798 mDetailsVBox->setVisible (aShown); 799 800 if (!aShown) 801 { 802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible()); 803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked()); 804 mFlagCB_Main->setText (mFlagCB_Details->text()); 805 if (mFlagCB_Details->hasFocus()) 806 mFlagCB_Main->setFocus(); 807 mFlagCB = mFlagCB_Main; 808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); 809 } 810 } 811 812 void QIMessageBox::detailsBack() 813 { 814 if (mDetailsIndex > 0) 815 { 816 -- mDetailsIndex; 817 refreshDetails(); 818 } 819 } 820 821 void QIMessageBox::detailsNext() 822 { 823 if (mDetailsIndex < mDetailsList.size() - 1) 824 { 825 ++ mDetailsIndex; 826 refreshDetails(); 827 } 828 } 829 830 void QIMessageBox::reject() 831 { 832 if (mButtonEsc) 833 { 834 QDialog::reject(); 835 setResult (mButtonEsc & ButtonMask); 836 } 837 } 838 839 #include "QIMessageBox.moc" 840 60 #endif -
trunk/src/VBox/Frontends/VirtualBox/include/QIArrowSplitter.h
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBox class implementation4 * VirtualBox Qt extensions: QIArrowSplitter class declaration 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 */ 22 22 23 #ifndef __QIArrowSplitter_h__ 24 #define __QIArrowSplitter_h__ 25 23 26 /* VBox includes */ 24 #include "VBoxDefs.h" 25 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 27 #include "QIArrowButtonPress.h" 28 #include "QIArrowButtonSwitch.h" 32 29 33 30 /* Qt includes */ 31 #include <QWidget> 34 32 #include <QHBoxLayout> 35 #include <QLabel>36 #include <QPushButton>37 #include <QStyleOptionFocusRect>38 #include <QStylePainter>39 #include <QToolButton>40 #include <QKeyEvent>41 33 42 /** @class QIRichToolButton 43 * 44 * The QIRichToolButton class is a tool-botton with separate text-label. 45 * It is declared here until moved into separate file in case 46 * of it will be used somewhere except problem-reporter dialog. 47 */ 48 class QIRichToolButton : public QWidget 49 { 50 Q_OBJECT; 34 /* VBox forwards */ 35 class QIArrowButtonPress; 36 class QIArrowButtonSwitch; 51 37 52 public: 53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0) 55 : QWidget (aParent) 56 , mButton (new QToolButton()) 57 , mLabel (new QLabel (aName)) 58 { 59 /* Setup itself */ 60 setFocusPolicy (Qt::StrongFocus); 61 62 /* Setup tool-button */ 63 mButton->setAutoRaise (true); 64 mButton->setFixedSize (17, 16); 65 mButton->setFocusPolicy (Qt::NoFocus); 66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}"); 67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked())); 68 69 /* Setup text-label */ 70 mLabel->setBuddy (mButton); 71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}"); 72 73 /* Setup main-layout */ 74 QHBoxLayout *mainLayout = new QHBoxLayout (this); 75 VBoxGlobal::setLayoutMargin (mainLayout, 0); 76 mainLayout->setSpacing (0); 77 mainLayout->addWidget (mButton); 78 mainLayout->addWidget (mLabel); 79 80 /* Install event-filter */ 81 qApp->installEventFilter (this); 82 } 83 84 void animateClick() { mButton->animateClick(); } 85 86 void setText (const QString &aName) { mLabel->setText (aName); } 87 88 signals: 89 90 void clicked(); 91 92 protected slots: 93 94 virtual void buttonClicked() 95 { 96 emit clicked(); 97 } 98 99 protected: 100 101 bool eventFilter (QObject *aObject, QEvent *aEvent) 102 { 103 /* Process only QIRichToolButton or children */ 104 if (!(aObject == this || children().contains (aObject))) 105 return QWidget::eventFilter (aObject, aEvent); 106 107 /* Process keyboard events */ 108 if (aEvent->type() == QEvent::KeyPress) 109 { 110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 111 if (kEvent->key() == Qt::Key_Space) 112 animateClick(); 113 } 114 115 /* Process mouse events */ 116 if ((aEvent->type() == QEvent::MouseButtonPress || 117 aEvent->type() == QEvent::MouseButtonDblClick) 118 && aObject == mLabel) 119 { 120 /* Label click as toggle */ 121 animateClick(); 122 } 123 124 /* Default one handler */ 125 return QWidget::eventFilter (aObject, aEvent); 126 } 127 128 void paintEvent (QPaintEvent *aEvent) 129 { 130 /* Draw focus around mLabel if focused */ 131 if (hasFocus()) 132 { 133 QStylePainter painter (this); 134 QStyleOptionFocusRect option; 135 option.initFrom (this); 136 option.rect = mLabel->frameGeometry(); 137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option); 138 } 139 QWidget::paintEvent (aEvent); 140 } 141 142 QToolButton *mButton; 143 QLabel *mLabel; 144 }; 145 146 /** @class QIArrowButtonSwitch 147 * 148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 152 */ 153 class QIArrowButtonSwitch : public QIRichToolButton 154 { 155 Q_OBJECT; 156 157 public: 158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 162 { 163 updateIcon(); 164 } 165 166 bool isExpanded() const { return mIsExpanded; } 167 168 private slots: 169 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 176 177 private: 178 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 203 204 bool mIsExpanded; 205 }; 206 207 /** @class QIArrowButtonPress 208 * 209 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 213 */ 214 class QIArrowButtonPress : public QIRichToolButton 215 { 216 Q_OBJECT; 217 218 public: 219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 226 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 38 /* Qt forwards */ 39 class QVBoxLayout; 256 40 257 41 /** @class QIArrowSplitter 258 42 * 259 43 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 44 * 262 45 */ 263 46 class QIArrowSplitter : public QWidget … … 267 50 public: 268 51 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 52 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0); 279 53 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 54 void setMultiPaging (bool aMultiPage); 283 55 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 56 void setButtonEnabled (bool aNext, bool aEnabled); 288 57 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 58 void setName (const QString &aName); 323 59 324 60 public slots: 325 61 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 62 void toggleWidget(); 331 63 332 64 signals: … … 337 69 private: 338 70 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 71 bool eventFilter (QObject *aObject, QEvent *aEvent); 344 72 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 73 void relayout(); 416 74 417 75 QVBoxLayout *mMainLayout; … … 422 80 }; 423 81 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 549 } 550 551 /** 552 * Returns the text of the given message box button. 553 * See QMessageBox::buttonText() for details. 554 * 555 * @param aButton Button index (0, 1 or 2). 556 */ 557 QString QIMessageBox::buttonText (int aButton) const 558 { 559 switch (aButton) 560 { 561 case 0: if (mButton0PB) return mButton0PB->text(); break; 562 case 1: if (mButton1PB) return mButton1PB->text(); break; 563 case 2: if (mButton2PB) return mButton2PB->text(); break; 564 default: break; 565 } 566 567 return QString::null; 568 } 569 570 /** 571 * Sets the text of the given message box button. 572 * See QMessageBox::setButtonText() for details. 573 * 574 * @param aButton Button index (0, 1 or 2). 575 * @param aText New button text. 576 */ 577 void QIMessageBox::setButtonText (int aButton, const QString &aText) 578 { 579 switch (aButton) 580 { 581 case 0: if (mButton0PB) mButton0PB->setText (aText); break; 582 case 1: if (mButton1PB) mButton1PB->setText (aText); break; 583 case 2: if (mButton2PB) mButton2PB->setText (aText); break; 584 default: break; 585 } 586 } 587 588 /** @fn QIMessageBox::flagText() const 589 * 590 * Returns the text of the optional message box flag. If the flag is hidden 591 * (by default) a null string is returned. 592 * 593 * @see #setFlagText() 594 */ 595 596 /** 597 * Sets the text for the optional message box flag (check box) that is 598 * displayed under the message text. Passing the null string as the argument 599 * will hide the flag. By default, the flag is hidden. 600 */ 601 void QIMessageBox::setFlagText (const QString &aText) 602 { 603 if (aText.isNull()) 604 { 605 mFlagCB->hide(); 606 } 607 else 608 { 609 mFlagCB->setText (aText); 610 mFlagCB->show(); 611 mFlagCB->setFocus(); 612 } 613 } 614 615 /** @fn QIMessageBox::isFlagChecked() const 616 * 617 * Returns true if the optional message box flag is checked and false 618 * otherwise. By default, the flag is not checked. 619 * 620 * @see #setFlagChecked() 621 * @see #setFlagText() 622 */ 623 624 /** @fn QIMessageBox::setFlagChecked (bool) 625 * 626 * Sets the state of the optional message box flag to a value of the argument. 627 * 628 * @see #isFlagChecked() 629 * @see #setFlagText() 630 */ 631 632 QPushButton *QIMessageBox::createButton (int aButton) 633 { 634 if (aButton == 0) 635 return 0; 636 637 QString text; 638 QDialogButtonBox::ButtonRole role; 639 switch (aButton & ButtonMask) 640 { 641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break; 642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break; 643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break; 644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break; 645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break; 646 default: 647 AssertMsgFailed (("Type %d is not implemented", aButton)); 648 return NULL; 649 } 650 651 QPushButton *b = mButtonBox->addButton (text, role); 652 653 if (aButton & Default) 654 { 655 b->setDefault (true); 656 b->setFocus(); 657 } 658 659 if (aButton & Escape) 660 mButtonEsc = aButton & ButtonMask; 661 662 return b; 663 } 664 665 /** @fn QIMessageBox::detailsText() const 666 * 667 * Returns the text of the optional details box. The details box is empty 668 * by default, so QString::null will be returned. 669 * 670 * @see #setDetailsText() 671 */ 672 673 /** 674 * Sets the text for the optional details box. Note that the details box 675 * is hidden by default, call #setDetailsShown(true) to make it visible. 676 * 677 * @see #detailsText() 678 * @see #setDetailsShown() 679 */ 680 void QIMessageBox::setDetailsText (const QString &aText) 681 { 682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty.")); 683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts)); 685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph.")); 686 687 foreach (QString paragraph, paragraphs) 688 { 689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts)); 690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts.")); 691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]); 692 } 693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1); 695 mDetailsIndex = 0; 696 refreshDetails(); 697 } 698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon) 700 { 701 QIcon icon; 702 switch (aIcon) 703 { 704 case QIMessageBox::Information: 705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this); 706 break; 707 case QMessageBox::Warning: 708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this); 709 break; 710 case QIMessageBox::Critical: 711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this); 712 break; 713 case QIMessageBox::Question: 714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this); 715 break; 716 case QIMessageBox::GuruMeditation: 717 icon = QIcon (":/meditation_32px.png"); 718 break; 719 default: 720 break; 721 } 722 if (!icon.isNull()) 723 { 724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this); 725 return icon.pixmap (size, size); 726 }else 727 return QPixmap(); 728 } 729 730 void QIMessageBox::closeEvent (QCloseEvent *e) 731 { 732 if (mWasDone) 733 e->accept(); 734 else 735 e->ignore(); 736 } 737 738 void QIMessageBox::showEvent (QShowEvent *e) 739 { 740 if (!mWasPolished) 741 { 742 /* Polishing sub-widgets */ 743 resize (minimumSizeHint()); 744 qApp->processEvents(); 745 mTextLabel->setMinimumWidth (mTextLabel->width()); 746 mTextLabel->updateSizeHint(); 747 qApp->processEvents(); 748 setFixedWidth (width()); 749 mDetailsSplitter->toggleWidget(); 750 mWasPolished = true; 751 } 752 753 QIDialog::showEvent (e); 754 } 755 756 void QIMessageBox::refreshDetails() 757 { 758 /* Update message text iteself */ 759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first); 760 mTextLabel->updateSizeHint(); 761 /* Update details table */ 762 mDetailsText->setText (mDetailsList [mDetailsIndex].second); 763 setDetailsShown (!mDetailsText->toPlainText().isEmpty()); 764 765 /* Update multi-paging system */ 766 if (mDetailsList.size() > 1) 767 { 768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1); 769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0); 770 } 771 772 /* Update details label */ 773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") : 774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size())); 775 } 776 777 /** 778 * Sets the visibility state of the optional details box 779 * to a value of the argument. 780 * 781 * @see #isDetailsShown() 782 * @see #setDetailsText() 783 */ 784 void QIMessageBox::setDetailsShown (bool aShown) 785 { 786 if (aShown) 787 { 788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible()); 789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked()); 790 mFlagCB_Details->setText (mFlagCB_Main->text()); 791 if (mFlagCB_Main->hasFocus()) 792 mFlagCB_Details->setFocus(); 793 mFlagCB_Main->setVisible (false); 794 mFlagCB = mFlagCB_Details; 795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum); 796 } 797 798 mDetailsVBox->setVisible (aShown); 799 800 if (!aShown) 801 { 802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible()); 803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked()); 804 mFlagCB_Main->setText (mFlagCB_Details->text()); 805 if (mFlagCB_Details->hasFocus()) 806 mFlagCB_Main->setFocus(); 807 mFlagCB = mFlagCB_Main; 808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); 809 } 810 } 811 812 void QIMessageBox::detailsBack() 813 { 814 if (mDetailsIndex > 0) 815 { 816 -- mDetailsIndex; 817 refreshDetails(); 818 } 819 } 820 821 void QIMessageBox::detailsNext() 822 { 823 if (mDetailsIndex < mDetailsList.size() - 1) 824 { 825 ++ mDetailsIndex; 826 refreshDetails(); 827 } 828 } 829 830 void QIMessageBox::reject() 831 { 832 if (mButtonEsc) 833 { 834 QDialog::reject(); 835 setResult (mButtonEsc & ButtonMask); 836 } 837 } 838 839 #include "QIMessageBox.moc" 840 82 #endif -
trunk/src/VBox/Frontends/VirtualBox/include/QIMessageBox.h
r18071 r22948 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 26 26 /* VBox includes */ 27 27 #include "QIDialog.h" 28 #include "QIArrowSplitter.h" 28 29 29 30 /* Qt includes */ -
trunk/src/VBox/Frontends/VirtualBox/include/QIRichToolButton.h
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBox class implementation4 * VirtualBox Qt extensions: QIRichToolButton class declaration 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 */ 22 22 23 /* VBox includes */ 24 #include "VBoxDefs.h" 25 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 23 #ifndef __QIRichToolButton_h__ 24 #define __QIRichToolButton_h__ 32 25 33 26 /* Qt includes */ 34 #include <QHBoxLayout>35 27 #include <QLabel> 36 #include <QPushButton> 37 #include <QStyleOptionFocusRect> 38 #include <QStylePainter> 28 #include <QWidget> 39 29 #include <QToolButton> 40 #include <QKeyEvent>41 30 42 31 /** @class QIRichToolButton 43 32 * 44 33 * The QIRichToolButton class is a tool-botton with separate text-label. 45 * It is declared here until moved into separate file in case 46 * of it will be used somewhere except problem-reporter dialog. 34 * 47 35 */ 48 36 class QIRichToolButton : public QWidget … … 52 40 public: 53 41 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0) 55 : QWidget (aParent) 56 , mButton (new QToolButton()) 57 , mLabel (new QLabel (aName)) 58 { 59 /* Setup itself */ 60 setFocusPolicy (Qt::StrongFocus); 61 62 /* Setup tool-button */ 63 mButton->setAutoRaise (true); 64 mButton->setFixedSize (17, 16); 65 mButton->setFocusPolicy (Qt::NoFocus); 66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}"); 67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked())); 68 69 /* Setup text-label */ 70 mLabel->setBuddy (mButton); 71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}"); 72 73 /* Setup main-layout */ 74 QHBoxLayout *mainLayout = new QHBoxLayout (this); 75 VBoxGlobal::setLayoutMargin (mainLayout, 0); 76 mainLayout->setSpacing (0); 77 mainLayout->addWidget (mButton); 78 mainLayout->addWidget (mLabel); 79 80 /* Install event-filter */ 81 qApp->installEventFilter (this); 82 } 42 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0); 83 43 84 44 void animateClick() { mButton->animateClick(); } 85 86 45 void setText (const QString &aName) { mLabel->setText (aName); } 87 46 … … 92 51 protected slots: 93 52 94 virtual void buttonClicked() 95 { 96 emit clicked(); 97 } 53 virtual void buttonClicked() { emit clicked(); } 98 54 99 55 protected: 100 56 101 bool eventFilter (QObject *aObject, QEvent *aEvent) 102 { 103 /* Process only QIRichToolButton or children */ 104 if (!(aObject == this || children().contains (aObject))) 105 return QWidget::eventFilter (aObject, aEvent); 106 107 /* Process keyboard events */ 108 if (aEvent->type() == QEvent::KeyPress) 109 { 110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 111 if (kEvent->key() == Qt::Key_Space) 112 animateClick(); 113 } 114 115 /* Process mouse events */ 116 if ((aEvent->type() == QEvent::MouseButtonPress || 117 aEvent->type() == QEvent::MouseButtonDblClick) 118 && aObject == mLabel) 119 { 120 /* Label click as toggle */ 121 animateClick(); 122 } 123 124 /* Default one handler */ 125 return QWidget::eventFilter (aObject, aEvent); 126 } 127 128 void paintEvent (QPaintEvent *aEvent) 129 { 130 /* Draw focus around mLabel if focused */ 131 if (hasFocus()) 132 { 133 QStylePainter painter (this); 134 QStyleOptionFocusRect option; 135 option.initFrom (this); 136 option.rect = mLabel->frameGeometry(); 137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option); 138 } 139 QWidget::paintEvent (aEvent); 140 } 57 bool eventFilter (QObject *aObject, QEvent *aEvent); 58 void paintEvent (QPaintEvent *aEvent); 141 59 142 60 QToolButton *mButton; … … 144 62 }; 145 63 146 /** @class QIArrowButtonSwitch 147 * 148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 152 */ 153 class QIArrowButtonSwitch : public QIRichToolButton 154 { 155 Q_OBJECT; 156 157 public: 158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 162 { 163 updateIcon(); 164 } 165 166 bool isExpanded() const { return mIsExpanded; } 167 168 private slots: 169 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 176 177 private: 178 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 203 204 bool mIsExpanded; 205 }; 206 207 /** @class QIArrowButtonPress 208 * 209 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 213 */ 214 class QIArrowButtonPress : public QIRichToolButton 215 { 216 Q_OBJECT; 217 218 public: 219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 226 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 256 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 549 } 550 551 /** 552 * Returns the text of the given message box button. 553 * See QMessageBox::buttonText() for details. 554 * 555 * @param aButton Button index (0, 1 or 2). 556 */ 557 QString QIMessageBox::buttonText (int aButton) const 558 { 559 switch (aButton) 560 { 561 case 0: if (mButton0PB) return mButton0PB->text(); break; 562 case 1: if (mButton1PB) return mButton1PB->text(); break; 563 case 2: if (mButton2PB) return mButton2PB->text(); break; 564 default: break; 565 } 566 567 return QString::null; 568 } 569 570 /** 571 * Sets the text of the given message box button. 572 * See QMessageBox::setButtonText() for details. 573 * 574 * @param aButton Button index (0, 1 or 2). 575 * @param aText New button text. 576 */ 577 void QIMessageBox::setButtonText (int aButton, const QString &aText) 578 { 579 switch (aButton) 580 { 581 case 0: if (mButton0PB) mButton0PB->setText (aText); break; 582 case 1: if (mButton1PB) mButton1PB->setText (aText); break; 583 case 2: if (mButton2PB) mButton2PB->setText (aText); break; 584 default: break; 585 } 586 } 587 588 /** @fn QIMessageBox::flagText() const 589 * 590 * Returns the text of the optional message box flag. If the flag is hidden 591 * (by default) a null string is returned. 592 * 593 * @see #setFlagText() 594 */ 595 596 /** 597 * Sets the text for the optional message box flag (check box) that is 598 * displayed under the message text. Passing the null string as the argument 599 * will hide the flag. By default, the flag is hidden. 600 */ 601 void QIMessageBox::setFlagText (const QString &aText) 602 { 603 if (aText.isNull()) 604 { 605 mFlagCB->hide(); 606 } 607 else 608 { 609 mFlagCB->setText (aText); 610 mFlagCB->show(); 611 mFlagCB->setFocus(); 612 } 613 } 614 615 /** @fn QIMessageBox::isFlagChecked() const 616 * 617 * Returns true if the optional message box flag is checked and false 618 * otherwise. By default, the flag is not checked. 619 * 620 * @see #setFlagChecked() 621 * @see #setFlagText() 622 */ 623 624 /** @fn QIMessageBox::setFlagChecked (bool) 625 * 626 * Sets the state of the optional message box flag to a value of the argument. 627 * 628 * @see #isFlagChecked() 629 * @see #setFlagText() 630 */ 631 632 QPushButton *QIMessageBox::createButton (int aButton) 633 { 634 if (aButton == 0) 635 return 0; 636 637 QString text; 638 QDialogButtonBox::ButtonRole role; 639 switch (aButton & ButtonMask) 640 { 641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break; 642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break; 643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break; 644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break; 645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break; 646 default: 647 AssertMsgFailed (("Type %d is not implemented", aButton)); 648 return NULL; 649 } 650 651 QPushButton *b = mButtonBox->addButton (text, role); 652 653 if (aButton & Default) 654 { 655 b->setDefault (true); 656 b->setFocus(); 657 } 658 659 if (aButton & Escape) 660 mButtonEsc = aButton & ButtonMask; 661 662 return b; 663 } 664 665 /** @fn QIMessageBox::detailsText() const 666 * 667 * Returns the text of the optional details box. The details box is empty 668 * by default, so QString::null will be returned. 669 * 670 * @see #setDetailsText() 671 */ 672 673 /** 674 * Sets the text for the optional details box. Note that the details box 675 * is hidden by default, call #setDetailsShown(true) to make it visible. 676 * 677 * @see #detailsText() 678 * @see #setDetailsShown() 679 */ 680 void QIMessageBox::setDetailsText (const QString &aText) 681 { 682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty.")); 683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts)); 685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph.")); 686 687 foreach (QString paragraph, paragraphs) 688 { 689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts)); 690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts.")); 691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]); 692 } 693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1); 695 mDetailsIndex = 0; 696 refreshDetails(); 697 } 698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon) 700 { 701 QIcon icon; 702 switch (aIcon) 703 { 704 case QIMessageBox::Information: 705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this); 706 break; 707 case QMessageBox::Warning: 708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this); 709 break; 710 case QIMessageBox::Critical: 711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this); 712 break; 713 case QIMessageBox::Question: 714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this); 715 break; 716 case QIMessageBox::GuruMeditation: 717 icon = QIcon (":/meditation_32px.png"); 718 break; 719 default: 720 break; 721 } 722 if (!icon.isNull()) 723 { 724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this); 725 return icon.pixmap (size, size); 726 }else 727 return QPixmap(); 728 } 729 730 void QIMessageBox::closeEvent (QCloseEvent *e) 731 { 732 if (mWasDone) 733 e->accept(); 734 else 735 e->ignore(); 736 } 737 738 void QIMessageBox::showEvent (QShowEvent *e) 739 { 740 if (!mWasPolished) 741 { 742 /* Polishing sub-widgets */ 743 resize (minimumSizeHint()); 744 qApp->processEvents(); 745 mTextLabel->setMinimumWidth (mTextLabel->width()); 746 mTextLabel->updateSizeHint(); 747 qApp->processEvents(); 748 setFixedWidth (width()); 749 mDetailsSplitter->toggleWidget(); 750 mWasPolished = true; 751 } 752 753 QIDialog::showEvent (e); 754 } 755 756 void QIMessageBox::refreshDetails() 757 { 758 /* Update message text iteself */ 759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first); 760 mTextLabel->updateSizeHint(); 761 /* Update details table */ 762 mDetailsText->setText (mDetailsList [mDetailsIndex].second); 763 setDetailsShown (!mDetailsText->toPlainText().isEmpty()); 764 765 /* Update multi-paging system */ 766 if (mDetailsList.size() > 1) 767 { 768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1); 769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0); 770 } 771 772 /* Update details label */ 773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") : 774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size())); 775 } 776 777 /** 778 * Sets the visibility state of the optional details box 779 * to a value of the argument. 780 * 781 * @see #isDetailsShown() 782 * @see #setDetailsText() 783 */ 784 void QIMessageBox::setDetailsShown (bool aShown) 785 { 786 if (aShown) 787 { 788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible()); 789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked()); 790 mFlagCB_Details->setText (mFlagCB_Main->text()); 791 if (mFlagCB_Main->hasFocus()) 792 mFlagCB_Details->setFocus(); 793 mFlagCB_Main->setVisible (false); 794 mFlagCB = mFlagCB_Details; 795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum); 796 } 797 798 mDetailsVBox->setVisible (aShown); 799 800 if (!aShown) 801 { 802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible()); 803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked()); 804 mFlagCB_Main->setText (mFlagCB_Details->text()); 805 if (mFlagCB_Details->hasFocus()) 806 mFlagCB_Main->setFocus(); 807 mFlagCB = mFlagCB_Main; 808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); 809 } 810 } 811 812 void QIMessageBox::detailsBack() 813 { 814 if (mDetailsIndex > 0) 815 { 816 -- mDetailsIndex; 817 refreshDetails(); 818 } 819 } 820 821 void QIMessageBox::detailsNext() 822 { 823 if (mDetailsIndex < mDetailsList.size() - 1) 824 { 825 ++ mDetailsIndex; 826 refreshDetails(); 827 } 828 } 829 830 void QIMessageBox::reject() 831 { 832 if (mButtonEsc) 833 { 834 QDialog::reject(); 835 setResult (mButtonEsc & ButtonMask); 836 } 837 } 838 839 #include "QIMessageBox.moc" 840 64 #endif -
trunk/src/VBox/Frontends/VirtualBox/src/QIArrowButtonPress.cpp
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBoxclass implementation4 * VirtualBox Qt extensions: QIArrowButtonPress class implementation 5 5 */ 6 6 … … 22 22 23 23 /* VBox includes */ 24 #include "VBoxDefs.h"25 24 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 25 #include "QIArrowButtonPress.h" 32 26 33 27 /* Qt includes */ 34 #include <QHBoxLayout>35 #include <QLabel>36 #include <QPushButton>37 #include <QStyleOptionFocusRect>38 #include <QStylePainter>39 #include <QToolButton>40 28 #include <QKeyEvent> 41 29 42 /** @class QIRichToolButton43 *44 * The QIRichToolButton class is a tool-botton with separate text-label.45 * It is declared here until moved into separate file in case46 * of it will be used somewhere except problem-reporter dialog.47 */48 class QIRichToolButton : public QWidget49 {50 Q_OBJECT;51 52 public:53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0)55 : QWidget (aParent)56 , mButton (new QToolButton())57 , mLabel (new QLabel (aName))58 {59 /* Setup itself */60 setFocusPolicy (Qt::StrongFocus);61 62 /* Setup tool-button */63 mButton->setAutoRaise (true);64 mButton->setFixedSize (17, 16);65 mButton->setFocusPolicy (Qt::NoFocus);66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}");67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked()));68 69 /* Setup text-label */70 mLabel->setBuddy (mButton);71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}");72 73 /* Setup main-layout */74 QHBoxLayout *mainLayout = new QHBoxLayout (this);75 VBoxGlobal::setLayoutMargin (mainLayout, 0);76 mainLayout->setSpacing (0);77 mainLayout->addWidget (mButton);78 mainLayout->addWidget (mLabel);79 80 /* Install event-filter */81 qApp->installEventFilter (this);82 }83 84 void animateClick() { mButton->animateClick(); }85 86 void setText (const QString &aName) { mLabel->setText (aName); }87 88 signals:89 90 void clicked();91 92 protected slots:93 94 virtual void buttonClicked()95 {96 emit clicked();97 }98 99 protected:100 101 bool eventFilter (QObject *aObject, QEvent *aEvent)102 {103 /* Process only QIRichToolButton or children */104 if (!(aObject == this || children().contains (aObject)))105 return QWidget::eventFilter (aObject, aEvent);106 107 /* Process keyboard events */108 if (aEvent->type() == QEvent::KeyPress)109 {110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);111 if (kEvent->key() == Qt::Key_Space)112 animateClick();113 }114 115 /* Process mouse events */116 if ((aEvent->type() == QEvent::MouseButtonPress ||117 aEvent->type() == QEvent::MouseButtonDblClick)118 && aObject == mLabel)119 {120 /* Label click as toggle */121 animateClick();122 }123 124 /* Default one handler */125 return QWidget::eventFilter (aObject, aEvent);126 }127 128 void paintEvent (QPaintEvent *aEvent)129 {130 /* Draw focus around mLabel if focused */131 if (hasFocus())132 {133 QStylePainter painter (this);134 QStyleOptionFocusRect option;135 option.initFrom (this);136 option.rect = mLabel->frameGeometry();137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option);138 }139 QWidget::paintEvent (aEvent);140 }141 142 QToolButton *mButton;143 QLabel *mLabel;144 };145 146 /** @class QIArrowButtonSwitch147 *148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label,149 * used as collaps/expand switch in QIMessageBox class.150 * It is declared here until moved into separate file in case151 * of it will be used somewhere except problem-reporter dialog.152 */153 class QIArrowButtonSwitch : public QIRichToolButton154 {155 Q_OBJECT;156 157 public:158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0)160 : QIRichToolButton (aName, aParent)161 , mIsExpanded (false)162 {163 updateIcon();164 }165 166 bool isExpanded() const { return mIsExpanded; }167 168 private slots:169 170 void buttonClicked()171 {172 mIsExpanded = !mIsExpanded;173 updateIcon();174 QIRichToolButton::buttonClicked();175 }176 177 private:178 179 void updateIcon()180 {181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ?182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png"));183 }184 185 bool eventFilter (QObject *aObject, QEvent *aEvent)186 {187 /* Process only QIArrowButtonSwitch or children */188 if (!(aObject == this || children().contains (aObject)))189 return QIRichToolButton::eventFilter (aObject, aEvent);190 191 /* Process keyboard events */192 if (aEvent->type() == QEvent::KeyPress)193 {194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) ||196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus))197 animateClick();198 }199 200 /* Default one handler */201 return QIRichToolButton::eventFilter (aObject, aEvent);202 }203 204 bool mIsExpanded;205 };206 30 207 31 /** @class QIArrowButtonPress … … 209 33 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 34 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 35 * 213 36 */ 214 class QIArrowButtonPress : public QIRichToolButton 37 38 QIArrowButtonPress::QIArrowButtonPress (bool aNext, const QString &aName, QWidget *aParent) 39 : QIRichToolButton (aName, aParent) 40 , mNext (aNext) 215 41 { 216 Q_OBJECT; 42 updateIcon(); 43 } 217 44 218 public: 45 void QIArrowButtonPress::updateIcon() 46 { 47 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 48 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 49 } 219 50 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 51 bool QIArrowButtonPress::eventFilter (QObject *aObject, QEvent *aEvent) 52 { 53 /* Process only QIArrowButtonPress or children */ 54 if (!(aObject == this || children().contains (aObject))) 55 return QIRichToolButton::eventFilter (aObject, aEvent); 56 57 /* Process keyboard events */ 58 if (aEvent->type() == QEvent::KeyPress) 223 59 { 224 updateIcon(); 60 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 61 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 62 (!mNext && kEvent->key() == Qt::Key_PageDown)) 63 animateClick(); 225 64 } 226 65 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 256 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 66 /* Default one handler */ 67 return QIRichToolButton::eventFilter (aObject, aEvent); 549 68 } 550 551 /**552 * Returns the text of the given message box button.553 * See QMessageBox::buttonText() for details.554 *555 * @param aButton Button index (0, 1 or 2).556 */557 QString QIMessageBox::buttonText (int aButton) const558 {559 switch (aButton)560 {561 case 0: if (mButton0PB) return mButton0PB->text(); break;562 case 1: if (mButton1PB) return mButton1PB->text(); break;563 case 2: if (mButton2PB) return mButton2PB->text(); break;564 default: break;565 }566 567 return QString::null;568 }569 570 /**571 * Sets the text of the given message box button.572 * See QMessageBox::setButtonText() for details.573 *574 * @param aButton Button index (0, 1 or 2).575 * @param aText New button text.576 */577 void QIMessageBox::setButtonText (int aButton, const QString &aText)578 {579 switch (aButton)580 {581 case 0: if (mButton0PB) mButton0PB->setText (aText); break;582 case 1: if (mButton1PB) mButton1PB->setText (aText); break;583 case 2: if (mButton2PB) mButton2PB->setText (aText); break;584 default: break;585 }586 }587 588 /** @fn QIMessageBox::flagText() const589 *590 * Returns the text of the optional message box flag. If the flag is hidden591 * (by default) a null string is returned.592 *593 * @see #setFlagText()594 */595 596 /**597 * Sets the text for the optional message box flag (check box) that is598 * displayed under the message text. Passing the null string as the argument599 * will hide the flag. By default, the flag is hidden.600 */601 void QIMessageBox::setFlagText (const QString &aText)602 {603 if (aText.isNull())604 {605 mFlagCB->hide();606 }607 else608 {609 mFlagCB->setText (aText);610 mFlagCB->show();611 mFlagCB->setFocus();612 }613 }614 615 /** @fn QIMessageBox::isFlagChecked() const616 *617 * Returns true if the optional message box flag is checked and false618 * otherwise. By default, the flag is not checked.619 *620 * @see #setFlagChecked()621 * @see #setFlagText()622 */623 624 /** @fn QIMessageBox::setFlagChecked (bool)625 *626 * Sets the state of the optional message box flag to a value of the argument.627 *628 * @see #isFlagChecked()629 * @see #setFlagText()630 */631 632 QPushButton *QIMessageBox::createButton (int aButton)633 {634 if (aButton == 0)635 return 0;636 637 QString text;638 QDialogButtonBox::ButtonRole role;639 switch (aButton & ButtonMask)640 {641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break;642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break;643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break;644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break;645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break;646 default:647 AssertMsgFailed (("Type %d is not implemented", aButton));648 return NULL;649 }650 651 QPushButton *b = mButtonBox->addButton (text, role);652 653 if (aButton & Default)654 {655 b->setDefault (true);656 b->setFocus();657 }658 659 if (aButton & Escape)660 mButtonEsc = aButton & ButtonMask;661 662 return b;663 }664 665 /** @fn QIMessageBox::detailsText() const666 *667 * Returns the text of the optional details box. The details box is empty668 * by default, so QString::null will be returned.669 *670 * @see #setDetailsText()671 */672 673 /**674 * Sets the text for the optional details box. Note that the details box675 * is hidden by default, call #setDetailsShown(true) to make it visible.676 *677 * @see #detailsText()678 * @see #setDetailsShown()679 */680 void QIMessageBox::setDetailsText (const QString &aText)681 {682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty."));683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts));685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph."));686 687 foreach (QString paragraph, paragraphs)688 {689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts));690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts."));691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]);692 }693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1);695 mDetailsIndex = 0;696 refreshDetails();697 }698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon)700 {701 QIcon icon;702 switch (aIcon)703 {704 case QIMessageBox::Information:705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this);706 break;707 case QMessageBox::Warning:708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this);709 break;710 case QIMessageBox::Critical:711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this);712 break;713 case QIMessageBox::Question:714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this);715 break;716 case QIMessageBox::GuruMeditation:717 icon = QIcon (":/meditation_32px.png");718 break;719 default:720 break;721 }722 if (!icon.isNull())723 {724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this);725 return icon.pixmap (size, size);726 }else727 return QPixmap();728 }729 730 void QIMessageBox::closeEvent (QCloseEvent *e)731 {732 if (mWasDone)733 e->accept();734 else735 e->ignore();736 }737 738 void QIMessageBox::showEvent (QShowEvent *e)739 {740 if (!mWasPolished)741 {742 /* Polishing sub-widgets */743 resize (minimumSizeHint());744 qApp->processEvents();745 mTextLabel->setMinimumWidth (mTextLabel->width());746 mTextLabel->updateSizeHint();747 qApp->processEvents();748 setFixedWidth (width());749 mDetailsSplitter->toggleWidget();750 mWasPolished = true;751 }752 753 QIDialog::showEvent (e);754 }755 756 void QIMessageBox::refreshDetails()757 {758 /* Update message text iteself */759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first);760 mTextLabel->updateSizeHint();761 /* Update details table */762 mDetailsText->setText (mDetailsList [mDetailsIndex].second);763 setDetailsShown (!mDetailsText->toPlainText().isEmpty());764 765 /* Update multi-paging system */766 if (mDetailsList.size() > 1)767 {768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1);769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0);770 }771 772 /* Update details label */773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") :774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size()));775 }776 777 /**778 * Sets the visibility state of the optional details box779 * to a value of the argument.780 *781 * @see #isDetailsShown()782 * @see #setDetailsText()783 */784 void QIMessageBox::setDetailsShown (bool aShown)785 {786 if (aShown)787 {788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible());789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked());790 mFlagCB_Details->setText (mFlagCB_Main->text());791 if (mFlagCB_Main->hasFocus())792 mFlagCB_Details->setFocus();793 mFlagCB_Main->setVisible (false);794 mFlagCB = mFlagCB_Details;795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum);796 }797 798 mDetailsVBox->setVisible (aShown);799 800 if (!aShown)801 {802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible());803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked());804 mFlagCB_Main->setText (mFlagCB_Details->text());805 if (mFlagCB_Details->hasFocus())806 mFlagCB_Main->setFocus();807 mFlagCB = mFlagCB_Main;808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);809 }810 }811 812 void QIMessageBox::detailsBack()813 {814 if (mDetailsIndex > 0)815 {816 -- mDetailsIndex;817 refreshDetails();818 }819 }820 821 void QIMessageBox::detailsNext()822 {823 if (mDetailsIndex < mDetailsList.size() - 1)824 {825 ++ mDetailsIndex;826 refreshDetails();827 }828 }829 830 void QIMessageBox::reject()831 {832 if (mButtonEsc)833 {834 QDialog::reject();835 setResult (mButtonEsc & ButtonMask);836 }837 }838 839 #include "QIMessageBox.moc"840 -
trunk/src/VBox/Frontends/VirtualBox/src/QIArrowButtonSwitch.cpp
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBoxclass implementation4 * VirtualBox Qt extensions: QIArrowButtonSwitch class implementation 5 5 */ 6 6 … … 22 22 23 23 /* VBox includes */ 24 #include "VBoxDefs.h"25 24 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 25 #include "QIArrowButtonSwitch.h" 32 26 33 27 /* Qt includes */ 34 #include <QHBoxLayout>35 #include <QLabel>36 #include <QPushButton>37 #include <QStyleOptionFocusRect>38 #include <QStylePainter>39 #include <QToolButton>40 28 #include <QKeyEvent> 41 29 42 /** @class QIRichToolButton43 *44 * The QIRichToolButton class is a tool-botton with separate text-label.45 * It is declared here until moved into separate file in case46 * of it will be used somewhere except problem-reporter dialog.47 */48 class QIRichToolButton : public QWidget49 {50 Q_OBJECT;51 52 public:53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0)55 : QWidget (aParent)56 , mButton (new QToolButton())57 , mLabel (new QLabel (aName))58 {59 /* Setup itself */60 setFocusPolicy (Qt::StrongFocus);61 62 /* Setup tool-button */63 mButton->setAutoRaise (true);64 mButton->setFixedSize (17, 16);65 mButton->setFocusPolicy (Qt::NoFocus);66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}");67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked()));68 69 /* Setup text-label */70 mLabel->setBuddy (mButton);71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}");72 73 /* Setup main-layout */74 QHBoxLayout *mainLayout = new QHBoxLayout (this);75 VBoxGlobal::setLayoutMargin (mainLayout, 0);76 mainLayout->setSpacing (0);77 mainLayout->addWidget (mButton);78 mainLayout->addWidget (mLabel);79 80 /* Install event-filter */81 qApp->installEventFilter (this);82 }83 84 void animateClick() { mButton->animateClick(); }85 86 void setText (const QString &aName) { mLabel->setText (aName); }87 88 signals:89 90 void clicked();91 92 protected slots:93 94 virtual void buttonClicked()95 {96 emit clicked();97 }98 99 protected:100 101 bool eventFilter (QObject *aObject, QEvent *aEvent)102 {103 /* Process only QIRichToolButton or children */104 if (!(aObject == this || children().contains (aObject)))105 return QWidget::eventFilter (aObject, aEvent);106 107 /* Process keyboard events */108 if (aEvent->type() == QEvent::KeyPress)109 {110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);111 if (kEvent->key() == Qt::Key_Space)112 animateClick();113 }114 115 /* Process mouse events */116 if ((aEvent->type() == QEvent::MouseButtonPress ||117 aEvent->type() == QEvent::MouseButtonDblClick)118 && aObject == mLabel)119 {120 /* Label click as toggle */121 animateClick();122 }123 124 /* Default one handler */125 return QWidget::eventFilter (aObject, aEvent);126 }127 128 void paintEvent (QPaintEvent *aEvent)129 {130 /* Draw focus around mLabel if focused */131 if (hasFocus())132 {133 QStylePainter painter (this);134 QStyleOptionFocusRect option;135 option.initFrom (this);136 option.rect = mLabel->frameGeometry();137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option);138 }139 QWidget::paintEvent (aEvent);140 }141 142 QToolButton *mButton;143 QLabel *mLabel;144 };145 30 146 31 /** @class QIArrowButtonSwitch … … 148 33 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 34 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 35 * 152 36 */ 153 class QIArrowButtonSwitch : public QIRichToolButton 37 38 QIArrowButtonSwitch::QIArrowButtonSwitch (const QString &aName, QWidget *aParent) 39 : QIRichToolButton (aName, aParent) 40 , mIsExpanded (false) 154 41 { 155 Q_OBJECT; 42 updateIcon(); 43 } 156 44 157 public: 45 void QIArrowButtonSwitch::buttonClicked() 46 { 47 mIsExpanded = !mIsExpanded; 48 updateIcon(); 49 QIRichToolButton::buttonClicked(); 50 } 158 51 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 52 void QIArrowButtonSwitch::updateIcon() 53 { 54 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 55 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 56 } 57 58 bool QIArrowButtonSwitch::eventFilter (QObject *aObject, QEvent *aEvent) 59 { 60 /* Process only QIArrowButtonSwitch or children */ 61 if (!(aObject == this || children().contains (aObject))) 62 return QIRichToolButton::eventFilter (aObject, aEvent); 63 64 /* Process keyboard events */ 65 if (aEvent->type() == QEvent::KeyPress) 162 66 { 163 updateIcon(); 67 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 68 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 69 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 70 animateClick(); 164 71 } 165 72 166 bool isExpanded() const { return mIsExpanded; } 167 168 private slots: 169 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 176 177 private: 178 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 203 204 bool mIsExpanded; 205 }; 206 207 /** @class QIArrowButtonPress 208 * 209 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 213 */ 214 class QIArrowButtonPress : public QIRichToolButton 215 { 216 Q_OBJECT; 217 218 public: 219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 226 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 256 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 73 /* Default one handler */ 74 return QIRichToolButton::eventFilter (aObject, aEvent); 549 75 } 550 551 /**552 * Returns the text of the given message box button.553 * See QMessageBox::buttonText() for details.554 *555 * @param aButton Button index (0, 1 or 2).556 */557 QString QIMessageBox::buttonText (int aButton) const558 {559 switch (aButton)560 {561 case 0: if (mButton0PB) return mButton0PB->text(); break;562 case 1: if (mButton1PB) return mButton1PB->text(); break;563 case 2: if (mButton2PB) return mButton2PB->text(); break;564 default: break;565 }566 567 return QString::null;568 }569 570 /**571 * Sets the text of the given message box button.572 * See QMessageBox::setButtonText() for details.573 *574 * @param aButton Button index (0, 1 or 2).575 * @param aText New button text.576 */577 void QIMessageBox::setButtonText (int aButton, const QString &aText)578 {579 switch (aButton)580 {581 case 0: if (mButton0PB) mButton0PB->setText (aText); break;582 case 1: if (mButton1PB) mButton1PB->setText (aText); break;583 case 2: if (mButton2PB) mButton2PB->setText (aText); break;584 default: break;585 }586 }587 588 /** @fn QIMessageBox::flagText() const589 *590 * Returns the text of the optional message box flag. If the flag is hidden591 * (by default) a null string is returned.592 *593 * @see #setFlagText()594 */595 596 /**597 * Sets the text for the optional message box flag (check box) that is598 * displayed under the message text. Passing the null string as the argument599 * will hide the flag. By default, the flag is hidden.600 */601 void QIMessageBox::setFlagText (const QString &aText)602 {603 if (aText.isNull())604 {605 mFlagCB->hide();606 }607 else608 {609 mFlagCB->setText (aText);610 mFlagCB->show();611 mFlagCB->setFocus();612 }613 }614 615 /** @fn QIMessageBox::isFlagChecked() const616 *617 * Returns true if the optional message box flag is checked and false618 * otherwise. By default, the flag is not checked.619 *620 * @see #setFlagChecked()621 * @see #setFlagText()622 */623 624 /** @fn QIMessageBox::setFlagChecked (bool)625 *626 * Sets the state of the optional message box flag to a value of the argument.627 *628 * @see #isFlagChecked()629 * @see #setFlagText()630 */631 632 QPushButton *QIMessageBox::createButton (int aButton)633 {634 if (aButton == 0)635 return 0;636 637 QString text;638 QDialogButtonBox::ButtonRole role;639 switch (aButton & ButtonMask)640 {641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break;642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break;643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break;644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break;645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break;646 default:647 AssertMsgFailed (("Type %d is not implemented", aButton));648 return NULL;649 }650 651 QPushButton *b = mButtonBox->addButton (text, role);652 653 if (aButton & Default)654 {655 b->setDefault (true);656 b->setFocus();657 }658 659 if (aButton & Escape)660 mButtonEsc = aButton & ButtonMask;661 662 return b;663 }664 665 /** @fn QIMessageBox::detailsText() const666 *667 * Returns the text of the optional details box. The details box is empty668 * by default, so QString::null will be returned.669 *670 * @see #setDetailsText()671 */672 673 /**674 * Sets the text for the optional details box. Note that the details box675 * is hidden by default, call #setDetailsShown(true) to make it visible.676 *677 * @see #detailsText()678 * @see #setDetailsShown()679 */680 void QIMessageBox::setDetailsText (const QString &aText)681 {682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty."));683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts));685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph."));686 687 foreach (QString paragraph, paragraphs)688 {689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts));690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts."));691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]);692 }693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1);695 mDetailsIndex = 0;696 refreshDetails();697 }698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon)700 {701 QIcon icon;702 switch (aIcon)703 {704 case QIMessageBox::Information:705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this);706 break;707 case QMessageBox::Warning:708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this);709 break;710 case QIMessageBox::Critical:711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this);712 break;713 case QIMessageBox::Question:714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this);715 break;716 case QIMessageBox::GuruMeditation:717 icon = QIcon (":/meditation_32px.png");718 break;719 default:720 break;721 }722 if (!icon.isNull())723 {724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this);725 return icon.pixmap (size, size);726 }else727 return QPixmap();728 }729 730 void QIMessageBox::closeEvent (QCloseEvent *e)731 {732 if (mWasDone)733 e->accept();734 else735 e->ignore();736 }737 738 void QIMessageBox::showEvent (QShowEvent *e)739 {740 if (!mWasPolished)741 {742 /* Polishing sub-widgets */743 resize (minimumSizeHint());744 qApp->processEvents();745 mTextLabel->setMinimumWidth (mTextLabel->width());746 mTextLabel->updateSizeHint();747 qApp->processEvents();748 setFixedWidth (width());749 mDetailsSplitter->toggleWidget();750 mWasPolished = true;751 }752 753 QIDialog::showEvent (e);754 }755 756 void QIMessageBox::refreshDetails()757 {758 /* Update message text iteself */759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first);760 mTextLabel->updateSizeHint();761 /* Update details table */762 mDetailsText->setText (mDetailsList [mDetailsIndex].second);763 setDetailsShown (!mDetailsText->toPlainText().isEmpty());764 765 /* Update multi-paging system */766 if (mDetailsList.size() > 1)767 {768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1);769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0);770 }771 772 /* Update details label */773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") :774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size()));775 }776 777 /**778 * Sets the visibility state of the optional details box779 * to a value of the argument.780 *781 * @see #isDetailsShown()782 * @see #setDetailsText()783 */784 void QIMessageBox::setDetailsShown (bool aShown)785 {786 if (aShown)787 {788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible());789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked());790 mFlagCB_Details->setText (mFlagCB_Main->text());791 if (mFlagCB_Main->hasFocus())792 mFlagCB_Details->setFocus();793 mFlagCB_Main->setVisible (false);794 mFlagCB = mFlagCB_Details;795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum);796 }797 798 mDetailsVBox->setVisible (aShown);799 800 if (!aShown)801 {802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible());803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked());804 mFlagCB_Main->setText (mFlagCB_Details->text());805 if (mFlagCB_Details->hasFocus())806 mFlagCB_Main->setFocus();807 mFlagCB = mFlagCB_Main;808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);809 }810 }811 812 void QIMessageBox::detailsBack()813 {814 if (mDetailsIndex > 0)815 {816 -- mDetailsIndex;817 refreshDetails();818 }819 }820 821 void QIMessageBox::detailsNext()822 {823 if (mDetailsIndex < mDetailsList.size() - 1)824 {825 ++ mDetailsIndex;826 refreshDetails();827 }828 }829 830 void QIMessageBox::reject()831 {832 if (mButtonEsc)833 {834 QDialog::reject();835 setResult (mButtonEsc & ButtonMask);836 }837 }838 839 #include "QIMessageBox.moc"840 -
trunk/src/VBox/Frontends/VirtualBox/src/QIArrowSplitter.cpp
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBoxclass implementation4 * VirtualBox Qt extensions: QIArrowSplitter class implementation 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 22 22 23 23 /* VBox includes */ 24 #include "VBoxDefs.h"25 24 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 25 #include "QIArrowSplitter.h" 32 26 33 27 /* Qt includes */ 34 28 #include <QHBoxLayout> 35 #include <QLabel>36 #include <QPushButton>37 #include <QStyleOptionFocusRect>38 #include <QStylePainter>39 #include <QToolButton>40 29 #include <QKeyEvent> 41 30 42 /** @class QIRichToolButton 43 *44 * The QIRichToolButton class is a tool-botton with separate text-label.45 * It is declared here until moved into separate file in case46 * of it will be used somewhere except problem-reporter dialog.47 */48 class QIRichToolButton : public QWidget 31 QIArrowSplitter::QIArrowSplitter (QWidget *aChild, QWidget *aParent) 32 : QWidget (aParent) 33 , mMainLayout (new QVBoxLayout (this)) 34 , mSwitchButton (new QIArrowButtonSwitch()) 35 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 36 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 37 , mChild (aChild) 49 38 { 50 Q_OBJECT; 39 /* Setup main-layout */ 40 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 51 41 52 public: 42 /* Setup buttons */ 43 mBackButton->setVisible (false); 44 mNextButton->setVisible (false); 53 45 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0) 55 : QWidget (aParent) 56 , mButton (new QToolButton()) 57 , mLabel (new QLabel (aName)) 46 /* Setup connections */ 47 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 48 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 49 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 50 51 /* Setup button layout */ 52 QHBoxLayout *buttonLayout = new QHBoxLayout(); 53 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 54 buttonLayout->setSpacing (0); 55 buttonLayout->addWidget (mSwitchButton); 56 buttonLayout->addStretch(); 57 buttonLayout->addWidget (mBackButton); 58 buttonLayout->addWidget (mNextButton); 59 60 /* Append layout with children */ 61 mMainLayout->addLayout (buttonLayout); 62 mMainLayout->addWidget (mChild); 63 64 /* Install event-filter */ 65 qApp->installEventFilter (this); 66 } 67 68 void QIArrowSplitter::setMultiPaging (bool aMultiPage) 69 { 70 mBackButton->setVisible (aMultiPage); 71 mNextButton->setVisible (aMultiPage); 72 } 73 74 void QIArrowSplitter::setButtonEnabled (bool aNext, bool aEnabled) 75 { 76 aNext ? mNextButton->setEnabled (aEnabled) 77 : mBackButton->setEnabled (aEnabled); 78 } 79 80 void QIArrowSplitter::setName (const QString &aName) 81 { 82 mSwitchButton->setText (aName); 83 relayout(); 84 } 85 86 void QIArrowSplitter::toggleWidget() 87 { 88 mChild->setVisible (mSwitchButton->isExpanded()); 89 relayout(); 90 } 91 92 bool QIArrowSplitter::eventFilter (QObject *aObject, QEvent *aEvent) 93 { 94 /* Process only parent window children */ 95 if (!(aObject == window() || window()->children().contains (aObject))) 96 return QWidget::eventFilter (aObject, aEvent); 97 98 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 99 if (aObject == mSwitchButton || 100 aObject == mBackButton || 101 aObject == mNextButton || 102 mSwitchButton->children().contains (aObject) || 103 mBackButton->children().contains (aObject) || 104 mNextButton->children().contains (aObject)) 105 return QWidget::eventFilter (aObject, aEvent); 106 107 /* Process some keyboard events */ 108 if (aEvent->type() == QEvent::KeyPress) 58 109 { 59 /* Setup itself */ 60 setFocusPolicy (Qt::StrongFocus); 61 62 /* Setup tool-button */ 63 mButton->setAutoRaise (true); 64 mButton->setFixedSize (17, 16); 65 mButton->setFocusPolicy (Qt::NoFocus); 66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}"); 67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked())); 68 69 /* Setup text-label */ 70 mLabel->setBuddy (mButton); 71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}"); 72 73 /* Setup main-layout */ 74 QHBoxLayout *mainLayout = new QHBoxLayout (this); 75 VBoxGlobal::setLayoutMargin (mainLayout, 0); 76 mainLayout->setSpacing (0); 77 mainLayout->addWidget (mButton); 78 mainLayout->addWidget (mLabel); 79 80 /* Install event-filter */ 81 qApp->installEventFilter (this); 110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 111 switch (kEvent->key()) 112 { 113 case Qt::Key_Plus: 114 { 115 if (!mSwitchButton->isExpanded()) 116 mSwitchButton->animateClick(); 117 break; 118 } 119 case Qt::Key_Minus: 120 { 121 if (mSwitchButton->isExpanded()) 122 mSwitchButton->animateClick(); 123 break; 124 } 125 case Qt::Key_PageUp: 126 { 127 if (mNextButton->isEnabled()) 128 mNextButton->animateClick(); 129 break; 130 } 131 case Qt::Key_PageDown: 132 { 133 if (mBackButton->isEnabled()) 134 mBackButton->animateClick(); 135 break; 136 } 137 } 82 138 } 83 139 84 void animateClick() { mButton->animateClick(); } 140 /* Default one handler */ 141 return QWidget::eventFilter (aObject, aEvent); 142 } 85 143 86 void setText (const QString &aName) { mLabel->setText (aName); } 87 88 signals: 89 90 void clicked(); 91 92 protected slots: 93 94 virtual void buttonClicked() 144 void QIArrowSplitter::relayout() 145 { 146 /* Update full layout system of message window */ 147 QList <QLayout*> layouts = findChildren <QLayout*> (); 148 foreach (QLayout *item, layouts) 95 149 { 96 emit clicked(); 150 item->update(); 151 item->activate(); 97 152 } 98 153 99 protected: 154 /* Update main layout of message window at last */ 155 window()->layout()->update(); 156 window()->layout()->activate(); 157 qApp->processEvents(); 100 158 101 bool eventFilter (QObject *aObject, QEvent *aEvent) 102 { 103 /* Process only QIRichToolButton or children */ 104 if (!(aObject == this || children().contains (aObject))) 105 return QWidget::eventFilter (aObject, aEvent); 159 /* Now resize window to minimum possible size */ 160 window()->resize (window()->minimumSizeHint()); 161 qApp->processEvents(); 106 162 107 /* Process keyboard events */ 108 if (aEvent->type() == QEvent::KeyPress) 109 { 110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 111 if (kEvent->key() == Qt::Key_Space) 112 animateClick(); 113 } 114 115 /* Process mouse events */ 116 if ((aEvent->type() == QEvent::MouseButtonPress || 117 aEvent->type() == QEvent::MouseButtonDblClick) 118 && aObject == mLabel) 119 { 120 /* Label click as toggle */ 121 animateClick(); 122 } 123 124 /* Default one handler */ 125 return QWidget::eventFilter (aObject, aEvent); 126 } 127 128 void paintEvent (QPaintEvent *aEvent) 129 { 130 /* Draw focus around mLabel if focused */ 131 if (hasFocus()) 132 { 133 QStylePainter painter (this); 134 QStyleOptionFocusRect option; 135 option.initFrom (this); 136 option.rect = mLabel->frameGeometry(); 137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option); 138 } 139 QWidget::paintEvent (aEvent); 140 } 141 142 QToolButton *mButton; 143 QLabel *mLabel; 144 }; 145 146 /** @class QIArrowButtonSwitch 147 * 148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 152 */ 153 class QIArrowButtonSwitch : public QIRichToolButton 154 { 155 Q_OBJECT; 156 157 public: 158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 162 { 163 updateIcon(); 164 } 165 166 bool isExpanded() const { return mIsExpanded; } 167 168 private slots: 169 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 176 177 private: 178 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 203 204 bool mIsExpanded; 205 }; 206 207 /** @class QIArrowButtonPress 208 * 209 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 213 */ 214 class QIArrowButtonPress : public QIRichToolButton 215 { 216 Q_OBJECT; 217 218 public: 219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 226 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 256 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 163 /* Check if we have to make dialog fixed in height */ 164 if (mSwitchButton->isExpanded()) 165 window()->setMaximumHeight (QWIDGETSIZE_MAX); 166 else 167 window()->setFixedHeight (window()->minimumSizeHint().height()); 549 168 } 550 551 /**552 * Returns the text of the given message box button.553 * See QMessageBox::buttonText() for details.554 *555 * @param aButton Button index (0, 1 or 2).556 */557 QString QIMessageBox::buttonText (int aButton) const558 {559 switch (aButton)560 {561 case 0: if (mButton0PB) return mButton0PB->text(); break;562 case 1: if (mButton1PB) return mButton1PB->text(); break;563 case 2: if (mButton2PB) return mButton2PB->text(); break;564 default: break;565 }566 567 return QString::null;568 }569 570 /**571 * Sets the text of the given message box button.572 * See QMessageBox::setButtonText() for details.573 *574 * @param aButton Button index (0, 1 or 2).575 * @param aText New button text.576 */577 void QIMessageBox::setButtonText (int aButton, const QString &aText)578 {579 switch (aButton)580 {581 case 0: if (mButton0PB) mButton0PB->setText (aText); break;582 case 1: if (mButton1PB) mButton1PB->setText (aText); break;583 case 2: if (mButton2PB) mButton2PB->setText (aText); break;584 default: break;585 }586 }587 588 /** @fn QIMessageBox::flagText() const589 *590 * Returns the text of the optional message box flag. If the flag is hidden591 * (by default) a null string is returned.592 *593 * @see #setFlagText()594 */595 596 /**597 * Sets the text for the optional message box flag (check box) that is598 * displayed under the message text. Passing the null string as the argument599 * will hide the flag. By default, the flag is hidden.600 */601 void QIMessageBox::setFlagText (const QString &aText)602 {603 if (aText.isNull())604 {605 mFlagCB->hide();606 }607 else608 {609 mFlagCB->setText (aText);610 mFlagCB->show();611 mFlagCB->setFocus();612 }613 }614 615 /** @fn QIMessageBox::isFlagChecked() const616 *617 * Returns true if the optional message box flag is checked and false618 * otherwise. By default, the flag is not checked.619 *620 * @see #setFlagChecked()621 * @see #setFlagText()622 */623 624 /** @fn QIMessageBox::setFlagChecked (bool)625 *626 * Sets the state of the optional message box flag to a value of the argument.627 *628 * @see #isFlagChecked()629 * @see #setFlagText()630 */631 632 QPushButton *QIMessageBox::createButton (int aButton)633 {634 if (aButton == 0)635 return 0;636 637 QString text;638 QDialogButtonBox::ButtonRole role;639 switch (aButton & ButtonMask)640 {641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break;642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break;643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break;644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break;645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break;646 default:647 AssertMsgFailed (("Type %d is not implemented", aButton));648 return NULL;649 }650 651 QPushButton *b = mButtonBox->addButton (text, role);652 653 if (aButton & Default)654 {655 b->setDefault (true);656 b->setFocus();657 }658 659 if (aButton & Escape)660 mButtonEsc = aButton & ButtonMask;661 662 return b;663 }664 665 /** @fn QIMessageBox::detailsText() const666 *667 * Returns the text of the optional details box. The details box is empty668 * by default, so QString::null will be returned.669 *670 * @see #setDetailsText()671 */672 673 /**674 * Sets the text for the optional details box. Note that the details box675 * is hidden by default, call #setDetailsShown(true) to make it visible.676 *677 * @see #detailsText()678 * @see #setDetailsShown()679 */680 void QIMessageBox::setDetailsText (const QString &aText)681 {682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty."));683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts));685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph."));686 687 foreach (QString paragraph, paragraphs)688 {689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts));690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts."));691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]);692 }693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1);695 mDetailsIndex = 0;696 refreshDetails();697 }698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon)700 {701 QIcon icon;702 switch (aIcon)703 {704 case QIMessageBox::Information:705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this);706 break;707 case QMessageBox::Warning:708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this);709 break;710 case QIMessageBox::Critical:711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this);712 break;713 case QIMessageBox::Question:714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this);715 break;716 case QIMessageBox::GuruMeditation:717 icon = QIcon (":/meditation_32px.png");718 break;719 default:720 break;721 }722 if (!icon.isNull())723 {724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this);725 return icon.pixmap (size, size);726 }else727 return QPixmap();728 }729 730 void QIMessageBox::closeEvent (QCloseEvent *e)731 {732 if (mWasDone)733 e->accept();734 else735 e->ignore();736 }737 738 void QIMessageBox::showEvent (QShowEvent *e)739 {740 if (!mWasPolished)741 {742 /* Polishing sub-widgets */743 resize (minimumSizeHint());744 qApp->processEvents();745 mTextLabel->setMinimumWidth (mTextLabel->width());746 mTextLabel->updateSizeHint();747 qApp->processEvents();748 setFixedWidth (width());749 mDetailsSplitter->toggleWidget();750 mWasPolished = true;751 }752 753 QIDialog::showEvent (e);754 }755 756 void QIMessageBox::refreshDetails()757 {758 /* Update message text iteself */759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first);760 mTextLabel->updateSizeHint();761 /* Update details table */762 mDetailsText->setText (mDetailsList [mDetailsIndex].second);763 setDetailsShown (!mDetailsText->toPlainText().isEmpty());764 765 /* Update multi-paging system */766 if (mDetailsList.size() > 1)767 {768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1);769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0);770 }771 772 /* Update details label */773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") :774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size()));775 }776 777 /**778 * Sets the visibility state of the optional details box779 * to a value of the argument.780 *781 * @see #isDetailsShown()782 * @see #setDetailsText()783 */784 void QIMessageBox::setDetailsShown (bool aShown)785 {786 if (aShown)787 {788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible());789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked());790 mFlagCB_Details->setText (mFlagCB_Main->text());791 if (mFlagCB_Main->hasFocus())792 mFlagCB_Details->setFocus();793 mFlagCB_Main->setVisible (false);794 mFlagCB = mFlagCB_Details;795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum);796 }797 798 mDetailsVBox->setVisible (aShown);799 800 if (!aShown)801 {802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible());803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked());804 mFlagCB_Main->setText (mFlagCB_Details->text());805 if (mFlagCB_Details->hasFocus())806 mFlagCB_Main->setFocus();807 mFlagCB = mFlagCB_Main;808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);809 }810 }811 812 void QIMessageBox::detailsBack()813 {814 if (mDetailsIndex > 0)815 {816 -- mDetailsIndex;817 refreshDetails();818 }819 }820 821 void QIMessageBox::detailsNext()822 {823 if (mDetailsIndex < mDetailsList.size() - 1)824 {825 ++ mDetailsIndex;826 refreshDetails();827 }828 }829 830 void QIMessageBox::reject()831 {832 if (mButtonEsc)833 {834 QDialog::reject();835 setResult (mButtonEsc & ButtonMask);836 }837 }838 839 #include "QIMessageBox.moc"840 -
trunk/src/VBox/Frontends/VirtualBox/src/QIMessageBox.cpp
r19670 r22948 6 6 7 7 /* 8 * Copyright (C) 2006-200 8Sun Microsystems, Inc.8 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 24 24 #include "VBoxDefs.h" 25 25 #include "VBoxGlobal.h" 26 #include "QIArrowSplitter.h" 26 27 #include "QIMessageBox.h" 27 28 #include "QILabel.h" … … 40 41 #include <QKeyEvent> 41 42 42 /** @class QIRichToolButton43 *44 * The QIRichToolButton class is a tool-botton with separate text-label.45 * It is declared here until moved into separate file in case46 * of it will be used somewhere except problem-reporter dialog.47 */48 class QIRichToolButton : public QWidget49 {50 Q_OBJECT;51 52 public:53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0)55 : QWidget (aParent)56 , mButton (new QToolButton())57 , mLabel (new QLabel (aName))58 {59 /* Setup itself */60 setFocusPolicy (Qt::StrongFocus);61 62 /* Setup tool-button */63 mButton->setAutoRaise (true);64 mButton->setFixedSize (17, 16);65 mButton->setFocusPolicy (Qt::NoFocus);66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}");67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked()));68 69 /* Setup text-label */70 mLabel->setBuddy (mButton);71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}");72 73 /* Setup main-layout */74 QHBoxLayout *mainLayout = new QHBoxLayout (this);75 VBoxGlobal::setLayoutMargin (mainLayout, 0);76 mainLayout->setSpacing (0);77 mainLayout->addWidget (mButton);78 mainLayout->addWidget (mLabel);79 80 /* Install event-filter */81 qApp->installEventFilter (this);82 }83 84 void animateClick() { mButton->animateClick(); }85 86 void setText (const QString &aName) { mLabel->setText (aName); }87 88 signals:89 90 void clicked();91 92 protected slots:93 94 virtual void buttonClicked()95 {96 emit clicked();97 }98 99 protected:100 101 bool eventFilter (QObject *aObject, QEvent *aEvent)102 {103 /* Process only QIRichToolButton or children */104 if (!(aObject == this || children().contains (aObject)))105 return QWidget::eventFilter (aObject, aEvent);106 107 /* Process keyboard events */108 if (aEvent->type() == QEvent::KeyPress)109 {110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);111 if (kEvent->key() == Qt::Key_Space)112 animateClick();113 }114 115 /* Process mouse events */116 if ((aEvent->type() == QEvent::MouseButtonPress ||117 aEvent->type() == QEvent::MouseButtonDblClick)118 && aObject == mLabel)119 {120 /* Label click as toggle */121 animateClick();122 }123 124 /* Default one handler */125 return QWidget::eventFilter (aObject, aEvent);126 }127 128 void paintEvent (QPaintEvent *aEvent)129 {130 /* Draw focus around mLabel if focused */131 if (hasFocus())132 {133 QStylePainter painter (this);134 QStyleOptionFocusRect option;135 option.initFrom (this);136 option.rect = mLabel->frameGeometry();137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option);138 }139 QWidget::paintEvent (aEvent);140 }141 142 QToolButton *mButton;143 QLabel *mLabel;144 };145 146 /** @class QIArrowButtonSwitch147 *148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label,149 * used as collaps/expand switch in QIMessageBox class.150 * It is declared here until moved into separate file in case151 * of it will be used somewhere except problem-reporter dialog.152 */153 class QIArrowButtonSwitch : public QIRichToolButton154 {155 Q_OBJECT;156 157 public:158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0)160 : QIRichToolButton (aName, aParent)161 , mIsExpanded (false)162 {163 updateIcon();164 }165 166 bool isExpanded() const { return mIsExpanded; }167 168 private slots:169 170 void buttonClicked()171 {172 mIsExpanded = !mIsExpanded;173 updateIcon();174 QIRichToolButton::buttonClicked();175 }176 177 private:178 179 void updateIcon()180 {181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ?182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png"));183 }184 185 bool eventFilter (QObject *aObject, QEvent *aEvent)186 {187 /* Process only QIArrowButtonSwitch or children */188 if (!(aObject == this || children().contains (aObject)))189 return QIRichToolButton::eventFilter (aObject, aEvent);190 191 /* Process keyboard events */192 if (aEvent->type() == QEvent::KeyPress)193 {194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) ||196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus))197 animateClick();198 }199 200 /* Default one handler */201 return QIRichToolButton::eventFilter (aObject, aEvent);202 }203 204 bool mIsExpanded;205 };206 207 /** @class QIArrowButtonPress208 *209 * The QIArrowButtonPress class is an arrow tool-botton with text-label,210 * used as back/next buttons in QIMessageBox class.211 * It is declared here until moved into separate file in case212 * of it will be used somewhere except problem-reporter dialog.213 */214 class QIArrowButtonPress : public QIRichToolButton215 {216 Q_OBJECT;217 218 public:219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0)221 : QIRichToolButton (aName, aParent)222 , mNext (aNext)223 {224 updateIcon();225 }226 227 private:228 229 void updateIcon()230 {231 mButton->setIcon (VBoxGlobal::iconSet (mNext ?232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png"));233 }234 235 bool eventFilter (QObject *aObject, QEvent *aEvent)236 {237 /* Process only QIArrowButtonPress or children */238 if (!(aObject == this || children().contains (aObject)))239 return QIRichToolButton::eventFilter (aObject, aEvent);240 241 /* Process keyboard events */242 if (aEvent->type() == QEvent::KeyPress)243 {244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);245 if ((mNext && kEvent->key() == Qt::Key_PageUp) ||246 (!mNext && kEvent->key() == Qt::Key_PageDown))247 animateClick();248 }249 250 /* Default one handler */251 return QIRichToolButton::eventFilter (aObject, aEvent);252 }253 254 bool mNext;255 };256 257 /** @class QIArrowSplitter258 *259 * The QIArrowSplitter class is a folding widget placeholder.260 * It is declared here until moved into separate file in case261 * of it will be used somewhere except problem-reporter dialog.262 */263 class QIArrowSplitter : public QWidget264 {265 Q_OBJECT;266 267 public:268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0)270 : QWidget (aParent)271 , mMainLayout (new QVBoxLayout (this))272 , mSwitchButton (new QIArrowButtonSwitch())273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back")))274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next")))275 , mChild (aChild)276 {277 /* Setup main-layout */278 VBoxGlobal::setLayoutMargin (mMainLayout, 0);279 280 /* Setup buttons */281 mBackButton->setVisible (false);282 mNextButton->setVisible (false);283 284 /* Setup connections */285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget()));286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails()));287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails()));288 289 /* Setup button layout */290 QHBoxLayout *buttonLayout = new QHBoxLayout();291 VBoxGlobal::setLayoutMargin (buttonLayout, 0);292 buttonLayout->setSpacing (0);293 buttonLayout->addWidget (mSwitchButton);294 buttonLayout->addStretch();295 buttonLayout->addWidget (mBackButton);296 buttonLayout->addWidget (mNextButton);297 298 /* Append layout with children */299 mMainLayout->addLayout (buttonLayout);300 mMainLayout->addWidget (mChild);301 302 /* Install event-filter */303 qApp->installEventFilter (this);304 }305 306 void setMultiPaging (bool aMultiPage)307 {308 mBackButton->setVisible (aMultiPage);309 mNextButton->setVisible (aMultiPage);310 }311 312 void setButtonEnabled (bool aNext, bool aEnabled)313 {314 aNext ? mNextButton->setEnabled (aEnabled)315 : mBackButton->setEnabled (aEnabled);316 }317 318 void setName (const QString &aName)319 {320 mSwitchButton->setText (aName);321 relayout();322 }323 324 public slots:325 326 void toggleWidget()327 {328 mChild->setVisible (mSwitchButton->isExpanded());329 relayout();330 }331 332 signals:333 334 void showBackDetails();335 void showNextDetails();336 337 private:338 339 bool eventFilter (QObject *aObject, QEvent *aEvent)340 {341 /* Process only parent window children */342 if (!(aObject == window() || window()->children().contains (aObject)))343 return QWidget::eventFilter (aObject, aEvent);344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */346 if (aObject == mSwitchButton ||347 aObject == mBackButton ||348 aObject == mNextButton ||349 mSwitchButton->children().contains (aObject) ||350 mBackButton->children().contains (aObject) ||351 mNextButton->children().contains (aObject))352 return QWidget::eventFilter (aObject, aEvent);353 354 /* Process some keyboard events */355 if (aEvent->type() == QEvent::KeyPress)356 {357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent);358 switch (kEvent->key())359 {360 case Qt::Key_Plus:361 {362 if (!mSwitchButton->isExpanded())363 mSwitchButton->animateClick();364 break;365 }366 case Qt::Key_Minus:367 {368 if (mSwitchButton->isExpanded())369 mSwitchButton->animateClick();370 break;371 }372 case Qt::Key_PageUp:373 {374 if (mNextButton->isEnabled())375 mNextButton->animateClick();376 break;377 }378 case Qt::Key_PageDown:379 {380 if (mBackButton->isEnabled())381 mBackButton->animateClick();382 break;383 }384 }385 }386 387 /* Default one handler */388 return QWidget::eventFilter (aObject, aEvent);389 }390 391 void relayout()392 {393 /* Update full layout system of message window */394 QList <QLayout*> layouts = findChildren <QLayout*> ();395 foreach (QLayout *item, layouts)396 {397 item->update();398 item->activate();399 }400 401 /* Update main layout of message window at last */402 window()->layout()->update();403 window()->layout()->activate();404 qApp->processEvents();405 406 /* Now resize window to minimum possible size */407 window()->resize (window()->minimumSizeHint());408 qApp->processEvents();409 410 /* Check if we have to make dialog fixed in height */411 if (mSwitchButton->isExpanded())412 window()->setMaximumHeight (QWIDGETSIZE_MAX);413 else414 window()->setFixedHeight (window()->minimumSizeHint().height());415 }416 417 QVBoxLayout *mMainLayout;418 QIArrowButtonSwitch *mSwitchButton;419 QIArrowButtonPress *mBackButton;420 QIArrowButtonPress *mNextButton;421 QWidget *mChild;422 };423 43 424 44 /** @class QIMessageBox … … 836 456 } 837 457 } 838 839 #include "QIMessageBox.moc"840 -
trunk/src/VBox/Frontends/VirtualBox/src/QIRichToolButton.cpp
r22947 r22948 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VirtualBox Qt extensions: QI MessageBoxclass implementation4 * VirtualBox Qt extensions: QIRichToolButton class implementation 5 5 */ 6 6 … … 22 22 23 23 /* VBox includes */ 24 #include "VBoxDefs.h"25 24 #include "VBoxGlobal.h" 26 #include "QIMessageBox.h" 27 #include "QILabel.h" 28 #include "QIDialogButtonBox.h" 29 #ifdef Q_WS_MAC 30 # include "VBoxConsoleWnd.h" 31 #endif /* Q_WS_MAC */ 25 #include "QIRichToolButton.h" 32 26 33 27 /* Qt includes */ 28 #include <QLabel> 34 29 #include <QHBoxLayout> 35 #include <QLabel>36 #include <QPushButton>37 #include <QStyleOptionFocusRect>38 #include <QStylePainter>39 30 #include <QToolButton> 40 31 #include <QKeyEvent> 32 #include <QStylePainter> 33 #include <QStyleOptionFocusRect> 41 34 42 /** @class QIRichToolButton 43 * 44 * The QIRichToolButton class is a tool-botton with separate text-label. 45 * It is declared here until moved into separate file in case 46 * of it will be used somewhere except problem-reporter dialog. 47 */ 48 class QIRichToolButton : public QWidget 49 { 50 Q_OBJECT; 51 52 public: 53 54 QIRichToolButton (const QString &aName = QString::null, QWidget *aParent = 0) 35 QIRichToolButton::QIRichToolButton (const QString &aName, QWidget *aParent) 55 36 : QWidget (aParent) 56 37 , mButton (new QToolButton()) 57 38 , mLabel (new QLabel (aName)) 39 { 40 /* Setup itself */ 41 setFocusPolicy (Qt::StrongFocus); 42 43 /* Setup tool-button */ 44 mButton->setAutoRaise (true); 45 mButton->setFixedSize (17, 16); 46 mButton->setFocusPolicy (Qt::NoFocus); 47 mButton->setStyleSheet ("QToolButton {border: 0px none black;}"); 48 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked())); 49 50 /* Setup text-label */ 51 mLabel->setBuddy (mButton); 52 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}"); 53 54 /* Setup main-layout */ 55 QHBoxLayout *mainLayout = new QHBoxLayout (this); 56 VBoxGlobal::setLayoutMargin (mainLayout, 0); 57 mainLayout->setSpacing (0); 58 mainLayout->addWidget (mButton); 59 mainLayout->addWidget (mLabel); 60 61 /* Install event-filter */ 62 qApp->installEventFilter (this); 63 } 64 65 bool QIRichToolButton::eventFilter (QObject *aObject, QEvent *aEvent) 66 { 67 /* Process only QIRichToolButton or children */ 68 if (!(aObject == this || children().contains (aObject))) 69 return QWidget::eventFilter (aObject, aEvent); 70 71 /* Process keyboard events */ 72 if (aEvent->type() == QEvent::KeyPress) 58 73 { 59 /* Setup itself */ 60 setFocusPolicy (Qt::StrongFocus); 61 62 /* Setup tool-button */ 63 mButton->setAutoRaise (true); 64 mButton->setFixedSize (17, 16); 65 mButton->setFocusPolicy (Qt::NoFocus); 66 mButton->setStyleSheet ("QToolButton {border: 0px none black;}"); 67 connect (mButton, SIGNAL (clicked (bool)), this, SLOT (buttonClicked())); 68 69 /* Setup text-label */ 70 mLabel->setBuddy (mButton); 71 mLabel->setStyleSheet ("QLabel {padding: 2px 0px 2px 0px;}"); 72 73 /* Setup main-layout */ 74 QHBoxLayout *mainLayout = new QHBoxLayout (this); 75 VBoxGlobal::setLayoutMargin (mainLayout, 0); 76 mainLayout->setSpacing (0); 77 mainLayout->addWidget (mButton); 78 mainLayout->addWidget (mLabel); 79 80 /* Install event-filter */ 81 qApp->installEventFilter (this); 74 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 75 if (kEvent->key() == Qt::Key_Space) 76 animateClick(); 82 77 } 83 78 84 void animateClick() { mButton->animateClick(); } 85 86 void setText (const QString &aName) { mLabel->setText (aName); } 87 88 signals: 89 90 void clicked(); 91 92 protected slots: 93 94 virtual void buttonClicked() 79 /* Process mouse events */ 80 if ((aEvent->type() == QEvent::MouseButtonPress || 81 aEvent->type() == QEvent::MouseButtonDblClick) 82 && aObject == mLabel) 95 83 { 96 emit clicked(); 84 /* Label click as toggle */ 85 animateClick(); 97 86 } 98 87 99 protected: 100 101 bool eventFilter (QObject *aObject, QEvent *aEvent) 102 { 103 /* Process only QIRichToolButton or children */ 104 if (!(aObject == this || children().contains (aObject))) 105 return QWidget::eventFilter (aObject, aEvent); 106 107 /* Process keyboard events */ 108 if (aEvent->type() == QEvent::KeyPress) 109 { 110 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 111 if (kEvent->key() == Qt::Key_Space) 112 animateClick(); 113 } 114 115 /* Process mouse events */ 116 if ((aEvent->type() == QEvent::MouseButtonPress || 117 aEvent->type() == QEvent::MouseButtonDblClick) 118 && aObject == mLabel) 119 { 120 /* Label click as toggle */ 121 animateClick(); 122 } 123 124 /* Default one handler */ 125 return QWidget::eventFilter (aObject, aEvent); 126 } 127 128 void paintEvent (QPaintEvent *aEvent) 129 { 130 /* Draw focus around mLabel if focused */ 131 if (hasFocus()) 132 { 133 QStylePainter painter (this); 134 QStyleOptionFocusRect option; 135 option.initFrom (this); 136 option.rect = mLabel->frameGeometry(); 137 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option); 138 } 139 QWidget::paintEvent (aEvent); 140 } 141 142 QToolButton *mButton; 143 QLabel *mLabel; 144 }; 145 146 /** @class QIArrowButtonSwitch 147 * 148 * The QIArrowButtonSwitch class is an arrow tool-botton with text-label, 149 * used as collaps/expand switch in QIMessageBox class. 150 * It is declared here until moved into separate file in case 151 * of it will be used somewhere except problem-reporter dialog. 152 */ 153 class QIArrowButtonSwitch : public QIRichToolButton 154 { 155 Q_OBJECT; 156 157 public: 158 159 QIArrowButtonSwitch (const QString &aName = QString::null, QWidget *aParent = 0) 160 : QIRichToolButton (aName, aParent) 161 , mIsExpanded (false) 162 { 163 updateIcon(); 164 } 165 166 bool isExpanded() const { return mIsExpanded; } 167 168 private slots: 169 170 void buttonClicked() 171 { 172 mIsExpanded = !mIsExpanded; 173 updateIcon(); 174 QIRichToolButton::buttonClicked(); 175 } 176 177 private: 178 179 void updateIcon() 180 { 181 mButton->setIcon (VBoxGlobal::iconSet (mIsExpanded ? 182 ":/arrow_down_10px.png" : ":/arrow_right_10px.png")); 183 } 184 185 bool eventFilter (QObject *aObject, QEvent *aEvent) 186 { 187 /* Process only QIArrowButtonSwitch or children */ 188 if (!(aObject == this || children().contains (aObject))) 189 return QIRichToolButton::eventFilter (aObject, aEvent); 190 191 /* Process keyboard events */ 192 if (aEvent->type() == QEvent::KeyPress) 193 { 194 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 195 if ((mIsExpanded && kEvent->key() == Qt::Key_Minus) || 196 (!mIsExpanded && kEvent->key() == Qt::Key_Plus)) 197 animateClick(); 198 } 199 200 /* Default one handler */ 201 return QIRichToolButton::eventFilter (aObject, aEvent); 202 } 203 204 bool mIsExpanded; 205 }; 206 207 /** @class QIArrowButtonPress 208 * 209 * The QIArrowButtonPress class is an arrow tool-botton with text-label, 210 * used as back/next buttons in QIMessageBox class. 211 * It is declared here until moved into separate file in case 212 * of it will be used somewhere except problem-reporter dialog. 213 */ 214 class QIArrowButtonPress : public QIRichToolButton 215 { 216 Q_OBJECT; 217 218 public: 219 220 QIArrowButtonPress (bool aNext, const QString &aName = QString::null, QWidget *aParent = 0) 221 : QIRichToolButton (aName, aParent) 222 , mNext (aNext) 223 { 224 updateIcon(); 225 } 226 227 private: 228 229 void updateIcon() 230 { 231 mButton->setIcon (VBoxGlobal::iconSet (mNext ? 232 ":/arrow_right_10px.png" : ":/arrow_left_10px.png")); 233 } 234 235 bool eventFilter (QObject *aObject, QEvent *aEvent) 236 { 237 /* Process only QIArrowButtonPress or children */ 238 if (!(aObject == this || children().contains (aObject))) 239 return QIRichToolButton::eventFilter (aObject, aEvent); 240 241 /* Process keyboard events */ 242 if (aEvent->type() == QEvent::KeyPress) 243 { 244 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 245 if ((mNext && kEvent->key() == Qt::Key_PageUp) || 246 (!mNext && kEvent->key() == Qt::Key_PageDown)) 247 animateClick(); 248 } 249 250 /* Default one handler */ 251 return QIRichToolButton::eventFilter (aObject, aEvent); 252 } 253 254 bool mNext; 255 }; 256 257 /** @class QIArrowSplitter 258 * 259 * The QIArrowSplitter class is a folding widget placeholder. 260 * It is declared here until moved into separate file in case 261 * of it will be used somewhere except problem-reporter dialog. 262 */ 263 class QIArrowSplitter : public QWidget 264 { 265 Q_OBJECT; 266 267 public: 268 269 QIArrowSplitter (QWidget *aChild, QWidget *aParent = 0) 270 : QWidget (aParent) 271 , mMainLayout (new QVBoxLayout (this)) 272 , mSwitchButton (new QIArrowButtonSwitch()) 273 , mBackButton (new QIArrowButtonPress (false, tr ("&Back"))) 274 , mNextButton (new QIArrowButtonPress (true, tr ("&Next"))) 275 , mChild (aChild) 276 { 277 /* Setup main-layout */ 278 VBoxGlobal::setLayoutMargin (mMainLayout, 0); 279 280 /* Setup buttons */ 281 mBackButton->setVisible (false); 282 mNextButton->setVisible (false); 283 284 /* Setup connections */ 285 connect (mSwitchButton, SIGNAL (clicked()), this, SLOT (toggleWidget())); 286 connect (mBackButton, SIGNAL (clicked()), this, SIGNAL (showBackDetails())); 287 connect (mNextButton, SIGNAL (clicked()), this, SIGNAL (showNextDetails())); 288 289 /* Setup button layout */ 290 QHBoxLayout *buttonLayout = new QHBoxLayout(); 291 VBoxGlobal::setLayoutMargin (buttonLayout, 0); 292 buttonLayout->setSpacing (0); 293 buttonLayout->addWidget (mSwitchButton); 294 buttonLayout->addStretch(); 295 buttonLayout->addWidget (mBackButton); 296 buttonLayout->addWidget (mNextButton); 297 298 /* Append layout with children */ 299 mMainLayout->addLayout (buttonLayout); 300 mMainLayout->addWidget (mChild); 301 302 /* Install event-filter */ 303 qApp->installEventFilter (this); 304 } 305 306 void setMultiPaging (bool aMultiPage) 307 { 308 mBackButton->setVisible (aMultiPage); 309 mNextButton->setVisible (aMultiPage); 310 } 311 312 void setButtonEnabled (bool aNext, bool aEnabled) 313 { 314 aNext ? mNextButton->setEnabled (aEnabled) 315 : mBackButton->setEnabled (aEnabled); 316 } 317 318 void setName (const QString &aName) 319 { 320 mSwitchButton->setText (aName); 321 relayout(); 322 } 323 324 public slots: 325 326 void toggleWidget() 327 { 328 mChild->setVisible (mSwitchButton->isExpanded()); 329 relayout(); 330 } 331 332 signals: 333 334 void showBackDetails(); 335 void showNextDetails(); 336 337 private: 338 339 bool eventFilter (QObject *aObject, QEvent *aEvent) 340 { 341 /* Process only parent window children */ 342 if (!(aObject == window() || window()->children().contains (aObject))) 343 return QWidget::eventFilter (aObject, aEvent); 344 345 /* Do not process QIArrowButtonSwitch & QIArrowButtonPress children */ 346 if (aObject == mSwitchButton || 347 aObject == mBackButton || 348 aObject == mNextButton || 349 mSwitchButton->children().contains (aObject) || 350 mBackButton->children().contains (aObject) || 351 mNextButton->children().contains (aObject)) 352 return QWidget::eventFilter (aObject, aEvent); 353 354 /* Process some keyboard events */ 355 if (aEvent->type() == QEvent::KeyPress) 356 { 357 QKeyEvent *kEvent = static_cast <QKeyEvent*> (aEvent); 358 switch (kEvent->key()) 359 { 360 case Qt::Key_Plus: 361 { 362 if (!mSwitchButton->isExpanded()) 363 mSwitchButton->animateClick(); 364 break; 365 } 366 case Qt::Key_Minus: 367 { 368 if (mSwitchButton->isExpanded()) 369 mSwitchButton->animateClick(); 370 break; 371 } 372 case Qt::Key_PageUp: 373 { 374 if (mNextButton->isEnabled()) 375 mNextButton->animateClick(); 376 break; 377 } 378 case Qt::Key_PageDown: 379 { 380 if (mBackButton->isEnabled()) 381 mBackButton->animateClick(); 382 break; 383 } 384 } 385 } 386 387 /* Default one handler */ 388 return QWidget::eventFilter (aObject, aEvent); 389 } 390 391 void relayout() 392 { 393 /* Update full layout system of message window */ 394 QList <QLayout*> layouts = findChildren <QLayout*> (); 395 foreach (QLayout *item, layouts) 396 { 397 item->update(); 398 item->activate(); 399 } 400 401 /* Update main layout of message window at last */ 402 window()->layout()->update(); 403 window()->layout()->activate(); 404 qApp->processEvents(); 405 406 /* Now resize window to minimum possible size */ 407 window()->resize (window()->minimumSizeHint()); 408 qApp->processEvents(); 409 410 /* Check if we have to make dialog fixed in height */ 411 if (mSwitchButton->isExpanded()) 412 window()->setMaximumHeight (QWIDGETSIZE_MAX); 413 else 414 window()->setFixedHeight (window()->minimumSizeHint().height()); 415 } 416 417 QVBoxLayout *mMainLayout; 418 QIArrowButtonSwitch *mSwitchButton; 419 QIArrowButtonPress *mBackButton; 420 QIArrowButtonPress *mNextButton; 421 QWidget *mChild; 422 }; 423 424 /** @class QIMessageBox 425 * 426 * The QIMessageBox class is a message box similar to QMessageBox. 427 * It partly implements the QMessageBox interface and adds some enhanced 428 * functionality. 429 */ 430 431 /** 432 * See QMessageBox for details. 433 */ 434 QIMessageBox::QIMessageBox (const QString &aCaption, const QString &aText, 435 Icon aIcon, int aButton0, int aButton1, int aButton2, 436 QWidget *aParent, const char *aName, bool aModal) 437 : QIDialog (aParent) 438 , mText (aText) 439 , mDetailsIndex (-1) 440 , mWasDone (false) 441 , mWasPolished (false) 442 { 443 #ifdef Q_WS_MAC 444 /* Sheets are broken if the window is in fullscreen mode. So make it a 445 * normal window in that case. */ 446 VBoxConsoleWnd *cwnd = qobject_cast<VBoxConsoleWnd*> (aParent); 447 if (cwnd == NULL || 448 (!cwnd->isTrueFullscreen() && 449 !cwnd->isTrueSeamless())) 450 setWindowFlags (Qt::Sheet); 451 #endif /* Q_WS_MAC */ 452 453 setWindowTitle (aCaption); 454 /* Necessary to later find some of the message boxes */ 455 setObjectName (aName); 456 setModal (aModal); 457 458 mButton0 = aButton0; 459 mButton1 = aButton1; 460 mButton2 = aButton2; 461 462 QVBoxLayout *layout = new QVBoxLayout (this); 463 #ifdef Q_WS_MAC 464 layout->setContentsMargins (40, 11, 40, 11); 465 #else /* !Q_WS_MAC */ 466 VBoxGlobal::setLayoutMargin (layout, 11); 467 #endif /* !Q_WS_MAC */ 468 layout->setSpacing (10); 469 layout->setSizeConstraint (QLayout::SetMinimumSize); 470 471 QWidget *main = new QWidget(); 472 473 QHBoxLayout *hLayout = new QHBoxLayout (main); 474 VBoxGlobal::setLayoutMargin (hLayout, 0); 475 hLayout->setSpacing (10); 476 layout->addWidget (main); 477 478 mIconLabel = new QLabel(); 479 mIconLabel->setPixmap (standardPixmap (aIcon)); 480 mIconLabel->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Minimum); 481 mIconLabel->setAlignment (Qt::AlignHCenter | Qt::AlignTop); 482 hLayout->addWidget (mIconLabel); 483 484 QVBoxLayout* messageVBoxLayout = new QVBoxLayout(); 485 VBoxGlobal::setLayoutMargin (messageVBoxLayout, 0); 486 messageVBoxLayout->setSpacing (10); 487 hLayout->addLayout (messageVBoxLayout); 488 489 mTextLabel = new QILabel (aText); 490 mTextLabel->setAlignment (Qt::AlignLeft | Qt::AlignTop); 491 mTextLabel->setWordWrap (true); 492 QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Minimum); 493 sp.setHeightForWidth (true); 494 mTextLabel->setSizePolicy (sp); 495 messageVBoxLayout->addWidget (mTextLabel); 496 497 mFlagCB_Main = new QCheckBox(); 498 mFlagCB_Main->hide(); 499 messageVBoxLayout->addWidget (mFlagCB_Main); 500 501 mDetailsVBox = new QWidget(); 502 layout->addWidget (mDetailsVBox); 503 504 QVBoxLayout* detailsVBoxLayout = new QVBoxLayout (mDetailsVBox); 505 VBoxGlobal::setLayoutMargin (detailsVBoxLayout, 0); 506 detailsVBoxLayout->setSpacing (10); 507 508 mDetailsText = new QTextEdit(); 509 { 510 /* Calculate the minimum size dynamically, approx. 511 * for 40 chars, 4 lines & 2 <table> margins */ 512 QFontMetrics fm = mDetailsText->fontMetrics(); 513 mDetailsText->setMinimumSize (fm.width ('m') * 40, 514 fm.lineSpacing() * 4 + 4 * 2); 515 } 516 mDetailsText->setReadOnly (true); 517 mDetailsText->setSizePolicy (QSizePolicy::Expanding, 518 QSizePolicy::MinimumExpanding); 519 mDetailsSplitter = new QIArrowSplitter (mDetailsText); 520 connect (mDetailsSplitter, SIGNAL (showBackDetails()), this, SLOT (detailsBack())); 521 connect (mDetailsSplitter, SIGNAL (showNextDetails()), this, SLOT (detailsNext())); 522 detailsVBoxLayout->addWidget (mDetailsSplitter); 523 524 mFlagCB_Details = new QCheckBox(); 525 mFlagCB_Details->hide(); 526 detailsVBoxLayout->addWidget (mFlagCB_Details); 527 528 mSpacer = new QSpacerItem (0, 0); 529 layout->addItem (mSpacer); 530 531 mButtonBox = new QIDialogButtonBox; 532 mButtonBox->setCenterButtons (true); 533 layout->addWidget (mButtonBox); 534 535 mButtonEsc = 0; 536 537 mButton0PB = createButton (aButton0); 538 if (mButton0PB) 539 connect (mButton0PB, SIGNAL (clicked()), SLOT (done0())); 540 mButton1PB = createButton (aButton1); 541 if (mButton1PB) 542 connect (mButton1PB, SIGNAL (clicked()), SLOT (done1())); 543 mButton2PB = createButton (aButton2); 544 if (mButton2PB) 545 connect (mButton2PB, SIGNAL (clicked()), SLOT (done2())); 546 547 /* this call is a must -- it initializes mFlagCB and mSpacer */ 548 setDetailsShown (false); 88 /* Default one handler */ 89 return QWidget::eventFilter (aObject, aEvent); 549 90 } 550 91 551 /** 552 * Returns the text of the given message box button. 553 * See QMessageBox::buttonText() for details. 554 * 555 * @param aButton Button index (0, 1 or 2). 556 */ 557 QString QIMessageBox::buttonText (int aButton) const 92 void QIRichToolButton::paintEvent (QPaintEvent *aEvent) 558 93 { 559 switch (aButton) 94 /* Draw focus around mLabel if focused */ 95 if (hasFocus()) 560 96 { 561 case 0: if (mButton0PB) return mButton0PB->text(); break; 562 case 1: if (mButton1PB) return mButton1PB->text(); break; 563 case 2: if (mButton2PB) return mButton2PB->text(); break; 564 default: break; 97 QStylePainter painter (this); 98 QStyleOptionFocusRect option; 99 option.initFrom (this); 100 option.rect = mLabel->frameGeometry(); 101 painter.drawPrimitive (QStyle::PE_FrameFocusRect, option); 565 102 } 566 567 return QString::null; 103 QWidget::paintEvent (aEvent); 568 104 } 569 570 /**571 * Sets the text of the given message box button.572 * See QMessageBox::setButtonText() for details.573 *574 * @param aButton Button index (0, 1 or 2).575 * @param aText New button text.576 */577 void QIMessageBox::setButtonText (int aButton, const QString &aText)578 {579 switch (aButton)580 {581 case 0: if (mButton0PB) mButton0PB->setText (aText); break;582 case 1: if (mButton1PB) mButton1PB->setText (aText); break;583 case 2: if (mButton2PB) mButton2PB->setText (aText); break;584 default: break;585 }586 }587 588 /** @fn QIMessageBox::flagText() const589 *590 * Returns the text of the optional message box flag. If the flag is hidden591 * (by default) a null string is returned.592 *593 * @see #setFlagText()594 */595 596 /**597 * Sets the text for the optional message box flag (check box) that is598 * displayed under the message text. Passing the null string as the argument599 * will hide the flag. By default, the flag is hidden.600 */601 void QIMessageBox::setFlagText (const QString &aText)602 {603 if (aText.isNull())604 {605 mFlagCB->hide();606 }607 else608 {609 mFlagCB->setText (aText);610 mFlagCB->show();611 mFlagCB->setFocus();612 }613 }614 615 /** @fn QIMessageBox::isFlagChecked() const616 *617 * Returns true if the optional message box flag is checked and false618 * otherwise. By default, the flag is not checked.619 *620 * @see #setFlagChecked()621 * @see #setFlagText()622 */623 624 /** @fn QIMessageBox::setFlagChecked (bool)625 *626 * Sets the state of the optional message box flag to a value of the argument.627 *628 * @see #isFlagChecked()629 * @see #setFlagText()630 */631 632 QPushButton *QIMessageBox::createButton (int aButton)633 {634 if (aButton == 0)635 return 0;636 637 QString text;638 QDialogButtonBox::ButtonRole role;639 switch (aButton & ButtonMask)640 {641 case Ok: text = tr ("OK"); role = QDialogButtonBox::AcceptRole; break;642 case Yes: text = tr ("Yes"); role = QDialogButtonBox::YesRole; break;643 case No: text = tr ("No"); role = QDialogButtonBox::NoRole; break;644 case Cancel: text = tr ("Cancel"); role = QDialogButtonBox::RejectRole; break;645 case Ignore: text = tr ("Ignore"); role = QDialogButtonBox::AcceptRole; break;646 default:647 AssertMsgFailed (("Type %d is not implemented", aButton));648 return NULL;649 }650 651 QPushButton *b = mButtonBox->addButton (text, role);652 653 if (aButton & Default)654 {655 b->setDefault (true);656 b->setFocus();657 }658 659 if (aButton & Escape)660 mButtonEsc = aButton & ButtonMask;661 662 return b;663 }664 665 /** @fn QIMessageBox::detailsText() const666 *667 * Returns the text of the optional details box. The details box is empty668 * by default, so QString::null will be returned.669 *670 * @see #setDetailsText()671 */672 673 /**674 * Sets the text for the optional details box. Note that the details box675 * is hidden by default, call #setDetailsShown(true) to make it visible.676 *677 * @see #detailsText()678 * @see #setDetailsShown()679 */680 void QIMessageBox::setDetailsText (const QString &aText)681 {682 AssertMsg (!aText.isEmpty(), ("Details text should NOT be empty."));683 684 QStringList paragraphs (aText.split ("<!--EOP-->", QString::SkipEmptyParts));685 AssertMsg (paragraphs.size() != 0, ("There should be at least one paragraph."));686 687 foreach (QString paragraph, paragraphs)688 {689 QStringList parts (paragraph.split ("<!--EOM-->", QString::KeepEmptyParts));690 AssertMsg (parts.size() == 2, ("Each paragraph should consist of 2 parts."));691 mDetailsList << QPair <QString, QString> (parts [0], parts [1]);692 }693 694 mDetailsSplitter->setMultiPaging (mDetailsList.size() > 1);695 mDetailsIndex = 0;696 refreshDetails();697 }698 699 QPixmap QIMessageBox::standardPixmap (QIMessageBox::Icon aIcon)700 {701 QIcon icon;702 switch (aIcon)703 {704 case QIMessageBox::Information:705 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxInformation, this);706 break;707 case QMessageBox::Warning:708 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this);709 break;710 case QIMessageBox::Critical:711 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxCritical, this);712 break;713 case QIMessageBox::Question:714 icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxQuestion, this);715 break;716 case QIMessageBox::GuruMeditation:717 icon = QIcon (":/meditation_32px.png");718 break;719 default:720 break;721 }722 if (!icon.isNull())723 {724 int size = style()->pixelMetric (QStyle::PM_MessageBoxIconSize, 0, this);725 return icon.pixmap (size, size);726 }else727 return QPixmap();728 }729 730 void QIMessageBox::closeEvent (QCloseEvent *e)731 {732 if (mWasDone)733 e->accept();734 else735 e->ignore();736 }737 738 void QIMessageBox::showEvent (QShowEvent *e)739 {740 if (!mWasPolished)741 {742 /* Polishing sub-widgets */743 resize (minimumSizeHint());744 qApp->processEvents();745 mTextLabel->setMinimumWidth (mTextLabel->width());746 mTextLabel->updateSizeHint();747 qApp->processEvents();748 setFixedWidth (width());749 mDetailsSplitter->toggleWidget();750 mWasPolished = true;751 }752 753 QIDialog::showEvent (e);754 }755 756 void QIMessageBox::refreshDetails()757 {758 /* Update message text iteself */759 mTextLabel->setText (mText + mDetailsList [mDetailsIndex].first);760 mTextLabel->updateSizeHint();761 /* Update details table */762 mDetailsText->setText (mDetailsList [mDetailsIndex].second);763 setDetailsShown (!mDetailsText->toPlainText().isEmpty());764 765 /* Update multi-paging system */766 if (mDetailsList.size() > 1)767 {768 mDetailsSplitter->setButtonEnabled (true, mDetailsIndex < mDetailsList.size() - 1);769 mDetailsSplitter->setButtonEnabled (false, mDetailsIndex > 0);770 }771 772 /* Update details label */773 mDetailsSplitter->setName (mDetailsList.size() == 1 ? tr ("&Details") :774 tr ("&Details (%1 of %2)").arg (mDetailsIndex + 1).arg (mDetailsList.size()));775 }776 777 /**778 * Sets the visibility state of the optional details box779 * to a value of the argument.780 *781 * @see #isDetailsShown()782 * @see #setDetailsText()783 */784 void QIMessageBox::setDetailsShown (bool aShown)785 {786 if (aShown)787 {788 mFlagCB_Details->setVisible (mFlagCB_Main->isVisible());789 mFlagCB_Details->setChecked (mFlagCB_Main->isChecked());790 mFlagCB_Details->setText (mFlagCB_Main->text());791 if (mFlagCB_Main->hasFocus())792 mFlagCB_Details->setFocus();793 mFlagCB_Main->setVisible (false);794 mFlagCB = mFlagCB_Details;795 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum);796 }797 798 mDetailsVBox->setVisible (aShown);799 800 if (!aShown)801 {802 mFlagCB_Main->setVisible (mFlagCB_Details->isVisible());803 mFlagCB_Main->setChecked (mFlagCB_Details->isChecked());804 mFlagCB_Main->setText (mFlagCB_Details->text());805 if (mFlagCB_Details->hasFocus())806 mFlagCB_Main->setFocus();807 mFlagCB = mFlagCB_Main;808 mSpacer->changeSize (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);809 }810 }811 812 void QIMessageBox::detailsBack()813 {814 if (mDetailsIndex > 0)815 {816 -- mDetailsIndex;817 refreshDetails();818 }819 }820 821 void QIMessageBox::detailsNext()822 {823 if (mDetailsIndex < mDetailsList.size() - 1)824 {825 ++ mDetailsIndex;826 refreshDetails();827 }828 }829 830 void QIMessageBox::reject()831 {832 if (mButtonEsc)833 {834 QDialog::reject();835 setResult (mButtonEsc & ButtonMask);836 }837 }838 839 #include "QIMessageBox.moc"840
Note:
See TracChangeset
for help on using the changeset viewer.