VirtualBox

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

Last change on this file since 102493 was 101330, checked in by vboxsync, 12 months ago

FE/Qt: bugref:10513: Small NLS adjustment for VM settings / Storage page.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.5 KB
Line 
1/* $Id: UIMediumItem.cpp 101330 2023-10-03 14:19:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMediumItem class implementation.
4 */
5
6/*
7 * Copyright (C) 2009-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 <QDir>
31
32/* GUI includes: */
33#include "QIFileDialog.h"
34#include "QIMessageBox.h"
35#include "UICommon.h"
36#include "UIExtraDataManager.h"
37#include "UIIconPool.h"
38#include "UIMediumItem.h"
39#include "UIMessageCenter.h"
40#include "UINotificationCenter.h"
41#include "UITranslator.h"
42
43/* COM includes: */
44#include "CMachine.h"
45#include "CMediumAttachment.h"
46#include "CMediumFormat.h"
47#include "CStorageController.h"
48
49
50/*********************************************************************************************************************************
51* Class UIMediumItem implementation. *
52*********************************************************************************************************************************/
53
54UIMediumItem::UIMediumItem(const UIMedium &guiMedium, QITreeWidget *pParent)
55 : QITreeWidgetItem(pParent)
56 , m_guiMedium(guiMedium)
57{
58 refresh();
59}
60
61UIMediumItem::UIMediumItem(const UIMedium &guiMedium, UIMediumItem *pParent)
62 : QITreeWidgetItem(pParent)
63 , m_guiMedium(guiMedium)
64{
65 refresh();
66}
67
68UIMediumItem::UIMediumItem(const UIMedium &guiMedium, QITreeWidgetItem *pParent)
69 : QITreeWidgetItem(pParent)
70 , m_guiMedium(guiMedium)
71{
72 refresh();
73}
74
75bool UIMediumItem::move()
76{
77 /* Open file-save dialog to choose location for current medium: */
78 const QString strFileName = QIFileDialog::getSaveFileName(location(),
79 tr("Current extension (*.%1)")
80 .arg(QFileInfo(location()).suffix()),
81 treeWidget(),
82 tr("Choose the location of this medium"),
83 0, true, true);
84 if (strFileName.isNull() || strFileName == location())
85 return false;
86
87 /* Search for corresponding medium: */
88 CMedium comMedium = medium().medium();
89 if (comMedium.isNull() || !comMedium.isOk())
90 return false;
91
92 /* Assign new medium location: */
93 UINotificationProgressMediumMove *pNotification = new UINotificationProgressMediumMove(comMedium,
94 strFileName);
95 connect(pNotification, &UINotificationProgressMediumMove::sigProgressFinished,
96 this, &UIMediumItem::sltHandleMoveProgressFinished);
97 gpNotificationCenter->append(pNotification);
98
99 /* Positive: */
100 return true;
101}
102
103bool UIMediumItem::release(bool fShowMessageBox, bool fInduced)
104{
105 /* Refresh medium and item: */
106 m_guiMedium.refresh();
107 refresh();
108
109 /* Make sure medium was not released yet: */
110 if (medium().curStateMachineIds().isEmpty())
111 return true;
112
113 /* Confirm release: */
114 if (fShowMessageBox)
115 if (!msgCenter().confirmMediumRelease(medium(), fInduced, treeWidget()))
116 return false;
117
118 /* Release: */
119 foreach (const QUuid &uMachineId, medium().curStateMachineIds())
120 if (!releaseFrom(uMachineId))
121 return false;
122
123 /* True by default: */
124 return true;
125}
126
127void UIMediumItem::refreshAll()
128{
129 m_guiMedium.blockAndQueryState();
130 refresh();
131}
132
133void UIMediumItem::setMedium(const UIMedium &guiMedium)
134{
135 m_guiMedium = guiMedium;
136 refresh();
137}
138
139bool UIMediumItem::operator<(const QTreeWidgetItem &other) const
140{
141 int iColumn = treeWidget()->sortColumn();
142 ULONG64 uThisValue = UITranslator::parseSize( text(iColumn));
143 ULONG64 uThatValue = UITranslator::parseSize(other.text(iColumn));
144 return uThisValue && uThatValue ? uThisValue < uThatValue : QTreeWidgetItem::operator<(other);
145}
146
147bool UIMediumItem::isMediumModifiable() const
148{
149 if (medium().isNull())
150 return false;
151 if (m_enmDeviceType == UIMediumDeviceType_DVD || m_enmDeviceType == UIMediumDeviceType_Floppy)
152 return false;
153 foreach (const QUuid &uMachineId, medium().curStateMachineIds())
154 {
155 CMachine comMachine = uiCommon().virtualBox().FindMachine(uMachineId.toString());
156 if (comMachine.isNull())
157 continue;
158 if (comMachine.GetState() != KMachineState_PoweredOff &&
159 comMachine.GetState() != KMachineState_Aborted &&
160 comMachine.GetState() != KMachineState_AbortedSaved)
161 return false;
162 }
163 return true;
164}
165
166bool UIMediumItem::isMediumAttachedTo(QUuid uId)
167{
168 if (medium().isNull())
169 return false;
170 return medium().curStateMachineIds().contains(uId);
171}
172
173bool UIMediumItem::changeMediumType(KMediumType enmNewType)
174{
175 /* Cache the list of VMs the medium is attached to. We will need this for the re-attachment: */
176 QList<AttachmentCache> attachmentCacheList;
177 foreach (const QUuid &uMachineId, medium().curStateMachineIds())
178 {
179 const CMachine &comMachine = uiCommon().virtualBox().FindMachine(uMachineId.toString());
180 if (comMachine.isNull())
181 continue;
182 foreach (const CStorageController &comController, comMachine.GetStorageControllers())
183 {
184 if (comController.isNull())
185 continue;
186 const QString strControllerName = comController.GetName();
187 foreach (const CMediumAttachment &comAttachment, comMachine.GetMediumAttachmentsOfController(strControllerName))
188 {
189 if (comAttachment.isNull())
190 continue;
191 const CMedium &comMedium = comAttachment.GetMedium();
192 if (comMedium.isNull() || comMedium.GetId() != id())
193 continue;
194 AttachmentCache attachmentCache;
195 attachmentCache.m_uMachineId = uMachineId;
196 attachmentCache.m_strControllerName = strControllerName;
197 attachmentCache.m_enmControllerBus = comController.GetBus();
198 attachmentCache.m_iAttachmentPort = comAttachment.GetPort();
199 attachmentCache.m_iAttachmentDevice = comAttachment.GetDevice();
200 attachmentCacheList << attachmentCache;
201 }
202 }
203 }
204
205 /* Detach the medium from all the VMs it's attached to: */
206 if (!release(true, true))
207 return false;
208
209 /* Attempt to change medium type: */
210 CMedium comMedium = medium().medium();
211 comMedium.SetType(enmNewType);
212 if (!comMedium.isOk())
213 {
214 UINotificationMessage::cannotChangeMediumParameter(comMedium);
215 return false;
216 }
217
218 /* Reattach the medium to all the VMs it was previously attached: */
219 foreach (const AttachmentCache &attachmentCache, attachmentCacheList)
220 if (!attachTo(attachmentCache))
221 return false;
222
223 /* True finally: */
224 return true;
225}
226
227QString UIMediumItem::defaultText() const
228{
229 return tr("%1, %2: %3, %4: %5", "col.1 text, col.2 name: col.2 text, col.3 name: col.3 text")
230 .arg(text(0))
231 .arg(parentTree()->headerItem()->text(1)).arg(text(1))
232 .arg(parentTree()->headerItem()->text(2)).arg(text(2));
233}
234
235void UIMediumItem::sltHandleMoveProgressFinished()
236{
237 /* Recache item: */
238 refreshAll();
239}
240
241void UIMediumItem::sltHandleMediumRemoveRequest(CMedium comMedium)
242{
243 /* Close medium finally: */
244 comMedium.Close();
245 if (!comMedium.isOk())
246 UINotificationMessage::cannotCloseMedium(comMedium);
247}
248
249void UIMediumItem::refresh()
250{
251 /* Fill-in columns: */
252 setIcon(0, m_guiMedium.icon());
253 setText(0, m_guiMedium.name());
254 setText(1, m_guiMedium.logicalSize());
255 setText(2, m_guiMedium.size());
256 /* All columns get the same tooltip: */
257 QString strToolTip = m_guiMedium.toolTip();
258 for (int i = 0; i < treeWidget()->columnCount(); ++i)
259 setToolTip(i, strToolTip);
260
261 /* Gather medium data: */
262 m_fValid = !m_guiMedium.isNull()
263 && m_guiMedium.state() != KMediumState_Inaccessible;
264 m_enmDeviceType = m_guiMedium.type();
265 m_enmVariant = m_guiMedium.mediumVariant();
266 m_fHasChildren = m_guiMedium.hasChildren();
267 /* Gather medium options data: */
268 m_options.m_enmMediumType = m_guiMedium.mediumType();
269 m_options.m_strLocation = m_guiMedium.location();
270 m_options.m_uLogicalSize = m_guiMedium.logicalSizeInBytes();
271 m_options.m_strDescription = m_guiMedium.description();
272 /* Gather medium details data: */
273 m_details.m_aFields.clear();
274 switch (m_enmDeviceType)
275 {
276 case UIMediumDeviceType_HardDisk:
277 {
278 m_details.m_aLabels << tr("Format:");
279 m_details.m_aLabels << tr("Storage details:");
280 m_details.m_aLabels << tr("Attached to:");
281 m_details.m_aLabels << tr("Encryption key:");
282 m_details.m_aLabels << tr("UUID:");
283
284 m_details.m_aFields << hardDiskFormat();
285 m_details.m_aFields << details();
286 m_details.m_aFields << (usage().isNull() ?
287 formatFieldText(tr("<i>Not&nbsp;Attached</i>"), false) :
288 formatFieldText(usage()));
289 m_details.m_aFields << (encryptionPasswordID().isNull() ?
290 formatFieldText(tr("<i>Not&nbsp;Encrypted</i>"), false) :
291 formatFieldText(encryptionPasswordID()));
292 m_details.m_aFields << id().toString();
293
294 break;
295 }
296 case UIMediumDeviceType_DVD:
297 case UIMediumDeviceType_Floppy:
298 {
299 m_details.m_aLabels << tr("Attached to:");
300 m_details.m_aLabels << tr("UUID:");
301
302 m_details.m_aFields << (usage().isNull() ?
303 formatFieldText(tr("<i>Not&nbsp;Attached</i>"), false) :
304 formatFieldText(usage()));
305 m_details.m_aFields << id().toString();
306 break;
307 }
308 default:
309 break;
310 }
311}
312
313bool UIMediumItem::releaseFrom(const QUuid &uMachineId)
314{
315 /* Open session: */
316 CSession session = uiCommon().openSession(uMachineId);
317 if (session.isNull())
318 return false;
319
320 /* Get machine: */
321 CMachine machine = session.GetMachine();
322
323 /* Prepare result: */
324 bool fSuccess = false;
325
326 /* Release medium from machine: */
327 if (releaseFrom(machine))
328 {
329 /* Save machine settings: */
330 machine.SaveSettings();
331 if (!machine.isOk())
332 msgCenter().cannotSaveMachineSettings(machine, treeWidget());
333 else
334 fSuccess = true;
335 }
336
337 /* Close session: */
338 session.UnlockMachine();
339
340 /* Return result: */
341 return fSuccess;
342}
343
344bool UIMediumItem::attachTo(const AttachmentCache &attachmentCache)
345{
346 /* Open session: */
347 CSession comSession = uiCommon().openSession(attachmentCache.m_uMachineId);
348 if (comSession.isNull())
349 return false;
350
351 /* Attach device to machine: */
352 CMedium comMedium = medium().medium();
353 KDeviceType enmDeviceType = comMedium.GetDeviceType();
354 CMachine comMachine = comSession.GetMachine();
355 comMachine.AttachDevice(attachmentCache.m_strControllerName,
356 attachmentCache.m_iAttachmentPort,
357 attachmentCache.m_iAttachmentDevice,
358 enmDeviceType,
359 comMedium);
360 if (!comMachine.isOk())
361 msgCenter().cannotAttachDevice(comMachine,
362 mediumTypeToLocal(enmDeviceType),
363 comMedium.GetLocation(),
364 StorageSlot(attachmentCache.m_enmControllerBus,
365 attachmentCache.m_iAttachmentPort,
366 attachmentCache.m_iAttachmentDevice),
367 parentTree());
368 else
369 {
370 /* Save machine settings: */
371 comMachine.SaveSettings();
372 if (!comMachine.isOk())
373 msgCenter().cannotSaveMachineSettings(comMachine, parentTree());
374 }
375
376 /* Close session: */
377 comSession.UnlockMachine();
378
379 /* True finally: */
380 return true;
381}
382
383/* static */
384QString UIMediumItem::formatFieldText(const QString &strText, bool fCompact /* = true */,
385 const QString &strElipsis /* = "middle" */)
386{
387 QString strCompactString = QString("<compact elipsis=\"%1\">").arg(strElipsis);
388 QString strInfo = QString("<nobr>%1%2%3</nobr>")
389 .arg(fCompact ? strCompactString : "")
390 .arg(strText.isEmpty() ? tr("--", "no info") : strText)
391 .arg(fCompact ? "</compact>" : "");
392 return strInfo;
393}
394
395
396/*********************************************************************************************************************************
397* Class UIMediumItemHD implementation. *
398*********************************************************************************************************************************/
399
400UIMediumItemHD::UIMediumItemHD(const UIMedium &guiMedium, QITreeWidget *pParent)
401 : UIMediumItem(guiMedium, pParent)
402{
403}
404
405UIMediumItemHD::UIMediumItemHD(const UIMedium &guiMedium, UIMediumItem *pParent)
406 : UIMediumItem(guiMedium, pParent)
407{
408}
409
410UIMediumItemHD::UIMediumItemHD(const UIMedium &guiMedium, QITreeWidgetItem *pParent)
411 : UIMediumItem(guiMedium, pParent)
412{
413}
414
415bool UIMediumItemHD::remove(bool fShowMessageBox)
416{
417 /* Confirm medium removal: */
418 if (fShowMessageBox)
419 if (!msgCenter().confirmMediumRemoval(medium(), treeWidget()))
420 return false;
421
422 /* Propose to remove medium storage: */
423 if (!maybeRemoveStorage())
424 return false;
425
426 /* True by default: */
427 return true;
428}
429
430bool UIMediumItemHD::releaseFrom(CMachine comMachine)
431{
432 /* Was medium released from at least one attachment? */
433 bool fAtLeastOneRelease = false;
434
435 /* Enumerate attachments: */
436 CMediumAttachmentVector attachments = comMachine.GetMediumAttachments();
437 foreach (const CMediumAttachment &attachment, attachments)
438 {
439 /* Skip non-hard-disks: */
440 if (attachment.GetType() != KDeviceType_HardDisk)
441 continue;
442
443 /* Skip unrelated hard-disks: */
444 if (attachment.GetMedium().GetId() != id())
445 continue;
446
447 /* Remember controller: */
448 CStorageController controller = comMachine.GetStorageControllerByName(attachment.GetController());
449
450 /* Try to detach device: */
451 comMachine.DetachDevice(attachment.GetController(), attachment.GetPort(), attachment.GetDevice());
452 if (!comMachine.isOk())
453 {
454 /* Return failure: */
455 msgCenter().cannotDetachDevice(comMachine, UIMediumDeviceType_HardDisk, location(),
456 StorageSlot(controller.GetBus(), attachment.GetPort(), attachment.GetDevice()),
457 treeWidget());
458 return false;
459 }
460 else
461 fAtLeastOneRelease = true;
462 }
463
464 /* Return whether there was at least one release: */
465 return fAtLeastOneRelease;
466}
467
468bool UIMediumItemHD::maybeRemoveStorage()
469{
470 /* Acquire medium: */
471 CMedium comMedium = medium().medium();
472
473 /* We don't want to try to delete inaccessible storage as it will most likely fail.
474 * Note that UIMessageCenter::confirmMediumRemoval() is aware of that and
475 * will give a corresponding hint. Therefore, once the code is changed below,
476 * the hint should be re-checked for validity. */
477 bool fDeleteStorage = false;
478 qulonglong uCapability = 0;
479 foreach (KMediumFormatCapabilities capability, comMedium.GetMediumFormat().GetCapabilities())
480 uCapability |= capability;
481 if (state() != KMediumState_Inaccessible && uCapability & KMediumFormatCapabilities_File)
482 {
483 int rc = msgCenter().confirmDeleteHardDiskStorage(location(), treeWidget());
484 if (rc == AlertButton_Cancel)
485 return false;
486 fDeleteStorage = rc == AlertButton_Choice1;
487 }
488
489 /* If user wish to delete storage: */
490 if (fDeleteStorage)
491 {
492 /* Deleting medium storage first of all: */
493 UINotificationProgressMediumDeletingStorage *pNotification = new UINotificationProgressMediumDeletingStorage(comMedium);
494 connect(pNotification, &UINotificationProgressMediumDeletingStorage::sigMediumStorageDeleted,
495 this, &UIMediumItemHD::sltHandleMediumRemoveRequest);
496 gpNotificationCenter->append(pNotification);
497 }
498 /* Otherwise go to last step immediatelly: */
499 else
500 sltHandleMediumRemoveRequest(comMedium);
501
502 /* True by default: */
503 return true;
504}
505
506
507/*********************************************************************************************************************************
508* Class UIMediumItemCD implementation. *
509*********************************************************************************************************************************/
510
511UIMediumItemCD::UIMediumItemCD(const UIMedium &guiMedium, QITreeWidget *pParent)
512 : UIMediumItem(guiMedium, pParent)
513{
514}
515
516UIMediumItemCD::UIMediumItemCD(const UIMedium &guiMedium, QITreeWidgetItem *pParent)
517 : UIMediumItem(guiMedium, pParent)
518{
519}
520
521bool UIMediumItemCD::remove(bool fShowMessageBox)
522{
523 /* Confirm medium removal: */
524 if (fShowMessageBox)
525 if (!msgCenter().confirmMediumRemoval(medium(), treeWidget()))
526 return false;
527
528 /* Close optical-disk: */
529 sltHandleMediumRemoveRequest(medium().medium());
530
531 /* True by default: */
532 return true;
533}
534
535bool UIMediumItemCD::releaseFrom(CMachine comMachine)
536{
537 /* Was medium released from at least one attachment? */
538 bool fAtLeastOneRelease = false;
539
540 /* Enumerate attachments: */
541 CMediumAttachmentVector attachments = comMachine.GetMediumAttachments();
542 foreach (const CMediumAttachment &attachment, attachments)
543 {
544 /* Skip non-optical-disks: */
545 if (attachment.GetType() != KDeviceType_DVD)
546 continue;
547
548 /* Skip unrelated optical-disks: */
549 if (attachment.GetMedium().GetId() != id())
550 continue;
551
552 /* Try to unmount device: */
553 comMachine.MountMedium(attachment.GetController(), attachment.GetPort(), attachment.GetDevice(), CMedium(), false /* force */);
554 if (!comMachine.isOk())
555 {
556 /* Return failure: */
557 msgCenter().cannotRemountMedium(comMachine, medium(), false /* mount? */, false /* retry? */, treeWidget());
558 return false;
559 }
560 else
561 fAtLeastOneRelease = true;
562 }
563
564 /* Return whether there was at least one release: */
565 return fAtLeastOneRelease;
566}
567
568
569/*********************************************************************************************************************************
570* Class UIMediumItemFD implementation. *
571*********************************************************************************************************************************/
572
573UIMediumItemFD::UIMediumItemFD(const UIMedium &guiMedium, QITreeWidget *pParent)
574 : UIMediumItem(guiMedium, pParent)
575{
576}
577
578UIMediumItemFD::UIMediumItemFD(const UIMedium &guiMedium, QITreeWidgetItem *pParent)
579 : UIMediumItem(guiMedium, pParent)
580{
581}
582
583bool UIMediumItemFD::remove(bool fShowMessageBox)
584{
585 /* Confirm medium removal: */
586 if (fShowMessageBox)
587 if (!msgCenter().confirmMediumRemoval(medium(), treeWidget()))
588 return false;
589
590 /* Close floppy-disk: */
591 sltHandleMediumRemoveRequest(medium().medium());
592
593 /* True by default: */
594 return true;
595}
596
597bool UIMediumItemFD::releaseFrom(CMachine comMachine)
598{
599 /* Was medium released from at least one attachment? */
600 bool fAtLeastOneRelease = false;
601
602 /* Enumerate attachments: */
603 CMediumAttachmentVector attachments = comMachine.GetMediumAttachments();
604 foreach (const CMediumAttachment &attachment, attachments)
605 {
606 /* Skip non-floppy-disks: */
607 if (attachment.GetType() != KDeviceType_Floppy)
608 continue;
609
610 /* Skip unrelated floppy-disks: */
611 if (attachment.GetMedium().GetId() != id())
612 continue;
613
614 /* Try to unmount device: */
615 comMachine.MountMedium(attachment.GetController(), attachment.GetPort(), attachment.GetDevice(), CMedium(), false /* force */);
616 if (!comMachine.isOk())
617 {
618 /* Return failure: */
619 msgCenter().cannotRemountMedium(comMachine, medium(), false /* mount? */, false /* retry? */, treeWidget());
620 return false;
621 }
622 else
623 fAtLeastOneRelease = true;
624 }
625
626 /* Return whether there was at least one release: */
627 return fAtLeastOneRelease;
628}
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