VirtualBox

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

Last change on this file was 105164, checked in by vboxsync, 2 months ago

FE/Qt: bugref:10676: Accessibility fixes for Medium Manager; JAWS requires all buttons to have their text property assigned, cause opposing to VoiceOver it uses this property, not the tool-tip. S.a. similar patch r163068.

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