3
* VBox frontends: Qt4 GUI ("VirtualBox"):
4
* VBoxNewHDWzd class implementation
8
* Copyright (C) 2006-2008 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 "VBoxNewHDWzd.h"
24
#include "VBoxGlobal.h"
25
#include "VBoxProblemReporter.h"
26
#include "iprt/path.h"
29
#include <QFileDialog>
32
/** Minimum VDI size in MB */
33
static const quint64 MinVDISize = 4;
35
/** Initial VDI size in MB */
36
static const quint64 InitialVDISize = 2 * _1K;
39
* Composes a file name from the given relative or full file name based on the
40
* home directory and the default VDI directory. See IMedum::location for
43
static QString composeFullFileName (const QString &aName)
45
CVirtualBox vbox = vboxGlobal().virtualBox();
46
QString homeFolder = vbox.GetHomeFolder();
47
QString defaultFolder = vbox.GetSystemProperties().GetDefaultHardDiskFolder();
49
/* Note: the logic below must match the logic of the IMedum::location
50
* setter, otherwise the returned path may differ from the path actually
51
* set for the hard disk by the VirtualBox API */
54
if (fi.fileName() == aName)
56
/* no path info at all, use defaultFolder */
57
fi = QFileInfo (defaultFolder, aName);
59
else if (fi.isRelative())
61
/* resolve relatively to homeFolder */
62
fi = QFileInfo (homeFolder, aName);
65
return QDir::toNativeSeparators (fi.absoluteFilePath());
68
static inline int log2i (quint64 val)
80
static inline int sizeMBToSlider (quint64 val, int aSliderScale)
82
int pow = log2i (val);
83
quint64 tickMB = quint64 (1) << pow;
84
quint64 tickMBNext = quint64 (1) << (pow + 1);
85
int step = (val - tickMB) * aSliderScale / (tickMBNext - tickMB);
86
return pow * aSliderScale + step;
89
static inline quint64 sliderToSizeMB (int val, int aSliderScale)
91
int pow = val / aSliderScale;
92
int step = val % aSliderScale;
93
quint64 tickMB = quint64 (1) << pow;
94
quint64 tickMBNext = quint64 (1) << (pow + 1);
95
return tickMB + (tickMBNext - tickMB) * step / aSliderScale;
99
////////////////////////////////////////////////////////////////////////////////
102
VBoxNewHDWzd::VBoxNewHDWzd (QWidget *aParent)
103
: QIWithRetranslateUI<QIAbstractWizard> (aParent)
105
/* Apply UI decorations */
106
Ui::VBoxNewHDWzd::setupUi (this);
108
/* Initialize wizard hdr */
109
initializeWizardHdr();
111
/* Storage type page */
113
/* Name and Size page */
114
CSystemProperties sysProps = vboxGlobal().virtualBox().GetSystemProperties();
115
mMaxVDISize = sysProps.GetMaxVDISize();
116
/* Detect how many steps to recognize between adjacent powers of 2
117
* to ensure that the last slider step is exactly mMaxVDISize */
120
int pow = log2i (mMaxVDISize);
121
quint64 tickMB = quint64 (1) << pow;
122
if (tickMB < mMaxVDISize)
124
quint64 tickMBNext = quint64 (1) << (pow + 1);
125
quint64 gap = tickMBNext - mMaxVDISize;
126
mSliderScale = (int) ((tickMBNext - tickMB) / gap);
129
mSliderScale = qMax (mSliderScale, 8);
130
mLeName->setValidator (new QRegExpValidator (QRegExp (".+"), this));
131
mLeSize->setValidator (new QRegExpValidator (QRegExp (vboxGlobal().sizeRegexp()), this));
132
mLeSize->setAlignment (Qt::AlignRight);
133
mWValNameAndSize = new QIWidgetValidator (mPageNameAndSize, this);
134
connect (mWValNameAndSize, SIGNAL (validityChanged (const QIWidgetValidator *)),
135
this, SLOT (enableNext (const QIWidgetValidator *)));
136
connect (mWValNameAndSize, SIGNAL (isValidRequested (QIWidgetValidator *)),
137
this, SLOT (revalidate (QIWidgetValidator *)));
138
connect (mLeSize, SIGNAL (textChanged (const QString &)),
139
mWValNameAndSize, SLOT (revalidate()));
140
connect (mTbNameSelect, SIGNAL (clicked()), this, SLOT (tbNameSelectClicked()));
141
connect (mSlSize, SIGNAL (valueChanged (int)), this, SLOT (slSizeValueChanged (int)));
142
connect (mLeSize, SIGNAL (textChanged (const QString&)),
143
this, SLOT (leSizeTextChanged (const QString&)));
147
/* Image type page */
149
/* Name and Size page */
150
/// @todo NEWMEDIA use extension as reported by CMediumFormat
151
static ulong HDNumber = 0;
152
mLeName->setText (QString ("NewHardDisk%1.vdi").arg (++ HDNumber));
153
mSlSize->setFocusPolicy (Qt::StrongFocus);
154
mSlSize->setPageStep (mSliderScale);
155
mSlSize->setSingleStep (mSliderScale / 8);
156
mSlSize->setTickInterval (0);
157
mSlSize->setMinimum (sizeMBToSlider (MinVDISize, mSliderScale));
158
mSlSize->setMaximum (sizeMBToSlider (mMaxVDISize, mSliderScale));
159
mTxSizeMin->setText (vboxGlobal().formatSize (MinVDISize * _1M));
160
mTxSizeMax->setText (vboxGlobal().formatSize (mMaxVDISize * _1M));
161
/* limit the max. size of QILineEdit */
162
mLeSize->setFixedWidthByText ("88888.88 MB");
163
setRecommendedSize (InitialVDISize);
166
/* Update the next button state for pages with validation
167
* (validityChanged() connected to enableNext() will do the job) */
168
mWValNameAndSize->revalidate();
170
/* Initialize wizard ftr */
171
initializeWizardFtr();
176
void VBoxNewHDWzd::setRecommendedFileName (const QString &aName)
178
mLeName->setText (aName);
181
void VBoxNewHDWzd::setRecommendedSize (quint64 aSize)
183
AssertReturnVoid (aSize >= MinVDISize && aSize <= mMaxVDISize);
184
mCurrentSize = aSize;
185
mSlSize->setValue (sizeMBToSlider (mCurrentSize, mSliderScale));
186
mLeSize->setText (vboxGlobal().formatSize (mCurrentSize * _1M));
187
updateSizeToolTip (mCurrentSize * _1M);
190
void VBoxNewHDWzd::retranslateUi()
192
/* Translate uic generated strings */
193
Ui::VBoxNewHDWzd::retranslateUi (this);
195
QWidget *page = mPageStack->currentWidget();
197
if (page == mPageSummary)
199
QString type = mRbDynamicType->isChecked() ? mRbDynamicType->text()
200
: mRbFixedType->text();
201
type = VBoxGlobal::removeAccelMark (type);
203
quint64 sizeB = mCurrentSize * _1M;
205
/* compose summary */
206
QString summary = QString (
208
"<tr><td><nobr>%1: </nobr></td><td><nobr>%2</nobr></td></tr>"
209
"<tr><td><nobr>%3: </nobr></td><td><nobr>%4</nobr></td></tr>"
210
"<tr><td><nobr>%5: </nobr></td><td><nobr>%6 (%7 %8)</nobr></td></tr>"
213
.arg (tr ("Type", "summary")).arg (type)
214
.arg (tr ("Location", "summary")).arg (composeFullFileName (location()))
215
.arg (tr ("Size", "summary")).arg (VBoxGlobal::formatSize (sizeB))
216
.arg (sizeB).arg (tr ("Bytes", "summary"));
218
mTeSummary->setText (summary);
222
void VBoxNewHDWzd::accept()
224
/* Try to create the hard disk when the Finish button is pressed.
225
* On failure, the wisard will remain open to give it another try. */
226
if (createHardDisk())
227
QIAbstractWizard::accept();
230
void VBoxNewHDWzd::slSizeValueChanged (int aVal)
232
if (focusWidget() == mSlSize)
234
mCurrentSize = sliderToSizeMB (aVal, mSliderScale);
235
mLeSize->setText (vboxGlobal().formatSize (mCurrentSize * _1M));
236
updateSizeToolTip (mCurrentSize * _1M);
240
void VBoxNewHDWzd::leSizeTextChanged (const QString &aText)
242
if (focusWidget() == mLeSize)
244
mCurrentSize = vboxGlobal().parseSize (aText);
245
updateSizeToolTip (mCurrentSize);
247
mSlSize->setValue (sizeMBToSlider (mCurrentSize, mSliderScale));
251
void VBoxNewHDWzd::tbNameSelectClicked()
253
/* set the first parent directory that exists as the current */
254
QFileInfo fld (composeFullFileName (mLeName->text()));
257
QString dp = fld.path ();
258
fld = QFileInfo (dp);
260
while (!fld.exists() && !QDir (fld.absoluteFilePath()).isRoot());
264
CVirtualBox vbox = vboxGlobal().virtualBox();
265
fld = QFileInfo (vbox.GetSystemProperties().GetDefaultHardDiskFolder());
267
fld = vbox.GetHomeFolder();
270
QString selected = QFileDialog::getSaveFileName (
272
tr ("Select a file for the new hard disk image file"),
273
fld.absoluteFilePath(),
274
tr ("Hard disk images (*.vdi)"));
276
if (!selected.isEmpty())
278
if (QFileInfo (selected).completeSuffix().isEmpty())
280
mLeName->setText (QDir::toNativeSeparators (selected));
281
mLeName->selectAll();
286
void VBoxNewHDWzd::revalidate (QIWidgetValidator *aWval)
288
/* do individual validations for pages */
289
bool valid = aWval->isOtherValid();
291
if (aWval == mWValNameAndSize)
292
valid = mCurrentSize >= MinVDISize && mCurrentSize <= mMaxVDISize;
294
aWval->setOtherValid (valid);
297
void VBoxNewHDWzd::enableNext (const QIWidgetValidator *aWval)
299
nextButton (aWval->widget())->setEnabled (aWval->isValid());
302
void VBoxNewHDWzd::onPageShow()
304
/* Make sure all is properly translated & composed */
307
QWidget *page = mPageStack->currentWidget();
309
if (page == mPageWelcome)
310
nextButton (page)->setFocus();
311
else if (page == mPageType)
312
mRbDynamicType->isChecked() ? mRbDynamicType->setFocus() :
313
mRbFixedType->setFocus();
314
else if (page == mPageNameAndSize)
316
else if (page == mPageSummary)
317
mTeSummary->setFocus();
319
if (page == mPageSummary)
320
finishButton()->setDefault (true);
322
nextButton (page)->setDefault (true);
325
void VBoxNewHDWzd::showNextPage()
327
/* Warn user about already present hard-disk */
328
if (sender() == mBtnNext3 &&
329
QFileInfo (location()).exists())
331
vboxProblem().sayCannotOverwriteHardDiskStorage (this, location());
335
/* Switch to the next page */
336
QIAbstractWizard::showNextPage();
340
QString VBoxNewHDWzd::location()
342
QString name = QDir::toNativeSeparators (mLeName->text());
344
/* remove all trailing dots to avoid multiple dots before .vdi */
346
while (len = name.length(), len > 0 && name [len - 1] == '.')
347
name.truncate (len - 1);
349
QString ext = QFileInfo (name).completeSuffix();
351
if (RTPathCompare (ext.toUtf8(), "vdi") != 0)
357
bool VBoxNewHDWzd::isDynamicStorage()
359
return mRbDynamicType->isChecked();
362
void VBoxNewHDWzd::updateSizeToolTip (quint64 aSizeB)
364
QString tip = tr ("<nobr>%1 Bytes</nobr>").arg (aSizeB);
365
mSlSize->setToolTip (tip);
366
mLeSize->setToolTip (tip);
370
* Performs steps necessary to create a hard disk. This method handles all
371
* errors and shows the corresponding messages when appropriate.
373
* @return Wheter the creation was successful or not.
375
bool VBoxNewHDWzd::createHardDisk()
377
KMediumVariant variant = KMediumVariant_Standard;
378
QString loc = location();
380
AssertReturn (!loc.isEmpty(), false);
381
AssertReturn (mCurrentSize > 0, false);
383
CVirtualBox vbox = vboxGlobal().virtualBox();
387
CMedium hd = vbox.CreateHardDisk(QString ("VDI"), loc);
391
vboxProblem().cannotCreateHardDiskStorage (this, vbox, loc, hd,
396
if (!isDynamicStorage())
397
variant = (KMediumVariant)(KMediumVariant_Standard | KMediumVariant_Fixed);
399
progress = hd.CreateBaseStorage (mCurrentSize, variant);
403
vboxProblem().cannotCreateHardDiskStorage (this, vbox, loc, hd,
408
vboxProblem().showModalProgressDialog (progress, windowTitle(), parentWidget());
410
if (progress.GetCanceled())
413
if (!progress.isOk() || progress.GetResultCode() != 0)
415
vboxProblem().cannotCreateHardDiskStorage (this, vbox, loc, hd,
420
/* Inform everybody there is a new medium */
421
vboxGlobal().addMedium (VBoxMedium (CMedium (hd),
422
VBoxDefs::MediumType_HardDisk,
423
KMediumState_Created));