VirtualBox

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

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

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

These changes related both to NewVM and NewHD wizards.

  1. Labels sizeHint calculation based on minimum QLabel width. In case of there is no minimum QLabel width predefined – sizeHint calculation leads to wrong dialog height (dialog could be very tall).
  2. Own QTextEdit implementation with sizeHint based on contained text.
  3. The color of the dialog’s picture background is set to the color of the picture’s last pixel. So it is possible to vertically resize dialog & picture simultaneously.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 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 /* disable help buttons */
160 helpButton()->setShown (false);
161
162 /* fix tab order to get the proper direction
163 * (originally the focus goes Next/Finish -> Back -> Cancel -> page) */
164 QWidget::setTabOrder (backButton(), nextButton());
165 QWidget::setTabOrder (nextButton(), finishButton());
166 QWidget::setTabOrder (finishButton(), cancelButton());
167
168 /* setup connections and set validation for pages
169 * ---------------------------------------------------------------------- */
170
171 /* setup the pictures background color */
172 VBoxGlobal::fillPixmapBackGrd (pmWelcome);
173 VBoxGlobal::fillPixmapBackGrd (pmType);
174 VBoxGlobal::fillPixmapBackGrd (pmNameAndSize);
175 VBoxGlobal::fillPixmapBackGrd (pmSummary);
176
177 /* Image type page */
178
179 /* Name and Size page */
180
181 CSystemProperties sysProps = vboxGlobal().virtualBox().GetSystemProperties();
182
183 maxVDISize = sysProps.GetMaxVDISize();
184
185 /* Detect how many steps to recognize between adjacent powers of 2
186 * to ensure that the last slider step is exactly maxVDISize */
187 sliderScale = 0;
188 {
189 int pow = log2i (maxVDISize);
190 Q_UINT64 tickMB = Q_UINT64 (1) << pow;
191 if (tickMB < maxVDISize)
192 {
193 Q_UINT64 tickMBNext = Q_UINT64 (1) << (pow + 1);
194 Q_UINT64 gap = tickMBNext - maxVDISize;
195 /// @todo (r=dmik) overflow may happen if maxVDISize is TOO big
196 sliderScale = (int) ((tickMBNext - tickMB) / gap);
197 }
198 }
199 sliderScale = QMAX (sliderScale, 8);
200
201 leName->setValidator (new QRegExpValidator (QRegExp( ".+" ), this));
202
203 leSize->setValidator (new QRegExpValidator (vboxGlobal().sizeRegexp(), this));
204 leSize->setAlignment (Qt::AlignRight);
205
206 wvalNameAndSize = new QIWidgetValidator (pageNameAndSize, this);
207 connect (wvalNameAndSize, SIGNAL (validityChanged (const QIWidgetValidator *)),
208 this, SLOT (enableNext (const QIWidgetValidator *)));
209 connect (wvalNameAndSize, SIGNAL (isValidRequested (QIWidgetValidator *)),
210 this, SLOT (revalidate (QIWidgetValidator *)));
211 /* we ask revalidate only when currentSize is changed after manually
212 * editing the line edit field; the slider cannot produce invalid values */
213 connect (leSize, SIGNAL (textChanged (const QString &)),
214 wvalNameAndSize, SLOT (revalidate()));
215
216 /* Summary page */
217
218 teSummary = new VBoxTextView (pageSummary);
219 teSummary->setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum);
220 teSummary->setFrameShape (QTextEdit::NoFrame);
221 teSummary->setReadOnly (TRUE);
222 summaryLayout->insertWidget (1, teSummary);
223
224 /* filter out Enter keys in order to direct them to the default dlg button */
225 QIKeyFilter *ef = new QIKeyFilter (this, Key_Enter);
226 ef->watchOn (teSummary);
227
228 /* set initial values
229 * ---------------------------------------------------------------------- */
230
231 /* Image type page */
232
233 /* Name and Size page */
234
235 static ulong HDNumber = 0;
236 leName->setText (QString ("NewHardDisk%1.vdi").arg (++ HDNumber));
237
238 slSize->setFocusPolicy (QWidget::StrongFocus);
239 slSize->setPageStep (sliderScale);
240 slSize->setLineStep (sliderScale / 8);
241 slSize->setTickInterval (0);
242 slSize->setMinValue (sizeMBToSlider (MinVDISize, sliderScale));
243 slSize->setMaxValue (sizeMBToSlider (maxVDISize, sliderScale));
244
245 txSizeMin->setText (vboxGlobal().formatSize (MinVDISize * _1M));
246 txSizeMax->setText (vboxGlobal().formatSize (maxVDISize * _1M));
247
248 /* limit the max. size of QLineEdit (STUPID Qt has NO correct means for that) */
249 leSize->setMaximumSize (
250 leSize->fontMetrics().width ("88888.88 MB") + leSize->frameWidth() * 2,
251 leSize->height());
252
253 setRecommendedSize (InitialVDISize);
254
255 /* Summary page */
256
257 teSummary->setPaper (pageSummary->backgroundBrush());
258
259 /* update the next button state for pages with validation
260 * (validityChanged() connected to enableNext() will do the job) */
261 wvalNameAndSize->revalidate();
262
263 /* the finish button on the Summary page is always enabled */
264 setFinishEnabled (pageSummary, true);
265
266 /* setup minimum width for the sizeHint to be calculated correctly */
267 int wid = widthSpacer->minimumSize().width();
268 txWelcome->setMinimumWidth (wid);
269 textLabel1_2->setMinimumWidth (wid);
270 txNameComment->setMinimumWidth (wid);
271 txSizeComment->setMinimumWidth (wid);
272 txSummaryHdr->setMinimumWidth (wid);
273 txSummaryFtr->setMinimumWidth (wid);
274}
275
276
277void VBoxNewHDWzd::showEvent (QShowEvent *e)
278{
279 QDialog::showEvent (e);
280
281 /* one may think that QWidget::polish() is the right place to do things
282 * below, but apparently, by the time when QWidget::polish() is called,
283 * the widget style & layout are not fully done, at least the minimum
284 * size hint is not properly calculated. Since this is sometimes necessary,
285 * we provide our own "polish" implementation. */
286
287 layout()->activate();
288
289 /* resize to the miminum possible size */
290 resize (minimumSize());
291
292 VBoxGlobal::centerWidget (this, parentWidget());
293}
294
295
296void VBoxNewHDWzd::setRecommendedFileName (const QString &aName)
297{
298 leName->setText (aName);
299}
300
301
302void VBoxNewHDWzd::setRecommendedSize (Q_UINT64 aSize)
303{
304 AssertReturnVoid (aSize >= MinVDISize && aSize <= maxVDISize);
305 currentSize = aSize;
306 slSize->setValue (sizeMBToSlider (currentSize, sliderScale));
307 leSize->setText (vboxGlobal().formatSize (currentSize * _1M));
308 updateSizeToolTip (currentSize * _1M);
309}
310
311
312QString VBoxNewHDWzd::imageFileName()
313{
314 QString name = QDir::convertSeparators (leName->text());
315
316 /* remove all trailing dots to avoid multiple dots before .vdi */
317 int len;
318 while (len = name.length(), len > 0 && name [len - 1] == '.')
319 name.truncate (len - 1);
320
321 QString ext = QFileInfo (name).extension();
322 /* compare against the proper case */
323#if defined (Q_OS_LINUX)
324#elif defined (Q_OS_WIN) || defined (Q_OS_OS2) || defined (Q_OS_MACX)
325 ext = ext.lower();
326#else
327 #error Port me!
328#endif
329
330 if (ext != "vdi")
331 name += ".vdi";
332
333 return name;
334}
335
336
337Q_UINT64 VBoxNewHDWzd::imageSize()
338{
339 return currentSize;
340}
341
342
343bool VBoxNewHDWzd::isDynamicImage()
344{
345 return rbDynamicType->isOn();
346}
347
348
349void VBoxNewHDWzd::enableNext (const QIWidgetValidator *wval)
350{
351 setNextEnabled (wval->widget(), wval->isValid());
352}
353
354
355void VBoxNewHDWzd::revalidate (QIWidgetValidator *wval)
356{
357 /* do individual validations for pages */
358
359 QWidget *pg = wval->widget();
360 bool valid = wval->isOtherValid();
361
362 if (pg == pageNameAndSize)
363 {
364 valid = currentSize >= MinVDISize && currentSize <= maxVDISize;
365 }
366
367 wval->setOtherValid (valid);
368}
369
370
371void VBoxNewHDWzd::updateSizeToolTip (Q_UINT64 sizeB)
372{
373 QString tip = tr ("<nobr>%1 Bytes</nobr>").arg (sizeB);
374 QToolTip::add (slSize, tip);
375 QToolTip::add (leSize, tip);
376}
377
378void VBoxNewHDWzd::showPage( QWidget *page )
379{
380 if (currentPage() == pageNameAndSize)
381 {
382 if (QFileInfo (imageFileName()).exists())
383 {
384 vboxProblem().sayCannotOverwriteHardDiskImage (this, imageFileName());
385 return;
386 }
387 }
388
389 if (page == pageSummary)
390 {
391 QString type = rbDynamicType->isOn() ? rbDynamicType->text()
392 : rbFixedType->text();
393 type.remove ('&');
394
395 Q_UINT64 sizeB = imageSize() * _1M;
396
397 // compose summary
398 QString summary = QString (tr(
399 "<table>"
400 "<tr><td>Type:</td><td>%1</td></tr>"
401 "<tr><td>Location:</td><td>%2</td></tr>"
402 "<tr><td>Size:</td><td>%3&nbsp;(%4&nbsp;Bytes)</td></tr>"
403 "</table>"
404 ))
405 .arg (type)
406 .arg (composeFullFileName (imageFileName()))
407 .arg (VBoxGlobal::formatSize (sizeB))
408 .arg (sizeB);
409 teSummary->setText (summary);
410 /* set Finish to default */
411 finishButton()->setDefault (true);
412 }
413 else
414 {
415 /* always set Next to default */
416 nextButton()->setDefault (true);
417 }
418
419 QWizard::showPage (page);
420
421 /* fix focus on the last page. when we go to the last page
422 * having the Next in focus the focus goes to the Cancel
423 * button because when the Next hides Finish is not yet shown. */
424 if (page == pageSummary && focusWidget() == cancelButton())
425 finishButton()->setFocus();
426
427 /* setup focus for individual pages */
428 if (page == pageType)
429 {
430 bgType->setFocus();
431 }
432 else if (page == pageNameAndSize)
433 {
434 leName->setFocus();
435 }
436 else if (page == pageSummary)
437 {
438 teSummary->setFocus();
439 }
440
441 page->layout()->activate();
442}
443
444
445void VBoxNewHDWzd::accept()
446{
447 /*
448 * Try to create the hard disk when the Finish button is pressed.
449 * On failure, the wisard will remain open to give it another try.
450 */
451 if (createHardDisk())
452 QWizard::accept();
453}
454
455/**
456 * Performs steps necessary to create a hard disk. This method handles all
457 * errors and shows the corresponding messages when appropriate.
458 *
459 * @return wheter the creation was successful or not
460 */
461bool VBoxNewHDWzd::createHardDisk()
462{
463 QString src = imageFileName();
464 Q_UINT64 size = imageSize();
465
466 AssertReturn (!src.isEmpty(), false);
467 AssertReturn (size > 0, false);
468
469 CVirtualBox vbox = vboxGlobal().virtualBox();
470
471 CProgress progress;
472 CHardDisk hd = vbox.CreateHardDisk (CEnums::VirtualDiskImage);
473
474 /// @todo (dmik) later, change wrappers so that converting
475 // to CUnknown is not necessary for cross-assignments
476 CVirtualDiskImage vdi = CUnknown (hd);
477
478 if (!vbox.isOk())
479 {
480 vboxProblem().cannotCreateHardDiskImage (this,
481 vbox, src, vdi, progress);
482 return false;
483 }
484
485 vdi.SetFilePath (src);
486
487 if (isDynamicImage())
488 progress = vdi.CreateDynamicImage (size);
489 else
490 progress = vdi.CreateFixedImage (size);
491
492 if (!vdi.isOk())
493 {
494 vboxProblem().cannotCreateHardDiskImage (this,
495 vbox, src, vdi, progress);
496 return false;
497 }
498
499 vboxProblem().showModalProgressDialog (progress, caption(), parentWidget());
500
501 if (progress.GetResultCode() != 0)
502 {
503 vboxProblem().cannotCreateHardDiskImage (this,
504 vbox, src, vdi, progress);
505 return false;
506 }
507
508 vbox.RegisterHardDisk (hd);
509 if (!vbox.isOk())
510 {
511 vboxProblem().cannotRegisterMedia (this, vbox, VBoxDefs::HD,
512 vdi.GetFilePath());
513 /* delete the image file on failure */
514 vdi.DeleteImage();
515 return false;
516 }
517
518 chd = hd;
519 return true;
520}
521
522
523void VBoxNewHDWzd::slSize_valueChanged( int val )
524{
525 if (focusWidget() == slSize)
526 {
527 currentSize = sliderToSizeMB (val, sliderScale);
528 leSize->setText (vboxGlobal().formatSize (currentSize * _1M));
529 updateSizeToolTip (currentSize * _1M);
530 }
531}
532
533
534void VBoxNewHDWzd::leSize_textChanged( const QString &text )
535{
536 if (focusWidget() == leSize)
537 {
538 currentSize = vboxGlobal().parseSize (text);
539 updateSizeToolTip (currentSize);
540 currentSize /= _1M;
541 slSize->setValue (sizeMBToSlider (currentSize, sliderScale));
542 }
543}
544
545
546void VBoxNewHDWzd::tbNameSelect_clicked()
547{
548 /* set the first parent directory that exists as the current */
549 QFileInfo fld (composeFullFileName (leName->text()));
550 do
551 {
552 QString dp = fld.dirPath (false);
553 fld = QFileInfo (dp);
554 }
555 while (!fld.exists() && !QDir (fld.absFilePath()).isRoot());
556
557 if (!fld.exists())
558 {
559 CVirtualBox vbox = vboxGlobal().virtualBox();
560 fld = QFileInfo (vbox.GetSystemProperties().GetDefaultVDIFolder());
561 if (!fld.exists())
562 fld = vbox.GetHomeFolder();
563 }
564
565// QFileDialog fd (this, "NewDiskImageDialog", TRUE);
566// fd.setMode (QFileDialog::AnyFile);
567// fd.setViewMode (QFileDialog::List);
568// fd.addFilter (tr( "Hard disk images (*.vdi)" ));
569// fd.setCaption (tr( "Select a file for the new hard disk image file" ));
570// fd.setDir (d);
571
572 QString selected = QFileDialog::getSaveFileName (
573 fld.absFilePath(),
574 tr ("Hard disk images (*.vdi)"),
575 this,
576 "NewDiskImageDialog",
577 tr ("Select a file for the new hard disk image file"));
578
579// if ( fd.exec() == QDialog::Accepted ) {
580// leName->setText (QDir::convertSeparators (fd.selectedFile()));
581 if (selected)
582 {
583 if (QFileInfo (selected).extension().isEmpty())
584 selected += ".vdi";
585 leName->setText (QDir::convertSeparators (selected));
586 leName->selectAll();
587 leName->setFocus();
588 }
589}
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