VirtualBox

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

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

FE/Qt: UICommon: Switching dependency from UICommon to UIGlobalSession whenever is possible.

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