VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.cpp@ 35740

Last change on this file since 35740 was 35132, checked in by vboxsync, 14 years ago

FE/Qt: Some fix for r68968.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 18.2 KB
Line 
1/* $Id: UISettingsDialog.cpp 35132 2010-12-15 13:23:25Z vboxsync $ */
2/** @file
3 *
4 * VBox frontends: Qt GUI ("VirtualBox"):
5 * UISettingsDialog class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2010 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/* Global includes */
21#include <QPushButton>
22#include <QStackedWidget>
23#include <QTimer>
24#include <QCloseEvent>
25
26/* Local includes */
27#include "UISettingsDialog.h"
28#include "VBoxWarningPane.h"
29#include "VBoxGlobal.h"
30#include "VBoxProblemReporter.h"
31#include "QIWidgetValidator.h"
32#include "VBoxSettingsSelector.h"
33#include "UISettingsPage.h"
34#include "UIToolBar.h"
35#include "UIIconPool.h"
36#ifdef Q_WS_MAC
37# include "VBoxUtils.h"
38# if MAC_LEOPARD_STYLE
39# define VBOX_GUI_WITH_TOOLBAR_SETTINGS
40# endif /* MAC_LEOPARD_STYLE */
41#endif /* Q_WS_MAC */
42
43/* Settings Dialog Constructor: */
44UISettingsDialog::UISettingsDialog(QWidget *pParent /* = 0 */)
45 /* Parent class: */
46 : QIWithRetranslateUI<QIMainDialog>(pParent)
47 /* Protected variables: */
48 , m_pSelector(0)
49 , m_pStack(0)
50 /* Common variables: */
51 , m_fPolished(false)
52 /* Loading stuff: */
53 , m_fProcessed(false)
54 /* Error/Warning stuff: */
55 , m_fValid(true)
56 , m_fSilent(true)
57 , m_pWarningPane(new VBoxWarningPane(this))
58 /* Whats-this stuff: */
59 , m_pWhatsThisTimer(new QTimer(this))
60 , m_pWhatsThisCandidate(0)
61{
62 /* Apply UI decorations: */
63 Ui::UISettingsDialog::setupUi(this);
64
65#ifdef Q_WS_MAC
66 /* No status bar on the mac: */
67 setSizeGripEnabled(false);
68 setStatusBar(0);
69#endif /* Q_WS_MAC */
70
71 /* Page-title font is derived from the system font: */
72 QFont pageTitleFont = font();
73 pageTitleFont.setBold(true);
74 pageTitleFont.setPointSize(pageTitleFont.pointSize() + 2);
75 m_pLbTitle->setFont(pageTitleFont);
76
77 /* Get main grid layout: */
78 QGridLayout *pMainLayout = static_cast<QGridLayout*>(centralWidget()->layout());
79#ifdef VBOX_GUI_WITH_TOOLBAR_SETTINGS
80 /* No page-title with tool-bar: */
81 m_pLbTitle->hide();
82 /* No whats-this with tool-bar: */
83 m_pLbWhatsThis->hide();
84 /* Create modern tool-bar selector: */
85 m_pSelector = new VBoxSettingsToolBarSelector(this);
86 static_cast<UIToolBar*>(m_pSelector->widget())->setMacToolbar();
87 addToolBar(qobject_cast<QToolBar*>(m_pSelector->widget()));
88 /* No title in this mode, we change the title of the window: */
89 pMainLayout->setColumnMinimumWidth(0, 0);
90 pMainLayout->setHorizontalSpacing(0);
91#else
92 /* Create classical tree-view selector: */
93 m_pSelector = new VBoxSettingsTreeViewSelector(this);
94 pMainLayout->addWidget(m_pSelector->widget(), 0, 0, 3, 1);
95 m_pSelector->widget()->setFocus();
96 pMainLayout->setSpacing(10);
97#endif /* VBOX_GUI_WITH_TOOLBAR_SETTINGS */
98
99 /* Creating stack of pages: */
100 m_pStack = new QStackedWidget(m_pWtStackHandler);
101 QVBoxLayout *pStackLayout = new QVBoxLayout(m_pWtStackHandler);
102 pStackLayout->setContentsMargins(0, 0, 0, 0);
103 pStackLayout->addWidget(m_pStack);
104
105 /* Setup error & warning stuff: */
106 m_pButtonBox->addExtraWidget(m_pWarningPane);
107 m_errorIcon = UIIconPool::defaultIcon(UIIconPool::MessageBoxCriticalIcon, this).pixmap(16, 16);
108 m_warningIcon = UIIconPool::defaultIcon(UIIconPool::MessageBoxWarningIcon, this).pixmap(16, 16);
109
110 /* Setup whatsthis stuff: */
111 qApp->installEventFilter(this);
112 m_pWhatsThisTimer->setSingleShot(true);
113 connect(m_pWhatsThisTimer, SIGNAL(timeout()), this, SLOT(sltUpdateWhatsThis()));
114 m_pLbWhatsThis->setAutoFillBackground(true);
115 QPalette whatsThisPalette = m_pLbWhatsThis->palette();
116 whatsThisPalette.setBrush(QPalette::Window, whatsThisPalette.brush(QPalette::Midlight));
117 m_pLbWhatsThis->setPalette(whatsThisPalette);
118 m_pLbWhatsThis->setFixedHeight(m_pLbWhatsThis->frameWidth() * 2 +
119 m_pLbWhatsThis->margin() * 2 +
120 m_pLbWhatsThis->fontMetrics().lineSpacing() * 4);
121
122 /* Set the default button: */
123 m_pButtonBox->button(QDialogButtonBox::Ok)->setDefault(true);
124
125 /* Setup connections: */
126 connect(m_pSelector, SIGNAL(categoryChanged(int)), this, SLOT(sltCategoryChanged(int)));
127 connect(m_pButtonBox, SIGNAL(helpRequested()), &vboxProblem(), SLOT(showHelpHelpDialog()));
128
129 /* Translate UI: */
130 retranslateUi();
131}
132
133UISettingsDialog::~UISettingsDialog()
134{
135 /* Delete selector early! */
136 delete m_pSelector;
137}
138
139void UISettingsDialog::sltRevalidate(QIWidgetValidator *pValidator)
140{
141 /* Get related settings page: */
142 UISettingsPage *pSettingsPage = qobject_cast<UISettingsPage*>(pValidator->widget());
143 AssertMsg(pSettingsPage, ("Validator should corresponds a page!\n"));
144
145 /* Prepare empty warning & title: */
146 QString strWarning;
147 QString strTitle = m_pSelector->itemTextByPage(pSettingsPage);
148
149 /* Revalidate the page: */
150 bool fValid = pSettingsPage->revalidate(strWarning, strTitle);
151
152 /* If revalidation is fully passed - recorrelate the pages: */
153 if (fValid && strWarning.isEmpty())
154 fValid = recorrelate(pSettingsPage, strWarning);
155
156 /* Compose a message: */
157 strWarning = strWarning.isEmpty() ? QString() :
158 tr("On the <b>%1</b> page, %2").arg(strTitle, strWarning);
159 pValidator->setLastWarning(strWarning);
160 fValid ? setWarning(strWarning) : setError(strWarning);
161
162 /* Remember validation status: */
163 pValidator->setOtherValid(fValid);
164}
165
166void UISettingsDialog::sltCategoryChanged(int cId)
167{
168 int index = m_pages[cId];
169#ifdef Q_WS_MAC
170 QSize cs = size();
171 if (index < m_sizeList.count())
172 {
173 QSize ss = m_sizeList.at(index);
174 /* Switch to the new page first if we are shrinking: */
175 if (cs.height() > ss.height())
176 m_pStack->setCurrentIndex(index);
177 /* Do the animation: */
178 ::darwinWindowAnimateResize(this, QRect (x(), y(), ss.width(), ss.height()));
179 /* Switch to the new page last if we are zooming: */
180 if (cs.height() <= ss.height())
181 m_pStack->setCurrentIndex(index);
182 }
183 ::darwinSetShowsResizeIndicator(this, false);
184#else
185 m_pLbTitle->setText(m_pSelector->itemText(cId));
186 m_pStack->setCurrentIndex(index);
187#endif
188#ifdef VBOX_GUI_WITH_TOOLBAR_SETTINGS
189 setWindowTitle(title());
190#endif /* VBOX_GUI_WITH_TOOLBAR_SETTINGS */
191}
192
193void UISettingsDialog::sltMarkProcessed()
194{
195 m_fProcessed = true;
196}
197
198void UISettingsDialog::retranslateUi()
199{
200 /* Translate generated stuff: */
201 Ui::UISettingsDialog::retranslateUi(this);
202
203 /* Translate error/warning stuff: */
204 m_strErrorHint = tr("Invalid settings detected");
205 m_strWarningHint = tr("Non-optimal settings detected");
206 if (!m_fValid)
207 m_pWarningPane->setWarningText(m_strErrorHint);
208 else if (!m_fSilent)
209 m_pWarningPane->setWarningText(m_strWarningHint);
210
211 /* Get the list of validators: */
212 QList<QIWidgetValidator*> validatorsList = findChildren<QIWidgetValidator*>();
213 /* Retranslate all validators: */
214 for (int i = 0; i < validatorsList.size(); ++i)
215 {
216 QIWidgetValidator *pValidator = validatorsList[i];
217 pValidator->setCaption(m_pSelector->itemTextByPage(qobject_cast<UISettingsPage*>(pValidator->widget())));
218 }
219 /* Revalidate all pages to retranslate the warning messages also: */
220 for (int i = 0; i < validatorsList.size(); ++i)
221 {
222 QIWidgetValidator *pValidator = validatorsList[i];
223 if (!pValidator->isValid())
224 sltRevalidate(pValidator);
225 }
226}
227
228QString UISettingsDialog::titleExtension() const
229{
230#ifdef VBOX_GUI_WITH_TOOLBAR_SETTINGS
231 return m_pSelector->itemText(m_pSelector->currentId());
232#else
233 return tr("Settings");
234#endif
235}
236
237void UISettingsDialog::setError(const QString &strError)
238{
239 m_strErrorString = strError.isEmpty() ? QString() :
240 QString("<font color=red>%1</font>").arg(strError);
241
242 /* Do not touching QILabel until dialog is polished
243 * otherwise it can change its size to undefined: */
244 if (m_fPolished)
245 {
246 if (!m_strErrorString.isEmpty())
247 m_pLbWhatsThis->setText(m_strErrorString);
248 else
249 sltUpdateWhatsThis(true /* got focus? */);
250 }
251}
252
253void UISettingsDialog::setWarning(const QString &strWarning)
254{
255 m_strWarningString = strWarning.isEmpty() ? QString() :
256 QString("<font color=#ff5400>%1</font>").arg(strWarning);
257
258 /* Do not touching QILabel until dialog is polished
259 * otherwise it can change its size to undefined: */
260 if (m_fPolished)
261 {
262 if (!m_strWarningString.isEmpty())
263 m_pLbWhatsThis->setText(m_strWarningString);
264 else
265 sltUpdateWhatsThis(true /* got focus? */);
266 }
267}
268
269void UISettingsDialog::addItem(const QString &strBigIcon,
270 const QString &strBigIconDisabled,
271 const QString &strSmallIcon,
272 const QString &strSmallIconDisabled,
273 int cId,
274 const QString &strLink,
275 UISettingsPage *pSettingsPage /* = 0 */,
276 int iParentId /* = -1 */)
277{
278 QWidget *pPage = m_pSelector->addItem(strBigIcon, strBigIconDisabled,
279 strSmallIcon, strSmallIconDisabled,
280 cId, strLink, pSettingsPage, iParentId);
281 if (pPage)
282 {
283#ifdef Q_WS_MAC
284 /* On OSX we add a stretch to the vertical end to make sure the page is
285 * always top aligned. */
286 QWidget *pW = new QWidget();
287 pW->setContentsMargins(0, 0, 0, 0);
288 QVBoxLayout *pBox = new QVBoxLayout(pW);
289 VBoxGlobal::setLayoutMargin(pBox, 0);
290 pBox->addWidget(pPage);
291 pBox->addStretch(0);
292 m_pages[cId] = m_pStack->addWidget(pW);
293#else /* Q_WS_MAC */
294 m_pages[cId] = m_pStack->addWidget(pPage);
295#endif /* !Q_WS_MAC */
296 }
297 if (pSettingsPage)
298 assignValidator(pSettingsPage);
299}
300
301bool UISettingsDialog::recorrelate(QWidget * /* pPage */, QString & /* strWarning */)
302{
303 return true;
304}
305
306void UISettingsDialog::sltHandleValidityChanged(const QIWidgetValidator * /* pValidator */)
307{
308 /* Get validators list: */
309 QList<QIWidgetValidator*> validatorsList(findChildren<QIWidgetValidator*>());
310
311 /* Detect ERROR presence: */
312 {
313 setError(QString());
314 QString strError;
315 bool fNewValid = true;
316 for (int i = 0; i < validatorsList.size(); ++i)
317 {
318 QIWidgetValidator *pValidator = validatorsList[i];
319 fNewValid = pValidator->isValid();
320 if (!fNewValid)
321 {
322 strError = pValidator->warningText();
323 if (strError.isNull())
324 strError = pValidator->lastWarning();
325 break;
326 }
327 }
328
329 /* Try to set the generic error message when invalid
330 * but no specific message is provided: */
331 if (m_strErrorString.isNull() && !strError.isNull())
332 setError(strError);
333
334 m_fValid = fNewValid;
335 m_pWarningPane->setWarningPixmap(m_errorIcon);
336 m_pWarningPane->setWarningText(m_strErrorHint);
337#ifdef Q_WS_MAC
338 m_pWarningPane->setToolTip(m_strErrorString);
339#endif /* Q_WS_MAC */
340 m_pWarningPane->setVisible(!m_fValid);
341 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(m_fValid);
342
343 if (!m_fValid)
344 return;
345 }
346
347 /* Detect WARNING presence: */
348 {
349 setWarning(QString());
350 QString strWarning;
351 bool fNewSilent = true;
352 for (int i = 0; i < validatorsList.size(); ++i)
353 {
354 QIWidgetValidator *pValidator = validatorsList[i];
355 if (!pValidator->warningText().isNull() || !pValidator->lastWarning().isNull())
356 {
357 fNewSilent = false;
358 strWarning = pValidator->warningText();
359 if (strWarning.isNull())
360 strWarning = pValidator->lastWarning();
361 break;
362 }
363 }
364
365 /* Try to set the generic error message when invalid
366 * but no specific message is provided: */
367 if (m_strWarningString.isNull() && !strWarning.isNull())
368 setWarning(strWarning);
369
370 m_fSilent = fNewSilent;
371 m_pWarningPane->setWarningPixmap(m_warningIcon);
372 m_pWarningPane->setWarningText(m_strWarningHint);
373#ifdef Q_WS_MAC
374 m_pWarningPane->setToolTip(m_strWarningString);
375#endif /* Q_WS_MAC */
376 m_pWarningPane->setVisible(!m_fSilent);
377 }
378}
379
380void UISettingsDialog::sltUpdateWhatsThis(bool fGotFocus /* = false */)
381{
382 QString strWhatsThisText;
383 QWidget *pWhatsThisWidget = 0;
384
385 /* If focus had NOT changed: */
386 if (!fGotFocus)
387 {
388 /* We will use the recommended candidate: */
389 if (m_pWhatsThisCandidate && m_pWhatsThisCandidate != this)
390 pWhatsThisWidget = m_pWhatsThisCandidate;
391 }
392 /* If focus had changed: */
393 else
394 {
395 /* We will use the focused widget instead: */
396 pWhatsThisWidget = QApplication::focusWidget();
397 }
398
399 /* If the given widget lacks the whats-this text, look at its parent: */
400 while (pWhatsThisWidget && pWhatsThisWidget != this)
401 {
402 strWhatsThisText = pWhatsThisWidget->whatsThis();
403 if (!strWhatsThisText.isEmpty())
404 break;
405 pWhatsThisWidget = pWhatsThisWidget->parentWidget();
406 }
407
408#ifndef Q_WS_MAC
409 if (strWhatsThisText.isEmpty() && !m_strErrorString.isEmpty())
410 strWhatsThisText = m_strErrorString;
411 else if (strWhatsThisText.isEmpty() && !m_strWarningString.isEmpty())
412 strWhatsThisText = m_strWarningString;
413 if (strWhatsThisText.isEmpty())
414 strWhatsThisText = whatsThis();
415 m_pLbWhatsThis->setText(strWhatsThisText);
416#else
417 if (pWhatsThisWidget && !strWhatsThisText.isEmpty())
418 pWhatsThisWidget->setToolTip(QString("<qt>%1</qt>").arg(strWhatsThisText));
419#endif
420}
421
422void UISettingsDialog::reject()
423{
424 if (m_fProcessed)
425 QIMainDialog::reject();
426}
427
428bool UISettingsDialog::eventFilter(QObject *pObject, QEvent *pEvent)
429{
430 /* Ignore objects which are NOT widgets: */
431 if (!pObject->isWidgetType())
432 return QIMainDialog::eventFilter(pObject, pEvent);
433
434 /* Ignore widgets which window is NOT settings dialog: */
435 QWidget *pWidget = static_cast<QWidget*>(pObject);
436 if (pWidget->window() != this)
437 return QIMainDialog::eventFilter(pObject, pEvent);
438
439 /* Process different event-types: */
440 switch (pEvent->type())
441 {
442 /* Process enter/leave events to remember whats-this candidates: */
443 case QEvent::Enter:
444 case QEvent::Leave:
445 {
446 if (pEvent->type() == QEvent::Enter)
447 m_pWhatsThisCandidate = pWidget;
448 else
449 m_pWhatsThisCandidate = 0;
450
451 m_pWhatsThisTimer->start(100);
452 break;
453 }
454 /* Process focus-in event to update whats-this pane: */
455 case QEvent::FocusIn:
456 {
457 sltUpdateWhatsThis(true /* got focus? */);
458 break;
459 }
460 default:
461 break;
462 }
463
464 /* Base-class processing: */
465 return QIMainDialog::eventFilter(pObject, pEvent);
466}
467
468void UISettingsDialog::showEvent(QShowEvent *pEvent)
469{
470 /* Base-class processing: */
471 QIMainDialog::showEvent(pEvent);
472
473 /* One may think that QWidget::polish() is the right place to do things
474 * below, but apparently, by the time when QWidget::polish() is called,
475 * the widget style & layout are not fully done, at least the minimum
476 * size hint is not properly calculated. Since this is sometimes necessary,
477 * we provide our own "polish" implementation. */
478 if (m_fPolished)
479 return;
480
481 m_fPolished = true;
482
483 int iMinWidth = m_pSelector->minWidth();
484#ifdef Q_WS_MAC
485 /* Remove all title bar buttons (Buggy Qt): */
486 ::darwinSetHidesAllTitleButtons(this);
487
488 /* Set all size policies to ignored: */
489 for (int i = 0; i < m_pStack->count(); ++i)
490 m_pStack->widget(i)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
491 /* Activate every single page to get the optimal size: */
492 for (int i = m_pStack->count() - 1; i >= 0; --i)
493 {
494 m_pStack->widget(i)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
495 /* Prevent this widgets to go in the Small/Mini size state which is
496 * available on Mac OS X. Not sure why this happens but this seems to help
497 * against. */
498 QList <QWidget*> list = m_pStack->widget(i)->findChildren<QWidget*>();
499 for (int a = 0; a < list.size(); ++a)
500 {
501 QWidget *w = list.at(a);
502 if (w->parent() == m_pStack->widget(i))
503 w->setFixedHeight(w->sizeHint().height());
504 }
505 m_pStack->setCurrentIndex(i);
506 /* Now make sure the layout is freshly calculated. */
507 layout()->activate();
508 QSize s = minimumSize();
509 if (iMinWidth > s.width())
510 s.setWidth(iMinWidth);
511 m_sizeList.insert(0, s);
512 m_pStack->widget(i)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
513 }
514
515 sltCategoryChanged(m_pSelector->currentId());
516#else /* Q_WS_MAC */
517 /* Resize to the minimum possible size: */
518 QSize s = minimumSize();
519 if (iMinWidth > s.width())
520 s.setWidth(iMinWidth);
521 resize(s);
522#endif /* Q_WS_MAC */
523}
524
525void UISettingsDialog::closeEvent(QCloseEvent *pEvent)
526{
527 if (m_fProcessed)
528 QIMainDialog::closeEvent(pEvent);
529 else
530 pEvent->ignore();
531}
532
533void UISettingsDialog::assignValidator(UISettingsPage *pPage)
534{
535 QIWidgetValidator *pValidator = new QIWidgetValidator(m_pSelector->itemTextByPage(pPage), pPage, this);
536 connect(pValidator, SIGNAL(validityChanged(const QIWidgetValidator*)), this, SLOT(sltHandleValidityChanged(const QIWidgetValidator*)));
537 connect(pValidator, SIGNAL(isValidRequested(QIWidgetValidator*)), this, SLOT(sltRevalidate(QIWidgetValidator*)));
538 pPage->setValidator(pValidator);
539 pPage->setOrderAfter(m_pSelector->widget());
540}
541
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use