VirtualBox

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

Last change on this file since 102493 was 101563, checked in by vboxsync, 11 months ago

FE/Qt: bugref:10450: Get rid of Qt5 stuff; This one is about signal connection ambiguity stuff.

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