VirtualBox

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

Last change on this file was 104358, checked in by vboxsync, 5 weeks ago

FE/Qt. bugref:10622. More refactoring around the retranslation functionality.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use