VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMSettingsDlg.cpp@ 9782

Last change on this file since 9782 was 9782, checked in by vboxsync, 17 years ago

Fe/Qt4: Some code-spelling for VMSettings to make it similar to Global Settings, VBoxWarnIconLabel moved to VBoxVMSettingUtils (will be used in global settings too).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 17.8 KB
Line 
1/** @file
2 *
3 * VBox frontends: Qt4 GUI ("VirtualBox"):
4 * VBoxVMSettingsDlg class implementation
5 */
6
7/*
8 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include "VBoxVMSettingsDlg.h"
24#include "VBoxVMSettingsGeneral.h"
25#include "VBoxVMSettingsHD.h"
26#include "VBoxVMSettingsCD.h"
27#include "VBoxVMSettingsFD.h"
28#include "VBoxVMSettingsAudio.h"
29#include "VBoxVMSettingsNetwork.h"
30#include "VBoxVMSettingsSerial.h"
31#include "VBoxVMSettingsParallel.h"
32#include "VBoxVMSettingsUSB.h"
33#include "VBoxVMSettingsSF.h"
34#include "VBoxVMSettingsVRDP.h"
35
36#include "VBoxGlobal.h"
37#include "VBoxProblemReporter.h"
38#include "QIWidgetValidator.h"
39
40#include <QTimer>
41
42/**
43 * Returns the path to the item in the form of 'grandparent > parent > item'
44 * using the text of the first column of every item.
45 */
46static QString path (QTreeWidgetItem *aItem)
47{
48 static QString sep = ": ";
49 QString p;
50 QTreeWidgetItem *cur = aItem;
51 while (cur)
52 {
53 if (!p.isNull())
54 p = sep + p;
55 p = cur->text (0).simplified() + p;
56 cur = cur->parent();
57 }
58 return p;
59}
60
61static QTreeWidgetItem* findItem (QTreeWidget *aView,
62 const QString &aMatch, int aColumn)
63{
64 QList<QTreeWidgetItem*> list =
65 aView->findItems (aMatch, Qt::MatchExactly, aColumn);
66
67 return list.count() ? list [0] : 0;
68}
69
70VBoxVMSettingsDlg::VBoxVMSettingsDlg (QWidget *aParent,
71 const QString &aCategory,
72 const QString &aControl)
73 : QIWithRetranslateUI<QIMainDialog> (aParent)
74 , mPolished (false)
75 , mAllowResetFirstRunFlag (false)
76 , mValid (true)
77 , mWhatsThisTimer (new QTimer (this))
78 , mWhatsThisCandidate (NULL)
79{
80 /* Apply UI decorations */
81 Ui::VBoxVMSettingsDlg::setupUi (this);
82
83#ifndef Q_WS_MAC
84 setWindowIcon (QIcon (":/settings_16px.png"));
85#endif /* Q_WS_MAC */
86
87 mWarnIconLabel = new VBoxWarnIconLabel();
88
89 /* Setup warning icon */
90 QIcon icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this);
91 if (!icon.isNull())
92 mWarnIconLabel->setWarningPixmap (icon.pixmap (16, 16));
93
94 mButtonBox->addExtraWidget (mWarnIconLabel);
95
96 /* Page title font is derived from the system font */
97 QFont f = font();
98 f.setBold (true);
99 f.setPointSize (f.pointSize() + 2);
100 mLbTitle->setFont (f);
101
102 /* Setup the what's this label */
103 qApp->installEventFilter (this);
104 mWhatsThisTimer->setSingleShot (true);
105 connect (mWhatsThisTimer, SIGNAL (timeout()), this, SLOT (updateWhatsThis()));
106
107 mLbWhatsThis->setFixedHeight (mLbWhatsThis->frameWidth() * 2 +
108 6 /* seems that RichText adds some margin */ +
109 mLbWhatsThis->fontMetrics().lineSpacing() * 4);
110 mLbWhatsThis->setMinimumWidth (mLbWhatsThis->frameWidth() * 2 +
111 6 /* seems that RichText adds some margin */ +
112 mLbWhatsThis->fontMetrics().width ('m') * 40);
113
114 /* Common connections */
115 connect (mButtonBox, SIGNAL (accepted()), this, SLOT (accept()));
116 connect (mButtonBox, SIGNAL (rejected()), this, SLOT (reject()));
117 connect (mButtonBox, SIGNAL (helpRequested()), &vboxProblem(), SLOT (showHelpHelpDialog()));
118 connect (mTwSelector, SIGNAL (currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)),
119 this, SLOT (settingsGroupChanged (QTreeWidgetItem *, QTreeWidgetItem*)));
120 connect (&vboxGlobal(), SIGNAL (mediaEnumFinished (const VBoxMediaList &)),
121 this, SLOT (onMediaEnumerationDone()));
122
123 /* Parallel Port Page (currently disabled) */
124 //QTreeWidgetItem *item = findItem (mTwSelector, "#parallelPorts", listView_Link);
125 //Assert (item);
126 //if (item) item->setHidden (true);
127
128 /* Hide unnecessary columns and header */
129 mTwSelector->header()->hide();
130 mTwSelector->hideColumn (listView_Id);
131 mTwSelector->hideColumn (listView_Link);
132
133 /* Adjust selector list */
134 int minWid = 0;
135 for (int i = 0; i < mTwSelector->topLevelItemCount(); ++ i)
136 {
137 QTreeWidgetItem *item = mTwSelector->topLevelItem (i);
138 QFontMetrics fm (item->font (0));
139 int wid = fm.width (item->text (0)) +
140 16 /* icon */ + 2 * 8 /* 2 margins */;
141 minWid = wid > minWid ? wid : minWid;
142 int hei = fm.height() > 16 ?
143 fm.height() /* text height */ :
144 16 /* icon */ + 2 * 2 /* 2 margins */;
145 item->setSizeHint (0, QSize (wid, hei));
146 }
147 mTwSelector->setFixedWidth (minWid);
148
149 /* Sort selector by the id column (to have pages in the desired order) */
150 mTwSelector->sortItems (listView_Id, Qt::AscendingOrder);
151
152 /* Initially select the first settings page */
153 mTwSelector->setCurrentItem (mTwSelector->topLevelItem (0));
154
155 /* Setup Settings Dialog */
156 if (!aCategory.isNull())
157 {
158 /* Search for a list view item corresponding to the category */
159 QTreeWidgetItem *item = findItem (mTwSelector, aCategory, listView_Link);
160 if (item)
161 {
162 mTwSelector->setCurrentItem (item);
163
164 /* Search for a widget with the given name */
165 if (!aControl.isNull())
166 {
167 QObject *obj = mPageStack->currentWidget()->findChild<QWidget*> (aControl);
168 if (obj && obj->isWidgetType())
169 {
170 QWidget *w = static_cast<QWidget*> (obj);
171 QList<QWidget*> parents;
172 QWidget *p = w;
173 while ((p = p->parentWidget()) != NULL)
174 {
175 if (p->inherits ("QTabWidget"))
176 {
177 /* The tab contents widget is two steps down
178 * (QTabWidget -> QStackedWidget -> QWidget) */
179 QWidget *c = parents [parents.count() - 1];
180 if (c)
181 c = parents [parents.count() - 2];
182 if (c)
183 static_cast<QTabWidget*> (p)->setCurrentWidget (c);
184 }
185 parents.append (p);
186 }
187
188 w->setFocus();
189 }
190 }
191 }
192 }
193
194 /* Applying language settings */
195 retranslateUi();
196}
197
198void VBoxVMSettingsDlg::getFromMachine (const CMachine &aMachine)
199{
200 mMachine = aMachine;
201
202 setWindowTitle (dialogTitle());
203
204 CVirtualBox vbox = vboxGlobal().virtualBox();
205
206 /* General Page */
207 VBoxVMSettingsGeneral::getFromMachine (aMachine, mPageGeneral,
208 this, pagePath (mPageGeneral));
209
210 /* HD */
211 VBoxVMSettingsHD::getFromMachine (aMachine, mPageHD,
212 this, pagePath (mPageHD));
213
214 /* CD */
215 VBoxVMSettingsCD::getFromMachine (aMachine, mPageCD,
216 this, pagePath (mPageCD));
217
218 /* FD */
219 VBoxVMSettingsFD::getFromMachine (aMachine, mPageFD,
220 this, pagePath (mPageFD));
221
222 /* Audio */
223 VBoxVMSettingsAudio::getFromMachine (aMachine, mPageAudio);
224
225 /* Network */
226 VBoxVMSettingsNetwork::getFromMachine (aMachine, mPageNetwork,
227 this, pagePath (mPageNetwork));
228
229 /* Serial Ports */
230 VBoxVMSettingsSerial::getFromMachine (aMachine, mPageSerial,
231 this, pagePath (mPageSerial));
232
233 /* Parallel Ports */
234 VBoxVMSettingsParallel::getFromMachine (aMachine, mPageParallel,
235 this, pagePath (mPageParallel));
236
237 /* USB */
238 VBoxVMSettingsUSB::getFromMachine (aMachine, mPageUSB,
239 this, pagePath (mPageUSB));
240
241 /* Shared Folders */
242 VBoxVMSettingsSF::getFromMachineEx (aMachine, mPageShared, this);
243
244 /* Vrdp */
245 VBoxVMSettingsVRDP::getFromMachine (aMachine, mPageVrdp,
246 this, pagePath (mPageVrdp));
247
248 /* Finally set the reset First Run Wizard flag to "false" to make sure
249 * user will see this dialog if he hasn't change the boot-order
250 * and/or mounted images configuration */
251 mResetFirstRunFlag = false;
252}
253
254COMResult VBoxVMSettingsDlg::putBackToMachine()
255{
256 CVirtualBox vbox = vboxGlobal().virtualBox();
257
258 /* General Page */
259 VBoxVMSettingsGeneral::putBackToMachine();
260
261 /* HD */
262 VBoxVMSettingsHD::putBackToMachine();
263
264 /* CD */
265 VBoxVMSettingsCD::putBackToMachine();
266
267 /* FD */
268 VBoxVMSettingsFD::putBackToMachine();
269
270 /* Clear the "GUI_FirstRun" extra data key in case if the boot order
271 * and/or disk configuration were changed */
272 if (mResetFirstRunFlag)
273 mMachine.SetExtraData (VBoxDefs::GUI_FirstRun, QString::null);
274
275 /* Audio */
276 VBoxVMSettingsAudio::putBackToMachine();
277
278 /* Network */
279 VBoxVMSettingsNetwork::putBackToMachine();
280
281 /* Serial ports */
282 VBoxVMSettingsSerial::putBackToMachine();
283
284 /* Parallel ports */
285 VBoxVMSettingsParallel::putBackToMachine();
286
287 /* USB */
288 VBoxVMSettingsUSB::putBackToMachine();
289
290 /* Shared folders */
291 VBoxVMSettingsSF::putBackToMachineEx();
292
293 /* Vrdp */
294 VBoxVMSettingsVRDP::putBackToMachine();
295
296 return COMResult();
297}
298
299
300void VBoxVMSettingsDlg::retranslateUi()
301{
302 /* Unfortunately retranslateUi clears the QTreeWidget to do the
303 * translation. So save the current selected index. */
304 int ci = mPageStack->currentIndex();
305 /* Translate uic generated strings */
306 Ui::VBoxVMSettingsDlg::retranslateUi (this);
307 /* Set the old index */
308 mTwSelector->setCurrentItem (mTwSelector->topLevelItem (ci));
309
310 mWarnIconLabel->setWarningText (tr ("Invalid settings detected"));
311 mButtonBox->button (QDialogButtonBox::Ok)->setWhatsThis (tr ("Accepts (saves) changes and closes the dialog."));
312 mButtonBox->button (QDialogButtonBox::Cancel)->setWhatsThis (tr ("Cancels changes and closes the dialog."));
313 mButtonBox->button (QDialogButtonBox::Help)->setWhatsThis (tr ("Displays the dialog help."));
314
315 setWindowTitle (dialogTitle());
316
317 /* We have to make sure that the Serial & Network subpages are retranslated
318 * before they are revalidated. Cause: They do string comparing within
319 * vboxGlobal which is retranslated at that point already. */
320 QEvent* event = new QEvent (QEvent::LanguageChange);
321 qApp->sendEvent (mPageSerial, event);
322 qApp->sendEvent (mPageNetwork, event);
323
324 /* Revalidate all pages to retranslate the warning messages also. */
325 QList<QIWidgetValidator*> l = this->findChildren<QIWidgetValidator*>();
326 foreach (QIWidgetValidator *wval, l)
327 if (!wval->isValid())
328 revalidate (wval);
329}
330
331void VBoxVMSettingsDlg::enableOk (const QIWidgetValidator*)
332{
333 setWarning (QString::null);
334 QString wvalWarning;
335
336 /* Detect the overall validity */
337 bool newValid = true;
338 {
339 QList<QIWidgetValidator*> l = this->findChildren<QIWidgetValidator*>();
340 foreach (QIWidgetValidator *wval, l)
341 {
342 newValid = wval->isValid();
343 if (!newValid)
344 {
345 wvalWarning = wval->warningText();
346 break;
347 }
348 }
349 }
350
351 if (mWarnString.isNull() && !wvalWarning.isNull())
352 {
353 /* Try to set the generic error message when invalid but no specific
354 * message is provided */
355 setWarning (wvalWarning);
356 }
357
358 if (mValid != newValid)
359 {
360 mValid = newValid;
361 mButtonBox->button (QDialogButtonBox::Ok)->setEnabled (mValid);
362 mWarnIconLabel->setVisible (!mValid);
363 }
364}
365
366void VBoxVMSettingsDlg::revalidate (QIWidgetValidator *aWval)
367{
368 /* do individual validations for pages */
369 QWidget *pg = aWval->widget();
370 bool valid = aWval->isOtherValid();
371
372 QString warningText;
373 QString pageTitle = pagePath (pg);
374
375 if (pg == mPageHD)
376 valid = VBoxVMSettingsHD::revalidate (warningText);
377 else if (pg == mPageCD)
378 valid = VBoxVMSettingsCD::revalidate (warningText);
379 else if (pg == mPageFD)
380 valid = VBoxVMSettingsFD::revalidate (warningText);
381 else if (pg == mPageNetwork)
382 valid = VBoxVMSettingsNetwork::revalidate (warningText, pageTitle);
383 else if (pg == mPageSerial)
384 valid = VBoxVMSettingsSerial::revalidate (warningText, pageTitle);
385 else if (pg == mPageParallel)
386 valid = VBoxVMSettingsParallel::revalidate (warningText, pageTitle);
387
388 if (!valid)
389 setWarning (tr ("%1 on the <b>%2</b> page.")
390 .arg (warningText, pageTitle));
391
392 aWval->setOtherValid (valid);
393}
394
395void VBoxVMSettingsDlg::onMediaEnumerationDone()
396{
397 mAllowResetFirstRunFlag = true;
398}
399
400void VBoxVMSettingsDlg::settingsGroupChanged (QTreeWidgetItem *aItem,
401 QTreeWidgetItem *)
402{
403 if (aItem)
404 {
405 int id = aItem->text (1).toInt();
406 Assert (id >= 0);
407 mLbTitle->setText (::path (aItem));
408 mPageStack->setCurrentIndex (id);
409 }
410}
411
412void VBoxVMSettingsDlg::updateWhatsThis (bool aGotFocus /* = false */)
413{
414 QString text;
415
416 QWidget *widget = 0;
417 if (!aGotFocus)
418 {
419 if (mWhatsThisCandidate && mWhatsThisCandidate != this)
420 widget = mWhatsThisCandidate;
421 }
422 else
423 {
424 widget = QApplication::focusWidget();
425 }
426 /* If the given widget lacks the whats'this text, look at its parent */
427 while (widget && widget != this)
428 {
429 text = widget->whatsThis();
430 if (!text.isEmpty())
431 break;
432 widget = widget->parentWidget();
433 }
434
435 if (text.isEmpty() && !mWarnString.isEmpty())
436 text = mWarnString;
437 if (text.isEmpty())
438 text = whatsThis();
439
440 mLbWhatsThis->setText (text);
441}
442
443void VBoxVMSettingsDlg::resetFirstRunFlag()
444{
445 if (mAllowResetFirstRunFlag)
446 mResetFirstRunFlag = true;
447}
448
449void VBoxVMSettingsDlg::whatsThisCandidateDestroyed (QObject *aObj /*= NULL*/)
450{
451 /* sanity */
452 Assert (mWhatsThisCandidate == aObj);
453
454 if (mWhatsThisCandidate == aObj)
455 mWhatsThisCandidate = NULL;
456}
457
458bool VBoxVMSettingsDlg::eventFilter (QObject *aObject, QEvent *aEvent)
459{
460 if (!aObject->isWidgetType())
461 return QIMainDialog::eventFilter (aObject, aEvent);
462
463 QWidget *widget = static_cast<QWidget*> (aObject);
464 if (widget->topLevelWidget() != this)
465 return QIMainDialog::eventFilter (aObject, aEvent);
466
467 switch (aEvent->type())
468 {
469 case QEvent::Enter:
470 case QEvent::Leave:
471 {
472 if (aEvent->type() == QEvent::Enter)
473 {
474 /* What if Qt sends Enter w/o Leave... */
475 if (mWhatsThisCandidate)
476 disconnect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
477 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
478
479 mWhatsThisCandidate = widget;
480 /* make sure we don't reference a deleted object after the
481 * timer is shot */
482 connect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
483 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
484 }
485 else
486 {
487 /* cleanup */
488 if (mWhatsThisCandidate)
489 disconnect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
490 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
491 mWhatsThisCandidate = NULL;
492 }
493
494 mWhatsThisTimer->start (100);
495 break;
496 }
497 case QEvent::FocusIn:
498 {
499 updateWhatsThis (true /* aGotFocus */);
500 break;
501 }
502 default:
503 break;
504 }
505
506 return QIMainDialog::eventFilter (aObject, aEvent);
507}
508
509void VBoxVMSettingsDlg::showEvent (QShowEvent *aEvent)
510{
511 QIMainDialog::showEvent (aEvent);
512
513 /* One may think that QWidget::polish() is the right place to do things
514 * below, but apparently, by the time when QWidget::polish() is called,
515 * the widget style & layout are not fully done, at least the minimum
516 * size hint is not properly calculated. Since this is sometimes necessary,
517 * we provide our own "polish" implementation. */
518
519 if (mPolished)
520 return;
521
522 mPolished = true;
523
524 /* Resize to the minimum possible size */
525 resize (minimumSize());
526
527 VBoxGlobal::centerWidget (this, parentWidget());
528}
529
530/**
531 * Returns a path to the given page of this settings dialog. See ::path() for
532 * details.
533 */
534QString VBoxVMSettingsDlg::pagePath (QWidget *aPage)
535{
536 QTreeWidgetItem *li =
537 findItem (mTwSelector,
538 QString ("%1")
539 .arg (mPageStack->indexOf (aPage), 2, 10, QChar ('0')),
540 1);
541 return ::path (li);
542}
543
544void VBoxVMSettingsDlg::setWarning (const QString &aWarning)
545{
546 mWarnString = aWarning;
547 if (!aWarning.isEmpty())
548 mWarnString = QString ("<font color=red>%1</font>").arg (aWarning);
549
550 if (!mWarnString.isEmpty())
551 mLbWhatsThis->setText (mWarnString);
552 else
553 updateWhatsThis (true);
554}
555
556QString VBoxVMSettingsDlg::dialogTitle() const
557{
558 QString dialogTitle;
559 if (!mMachine.isNull())
560 dialogTitle = tr ("%1 - Settings").arg (mMachine.GetName());
561 return dialogTitle;
562}
563
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette