VirtualBox

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

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

FE/Qt4: Use QIWidthRetranslateUI at all places.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 18.6 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/* 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 : QIWithRetranslateUI<QIMainDialog> (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#ifndef Q_WS_MAC
104 setWindowIcon (QIcon (":/settings_16px.png"));
105#endif /* Q_WS_MAC */
106
107 mWarnIconLabel = new VBoxWarnIconLabel();
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 /* Applying language settings */
227 retranslateUi();
228}
229
230void VBoxVMSettingsDlg::getFromMachine (const CMachine &aMachine)
231{
232 mMachine = aMachine;
233
234 setWindowTitle (dialogTitle());
235
236 CVirtualBox vbox = vboxGlobal().virtualBox();
237
238 /* General Page */
239 VBoxVMSettingsGeneral::getFromMachine (aMachine, mPageGeneral,
240 this, pagePath (mPageGeneral));
241
242 /* HD */
243 VBoxVMSettingsHD::getFromMachine (aMachine, mPageHD,
244 this, pagePath (mPageHD));
245
246 /* CD */
247 VBoxVMSettingsCD::getFromMachine (aMachine, mPageCD,
248 this, pagePath (mPageCD));
249
250 /* FD */
251 VBoxVMSettingsFD::getFromMachine (aMachine, mPageFD,
252 this, pagePath (mPageFD));
253
254 /* Audio */
255 VBoxVMSettingsAudio::getFromMachine (aMachine, mPageAudio);
256
257 /* Network */
258 VBoxVMSettingsNetwork::getFromMachine (aMachine, mPageNetwork,
259 this, pagePath (mPageNetwork));
260
261 /* Serial Ports */
262 VBoxVMSettingsSerial::getFromMachine (aMachine, mPageSerial,
263 this, pagePath (mPageSerial));
264
265 /* Parallel Ports */
266 VBoxVMSettingsParallel::getFromMachine (aMachine, mPageParallel,
267 this, pagePath (mPageParallel));
268
269 /* USB */
270 VBoxVMSettingsUSB::getFromMachine (aMachine, mPageUSB,
271 this, pagePath (mPageUSB));
272
273 /* Shared Folders */
274 VBoxVMSettingsSF::getFromMachineEx (aMachine, mPageShared, this);
275
276 /* Vrdp */
277 VBoxVMSettingsVRDP::getFromMachine (aMachine, mPageVrdp,
278 this, pagePath (mPageVrdp));
279
280 /* Finally set the reset First Run Wizard flag to "false" to make sure
281 * user will see this dialog if he hasn't change the boot-order
282 * and/or mounted images configuration */
283 mResetFirstRunFlag = false;
284}
285
286COMResult VBoxVMSettingsDlg::putBackToMachine()
287{
288 CVirtualBox vbox = vboxGlobal().virtualBox();
289
290 /* General Page */
291 VBoxVMSettingsGeneral::putBackToMachine();
292
293 /* HD */
294 VBoxVMSettingsHD::putBackToMachine();
295
296 /* CD */
297 VBoxVMSettingsCD::putBackToMachine();
298
299 /* FD */
300 VBoxVMSettingsFD::putBackToMachine();
301
302 /* Clear the "GUI_FirstRun" extra data key in case if the boot order
303 * and/or disk configuration were changed */
304 if (mResetFirstRunFlag)
305 mMachine.SetExtraData (VBoxDefs::GUI_FirstRun, QString::null);
306
307 /* Audio */
308 VBoxVMSettingsAudio::putBackToMachine();
309
310 /* Network */
311 VBoxVMSettingsNetwork::putBackToMachine();
312
313 /* Serial ports */
314 VBoxVMSettingsSerial::putBackToMachine();
315
316 /* Parallel ports */
317 VBoxVMSettingsParallel::putBackToMachine();
318
319 /* USB */
320 VBoxVMSettingsUSB::putBackToMachine();
321
322 /* Shared folders */
323 VBoxVMSettingsSF::putBackToMachineEx();
324
325 /* Vrdp */
326 VBoxVMSettingsVRDP::putBackToMachine();
327
328 return COMResult();
329}
330
331
332void VBoxVMSettingsDlg::retranslateUi()
333{
334 /* Unfortunately retranslateUi clears the QTreeWidget to do the
335 * translation. So save the current selected index. */
336 int ci = mPageStack->currentIndex();
337 /* Translate uic generated strings */
338 Ui::VBoxVMSettingsDlg::retranslateUi (this);
339 /* Set the old index */
340 mTwSelector->setCurrentItem (mTwSelector->topLevelItem (ci));
341
342 mWarnIconLabel->setWarningText (tr ("Invalid settings detected"));
343 mButtonBox->button (QDialogButtonBox::Ok)->setWhatsThis (tr ("Accepts (saves) changes and closes the dialog."));
344 mButtonBox->button (QDialogButtonBox::Cancel)->setWhatsThis (tr ("Cancels changes and closes the dialog."));
345 mButtonBox->button (QDialogButtonBox::Help)->setWhatsThis (tr ("Displays the dialog help."));
346
347 setWindowTitle (dialogTitle());
348
349 /* We have to make sure that the Serial & Network subpages are retranslated
350 * before they are revalidated. Cause: They do string comparing within
351 * vboxGlobal which is retranslated at that point already. */
352 QEvent* event = new QEvent (QEvent::LanguageChange);
353 qApp->sendEvent (mPageSerial, event);
354 qApp->sendEvent (mPageNetwork, event);
355
356 /* Revalidate all pages to retranslate the warning messages also. */
357 QList<QIWidgetValidator*> l = this->findChildren<QIWidgetValidator*>();
358 foreach (QIWidgetValidator *wval, l)
359 if (!wval->isValid())
360 revalidate (wval);
361}
362
363void VBoxVMSettingsDlg::enableOk (const QIWidgetValidator*)
364{
365 setWarning (QString::null);
366 QString wvalWarning;
367
368 /* Detect the overall validity */
369 bool newValid = true;
370 {
371 QList<QIWidgetValidator*> l = this->findChildren<QIWidgetValidator*>();
372 foreach (QIWidgetValidator *wval, l)
373 {
374 newValid = wval->isValid();
375 if (!newValid)
376 {
377 wvalWarning = wval->warningText();
378 break;
379 }
380 }
381 }
382
383 if (mWarnString.isNull() && !wvalWarning.isNull())
384 {
385 /* Try to set the generic error message when invalid but no specific
386 * message is provided */
387 setWarning (wvalWarning);
388 }
389
390 if (mValid != newValid)
391 {
392 mValid = newValid;
393 mButtonBox->button (QDialogButtonBox::Ok)->setEnabled (mValid);
394 mWarnIconLabel->setVisible (!mValid);
395 }
396}
397
398void VBoxVMSettingsDlg::revalidate (QIWidgetValidator *aWval)
399{
400 /* do individual validations for pages */
401 QWidget *pg = aWval->widget();
402 bool valid = aWval->isOtherValid();
403
404 QString warningText;
405 QString pageTitle = pagePath (pg);
406
407 if (pg == mPageHD)
408 valid = VBoxVMSettingsHD::revalidate (warningText);
409 else if (pg == mPageCD)
410 valid = VBoxVMSettingsCD::revalidate (warningText);
411 else if (pg == mPageFD)
412 valid = VBoxVMSettingsFD::revalidate (warningText);
413 else if (pg == mPageNetwork)
414 valid = VBoxVMSettingsNetwork::revalidate (warningText, pageTitle);
415 else if (pg == mPageSerial)
416 valid = VBoxVMSettingsSerial::revalidate (warningText, pageTitle);
417 else if (pg == mPageParallel)
418 valid = VBoxVMSettingsParallel::revalidate (warningText, pageTitle);
419
420 if (!valid)
421 setWarning (tr ("%1 on the <b>%2</b> page.")
422 .arg (warningText, pageTitle));
423
424 aWval->setOtherValid (valid);
425}
426
427void VBoxVMSettingsDlg::onMediaEnumerationDone()
428{
429 mAllowResetFirstRunFlag = true;
430}
431
432void VBoxVMSettingsDlg::settingsGroupChanged (QTreeWidgetItem *aItem,
433 QTreeWidgetItem *)
434{
435 if (aItem)
436 {
437 int id = aItem->text (1).toInt();
438 Assert (id >= 0);
439 mLbTitle->setText (::path (aItem));
440 mPageStack->setCurrentIndex (id);
441 }
442}
443
444void VBoxVMSettingsDlg::updateWhatsThis (bool gotFocus /* = false */)
445{
446 QString text;
447
448 QWidget *widget = 0;
449 if (!gotFocus)
450 {
451 if (mWhatsThisCandidate && mWhatsThisCandidate != this)
452 widget = mWhatsThisCandidate;
453 }
454 else
455 {
456 widget = QApplication::focusWidget();
457 }
458 /* If the given widget lacks the whats'this text, look at its parent */
459 while (widget && widget != this)
460 {
461 text = widget->whatsThis();
462 if (!text.isEmpty())
463 break;
464 widget = widget->parentWidget();
465 }
466
467 if (text.isEmpty() && !mWarnString.isEmpty())
468 text = mWarnString;
469 if (text.isEmpty())
470 text = whatsThis();
471
472 mLbWhatsThis->setText (text);
473}
474
475void VBoxVMSettingsDlg::resetFirstRunFlag()
476{
477 if (mAllowResetFirstRunFlag)
478 mResetFirstRunFlag = true;
479}
480
481void VBoxVMSettingsDlg::whatsThisCandidateDestroyed (QObject *aObj /*= NULL*/)
482{
483 /* sanity */
484 Assert (mWhatsThisCandidate == aObj);
485
486 if (mWhatsThisCandidate == aObj)
487 mWhatsThisCandidate = NULL;
488}
489
490bool VBoxVMSettingsDlg::eventFilter (QObject *aObject, QEvent *aEvent)
491{
492 if (!aObject->isWidgetType())
493 return QIMainDialog::eventFilter (aObject, aEvent);
494
495 QWidget *widget = static_cast<QWidget*> (aObject);
496 if (widget->topLevelWidget() != this)
497 return QIMainDialog::eventFilter (aObject, aEvent);
498
499 switch (aEvent->type())
500 {
501 case QEvent::Enter:
502 case QEvent::Leave:
503 {
504 if (aEvent->type() == QEvent::Enter)
505 {
506 /* What if Qt sends Enter w/o Leave... */
507 if (mWhatsThisCandidate)
508 disconnect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
509 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
510
511 mWhatsThisCandidate = widget;
512 /* make sure we don't reference a deleted object after the
513 * timer is shot */
514 connect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
515 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
516 }
517 else
518 {
519 /* cleanup */
520 if (mWhatsThisCandidate)
521 disconnect (mWhatsThisCandidate, SIGNAL (destroyed (QObject *)),
522 this, SLOT (whatsThisCandidateDestroyed (QObject *)));
523 mWhatsThisCandidate = NULL;
524 }
525
526 mWhatsThisTimer->start (100);
527 break;
528 }
529 case QEvent::FocusIn:
530 {
531 updateWhatsThis (true /* gotFocus */);
532 break;
533 }
534 default:
535 break;
536 }
537
538 return QIMainDialog::eventFilter (aObject, aEvent);
539}
540
541void VBoxVMSettingsDlg::showEvent (QShowEvent *aEvent)
542{
543 QIMainDialog::showEvent (aEvent);
544
545 /* One may think that QWidget::polish() is the right place to do things
546 * below, but apparently, by the time when QWidget::polish() is called,
547 * the widget style & layout are not fully done, at least the minimum
548 * size hint is not properly calculated. Since this is sometimes necessary,
549 * we provide our own "polish" implementation. */
550
551 if (mPolished)
552 return;
553
554 mPolished = true;
555
556 /* resize to the minimum possible size */
557 resize (minimumSize());
558
559 VBoxGlobal::centerWidget (this, parentWidget());
560}
561
562/**
563 * Returns a path to the given page of this settings dialog. See ::path() for
564 * details.
565 */
566QString VBoxVMSettingsDlg::pagePath (QWidget *aPage)
567{
568 QTreeWidgetItem *li =
569 findItem (mTwSelector,
570 QString ("%1")
571 .arg (mPageStack->indexOf (aPage), 2, 10, QChar ('0')),
572 1);
573 return ::path (li);
574}
575
576void VBoxVMSettingsDlg::setWarning (const QString &aWarning)
577{
578 mWarnString = aWarning;
579 if (!aWarning.isEmpty())
580 mWarnString = QString ("<font color=red>%1</font>").arg (aWarning);
581
582 if (!mWarnString.isEmpty())
583 mLbWhatsThis->setText (mWarnString);
584 else
585 updateWhatsThis (true);
586}
587
588QString VBoxVMSettingsDlg::dialogTitle() const
589{
590 QString dialogTitle;
591 if (!mMachine.isNull())
592 dialogTitle = tr ("%1 - Settings").arg (mMachine.GetName());
593 return dialogTitle;
594}
595
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