VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumDetailsWidget.cpp@ 104158

Last change on this file since 104158 was 103710, checked in by vboxsync, 9 months ago

FE/Qt: Get rid of unwanted UICommon includes across whole the GUI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.7 KB
Line 
1/* $Id: UIMediumDetailsWidget.cpp 103710 2024-03-06 16:53:27Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMediumDetailsWidget class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QComboBox>
30#include <QLabel>
31#include <QPushButton>
32#include <QSlider>
33#include <QStackedLayout>
34#include <QStyle>
35#include <QTextEdit>
36#include <QVBoxLayout>
37
38/* GUI includes: */
39#include "QIDialogButtonBox.h"
40#include "QIFileDialog.h"
41#include "QILabel.h"
42#include "QILineEdit.h"
43#include "QITabWidget.h"
44#include "QIToolButton.h"
45#include "UIConverter.h"
46#include "UIIconPool.h"
47#include "UIMediumDetailsWidget.h"
48#include "UIMediumManager.h"
49#include "UIMediumSizeEditor.h"
50#include "UITranslator.h"
51
52/* COM includes: */
53#include "CSystemProperties.h"
54
55
56UIMediumDetailsWidget::UIMediumDetailsWidget(UIMediumManagerWidget *pParent, EmbedTo enmEmbedding)
57 : QIWithRetranslateUI<QWidget>(pParent)
58 , m_pParent(pParent)
59 , m_enmEmbedding(enmEmbedding)
60 , m_oldData(UIDataMedium())
61 , m_newData(UIDataMedium())
62 , m_pTabWidget(0)
63 , m_pLabelType(0), m_pComboBoxType(0), m_pErrorPaneType(0)
64 , m_pLabelLocation(0), m_pEditorLocation(0), m_pErrorPaneLocation(0), m_pButtonLocation(0)
65 , m_pLabelDescription(0), m_pEditorDescription(0), m_pErrorPaneDescription(0)
66 , m_pLabelSize(0), m_pEditorSize(0), m_pErrorPaneSize(0)
67 , m_pButtonBox(0)
68 , m_pProgressBar(0)
69 , m_fValid(true)
70 , m_pLayoutDetails(0)
71{
72 /* Prepare: */
73 prepare();
74}
75
76void UIMediumDetailsWidget::setCurrentType(UIMediumDeviceType enmType)
77{
78 /* If known type was requested => raise corresponding container: */
79 if (m_aContainers.contains(enmType))
80 m_pLayoutDetails->setCurrentWidget(infoContainer(enmType));
81}
82
83void UIMediumDetailsWidget::setData(const UIDataMedium &data)
84{
85 /* Cache old/new data: */
86 m_oldData = data;
87 m_newData = m_oldData;
88
89 /* Load options data: */
90 loadDataForOptions();
91 /* Load details data: */
92 loadDataForDetails();
93}
94
95void UIMediumDetailsWidget::enableDisableMediumModificationWidgets(bool fMediumIsModifiable)
96{
97 if (m_pComboBoxType)
98 m_pComboBoxType->setEnabled(fMediumIsModifiable);
99 if (m_pEditorLocation)
100 m_pEditorLocation->setEnabled(fMediumIsModifiable);
101 if (m_pEditorSize)
102 m_pEditorSize->setEnabled(fMediumIsModifiable);
103 if (m_pEditorDescription)
104 m_pEditorDescription->setEnabled(fMediumIsModifiable);
105}
106
107void UIMediumDetailsWidget::setOptionsEnabled(bool fEnabled)
108{
109 m_pTabWidget->widget(0)->setEnabled(fEnabled);
110}
111
112void UIMediumDetailsWidget::retranslateUi()
113{
114 /* Translate tab-widget: */
115 m_pTabWidget->setTabText(0, UIMediumManager::tr("&Attributes"));
116 m_pTabWidget->setTabText(1, UIMediumManager::tr("&Information"));
117
118 /* Translate 'Options' tab content. */
119
120 /* Translate labels: */
121 m_pLabelType->setText(UIMediumManager::tr("&Type:"));
122 m_pLabelLocation->setText(UIMediumManager::tr("&Location:"));
123 m_pLabelDescription->setText(UIMediumManager::tr("&Description:"));
124 m_pLabelSize->setText(UIMediumManager::tr("&Size:"));
125
126 /* Translate fields: */
127 m_pComboBoxType->setToolTip(UIMediumManager::tr("Holds the type of this medium."));
128 for (int i = 0; i < m_pComboBoxType->count(); ++i)
129 m_pComboBoxType->setItemText(i, gpConverter->toString(m_pComboBoxType->itemData(i).value<KMediumType>()));
130 m_pEditorLocation->setToolTip(UIMediumManager::tr("Holds the location of this medium."));
131 m_pButtonLocation->setToolTip(UIMediumManager::tr("Choose Medium Location"));
132 m_pEditorDescription->setToolTip(UIMediumManager::tr("Holds the description of this medium."));
133 m_pEditorSize->setToolTip(UIMediumManager::tr("Holds the size of this medium."));
134
135 /* Translate button-box: */
136 if (m_pButtonBox)
137 {
138 m_pButtonBox->button(QDialogButtonBox::Cancel)->setText(UIMediumManager::tr("Reset"));
139 m_pButtonBox->button(QDialogButtonBox::Ok)->setText(UIMediumManager::tr("Apply"));
140 m_pButtonBox->button(QDialogButtonBox::Cancel)->setShortcut(Qt::Key_Escape);
141 m_pButtonBox->button(QDialogButtonBox::Ok)->setShortcut(QString("Ctrl+Return"));
142 m_pButtonBox->button(QDialogButtonBox::Cancel)->setStatusTip(UIMediumManager::tr("Reset changes in current medium details"));
143 m_pButtonBox->button(QDialogButtonBox::Ok)->setStatusTip(UIMediumManager::tr("Apply changes in current medium details"));
144 m_pButtonBox->button(QDialogButtonBox::Cancel)->
145 setToolTip(UIMediumManager::tr("Reset Changes (%1)").arg(m_pButtonBox->button(QDialogButtonBox::Cancel)->shortcut().toString()));
146 m_pButtonBox->button(QDialogButtonBox::Ok)->
147 setToolTip(UIMediumManager::tr("Apply Changes (%1)").arg(m_pButtonBox->button(QDialogButtonBox::Ok)->shortcut().toString()));
148 }
149
150 /* Translate 'Details' tab content. */
151
152 /* Retranslate validation: */
153 retranslateValidation();
154}
155
156void UIMediumDetailsWidget::sltTypeIndexChanged(int iIndex)
157{
158 m_newData.m_options.m_enmMediumType = m_pComboBoxType->itemData(iIndex).value<KMediumType>();
159 revalidate(m_pErrorPaneType);
160 updateButtonStates();
161}
162
163void UIMediumDetailsWidget::sltLocationPathChanged(const QString &strPath)
164{
165 m_newData.m_options.m_strLocation = strPath;
166 revalidate(m_pErrorPaneLocation);
167 updateButtonStates();
168}
169
170void UIMediumDetailsWidget::sltChooseLocationPath()
171{
172 /* Open file-save dialog to choose location for current medium: */
173 const QString strFileName = QIFileDialog::getSaveFileName(m_pEditorLocation->text(),
174 QApplication::translate("UIMediumManager", "Current extension (*.%1)")
175 .arg(QFileInfo(m_oldData.m_options.m_strLocation).suffix()),
176 this,
177 QApplication::translate("UIMediumManager", "Choose the location of this medium"),
178 0, true, true);
179 if (!strFileName.isNull())
180 m_pEditorLocation->setText(QDir::toNativeSeparators(strFileName));
181}
182
183void UIMediumDetailsWidget::sltDescriptionTextChanged()
184{
185 m_newData.m_options.m_strDescription = m_pEditorDescription->toPlainText();
186 revalidate(m_pErrorPaneDescription);
187 updateButtonStates();
188}
189
190void UIMediumDetailsWidget::sltSizeValueChanged(qulonglong uSize)
191{
192 m_newData.m_options.m_uLogicalSize = uSize;
193 revalidate(m_pErrorPaneSize);
194 updateButtonStates();
195}
196
197void UIMediumDetailsWidget::sltHandleButtonBoxClick(QAbstractButton *pButton)
198{
199 /* Make sure button-box exists: */
200 AssertPtrReturnVoid(m_pButtonBox);
201
202 /* Disable buttons first of all: */
203 m_pButtonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
204 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
205
206 /* Compare with known buttons: */
207 if (pButton == m_pButtonBox->button(QDialogButtonBox::Cancel))
208 emit sigDataChangeRejected();
209 else
210 if (pButton == m_pButtonBox->button(QDialogButtonBox::Ok))
211 emit sigDataChangeAccepted();
212}
213
214void UIMediumDetailsWidget::prepare()
215{
216 /* Prepare this: */
217 prepareThis();
218
219 /* Apply language settings: */
220 retranslateUi();
221
222 /* Update button states finally: */
223 updateButtonStates();
224}
225
226void UIMediumDetailsWidget::prepareThis()
227{
228 /* Create layout: */
229 QVBoxLayout *pLayout = new QVBoxLayout(this);
230 AssertPtrReturnVoid(pLayout);
231 {
232 /* Configure layout: */
233 pLayout->setContentsMargins(0, 0, 0, 0);
234
235 /* Prepare tab-widget: */
236 prepareTabWidget();
237 }
238}
239
240void UIMediumDetailsWidget::prepareTabWidget()
241{
242 /* Create tab-widget: */
243 m_pTabWidget = new QITabWidget;
244 AssertPtrReturnVoid(m_pTabWidget);
245 {
246 /* Prepare 'Options' tab: */
247 prepareTabOptions();
248 /* Prepare 'Details' tab: */
249 prepareTabDetails();
250
251 /* Add into layout: */
252 layout()->addWidget(m_pTabWidget);
253 }
254}
255
256void UIMediumDetailsWidget::prepareTabOptions()
257{
258 /* Create 'Options' tab: */
259 QWidget *pTabOptions = new QWidget;
260 AssertPtrReturnVoid(pTabOptions);
261 {
262 /* Create 'Options' layout: */
263 QGridLayout *pLayoutOptions = new QGridLayout(pTabOptions);
264 AssertPtrReturnVoid(pLayoutOptions);
265 {
266#ifdef VBOX_WS_MAC
267 /* Configure layout: */
268 pLayoutOptions->setSpacing(10);
269 pLayoutOptions->setContentsMargins(10, 10, 10, 10);
270 // WORKAROUND:
271 // Using adjusted vertical spacing because there are special widgets which
272 // requires more care and attention, UIFilePathSelector and UIMediumSizeEditor.
273 pLayoutOptions->setVerticalSpacing(6);
274#endif
275
276 /* Get the required icon metric: */
277 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
278
279 /* Create type label: */
280 m_pLabelType = new QLabel;
281 AssertPtrReturnVoid(m_pLabelType);
282 {
283 /* Configure label: */
284 m_pLabelType->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
285 /* Add into layout: */
286 pLayoutOptions->addWidget(m_pLabelType, 0, 0);
287 }
288
289 /* Create type layout: */
290 QHBoxLayout *pLayoutType = new QHBoxLayout;
291 AssertPtrReturnVoid(pLayoutType);
292 {
293 /* Configure layout: */
294 pLayoutType->setContentsMargins(0, 0, 0, 0);
295
296 /* Create type editor: */
297 m_pComboBoxType = new QComboBox;
298 AssertPtrReturnVoid(m_pComboBoxType);
299 {
300 /* Configure editor: */
301 m_pLabelType->setBuddy(m_pComboBoxType);
302 m_pComboBoxType->setSizeAdjustPolicy(QComboBox::AdjustToContents);
303 m_pComboBoxType->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
304 connect(m_pComboBoxType, &QComboBox::activated,
305 this, &UIMediumDetailsWidget::sltTypeIndexChanged);
306 /* Add into layout: */
307 pLayoutType->addWidget(m_pComboBoxType);
308 }
309
310 /* Add stretch: */
311 pLayoutType->addStretch();
312
313 /* Create type error pane: */
314 m_pErrorPaneType = new QLabel;
315 AssertPtrReturnVoid(m_pErrorPaneType);
316 {
317 /* Configure label: */
318 m_pErrorPaneType->setAlignment(Qt::AlignCenter);
319 m_pErrorPaneType->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
320 .pixmap(QSize(iIconMetric, iIconMetric)));
321 /* Add into layout: */
322 pLayoutType->addWidget(m_pErrorPaneType);
323 }
324
325 /* Add into layout: */
326 pLayoutOptions->addLayout(pLayoutType, 0, 1);
327 }
328
329 /* Create location label: */
330 m_pLabelLocation = new QLabel;
331 AssertPtrReturnVoid(m_pLabelLocation);
332 {
333 /* Configure label: */
334 m_pLabelLocation->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
335 /* Add into layout: */
336 pLayoutOptions->addWidget(m_pLabelLocation, 1, 0);
337 }
338
339 /* Create location layout: */
340 QHBoxLayout *pLayoutLocation = new QHBoxLayout;
341 AssertPtrReturnVoid(pLayoutLocation);
342 {
343 /* Configure layout: */
344 pLayoutLocation->setContentsMargins(0, 0, 0, 0);
345
346 /* Create location editor: */
347 m_pEditorLocation = new QLineEdit;
348 AssertPtrReturnVoid(m_pEditorLocation);
349 {
350 /* Configure editor: */
351 m_pLabelLocation->setBuddy(m_pEditorLocation);
352 m_pEditorLocation->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
353 connect(m_pEditorLocation, &QLineEdit::textChanged,
354 this, &UIMediumDetailsWidget::sltLocationPathChanged);
355 /* Add into layout: */
356 pLayoutLocation->addWidget(m_pEditorLocation);
357 }
358
359 /* Create location error pane: */
360 m_pErrorPaneLocation = new QLabel;
361 AssertPtrReturnVoid(m_pErrorPaneLocation);
362 {
363 /* Configure label: */
364 m_pErrorPaneLocation->setAlignment(Qt::AlignCenter);
365 m_pErrorPaneLocation->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
366 .pixmap(QSize(iIconMetric, iIconMetric)));
367 /* Add into layout: */
368 pLayoutLocation->addWidget(m_pErrorPaneLocation);
369 }
370
371 /* Create location button: */
372 m_pButtonLocation = new QIToolButton;
373 AssertPtrReturnVoid(m_pButtonLocation);
374 {
375 /* Configure editor: */
376 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
377 m_pButtonLocation->setIconSize(QSize(iIconMetric, iIconMetric));
378 m_pButtonLocation->setIcon(UIIconPool::iconSet(":/select_file_16px.png"));
379 m_pButtonLocation->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
380 connect(m_pButtonLocation, &QIToolButton::clicked,
381 this, &UIMediumDetailsWidget::sltChooseLocationPath);
382 /* Add into layout: */
383 pLayoutLocation->addWidget(m_pButtonLocation);
384 }
385
386 /* Add into layout: */
387 pLayoutOptions->addLayout(pLayoutLocation, 1, 1);
388 }
389
390 /* Create description label: */
391 m_pLabelDescription = new QLabel;
392 AssertPtrReturnVoid(m_pLabelDescription);
393 {
394 /* Configure label: */
395 m_pLabelDescription->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
396 /* Add into layout: */
397 pLayoutOptions->addWidget(m_pLabelDescription, 2, 0);
398 }
399
400 /* Create description layout: */
401 QGridLayout *pLayoutDescription = new QGridLayout;
402 AssertPtrReturnVoid(pLayoutDescription);
403 {
404 /* Configure layout: */
405 pLayoutDescription->setContentsMargins(0, 0, 0, 0);
406
407 /* Create description editor: */
408 m_pEditorDescription = new QTextEdit;
409 AssertPtrReturnVoid(m_pEditorDescription);
410 {
411 /* Configure editor: */
412 m_pLabelDescription->setBuddy(m_pEditorDescription);
413 QFontMetrics fontMetrics = m_pEditorDescription->fontMetrics();
414 QTextDocument *pTextDocument = m_pEditorDescription->document();
415 const int iMinimumHeight = fontMetrics.lineSpacing() * 3
416 + pTextDocument->documentMargin() * 2
417 + m_pEditorDescription->frameWidth() * 2;
418 m_pEditorDescription->setMaximumHeight(iMinimumHeight);
419 connect(m_pEditorDescription, &QTextEdit::textChanged,
420 this, &UIMediumDetailsWidget::sltDescriptionTextChanged);
421 /* Add into layout: */
422 pLayoutDescription->addWidget(m_pEditorDescription, 0, 0, 2, 1);
423 }
424
425 /* Create description error pane: */
426 m_pErrorPaneDescription = new QLabel;
427 AssertPtrReturnVoid(m_pErrorPaneDescription);
428 {
429 /* Configure label: */
430 m_pErrorPaneDescription->setAlignment(Qt::AlignCenter);
431 m_pErrorPaneDescription->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
432 m_pErrorPaneDescription->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
433 .pixmap(QSize(iIconMetric, iIconMetric)));
434 /* Add into layout: */
435 pLayoutDescription->addWidget(m_pErrorPaneDescription, 0, 1, Qt::AlignCenter);
436 }
437
438 /* Add into layout: */
439 pLayoutOptions->addLayout(pLayoutDescription, 2, 1, 2, 1);
440 }
441
442 /* Create size label: */
443 m_pLabelSize = new QLabel;
444 AssertPtrReturnVoid(m_pLabelSize);
445 {
446 /* Configure label: */
447 m_pLabelSize->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
448 /* Add into layout: */
449 pLayoutOptions->addWidget(m_pLabelSize, 4, 0);
450 }
451
452 /* Create size layout: */
453 QGridLayout *pLayoutSize = new QGridLayout;
454 AssertPtrReturnVoid(pLayoutSize);
455 {
456 /* Configure layout: */
457 pLayoutSize->setContentsMargins(0, 0, 0, 0);
458#ifdef VBOX_WS_MAC
459 // WORKAROUND:
460 // Using adjusted vertical stretch because there is special widget
461 // which requires more care and attention, UIMediumSizeEditor.
462 pLayoutSize->setRowStretch(0, 3);
463 pLayoutSize->setRowStretch(1, 2);
464#endif
465
466 /* Create size editor: */
467 m_pEditorSize = new UIMediumSizeEditor(0 /* parent */);
468 AssertPtrReturnVoid(m_pEditorSize);
469 {
470 /* Configure editor: */
471 m_pLabelSize->setBuddy(m_pEditorSize);
472 m_pEditorSize->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
473 connect(m_pEditorSize, &UIMediumSizeEditor::sigSizeChanged,
474 this, &UIMediumDetailsWidget::sltSizeValueChanged);
475 /* Add into layout: */
476 pLayoutSize->addWidget(m_pEditorSize, 0, 0, 2, 1);
477 }
478
479 /* Create size error pane: */
480 m_pErrorPaneSize = new QLabel;
481 AssertPtrReturnVoid(m_pErrorPaneSize);
482 {
483 /* Configure label: */
484 m_pErrorPaneSize->setAlignment(Qt::AlignCenter);
485 m_pErrorPaneSize->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
486 m_pErrorPaneSize->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
487 .pixmap(QSize(iIconMetric, iIconMetric)));
488 /* Add into layout: */
489 pLayoutSize->addWidget(m_pErrorPaneSize, 0, 1, Qt::AlignCenter);
490 }
491
492 /* Add into layout: */
493 pLayoutOptions->addLayout(pLayoutSize, 4, 1, 2, 1);
494 }
495
496 /* Create stretch: */
497 QSpacerItem *pSpacer2 = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
498 AssertPtrReturnVoid(pSpacer2);
499 {
500 /* Add into layout: */
501 pLayoutOptions->addItem(pSpacer2, 6, 0, 1, 2);
502 }
503
504 /* If parent embedded into stack: */
505 if (m_enmEmbedding == EmbedTo_Stack)
506 {
507 /* Create button-box: */
508 m_pButtonBox = new QIDialogButtonBox;
509 AssertPtrReturnVoid(m_pButtonBox);
510 {
511 /* Configure button-box: */
512 m_pButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
513 connect(m_pButtonBox, &QIDialogButtonBox::clicked, this, &UIMediumDetailsWidget::sltHandleButtonBoxClick);
514
515 /* Create progress-bar: */
516 m_pProgressBar = new UIEnumerationProgressBar;
517 AssertPtrReturnVoid(m_pProgressBar);
518 {
519 /* Configure progress-bar: */
520 m_pProgressBar->hide();
521 /* Add progress-bar into button-box layout: */
522 m_pButtonBox->addExtraWidget(m_pProgressBar);
523 /* Notify parent it has progress-bar: */
524 m_pParent->setProgressBar(m_pProgressBar);
525 }
526 }
527
528 /* Add into layout: */
529 pLayoutOptions->addWidget(m_pButtonBox, 7, 0, 1, 2);
530 }
531 }
532
533 /* Add to tab-widget: */
534 m_pTabWidget->addTab(pTabOptions, QString());
535 }
536}
537
538void UIMediumDetailsWidget::prepareTabDetails()
539{
540 /* Create 'Details' tab: */
541 QWidget *pTabDetails = new QWidget;
542 AssertPtrReturnVoid(pTabDetails);
543 {
544 /* Create stacked layout: */
545 m_pLayoutDetails = new QStackedLayout(pTabDetails);
546 AssertPtrReturnVoid(m_pLayoutDetails);
547 {
548 /* Create information-containers: */
549 for (int i = (int)UIMediumDeviceType_HardDisk; i < (int)UIMediumDeviceType_All; ++i)
550 {
551 const UIMediumDeviceType enmType = (UIMediumDeviceType)i;
552 prepareInformationContainer(enmType, enmType == UIMediumDeviceType_HardDisk ? 5 : 2); /// @todo Remove hard-coded values.
553 }
554 }
555
556 /* Add to tab-widget: */
557 m_pTabWidget->addTab(pTabDetails, QString());
558 }
559}
560
561void UIMediumDetailsWidget::prepareInformationContainer(UIMediumDeviceType enmType, int cFields)
562{
563 /* Create information-container: */
564 m_aContainers[enmType] = new QWidget;
565 QWidget *pContainer = infoContainer(enmType);
566 AssertPtrReturnVoid(pContainer);
567 {
568 /* Create layout: */
569 new QGridLayout(pContainer);
570 QGridLayout *pLayout = qobject_cast<QGridLayout*>(pContainer->layout());
571 AssertPtrReturnVoid(pLayout);
572 {
573 /* Configure layout: */
574 pLayout->setVerticalSpacing(0);
575 pLayout->setColumnStretch(1, 1);
576
577 /* Create labels & fields: */
578 int i = 0;
579 for (; i < cFields; ++i)
580 {
581 /* Create label: */
582 m_aLabels[enmType] << new QLabel;
583 QLabel *pLabel = infoLabel(enmType, i);
584 AssertPtrReturnVoid(pLabel);
585 {
586 /* Configure label: */
587 pLabel->setMargin(2);
588 pLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
589
590 /* Add into layout: */
591 pLayout->addWidget(pLabel, i, 0);
592 }
593
594 /* Create field: */
595 m_aFields[enmType] << new QILabel;
596 QILabel *pField = infoField(enmType, i);
597 AssertPtrReturnVoid(pField);
598 {
599 /* Configure field: */
600 pField->setMargin(2);
601 pField->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
602 pField->setFullSizeSelection(true);
603
604 /* Add into layout: */
605 pLayout->addWidget(pField, i, 1);
606 }
607 }
608
609 /* Create stretch: */
610 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
611 AssertPtrReturnVoid(pSpacer);
612 {
613 /* Add into layout: */
614 pLayout->addItem(pSpacer, i, 0, 1, 2);
615 }
616 }
617
618 /* Add into layout: */
619 m_pLayoutDetails->addWidget(pContainer);
620 }
621}
622
623void UIMediumDetailsWidget::loadDataForOptions()
624{
625 /* Clear type combo-box: */
626 m_pLabelType->setEnabled(m_newData.m_fValid);
627 m_pComboBoxType->setEnabled(m_newData.m_fValid);
628 m_pComboBoxType->clear();
629 if (m_newData.m_fValid)
630 {
631 /* Populate type combo-box: */
632 switch (m_newData.m_enmDeviceType)
633 {
634 case UIMediumDeviceType_HardDisk:
635 {
636 /* No type changes for differencing disks: */
637 if (m_oldData.m_enmVariant & KMediumVariant_Diff)
638 m_pComboBoxType->addItem(QString(), m_oldData.m_options.m_enmMediumType);
639 else
640 {
641 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Normal));
642 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Immutable));
643 if (!m_newData.m_fHasChildren)
644 {
645 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Writethrough));
646 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Shareable));
647 }
648 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_MultiAttach));
649 }
650 break;
651 }
652 case UIMediumDeviceType_DVD:
653 {
654 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Readonly));
655 break;
656 }
657 case UIMediumDeviceType_Floppy:
658 {
659 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Writethrough));
660 m_pComboBoxType->addItem(QString(), QVariant::fromValue(KMediumType_Readonly));
661 break;
662 }
663 default:
664 break;
665 }
666 /* Translate type combo-box: */
667 for (int i = 0; i < m_pComboBoxType->count(); ++i)
668 {
669 m_pComboBoxType->setItemText(i, gpConverter->toString(m_pComboBoxType->itemData(i).value<KMediumType>()));
670 m_pComboBoxType->setItemData(i, mediumTypeTip(m_pComboBoxType->itemData(i).value<KMediumType>()), Qt::ToolTipRole);
671 }
672 }
673
674 /* Choose the item with required type to be the current one: */
675 for (int i = 0; i < m_pComboBoxType->count(); ++i)
676 if (m_pComboBoxType->itemData(i).value<KMediumType>() == m_newData.m_options.m_enmMediumType)
677 m_pComboBoxType->setCurrentIndex(i);
678 sltTypeIndexChanged(m_pComboBoxType->currentIndex());
679
680 /* Load location: */
681 m_pLabelLocation->setEnabled(m_newData.m_fValid);
682 m_pEditorLocation->setEnabled(m_newData.m_fValid);
683 m_pButtonLocation->setEnabled(m_newData.m_fValid);
684 m_pEditorLocation->setText(m_newData.m_options.m_strLocation);
685
686 /* Load description: */
687 m_pLabelDescription->setEnabled(m_newData.m_fValid);
688 m_pEditorDescription->setEnabled(m_newData.m_fValid);
689 m_pEditorDescription->setPlainText(m_newData.m_options.m_strDescription);
690
691 /* Load size: */
692 const bool fEnableResize = m_newData.m_fValid
693 && m_newData.m_enmDeviceType == UIMediumDeviceType_HardDisk
694 && !(m_newData.m_enmVariant & KMediumVariant_Fixed);
695 m_pLabelSize->setEnabled(fEnableResize);
696 m_pEditorSize->setEnabled(fEnableResize);
697 m_pEditorSize->setMediumSize(m_newData.m_options.m_uLogicalSize);
698 sltSizeValueChanged(m_pEditorSize->mediumSize());
699
700 /* Revalidate: */
701 revalidate();
702}
703
704void UIMediumDetailsWidget::loadDataForDetails()
705{
706 /* Get information-labels just to acquire their number: */
707 const QList<QLabel*> aLabels = m_aLabels.value(m_newData.m_enmDeviceType, QList<QLabel*>());
708 /* Get information-fields just to acquire their number: */
709 const QList<QILabel*> aFields = m_aFields.value(m_newData.m_enmDeviceType, QList<QILabel*>());
710 /* For each the label => update contents: */
711 for (int i = 0; i < aLabels.size(); ++i)
712 infoLabel(m_newData.m_enmDeviceType, i)->setText(m_newData.m_details.m_aLabels.value(i, QString()));
713 /* For each the field => update contents: */
714 for (int i = 0; i < aFields.size(); ++i)
715 {
716 infoField(m_newData.m_enmDeviceType, i)->setText(m_newData.m_details.m_aFields.value(i, QString()));
717 infoField(m_newData.m_enmDeviceType, i)->setEnabled(!infoField(m_newData.m_enmDeviceType, i)->text().trimmed().isEmpty());
718 }
719}
720
721void UIMediumDetailsWidget::revalidate(QWidget *pWidget /* = 0 */)
722{
723 /* Reset the result: */
724 m_fValid = true;
725
726 /* Validate 'Options' tab content: */
727 if (!pWidget || pWidget == m_pErrorPaneType)
728 {
729 /* Always valid for now: */
730 const bool fError = false;
731 m_pErrorPaneType->setVisible(fError);
732 if (fError)
733 m_fValid = false;
734 }
735 if (!pWidget || pWidget == m_pErrorPaneLocation)
736 {
737 /* If medium is valid itself, details are valid only is location is set: */
738 const bool fError = m_newData.m_fValid && m_newData.m_options.m_strLocation.isEmpty();
739 m_pErrorPaneLocation->setVisible(fError);
740 if (fError)
741 m_fValid = false;
742 }
743 if (!pWidget || pWidget == m_pErrorPaneDescription)
744 {
745 /* Always valid for now: */
746 const bool fError = false;
747 m_pErrorPaneDescription->setVisible(fError);
748 if (fError)
749 m_fValid = false;
750 }
751 if (!pWidget || pWidget == m_pErrorPaneSize)
752 {
753 /* Always valid for now: */
754 const bool fError = m_newData.m_options.m_uLogicalSize < m_oldData.m_options.m_uLogicalSize;
755 m_pErrorPaneSize->setVisible(fError);
756 if (fError)
757 m_fValid = false;
758 }
759
760 /* Retranslate validation: */
761 retranslateValidation(pWidget);
762}
763
764void UIMediumDetailsWidget::retranslateValidation(QWidget *pWidget /* = 0 */)
765{
766 /* Translate 'Interface' tab content: */
767// if (!pWidget || pWidget == m_pErrorPaneType)
768// m_pErrorPaneType->setToolTip(UIMediumManager::tr("Cannot change from type <b>%1</b> to <b>%2</b>.")
769// .arg(m_oldData.m_options.m_enmType).arg(m_newData.m_options.m_enmType));
770 if (!pWidget || pWidget == m_pErrorPaneLocation)
771 m_pErrorPaneLocation->setToolTip(UIMediumManager::tr("Location cannot be empty."));
772// if (!pWidget || pWidget == m_pErrorPaneDescription)
773// m_pErrorPaneDescription->setToolTip(UIMediumManager::tr("Cannot change medium description from <b>%1</b> to <b>%2</b>.")
774// .arg(m_oldData.m_options.m_strDescription)
775// .arg(m_newData.m_options.m_strDescription));
776 if (!pWidget || pWidget == m_pErrorPaneSize)
777 m_pErrorPaneSize->setToolTip(UIMediumManager::tr("Cannot change medium size from <b>%1</b> to <b>%2</b> as storage "
778 "shrinking is currently not implemented.")
779 .arg(UITranslator::formatSize(m_oldData.m_options.m_uLogicalSize))
780 .arg(UITranslator::formatSize(m_newData.m_options.m_uLogicalSize)));
781}
782
783void UIMediumDetailsWidget::updateButtonStates()
784{
785// if (m_newData != m_oldData)
786// {
787// if (m_newData.m_options != m_oldData.m_options)
788// {
789// if (m_newData.m_options.m_enmType != m_oldData.m_options.m_enmType)
790// printf("Type: %d\n", (int)m_newData.m_options.m_enmType);
791// if (m_newData.m_options.m_uLogicalSize != m_oldData.m_options.m_uLogicalSize)
792// printf("Size: %llu vs %llu\n", m_newData.m_options.m_uLogicalSize, m_oldData.m_options.m_uLogicalSize);
793// if (m_newData.m_options.m_strLocation != m_oldData.m_options.m_strLocation)
794// printf("Location: %s\n", m_newData.m_options.m_strLocation.toUtf8().constData());
795// if (m_newData.m_options.m_strDescription != m_oldData.m_options.m_strDescription)
796// printf("Description: %s\n", m_newData.m_options.m_strDescription.toUtf8().constData());
797// }
798// }
799
800 /* Update 'Apply' / 'Reset' button states: */
801 if (m_pButtonBox)
802 {
803 m_pButtonBox->button(QDialogButtonBox::Cancel)->setEnabled(m_oldData != m_newData);
804 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled((m_oldData != m_newData) && m_fValid);
805 }
806
807 /* Notify listeners as well: */
808 emit sigRejectAllowed(m_oldData != m_newData);
809 emit sigAcceptAllowed((m_oldData != m_newData) && m_fValid);
810}
811
812/* static */
813QString UIMediumDetailsWidget::mediumTypeTip(KMediumType enmType)
814{
815 switch (enmType)
816 {
817 case KMediumType_Normal:
818 return UIMediumManager::tr("This type of medium is attached directly or indirectly, preserved when taking "
819 "snapshots.");
820 case KMediumType_Immutable:
821 return UIMediumManager::tr("This type of medium is attached indirectly, changes are wiped out the next time the "
822 "virtual machine is started.");
823 case KMediumType_Writethrough:
824 return UIMediumManager::tr("This type of medium is attached directly, ignored when taking snapshots.");
825 case KMediumType_Shareable:
826 return UIMediumManager::tr("This type of medium is attached directly, allowed to be used concurrently by several "
827 "machines.");
828 case KMediumType_Readonly:
829 return UIMediumManager::tr("This type of medium is attached directly, and can be used by several machines.");
830 case KMediumType_MultiAttach:
831 return UIMediumManager::tr("This type of medium is attached indirectly, so that one base medium can be used for "
832 "several VMs which have their own differencing medium to store their modifications.");
833 default:
834 break;
835 }
836 AssertFailedReturn(QString());
837}
838
839QWidget *UIMediumDetailsWidget::infoContainer(UIMediumDeviceType enmType) const
840{
841 /* Return information-container for known medium type: */
842 return m_aContainers.value(enmType, 0);
843}
844
845QLabel *UIMediumDetailsWidget::infoLabel(UIMediumDeviceType enmType, int iIndex) const
846{
847 /* Acquire list of labels: */
848 const QList<QLabel*> aLabels = m_aLabels.value(enmType, QList<QLabel*>());
849
850 /* Return label for known index: */
851 return aLabels.value(iIndex, 0);
852}
853
854QILabel *UIMediumDetailsWidget::infoField(UIMediumDeviceType enmType, int iIndex) const
855{
856 /* Acquire list of fields: */
857 const QList<QILabel*> aFields = m_aFields.value(enmType, QList<QILabel*>());
858
859 /* Return label for known index: */
860 return aFields.value(iIndex, 0);
861}
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