VirtualBox

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

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

FE/Qt4: Removed the questionable QLivePointer class.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 17.2 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.virtualbox.org. 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/* Qt includes */
41#include <QTimer>
42
43/**
44 * Returns the path to the item in the form of 'grandparent > parent > item'
45 * using the text of the first column of every item.
46 */
47static QString path (QTreeWidgetItem *aItem)
48{
49 static QString sep = ": ";
50 QString p;
51 QTreeWidgetItem *cur = aItem;
52 while (cur)
53 {
54 if (!p.isNull())
55 p = sep + p;
56 p = cur->text (0).simplified() + p;
57 cur = cur->parent();
58 }
59 return p;
60}
61
62static QTreeWidgetItem* findItem (QTreeWidget *aView,
63 const QString &aMatch, int aColumn)
64{
65 QList<QTreeWidgetItem*> list =
66 aView->findItems (aMatch, Qt::MatchExactly, aColumn);
67
68 return list.count() ? list [0] : 0;
69}
70
71class VBoxWarnIconLabel: public QWidget
72{
73public:
74 VBoxWarnIconLabel (QWidget *aParent = NULL)
75 : QWidget (aParent)
76 {
77 QHBoxLayout *layout = new QHBoxLayout (this);
78 VBoxGlobal::setLayoutMargin (layout, 0);
79 layout->addWidget (&mIcon);
80 layout->addWidget (&mLabel);
81 }
82 void setWarningPixmap (const QPixmap& aPixmap) { mIcon.setPixmap (aPixmap); }
83 void setWarningText (const QString& aText) { mLabel.setText (aText); }
84
85private:
86 QLabel mIcon;
87 QLabel mLabel;
88};
89
90VBoxVMSettingsDlg::VBoxVMSettingsDlg (QWidget *aParent,
91 const QString &aCategory,
92 const QString &aControl)
93 : QDialog (aParent)
94 , mPolished (false)
95 , mAllowResetFirstRunFlag (false)
96 , mValid (true)
97 , mWhatsThisTimer (new QTimer (this))
98 , mWhatsThisCandidate (NULL)
99{
100 /* Apply UI decorations */
101 Ui::VBoxVMSettingsDlg::setupUi (this);
102
103 mWarnIconLabel = new VBoxWarnIconLabel();
104 mWarnIconLabel->setWarningText (tr ("Invalid settings detected"));
105 mButtonBox->button (QDialogButtonBox::Ok)->setWhatsThis (tr ("Accepts (saves) changes and closes the dialog."));
106 mButtonBox->button (QDialogButtonBox::Cancel)->setWhatsThis (tr ("Cancels changes and closes the dialog."));
107 mButtonBox->button (QDialogButtonBox::Help)->setWhatsThis (tr ("Displays the dialog help."));
108
109 /* Setup warning icon */
110 QIcon icon = vboxGlobal().standardIcon (QStyle::SP_MessageBoxWarning, this);
111 if (!icon.isNull())
112 mWarnIconLabel->setWarningPixmap (icon.pixmap (16, 16));
113
114 mButtonBox->addExtraWidget (mWarnIconLabel);
115
116 /* Page title font is derived from the system font */
117 QFont f = font();
118 f.setBold (true);
119 f.setPointSize (f.pointSize() + 2);
120 mLbTitle->setFont (f);
121
122 /* Setup the what's this label */
123 qApp->installEventFilter (this);
124 mWhatsThisTimer->setSingleShot (true);
125 connect (mWhatsThisTimer, SIGNAL (timeout()), this, SLOT (updateWhatsThis()));
126
127 mLbWhatsThis->setFixedHeight (mLbWhatsThis->frameWidth() * 2 +
128 6 /* seems that RichText adds some margin */ +
129 mLbWhatsThis->fontMetrics().lineSpacing() * 4);
130 mLbWhatsThis->setMinimumWidth (mLbWhatsThis->frameWidth() * 2 +
131 6 /* seems that RichText adds some margin */ +
132 mLbWhatsThis->fontMetrics().width ('m') * 40);
133
134 /*
135 * Setup connections and set validation for pages
136 * ----------------------------------------------------------------------
137 */
138
139 /* Common connections */
140
141 connect (mButtonBox, SIGNAL (accepted()), this, SLOT (accept()));
142 connect (mButtonBox, SIGNAL (rejected()), this, SLOT (reject()));
143 connect (mButtonBox, SIGNAL (helpRequested()), &vboxProblem(), SLOT (showHelpHelpDialog()));
144 connect (mTwSelector, SIGNAL (currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)),
145 this, SLOT (settingsGroupChanged (QTreeWidgetItem *, QTreeWidgetItem*)));
146 connect (&vboxGlobal(), SIGNAL (mediaEnumFinished (const VBoxMediaList &)),
147 this, SLOT (onMediaEnumerationDone()));
148
149 /* Parallel Port Page (currently disabled) */
150 //QTreeWidgetItem *item = findItem (mTwSelector, "#parallelPorts", listView_Link);
151 //Assert (item);
152 //if (item) item->setHidden (true);
153
154 /*
155 * Set initial values
156 * ----------------------------------------------------------------------
157 */
158
159 /* Common settings */
160
161 /* Hide unnecessary columns and header */
162 mTwSelector->header()->hide();
163 mTwSelector->hideColumn (listView_Id);
164 mTwSelector->hideColumn (listView_Link);
165
166 /* Adjust selector list */
167 int minWid = 0;
168 for (int i = 0; i < mTwSelector->topLevelItemCount(); ++ i)
169 {
170 QTreeWidgetItem *item = mTwSelector->topLevelItem (i);
171 QFontMetrics fm (item->font (0));
172 int wid = fm.width (item->text (0)) +
173 16 /* icon */ + 2 * 8 /* 2 margins */;
174 minWid = wid > minWid ? wid : minWid;
175 int hei = fm.height() > 16 ?
176 fm.height() /* text height */ :
177 16 /* icon */ + 2 * 2 /* 2 margins */;
178 item->setSizeHint (0, QSize (wid, hei));
179 }
180 mTwSelector->setFixedWidth (minWid);
181
182 /* Sort selector by the id column (to have pages in the desired order) */
183 mTwSelector->sortItems (listView_Id, Qt::AscendingOrder);
184
185 /* Initially select the first settings page */
186 mTwSelector->setCurrentItem (mTwSelector->topLevelItem (0));
187
188 /* Setup Settings Dialog */
189 if (!aCategory.isNull())
190 {
191 /* Search for a list view item corresponding to the category */
192 QTreeWidgetItem *item = findItem (mTwSelector, aCategory, listView_Link);
193 if (item)
194 {
195 mTwSelector->setCurrentItem (item);
196
197 /* Search for a widget with the given name */
198 if (!aControl.isNull())
199 {
200 QObject *obj = mPageStack->currentWidget()->findChild<QWidget*> (aControl);
201 if (obj && obj->isWidgetType())
202 {
203 QWidget *w = static_cast<QWidget*> (obj);
204 QList<QWidget*> parents;
205 QWidget *p = w;
206 while ((p = p->parentWidget()) != NULL)
207 {
208 if (p->inherits ("QTabWidget"))
209 {
210 /* The tab contents widget is two steps down
211 * (QTabWidget -> QStackedWidget -> QWidget) */
212 QWidget *c = parents [parents.count() - 1];
213 if (c)
214 c = parents [parents.count() - 2];
215 if (c)
216 static_cast<QTabWidget*> (p)->setCurrentWidget (c);
217 }
218 parents.append (p);
219 }
220
221 w->setFocus();
222 }
223 }
224 }
225 }
226}
227
228void VBoxVMSettingsDlg::getFromMachine (const CMachine &aMachine)
229{
230 mMachine = aMachine;
231
232 setWindowTitle (aMachine.GetName() + tr (" - Settings"));
233
234 CVirtualBox vbox = vboxGlobal().virtualBox();
235
236 /* General Page */
237 VBoxVMSettingsGeneral::getFromMachine (aMachine, mPageGeneral,
238 this, pagePath (mPageGeneral));
239
240 /* HD */
241 VBoxVMSettingsHD::getFromMachine (aMachine, mPageHD,
242 this, pagePath (mPageHD));
243
244 /* CD */
245 VBoxVMSettingsCD::getFromMachine (aMachine, mPageCD,
246 this, pagePath (mPageCD));
247
248 /* FD */
249 VBoxVMSettingsFD::getFromMachine (aMachine, mPageFD,
250 this, pagePath (mPageFD));
251
252 /* Audio */
253 VBoxVMSettingsAudio::getFromMachine (aMachine, mPageAudio);
254
255 /* Network */
256 VBoxVMSettingsNetwork::getFromMachine (aMachine, mPageNetwork,
257 this, pagePath (mPageNetwork));
258
259 /* Serial Ports */
260 VBoxVMSettingsSerial::getFromMachine (aMachine, mPageSerial,
261 this, pagePath (mPageSerial));
262
263 /* Parallel Ports */
264 VBoxVMSettingsParallel::getFromMachine (aMachine, mPageParallel,
265 this, pagePath (mPageParallel));
266
267 /* USB */
268 VBoxVMSettingsUSB::getFromMachine (aMachine, mPageUSB,
269 this, pagePath (mPageUSB));
270
271 /* Shared Folders */
272 VBoxVMSettingsSF::getFromMachineEx (aMachine, mPageShared, this);
273
274 /* Vrdp */
275 VBoxVMSettingsVRDP::getFromMachine (aMachine, mPageVrdp,
276 this, pagePath (mPageVrdp));
277
278 /* Finally set the reset First Run Wizard flag to "false" to make sure
279 * user will see this dialog if he hasn't change the boot-order
280 * and/or mounted images configuration */
281 mResetFirstRunFlag = false;
282}
283
284
285COMResult VBoxVMSettingsDlg::putBackToMachine()
286{
287 CVirtualBox vbox = vboxGlobal().virtualBox();
288
289 /* General Page */
290 VBoxVMSettingsGeneral::putBackToMachine();
291
292 /* HD */
293 VBoxVMSettingsHD::putBackToMachine();
294
295 /* CD */
296 VBoxVMSettingsCD::putBackToMachine();
297
298 /* FD */
299 VBoxVMSettingsFD::putBackToMachine();
300
301 /* Clear the "GUI_FirstRun" extra data key in case if the boot order
302 * and/or disk configuration were changed */
303 if (mResetFirstRunFlag)
304 mMachine.SetExtraData (VBoxDefs::GUI_FirstRun, QString::null);
305
306 /* Audio */
307 VBoxVMSettingsAudio::putBackToMachine();
308
309 /* Network */
310 VBoxVMSettingsNetwork::putBackToMachine();
311
312 /* Serial ports */
313 VBoxVMSettingsSerial::putBackToMachine();
314
315 /* Parallel ports */
316 VBoxVMSettingsParallel::putBackToMachine();
317
318 /* USB */
319 VBoxVMSettingsUSB::putBackToMachine();
320
321 /* Shared folders */
322 VBoxVMSettingsSF::putBackToMachineEx();
323
324 /* Vrdp */
325 VBoxVMSettingsVRDP::putBackToMachine();
326
327 return COMResult();
328}
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 Assert (aItem);
404 int id = aItem->text (1).toInt();
405 Assert (id >= 0);
406 mLbTitle->setText (::path (aItem));
407 mPageStack->setCurrentIndex (id);
408}
409
410void VBoxVMSettingsDlg::updateWhatsThis (bool gotFocus /* = false */)
411{
412 QString text;
413
414 QWidget *widget = 0;
415 if (!gotFocus)
416 {
417 if (mWhatsThisCandidate && mWhatsThisCandidate != this)
418 widget = mWhatsThisCandidate;
419 }
420 else
421 {
422 widget = QApplication::focusWidget();
423 }
424 /* If the given widget lacks the whats'this text, look at its parent */
425 while (widget && widget != this)
426 {
427 text = widget->whatsThis();
428 if (!text.isEmpty())
429 break;
430 widget = widget->parentWidget();
431 }
432
433 if (text.isEmpty() && !mWarnString.isEmpty())
434 text = mWarnString;
435 if (text.isEmpty())
436 text = whatsThis();
437
438 mLbWhatsThis->setText (text);
439}
440
441void VBoxVMSettingsDlg::resetFirstRunFlag()
442{
443 if (mAllowResetFirstRunFlag)
444 mResetFirstRunFlag = true;
445}
446
447void VBoxVMSettingsDlg::whatsThisCandidateDestroyed (QObject *aObj /*= NULL*/)
448{
449 /* sanity */
450 Assert (mWhatsThisCandidate == aObj);
451
452 if (mWhatsThisCandidate == aObj)
453 mWhatsThisCandidate = NULL;
454}
455
456bool VBoxVMSettingsDlg::eventFilter (QObject *aObject, QEvent *aEvent)
457{
458 if (!aObject->isWidgetType())
459 return QDialog::eventFilter (aObject, aEvent);
460
461 QWidget *widget = static_cast<QWidget*> (aObject);
462 if (widget->topLevelWidget() != this)
463 return QDialog::eventFilter (aObject, aEvent);
464
465 switch (aEvent->type())
466 {
467 case QEvent::Enter:
468 case QEvent::Leave:
469 {
470 if (aEvent->type() == QEvent::Enter)
471 {
472 /* What if Qt sends Enter w/o Leave... */
473 if (mWhatsThisCandidate)
474 disconnect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
475 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
476
477 mWhatsThisCandidate = widget;
478 /* make sure we don't reference a deleted object after the
479 * timer is shot */
480 connect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
481 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
482 }
483 else
484 {
485 /* cleanup */
486 if (mWhatsThisCandidate)
487 disconnect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
488 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
489 mWhatsThisCandidate = NULL;
490 }
491
492 mWhatsThisTimer->start (100);
493 break;
494 }
495 case QEvent::FocusIn:
496 {
497 updateWhatsThis (true /* gotFocus */);
498 break;
499 }
500 default:
501 break;
502 }
503
504 return QDialog::eventFilter (aObject, aEvent);
505}
506
507void VBoxVMSettingsDlg::showEvent (QShowEvent *aEvent)
508{
509 QDialog::showEvent (aEvent);
510
511 /* One may think that QWidget::polish() is the right place to do things
512 * below, but apparently, by the time when QWidget::polish() is called,
513 * the widget style & layout are not fully done, at least the minimum
514 * size hint is not properly calculated. Since this is sometimes necessary,
515 * we provide our own "polish" implementation. */
516
517 if (mPolished)
518 return;
519
520 mPolished = true;
521
522 /* resize to the minimum possible size */
523 resize (minimumSize());
524
525 VBoxGlobal::centerWidget (this, parentWidget());
526}
527
528/**
529 * Returns a path to the given page of this settings dialog. See ::path() for
530 * details.
531 */
532QString VBoxVMSettingsDlg::pagePath (QWidget *aPage)
533{
534 QTreeWidgetItem *li =
535 findItem (mTwSelector,
536 QString ("%1")
537 .arg (mPageStack->indexOf (aPage), 2, 10, QChar ('0')),
538 1);
539 return ::path (li);
540}
541
542void VBoxVMSettingsDlg::setWarning (const QString &aWarning)
543{
544 mWarnString = aWarning;
545 if (!aWarning.isEmpty())
546 mWarnString = QString ("<font color=red>%1</font>").arg (aWarning);
547
548 if (!mWarnString.isEmpty())
549 mLbWhatsThis->setText (mWarnString);
550 else
551 updateWhatsThis (true);
552}
553
Note: See TracBrowser for help on using the repository browser.

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