3
* VBox frontends: Qt4 GUI ("VirtualBox"):
4
* VBoxVMSettingsSystem class implementation
8
* Copyright (C) 2008-2009 Sun Microsystems, Inc.
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.
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.
23
#include "QIWidgetValidator.h"
24
#include "VBoxVMSettingsSystem.h"
26
#define ITEM_TYPE_ROLE Qt::UserRole + 1
29
* Calculates a suitable page step size for the given max value. The returned
30
* size is so that there will be no more than 32 pages. The minimum returned
33
static int calcPageStep (int aMax)
35
/* reasonable max. number of page steps is 32 */
36
uint page = ((uint) aMax + 31) / 32;
37
/* make it a power of 2 */
38
uint p = page, p2 = 0x1;
48
VBoxVMSettingsSystem::VBoxVMSettingsSystem()
50
/* Apply UI decorations */
51
Ui::VBoxVMSettingsSystem::setupUi (this);
54
CSystemProperties sys = vboxGlobal().virtualBox().GetSystemProperties();
55
const uint MinRAM = sys.GetMinGuestRAM();
56
const uint MaxRAM = sys.GetMaxGuestRAM();
57
const uint MinCPU = sys.GetMinGuestCPUCount();
58
const uint MaxCPU = sys.GetMaxGuestCPUCount();
60
/* Setup validators */
61
mLeMemory->setValidator (new QIntValidator (MinRAM, MaxRAM, this));
62
mLeCPU->setValidator (new QIntValidator (MinCPU, MaxCPU, this));
64
/* Setup connections */
65
connect (mSlMemory, SIGNAL (valueChanged (int)),
66
this, SLOT (valueChangedRAM (int)));
67
connect (mLeMemory, SIGNAL (textChanged (const QString&)),
68
this, SLOT (textChangedRAM (const QString&)));
70
connect (mTbBootItemUp, SIGNAL (clicked()),
71
this, SLOT (moveBootItemUp()));
72
connect (mTbBootItemDown, SIGNAL (clicked()),
73
this, SLOT (moveBootItemDown()));
74
connect (mTwBootOrder, SIGNAL (moveItemUp()),
75
this, SLOT (moveBootItemUp()));
76
connect (mTwBootOrder, SIGNAL (moveItemDown()),
77
this, SLOT (moveBootItemDown()));
78
connect (mTwBootOrder, SIGNAL (itemToggled()),
79
this, SIGNAL (tableChanged()));
80
connect (mTwBootOrder, SIGNAL (currentItemChanged (QTreeWidgetItem*,
82
this, SLOT (onCurrentBootItemChanged (QTreeWidgetItem*,
85
connect (mSlCPU, SIGNAL (valueChanged (int)),
86
this, SLOT (valueChangedCPU (int)));
87
connect (mLeCPU, SIGNAL (textChanged (const QString&)),
88
this, SLOT (textChangedCPU (const QString&)));
91
mTbBootItemUp->setIcon (VBoxGlobal::iconSet (":/list_moveup_16px.png",
92
":/list_moveup_disabled_16px.png"));
93
mTbBootItemDown->setIcon (VBoxGlobal::iconSet (":/list_movedown_16px.png",
94
":/list_movedown_disabled_16px.png"));
96
/* Setup memory slider */
97
mSlMemory->setPageStep (calcPageStep (MaxRAM));
98
mSlMemory->setSingleStep (mSlMemory->pageStep() / 4);
99
mSlMemory->setTickInterval (mSlMemory->pageStep());
100
/* Setup the scale so that ticks are at page step boundaries */
101
mSlMemory->setMinimum ((MinRAM / mSlMemory->pageStep()) * mSlMemory->pageStep());
102
mSlMemory->setMaximum (MaxRAM);
103
/* Limit min/max. size of QLineEdit */
104
mLeMemory->setFixedWidthByText (QString().fill ('8', 5));
105
/* Ensure mLeMemory value and validation is updated */
106
valueChangedRAM (mSlMemory->value());
108
/* Setup cpu slider */
109
mSlCPU->setPageStep (1);
110
mSlCPU->setSingleStep (1);
111
mSlCPU->setTickInterval (1);
112
/* Setup the scale so that ticks are at page step boundaries */
113
mSlCPU->setMinimum (MinCPU);
114
mSlCPU->setMaximum (MaxCPU);
115
/* Limit min/max. size of QLineEdit */
116
mLeCPU->setFixedWidthByText (QString().fill ('8', 3));
117
/* Ensure mLeMemory value and validation is updated */
118
valueChangedCPU (mSlCPU->value());
120
/* Install global event filter */
121
qApp->installEventFilter (this);
123
/* Applying language settings */
127
bool VBoxVMSettingsSystem::isHWVirtExEnabled() const
129
return mCbVirt->isChecked();
132
int VBoxVMSettingsSystem::cpuCount() const
134
return mSlCPU->value();
137
void VBoxVMSettingsSystem::getFrom (const CMachine &aMachine)
140
CBIOSSettings biosSettings = mMachine.GetBIOSSettings();
143
mSlMemory->setValue (aMachine.GetMemorySize());
147
mTwBootOrder->clear();
148
/* Load boot-items of current VM */
149
QStringList uniqueList;
150
for (int i = 1; i <= 4; ++ i)
152
KDeviceType type = mMachine.GetBootOrder (i);
153
if (type != KDeviceType_Null)
155
QString name = vboxGlobal().toString (type);
156
QTreeWidgetItem *item =
157
new QTreeWidgetItem (mTwBootOrder, QStringList (name));
158
QVariant vtype (type);
159
item->setData (0, ITEM_TYPE_ROLE, vtype);
160
item->setCheckState (0, Qt::Checked);
164
/* Load other unique boot-items */
165
for (int i = KDeviceType_Floppy; i < KDeviceType_USB; ++ i)
167
QString name = vboxGlobal().toString ((KDeviceType) i);
168
if (!uniqueList.contains (name))
170
QTreeWidgetItem *item =
171
new QTreeWidgetItem (mTwBootOrder, QStringList (name));
172
item->setData (0, ITEM_TYPE_ROLE, i);
173
item->setCheckState (0, Qt::Unchecked);
177
adjustBootOrderTWSize();
181
mCbAcpi->setChecked (biosSettings.GetACPIEnabled());
184
mCbApic->setChecked (biosSettings.GetIOAPICEnabled());
187
bool fVTxAMDVSupported = vboxGlobal().virtualBox().GetHost()
188
.GetProcessorFeature (KProcessorFeature_HWVirtEx);
189
mSlCPU->setEnabled (fVTxAMDVSupported);
190
mLeCPU->setEnabled (fVTxAMDVSupported);
191
mSlCPU->setValue (fVTxAMDVSupported ? aMachine.GetCPUCount() : 1);
194
bool fPAESupported = vboxGlobal().virtualBox().GetHost()
195
.GetProcessorFeature (KProcessorFeature_PAE);
196
mCbPae->setEnabled (fPAESupported);
197
mCbPae->setChecked (aMachine.GetPAEEnabled());
200
mCbVirt->setEnabled (fVTxAMDVSupported);
201
mCbVirt->setChecked (aMachine.GetHWVirtExEnabled());
204
mCbNestedPaging->setEnabled (fVTxAMDVSupported &&
205
aMachine.GetHWVirtExEnabled());
206
mCbNestedPaging->setChecked (aMachine.GetHWVirtExNestedPagingEnabled());
209
mValidator->revalidate();
212
void VBoxVMSettingsSystem::putBackTo()
214
CBIOSSettings biosSettings = mMachine.GetBIOSSettings();
217
mMachine.SetMemorySize (mSlMemory->value());
221
/* Search for checked items */
224
for (int i = 0; i < mTwBootOrder->topLevelItemCount(); ++ i)
226
QTreeWidgetItem *item = mTwBootOrder->topLevelItem (i);
227
if (item->checkState (0) == Qt::Checked)
229
KDeviceType type = vboxGlobal().toDeviceType (item->text (0));
230
mMachine.SetBootOrder (index ++, type);
234
/* Search for non-checked items */
235
for (int i = 0; i < mTwBootOrder->topLevelItemCount(); ++ i)
237
QTreeWidgetItem *item = mTwBootOrder->topLevelItem (i);
238
if (item->checkState (0) != Qt::Checked)
239
mMachine.SetBootOrder (index ++, KDeviceType_Null);
244
biosSettings.SetACPIEnabled (mCbAcpi->isChecked());
247
biosSettings.SetIOAPICEnabled (mCbApic->isChecked() ||
248
mSlCPU->value() > 1);
251
mMachine.SetCPUCount (mSlCPU->value());
254
mMachine.SetPAEEnabled (mCbPae->isChecked());
257
mMachine.SetHWVirtExEnabled (mCbVirt->checkState() == Qt::Checked ||
258
mSlCPU->value() > 1);
261
mMachine.SetHWVirtExNestedPagingEnabled (mCbNestedPaging->isChecked());
264
void VBoxVMSettingsSystem::setValidator (QIWidgetValidator *aVal)
267
connect (mCbApic, SIGNAL (stateChanged (int)), mValidator, SLOT (revalidate()));
268
connect (mCbVirt, SIGNAL (stateChanged (int)), mValidator, SLOT (revalidate()));
271
bool VBoxVMSettingsSystem::revalidate (QString &aWarning, QString & /* aTitle */)
273
/* Come up with some nice round percent boundraries relative to
274
* the system memory. A max of 75% on a 256GB config is ridiculous,
275
* even on an 8GB rig reserving 2GB for the OS is way to conservative.
276
* The max numbers can be estimated using the following program:
278
* double calcMaxPct(uint64_t cbRam)
280
* double cbRamOverhead = cbRam * 0.0390625; // 160 bytes per page.
281
* double cbRamForTheOS = RT_MAX(RT_MIN(_512M, cbRam * 0.25), _64M);
282
* double OSPct = (cbRamOverhead + cbRamForTheOS) * 100.0 / cbRam;
283
* double MaxPct = 100 - OSPct;
289
* uint64_t cbRam = _1G;
290
* for (; !(cbRam >> 33); cbRam += _1G)
291
* printf("%8lluGB %.1f%% %8lluKB\n", cbRam >> 30, calcMaxPct(cbRam),
292
* (uint64_t)(cbRam * calcMaxPct(cbRam) / 100.0) >> 20);
293
* for (; !(cbRam >> 51); cbRam <<= 1)
294
* printf("%8lluGB %.1f%% %8lluKB\n", cbRam >> 30, calcMaxPct(cbRam),
295
* (uint64_t)(cbRam * calcMaxPct(cbRam) / 100.0) >> 20);
299
* Note. We might wanna put these calculations somewhere global later. */
301
/* System RAM amount test */
302
ulong fullSize = vboxGlobal().virtualBox().GetHost().GetMemorySize();
303
double maxPct = 0.75;
304
double warnPct = 0.50;
307
else if (fullSize < 4096) /* 3GB */
309
else if (fullSize < 6144) /* 4-5GB */
314
else if (fullSize < 8192) /* 6-7GB */
319
else if (fullSize < 16384) /* 8-15GB */
324
else if (fullSize < 32768) /* 16-31GB */
329
else if (fullSize < 65536) /* 32-63GB */
334
else if (fullSize < 131072) /* 64-127GB */
345
if (mSlMemory->value() > maxPct * fullSize)
348
"you have assigned more than <b>%1%</b> of your computer's memory "
349
"(<b>%2</b>) to the virtual machine. Not enough memory is left "
350
"for your host operating system. Please select a smaller amount.")
351
.arg ((unsigned)(maxPct * 100))
352
.arg (vboxGlobal().formatSize ((uint64_t)fullSize * _1M));
355
if (mSlMemory->value() > warnPct * fullSize)
358
"you have assigned more than <b>%1%</b> of your computer's memory "
359
"(<b>%2</b>) to the virtual machine. Not enough memory might be "
360
"left for your host operating system. Continue at your own risk.")
361
.arg ((unsigned)(warnPct * 100))
362
.arg (vboxGlobal().formatSize ((uint64_t)fullSize * _1M));
366
/* VCPU amount test */
367
int totalCPUs = vboxGlobal().virtualBox().GetHost().GetProcessorOnlineCount();
368
if (mSlCPU->value() > 2 * totalCPUs)
371
"for performance reasons, the number of virtual CPUs attached to the "
372
"virtual machine may not be more than twice the number of physical "
373
"CPUs on the host (<b>%1</b>). Please reduce the number of virtual CPUs.")
377
if (mSlCPU->value() > totalCPUs)
380
"you have assigned more virtual CPUs to the virtual machine than "
381
"the number of physical CPUs on your host system (<b>%1</b>). "
382
"This is likely to degrade the performance of your virtual machine. "
383
"Please consider reducing the number of virtual CPUs.")
388
/* VCPU IO-APIC test */
389
if (mSlCPU->value() > 1 && !mCbApic->isChecked())
392
"you have assigned more than one virtual CPU to this VM. "
393
"This will not work unless the IO-APIC feature is also enabled. "
394
"This will be done automatically when you accept the VM Settings "
395
"by pressing the OK button.");
399
/* VCPU VT-x/AMD-V test */
400
if (mSlCPU->value() > 1 && !mCbVirt->isChecked())
403
"you have assigned more than one virtual CPU to this VM. "
404
"This will not work unless hardware virtualization (VT-x/AMD-V) is also enabled. "
405
"This will be done automatically when you accept the VM Settings "
406
"by pressing the OK button.");
413
void VBoxVMSettingsSystem::setOrderAfter (QWidget *aWidget)
415
setTabOrder (aWidget, mTwSystem->focusProxy());
416
setTabOrder (mTwSystem->focusProxy(), mSlMemory);
417
setTabOrder (mSlMemory, mLeMemory);
418
setTabOrder (mLeMemory, mTwBootOrder);
419
setTabOrder (mTwBootOrder, mTbBootItemUp);
420
setTabOrder (mTbBootItemUp, mTbBootItemDown);
421
setTabOrder (mTbBootItemDown, mCbAcpi);
422
setTabOrder (mCbAcpi, mCbApic);
424
setTabOrder (mCbApic, mSlCPU);
425
setTabOrder (mSlCPU, mLeCPU);
426
setTabOrder (mLeCPU, mCbPae);
428
setTabOrder (mCbPae, mCbVirt);
429
setTabOrder (mCbVirt, mCbNestedPaging);
432
void VBoxVMSettingsSystem::retranslateUi()
434
/* Translate uic generated strings */
435
Ui::VBoxVMSettingsSystem::retranslateUi (this);
437
/* Adjust the boot order tree widget */
438
mTwBootOrder->header()->setResizeMode (QHeaderView::ResizeToContents);
439
mTwBootOrder->resizeColumnToContents (0);
440
mTwBootOrder->updateGeometry();
441
/* Retranslate the boot order items */
442
QTreeWidgetItemIterator it (mTwBootOrder);
445
QTreeWidgetItem *item = (*it);
446
item->setText (0, vboxGlobal().toString (
447
static_cast <KDeviceType> (item->data (0, ITEM_TYPE_ROLE).toInt())));
450
/* Readjust the tree widget items size */
451
adjustBootOrderTWSize();
453
CSystemProperties sys = vboxGlobal().virtualBox().GetSystemProperties();
455
/* Retranslate the memory slider legend */
456
mLbMemoryMin->setText (tr ("<qt>%1 MB</qt>").arg (sys.GetMinGuestRAM()));
457
mLbMemoryMax->setText (tr ("<qt>%1 MB</qt>").arg (sys.GetMaxGuestRAM()));
459
/* Retranslate the cpu slider legend */
460
mLbCPUMin->setText (tr ("<qt>%1 CPU</qt>", "%1 is 1 for now").arg (sys.GetMinGuestCPUCount()));
461
mLbCPUMax->setText (tr ("<qt>%1 CPUs</qt>", "%1 is 32 for now").arg (sys.GetMaxGuestCPUCount()));
464
void VBoxVMSettingsSystem::valueChangedRAM (int aVal)
466
mLeMemory->setText (QString().setNum (aVal));
469
void VBoxVMSettingsSystem::textChangedRAM (const QString &aText)
471
mSlMemory->setValue (aText.toInt());
474
void VBoxVMSettingsSystem::moveBootItemUp()
476
QTreeWidgetItem *item = mTwBootOrder->currentItem();
478
if (!mTwBootOrder->itemAbove (item))
481
int index = mTwBootOrder->indexOfTopLevelItem (item);
482
QTreeWidgetItem *takenItem = mTwBootOrder->takeTopLevelItem (index);
483
Assert (takenItem == item);
485
mTwBootOrder->insertTopLevelItem (index - 1, takenItem);
486
mTwBootOrder->setCurrentItem (item);
491
void VBoxVMSettingsSystem::moveBootItemDown()
493
QTreeWidgetItem *item = mTwBootOrder->currentItem();
495
if (!mTwBootOrder->itemBelow (item))
498
int index = mTwBootOrder->indexOfTopLevelItem (item);
499
QTreeWidgetItem *takenItem = mTwBootOrder->takeTopLevelItem (index);
500
Assert (takenItem == item);
502
mTwBootOrder->insertTopLevelItem (index + 1, takenItem);
503
mTwBootOrder->setCurrentItem (item);
508
void VBoxVMSettingsSystem::onCurrentBootItemChanged (QTreeWidgetItem *aItem,
511
bool upEnabled = aItem && mTwBootOrder->itemAbove (aItem);
512
bool downEnabled = aItem && mTwBootOrder->itemBelow (aItem);
513
if ((mTbBootItemUp->hasFocus() && !upEnabled) ||
514
(mTbBootItemDown->hasFocus() && !downEnabled))
515
mTwBootOrder->setFocus();
516
mTbBootItemUp->setEnabled (upEnabled);
517
mTbBootItemDown->setEnabled (downEnabled);
520
void VBoxVMSettingsSystem::adjustBootOrderTWSize()
522
/* Calculate the optimal size of the tree widget & set it as fixed
525
QAbstractItemView *iv = qobject_cast <QAbstractItemView*> (mTwBootOrder);
527
mTwBootOrder->setFixedSize (
528
iv->sizeHintForColumn (0) + 2 * mTwBootOrder->frameWidth() + 4,
529
iv->sizeHintForRow (0) * mTwBootOrder->topLevelItemCount() + 2 * mTwBootOrder->frameWidth());
531
/* Update the layout system */
532
if (mTabMotherboard->layout())
534
mTabMotherboard->layout()->activate();
535
mTabMotherboard->layout()->update();
539
void VBoxVMSettingsSystem::valueChangedCPU (int aVal)
541
mLeCPU->setText (QString().setNum (aVal));
544
void VBoxVMSettingsSystem::textChangedCPU (const QString &aText)
546
mSlCPU->setValue (aText.toInt());
549
bool VBoxVMSettingsSystem::eventFilter (QObject *aObject, QEvent *aEvent)
551
if (!aObject->isWidgetType())
552
return QWidget::eventFilter (aObject, aEvent);
554
QWidget *widget = static_cast<QWidget*> (aObject);
555
if (widget->window() != window())
556
return QWidget::eventFilter (aObject, aEvent);
558
switch (aEvent->type())
560
case QEvent::FocusIn:
563
if (widget == mTwBootOrder)
565
if (!mTwBootOrder->currentItem())
566
mTwBootOrder->setCurrentItem (mTwBootOrder->topLevelItem (0));
568
onCurrentBootItemChanged (mTwBootOrder->currentItem());
569
mTwBootOrder->currentItem()->setSelected (true);
571
else if (widget != mTbBootItemUp && widget != mTbBootItemDown)
573
if (mTwBootOrder->currentItem())
575
mTwBootOrder->currentItem()->setSelected (false);
576
mTbBootItemUp->setEnabled (false);
577
mTbBootItemDown->setEnabled (false);
586
return QWidget::eventFilter (aObject, aEvent);