VirtualBox

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

Last change on this file since 37126 was 37109, checked in by vboxsync, 13 years ago

FE/Qt: 3887: Make certain settings editable during runtime: Opened VM settings dialog content now will be dynamically updated on machine data / state changes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use