VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/ui/VBoxNewHDWzd.ui.h@ 2578

Last change on this file since 2578 was 2578, checked in by vboxsync, 18 years ago

1764: Better default size in "Create VDI" wizard when called from "Create VM" wizard:

Own QLabel implementation to adjust QLabel::sizeHint automatically just before the label to be shown to avoid setting up the minimum width for the label. This label is used for both New VM & New HD Wizards.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.9 KB
Line 
1/**
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * "New hard disk" wizard UI include (Qt Designer)
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/****************************************************************************
24** ui.h extension file, included from the uic-generated form implementation.
25**
26** If you want to add, delete, or rename functions or slots, use
27** Qt Designer to update this file, preserving your code.
28**
29** You should not define a constructor or destructor in this file.
30** Instead, write your code in functions called init() and destroy().
31** These will automatically be called by the form's constructor and
32** destructor.
33*****************************************************************************/
34
35/** Minimum VDI size in MB */
36static const Q_UINT64 MinVDISize = 4;
37
38/** Initial VDI size in MB */
39static const Q_UINT64 InitialVDISize = 2 * _1K;
40
41/**
42 * Composes a file name from the given relative or full file name
43 * based on the home directory and the default VDI directory.
44 */
45static QString composeFullFileName (const QString file)
46{
47 CVirtualBox vbox = vboxGlobal().virtualBox();
48 QString homeFolder = vbox.GetHomeFolder();
49 QString defaultFolder = vbox.GetSystemProperties().GetDefaultVDIFolder();
50
51 QFileInfo fi = QFileInfo (file);
52 if (fi.fileName() == file)
53 {
54 /* no path info at all, use defaultFolder */
55 fi = QFileInfo (defaultFolder, file);
56 }
57 else if (fi.isRelative())
58 {
59 /* resolve relatively to homeFolder */
60 fi = QFileInfo (homeFolder, file);
61 }
62
63 return QDir::convertSeparators (fi.absFilePath());
64}
65
66/// @todo (r=dmik) not currently used
67#if 0
68class QISizeValidator : public QValidator
69{
70public:
71
72 QISizeValidator (QObject * aParent,
73 Q_UINT64 aMinSize, Q_UINT64 aMaxSize,
74 const char * aName = 0) :
75 QValidator (aParent, aName), mMinSize (aMinSize), mMaxSize (aMaxSize) {}
76
77 ~QISizeValidator() {}
78
79 State validate (QString &input, int &/*pos*/) const
80 {
81 QRegExp regexp ("^([^M^G^T^P^\\d\\s]*)(\\d+(([^\\s^\\d^M^G^T^P]+)(\\d*))?)?(\\s*)([MGTP]B?)?$");
82 int position = regexp.search (input);
83 if (position == -1)
84 return Invalid;
85 else
86 {
87 if (!regexp.cap (1).isEmpty() ||
88 regexp.cap (4).length() > 1 ||
89 regexp.cap (5).length() > 2 ||
90 regexp.cap (6).length() > 1)
91 return Invalid;
92
93 if (regexp.cap (7).length() == 1)
94 return Intermediate;
95
96 QString size = regexp.cap (2);
97 if (size.isEmpty())
98 return Intermediate;
99
100 bool result = false;
101 bool warning = false;
102 if (!regexp.cap (4).isEmpty() && regexp.cap (5).isEmpty())
103 {
104 size += "0";
105 warning = true;
106 }
107 QLocale::system().toDouble (size, &result);
108
109 Q_UINT64 sizeB = vboxGlobal().parseSize (input);
110 if (sizeB > mMaxSize || sizeB < mMinSize)
111 warning = true;
112
113 if (result)
114 return warning ? Intermediate : Acceptable;
115 else
116 return Invalid;
117 }
118 }
119
120protected:
121
122 Q_UINT64 mMinSize;
123 Q_UINT64 mMaxSize;
124};
125#endif
126
127static inline int log2i (Q_UINT64 val)
128{
129 Q_UINT64 n = val;
130 int pow = -1;
131 while (n)
132 {
133 ++ pow;
134 n >>= 1;
135 }
136 return pow;
137}
138
139static inline int sizeMBToSlider (Q_UINT64 val, int sliderScale)
140{
141 int pow = log2i (val);
142 Q_UINT64 tickMB = Q_UINT64 (1) << pow;
143 Q_UINT64 tickMBNext = Q_UINT64 (1) << (pow + 1);
144 int step = (val - tickMB) * sliderScale / (tickMBNext - tickMB);
145 return pow * sliderScale + step;
146}
147
148static inline Q_UINT64 sliderToSizeMB (int val, int sliderScale)
149{
150 int pow = val / sliderScale;
151 int step = val % sliderScale;
152 Q_UINT64 tickMB = Q_UINT64 (1) << pow;
153 Q_UINT64 tickMBNext = Q_UINT64 (1) << (pow + 1);
154 return tickMB + (tickMBNext - tickMB) * step / sliderScale;
155}
156
157void VBoxNewHDWzd::init()
158{
159 /* Wizard labels recreation */
160
161 QILabel *txWelcome = new QILabel (pageWelcome, "txWelcome");
162 txWelcome->setText (tr ("<p>This wizard will help you to create a new "
163 "virtual hard disk image for your virtual "
164 "machine.</p>\n""<p>Use the <b>Next</b> button to "
165 "go to the next page of the wizard\n""and the "
166 "<b>Back</b> button to return to the previous "
167 "page.</p>"));
168 layout33->insertWidget (0, txWelcome);
169
170 QILabel *textLabel1_2 = new QILabel (pageType, "textLabel1_2");
171 textLabel1_2->setText (tr ("<p>Select the type of virtual hard disk image "
172 "you want to create.</p>\n""<p>A "
173 "<b>dynamically expanding image</b> initially "
174 "occupies a very small amount\n""of space on "
175 "your physical hard disk. It will grow "
176 "dynamically (up to\n""the size specified) as "
177 "the Guest OS claims disk space.</p>\n""<p>A "
178 "<b>fixed-size image</b> does not grow. It is "
179 "stored in a file of approximately\n""the same "
180 "size as the size of the virtual hard "
181 "disk.</p>"));
182 layout12->insertWidget (0, textLabel1_2);
183
184 QILabel *txNameComment = new QILabel (pageNameAndSize, "txNameComment");
185 txNameComment->setText (tr ("<p>Press the <b>Select</b> button to select "
186 "the location and name of the file\n""to "
187 "store the virtual hard disk image or type a "
188 "file name in the entry field.</p>"));
189 layout36->insertWidget (0, txNameComment);
190
191 QILabel *txSizeComment = new QILabel (pageNameAndSize, "txSizeComment" );
192 txSizeComment->setText (tr ("<p>Select the size of the virtual hard disk "
193 "image in megabytes. This size will be "
194 "reported to the Guest OS\n""as the size of "
195 "the virtual hard disk.</p>"));
196 layout36->insertWidget (2, txSizeComment);
197
198 QILabel *txSummaryHdr = new QILabel (pageSummary, "txSummaryHdr");
199 txSummaryHdr->setText (tr ("You are going to create a new virtual hard "
200 "disk image with the following parameters:"));
201 summaryLayout->insertWidget (0, txSummaryHdr);
202
203 QILabel *txSummaryFtr = new QILabel (pageSummary, "txSummaryFtr");
204 txSummaryFtr->setText (tr ("If the above settings are correct, press the "
205 "<b>Finish</b> button.\n"
206 " Once you press "
207 "it, a new hard disk image will be created.\n"
208 " "));
209
210 /* disable help buttons */
211 helpButton()->setShown (false);
212
213 /* fix tab order to get the proper direction
214 * (originally the focus goes Next/Finish -> Back -> Cancel -> page) */
215 QWidget::setTabOrder (backButton(), nextButton());
216 QWidget::setTabOrder (nextButton(), finishButton());
217 QWidget::setTabOrder (finishButton(), cancelButton());
218
219 /* setup connections and set validation for pages
220 * ---------------------------------------------------------------------- */
221
222 /* setup the label clolors for nice scaling */
223 VBoxGlobal::adoptLabelPixmap (pmWelcome);
224 VBoxGlobal::adoptLabelPixmap (pmType);
225 VBoxGlobal::adoptLabelPixmap (pmNameAndSize);
226 VBoxGlobal::adoptLabelPixmap (pmSummary);
227
228 /* Image type page */
229
230 /* Name and Size page */
231
232 CSystemProperties sysProps = vboxGlobal().virtualBox().GetSystemProperties();
233
234 maxVDISize = sysProps.GetMaxVDISize();
235
236 /* Detect how many steps to recognize between adjacent powers of 2
237 * to ensure that the last slider step is exactly maxVDISize */
238 sliderScale = 0;
239 {
240 int pow = log2i (maxVDISize);
241 Q_UINT64 tickMB = Q_UINT64 (1) << pow;
242 if (tickMB < maxVDISize)
243 {
244 Q_UINT64 tickMBNext = Q_UINT64 (1) << (pow + 1);
245 Q_UINT64 gap = tickMBNext - maxVDISize;
246 /// @todo (r=dmik) overflow may happen if maxVDISize is TOO big
247 sliderScale = (int) ((tickMBNext - tickMB) / gap);
248 }
249 }
250 sliderScale = QMAX (sliderScale, 8);
251
252 leName->setValidator (new QRegExpValidator (QRegExp( ".+" ), this));
253
254 leSize->setValidator (new QRegExpValidator (vboxGlobal().sizeRegexp(), this));
255 leSize->setAlignment (Qt::AlignRight);
256
257 wvalNameAndSize = new QIWidgetValidator (pageNameAndSize, this);
258 connect (wvalNameAndSize, SIGNAL (validityChanged (const QIWidgetValidator *)),
259 this, SLOT (enableNext (const QIWidgetValidator *)));
260 connect (wvalNameAndSize, SIGNAL (isValidRequested (QIWidgetValidator *)),
261 this, SLOT (revalidate (QIWidgetValidator *)));
262 /* we ask revalidate only when currentSize is changed after manually
263 * editing the line edit field; the slider cannot produce invalid values */
264 connect (leSize, SIGNAL (textChanged (const QString &)),
265 wvalNameAndSize, SLOT (revalidate()));
266
267 /* Summary page */
268
269 teSummary = new QITextEdit (pageSummary);
270 teSummary->setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum);
271 teSummary->setFrameShape (QTextEdit::NoFrame);
272 teSummary->setReadOnly (TRUE);
273 summaryLayout->insertWidget (1, teSummary);
274 summaryLayout->insertWidget (2, txSummaryFtr);
275
276 /* filter out Enter keys in order to direct them to the default dlg button */
277 QIKeyFilter *ef = new QIKeyFilter (this, Key_Enter);
278 ef->watchOn (teSummary);
279
280 /* set initial values
281 * ---------------------------------------------------------------------- */
282
283 /* Image type page */
284
285 /* Name and Size page */
286
287 static ulong HDNumber = 0;
288 leName->setText (QString ("NewHardDisk%1.vdi").arg (++ HDNumber));
289
290 slSize->setFocusPolicy (QWidget::StrongFocus);
291 slSize->setPageStep (sliderScale);
292 slSize->setLineStep (sliderScale / 8);
293 slSize->setTickInterval (0);
294 slSize->setMinValue (sizeMBToSlider (MinVDISize, sliderScale));
295 slSize->setMaxValue (sizeMBToSlider (maxVDISize, sliderScale));
296
297 txSizeMin->setText (vboxGlobal().formatSize (MinVDISize * _1M));
298 txSizeMax->setText (vboxGlobal().formatSize (maxVDISize * _1M));
299
300 /* limit the max. size of QLineEdit (STUPID Qt has NO correct means for that) */
301 leSize->setMaximumSize (
302 leSize->fontMetrics().width ("88888.88 MB") + leSize->frameWidth() * 2,
303 leSize->height());
304
305 setRecommendedSize (InitialVDISize);
306
307 /* Summary page */
308
309 teSummary->setPaper (pageSummary->backgroundBrush());
310
311 /* update the next button state for pages with validation
312 * (validityChanged() connected to enableNext() will do the job) */
313 wvalNameAndSize->revalidate();
314
315 /* the finish button on the Summary page is always enabled */
316 setFinishEnabled (pageSummary, true);
317}
318
319
320void VBoxNewHDWzd::showEvent (QShowEvent *e)
321{
322 QDialog::showEvent (e);
323
324 /* one may think that QWidget::polish() is the right place to do things
325 * below, but apparently, by the time when QWidget::polish() is called,
326 * the widget style & layout are not fully done, at least the minimum
327 * size hint is not properly calculated. Since this is sometimes necessary,
328 * we provide our own "polish" implementation. */
329
330 layout()->activate();
331
332 /* resize to the miminum possible size */
333 resize (minimumSize());
334
335 VBoxGlobal::centerWidget (this, parentWidget());
336}
337
338
339void VBoxNewHDWzd::setRecommendedFileName (const QString &aName)
340{
341 leName->setText (aName);
342}
343
344
345void VBoxNewHDWzd::setRecommendedSize (Q_UINT64 aSize)
346{
347 AssertReturnVoid (aSize >= MinVDISize && aSize <= maxVDISize);
348 currentSize = aSize;
349 slSize->setValue (sizeMBToSlider (currentSize, sliderScale));
350 leSize->setText (vboxGlobal().formatSize (currentSize * _1M));
351 updateSizeToolTip (currentSize * _1M);
352}
353
354
355QString VBoxNewHDWzd::imageFileName()
356{
357 QString name = QDir::convertSeparators (leName->text());
358
359 /* remove all trailing dots to avoid multiple dots before .vdi */
360 int len;
361 while (len = name.length(), len > 0 && name [len - 1] == '.')
362 name.truncate (len - 1);
363
364 QString ext = QFileInfo (name).extension();
365 /* compare against the proper case */
366#if defined (Q_OS_LINUX)
367#elif defined (Q_OS_WIN) || defined (Q_OS_OS2) || defined (Q_OS_MACX)
368 ext = ext.lower();
369#else
370 #error Port me!
371#endif
372
373 if (ext != "vdi")
374 name += ".vdi";
375
376 return name;
377}
378
379
380Q_UINT64 VBoxNewHDWzd::imageSize()
381{
382 return currentSize;
383}
384
385
386bool VBoxNewHDWzd::isDynamicImage()
387{
388 return rbDynamicType->isOn();
389}
390
391
392void VBoxNewHDWzd::enableNext (const QIWidgetValidator *wval)
393{
394 setNextEnabled (wval->widget(), wval->isValid());
395}
396
397
398void VBoxNewHDWzd::revalidate (QIWidgetValidator *wval)
399{
400 /* do individual validations for pages */
401
402 QWidget *pg = wval->widget();
403 bool valid = wval->isOtherValid();
404
405 if (pg == pageNameAndSize)
406 {
407 valid = currentSize >= MinVDISize && currentSize <= maxVDISize;
408 }
409
410 wval->setOtherValid (valid);
411}
412
413
414void VBoxNewHDWzd::updateSizeToolTip (Q_UINT64 sizeB)
415{
416 QString tip = tr ("<nobr>%1 Bytes</nobr>").arg (sizeB);
417 QToolTip::add (slSize, tip);
418 QToolTip::add (leSize, tip);
419}
420
421void VBoxNewHDWzd::showPage( QWidget *page )
422{
423 if (currentPage() == pageNameAndSize)
424 {
425 if (QFileInfo (imageFileName()).exists())
426 {
427 vboxProblem().sayCannotOverwriteHardDiskImage (this, imageFileName());
428 return;
429 }
430 }
431
432 if (page == pageSummary)
433 {
434 QString type = rbDynamicType->isOn() ? rbDynamicType->text()
435 : rbFixedType->text();
436 type.remove ('&');
437
438 Q_UINT64 sizeB = imageSize() * _1M;
439
440 // compose summary
441 QString summary = QString (tr(
442 "<table>"
443 "<tr><td>Type:</td><td>%1</td></tr>"
444 "<tr><td>Location:</td><td>%2</td></tr>"
445 "<tr><td>Size:</td><td>%3&nbsp;(%4&nbsp;Bytes)</td></tr>"
446 "</table>"
447 ))
448 .arg (type)
449 .arg (composeFullFileName (imageFileName()))
450 .arg (VBoxGlobal::formatSize (sizeB))
451 .arg (sizeB);
452 teSummary->setText (summary);
453 /* set Finish to default */
454 finishButton()->setDefault (true);
455 }
456 else
457 {
458 /* always set Next to default */
459 nextButton()->setDefault (true);
460 }
461
462 QWizard::showPage (page);
463
464 /* fix focus on the last page. when we go to the last page
465 * having the Next in focus the focus goes to the Cancel
466 * button because when the Next hides Finish is not yet shown. */
467 if (page == pageSummary && focusWidget() == cancelButton())
468 finishButton()->setFocus();
469
470 /* setup focus for individual pages */
471 if (page == pageType)
472 {
473 bgType->setFocus();
474 }
475 else if (page == pageNameAndSize)
476 {
477 leName->setFocus();
478 }
479 else if (page == pageSummary)
480 {
481 teSummary->setFocus();
482 }
483
484 page->layout()->activate();
485}
486
487
488void VBoxNewHDWzd::accept()
489{
490 /*
491 * Try to create the hard disk when the Finish button is pressed.
492 * On failure, the wisard will remain open to give it another try.
493 */
494 if (createHardDisk())
495 QWizard::accept();
496}
497
498/**
499 * Performs steps necessary to create a hard disk. This method handles all
500 * errors and shows the corresponding messages when appropriate.
501 *
502 * @return wheter the creation was successful or not
503 */
504bool VBoxNewHDWzd::createHardDisk()
505{
506 QString src = imageFileName();
507 Q_UINT64 size = imageSize();
508
509 AssertReturn (!src.isEmpty(), false);
510 AssertReturn (size > 0, false);
511
512 CVirtualBox vbox = vboxGlobal().virtualBox();
513
514 CProgress progress;
515 CHardDisk hd = vbox.CreateHardDisk (CEnums::VirtualDiskImage);
516
517 /// @todo (dmik) later, change wrappers so that converting
518 // to CUnknown is not necessary for cross-assignments
519 CVirtualDiskImage vdi = CUnknown (hd);
520
521 if (!vbox.isOk())
522 {
523 vboxProblem().cannotCreateHardDiskImage (this,
524 vbox, src, vdi, progress);
525 return false;
526 }
527
528 vdi.SetFilePath (src);
529
530 if (isDynamicImage())
531 progress = vdi.CreateDynamicImage (size);
532 else
533 progress = vdi.CreateFixedImage (size);
534
535 if (!vdi.isOk())
536 {
537 vboxProblem().cannotCreateHardDiskImage (this,
538 vbox, src, vdi, progress);
539 return false;
540 }
541
542 vboxProblem().showModalProgressDialog (progress, caption(), parentWidget());
543
544 if (progress.GetResultCode() != 0)
545 {
546 vboxProblem().cannotCreateHardDiskImage (this,
547 vbox, src, vdi, progress);
548 return false;
549 }
550
551 vbox.RegisterHardDisk (hd);
552 if (!vbox.isOk())
553 {
554 vboxProblem().cannotRegisterMedia (this, vbox, VBoxDefs::HD,
555 vdi.GetFilePath());
556 /* delete the image file on failure */
557 vdi.DeleteImage();
558 return false;
559 }
560
561 chd = hd;
562 return true;
563}
564
565
566void VBoxNewHDWzd::slSize_valueChanged( int val )
567{
568 if (focusWidget() == slSize)
569 {
570 currentSize = sliderToSizeMB (val, sliderScale);
571 leSize->setText (vboxGlobal().formatSize (currentSize * _1M));
572 updateSizeToolTip (currentSize * _1M);
573 }
574}
575
576
577void VBoxNewHDWzd::leSize_textChanged( const QString &text )
578{
579 if (focusWidget() == leSize)
580 {
581 currentSize = vboxGlobal().parseSize (text);
582 updateSizeToolTip (currentSize);
583 currentSize /= _1M;
584 slSize->setValue (sizeMBToSlider (currentSize, sliderScale));
585 }
586}
587
588
589void VBoxNewHDWzd::tbNameSelect_clicked()
590{
591 /* set the first parent directory that exists as the current */
592 QFileInfo fld (composeFullFileName (leName->text()));
593 do
594 {
595 QString dp = fld.dirPath (false);
596 fld = QFileInfo (dp);
597 }
598 while (!fld.exists() && !QDir (fld.absFilePath()).isRoot());
599
600 if (!fld.exists())
601 {
602 CVirtualBox vbox = vboxGlobal().virtualBox();
603 fld = QFileInfo (vbox.GetSystemProperties().GetDefaultVDIFolder());
604 if (!fld.exists())
605 fld = vbox.GetHomeFolder();
606 }
607
608// QFileDialog fd (this, "NewDiskImageDialog", TRUE);
609// fd.setMode (QFileDialog::AnyFile);
610// fd.setViewMode (QFileDialog::List);
611// fd.addFilter (tr( "Hard disk images (*.vdi)" ));
612// fd.setCaption (tr( "Select a file for the new hard disk image file" ));
613// fd.setDir (d);
614
615 QString selected = QFileDialog::getSaveFileName (
616 fld.absFilePath(),
617 tr ("Hard disk images (*.vdi)"),
618 this,
619 "NewDiskImageDialog",
620 tr ("Select a file for the new hard disk image file"));
621
622// if ( fd.exec() == QDialog::Accepted ) {
623// leName->setText (QDir::convertSeparators (fd.selectedFile()));
624 if (selected)
625 {
626 if (QFileInfo (selected).extension().isEmpty())
627 selected += ".vdi";
628 leName->setText (QDir::convertSeparators (selected));
629 leName->selectAll();
630 leName->setFocus();
631 }
632}
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