1 | /* $Id: UIMediumTools.cpp 105820 2024-08-22 14:21:54Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBox Qt GUI - UIMediumTools class implementation.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2024 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 | #include <QMenu>
|
---|
32 |
|
---|
33 | /* GUI includes: */
|
---|
34 | #include "QIFileDialog.h"
|
---|
35 | #include "UIExtraDataManager.h"
|
---|
36 | #include "UIFDCreationDialog.h"
|
---|
37 | #include "UIGlobalSession.h"
|
---|
38 | #include "UIIconPool.h"
|
---|
39 | #include "UILocalMachineStuff.h"
|
---|
40 | #include "UIMediumEnumerator.h"
|
---|
41 | #include "UIMediumSelector.h"
|
---|
42 | #include "UIMediumTools.h"
|
---|
43 | #include "UIMessageCenter.h"
|
---|
44 | #include "UIModalWindowManager.h"
|
---|
45 | #include "UINotificationCenter.h"
|
---|
46 | #include "UIVisoCreator.h"
|
---|
47 | #include "UIWizardNewVD.h"
|
---|
48 |
|
---|
49 | /* COM includes: */
|
---|
50 | #include "CMachine.h"
|
---|
51 | #include "CMedium.h"
|
---|
52 | #include "CSession.h"
|
---|
53 | #include "CStorageController.h"
|
---|
54 | #include "CSystemProperties.h"
|
---|
55 |
|
---|
56 |
|
---|
57 | QString UIMediumTools::storageDetails(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml /* = true */)
|
---|
58 | {
|
---|
59 | /* Search for corresponding UI medium: */
|
---|
60 | const QUuid uMediumID = comMedium.isNull() ? UIMedium::nullID() : comMedium.GetId();
|
---|
61 | UIMedium guiMedium = gpMediumEnumerator->medium(uMediumID);
|
---|
62 | if (!comMedium.isNull() && guiMedium.isNull())
|
---|
63 | {
|
---|
64 | /* UI medium may be new and not among cached media, request enumeration: */
|
---|
65 | gpMediumEnumerator->enumerateMedia(CMediumVector() << comMedium);
|
---|
66 |
|
---|
67 | /* Search for corresponding UI medium again: */
|
---|
68 | guiMedium = gpMediumEnumerator->medium(uMediumID);
|
---|
69 | if (guiMedium.isNull())
|
---|
70 | {
|
---|
71 | /* Medium might be deleted already, return null string: */
|
---|
72 | return QString();
|
---|
73 | }
|
---|
74 | }
|
---|
75 |
|
---|
76 | /* For differencing hard-disk we have to request
|
---|
77 | * enumeration of whole tree based in it's root item: */
|
---|
78 | if ( comMedium.isNotNull()
|
---|
79 | && comMedium.GetDeviceType() == KDeviceType_HardDisk)
|
---|
80 | {
|
---|
81 | /* Traverse through parents to root to catch it: */
|
---|
82 | CMedium comRootMedium;
|
---|
83 | CMedium comParentMedium = comMedium.GetParent();
|
---|
84 | while (comParentMedium.isNotNull())
|
---|
85 | {
|
---|
86 | comRootMedium = comParentMedium;
|
---|
87 | comParentMedium = comParentMedium.GetParent();
|
---|
88 | }
|
---|
89 | /* Enumerate root if it's found and wasn't cached: */
|
---|
90 | if (comRootMedium.isNotNull())
|
---|
91 | {
|
---|
92 | const QUuid uRootId = comRootMedium.GetId();
|
---|
93 | if (gpMediumEnumerator->medium(uRootId).isNull())
|
---|
94 | gpMediumEnumerator->enumerateMedia(CMediumVector() << comRootMedium);
|
---|
95 | }
|
---|
96 | }
|
---|
97 |
|
---|
98 | /* Return UI medium details: */
|
---|
99 | return fUseHtml ? guiMedium.detailsHTML(true /* no diffs? */, fPredictDiff) :
|
---|
100 | guiMedium.details(true /* no diffs? */, fPredictDiff);
|
---|
101 | }
|
---|
102 |
|
---|
103 | bool UIMediumTools::acquireAmountOfImmutableImages(const CMachine &comMachine, ulong &cAmount)
|
---|
104 | {
|
---|
105 | /* Acquire state: */
|
---|
106 | ulong cAmountOfImmutableImages = 0;
|
---|
107 | const KMachineState enmState = comMachine.GetState();
|
---|
108 | bool fSuccess = comMachine.isOk();
|
---|
109 | if (!fSuccess)
|
---|
110 | UINotificationMessage::cannotAcquireMachineParameter(comMachine);
|
---|
111 | else
|
---|
112 | {
|
---|
113 | /// @todo Who knows why 13 years ago this condition was added ..
|
---|
114 | if (enmState == KMachineState_Paused)
|
---|
115 | {
|
---|
116 | const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments();
|
---|
117 | fSuccess = comMachine.isOk();
|
---|
118 | if (!fSuccess)
|
---|
119 | UINotificationMessage::cannotAcquireMachineParameter(comMachine);
|
---|
120 | else
|
---|
121 | {
|
---|
122 | /* Calculate the amount of immutable attachments: */
|
---|
123 | foreach (const CMediumAttachment &comAttachment, comAttachments)
|
---|
124 | {
|
---|
125 | /* Get the medium: */
|
---|
126 | const CMedium comMedium = comAttachment.GetMedium();
|
---|
127 | if ( comMedium.isNull() /* Null medium is valid case as well */
|
---|
128 | || comMedium.GetParent().isNull() /* Null parent is valid case as well */)
|
---|
129 | continue;
|
---|
130 | /* Get the base medium: */
|
---|
131 | const CMedium comBaseMedium = comMedium.GetBase();
|
---|
132 | fSuccess = comMedium.isOk();
|
---|
133 | if (!fSuccess)
|
---|
134 | UINotificationMessage::cannotAcquireMediumParameter(comMedium);
|
---|
135 | else
|
---|
136 | {
|
---|
137 | const KMediumType enmType = comBaseMedium.GetType();
|
---|
138 | fSuccess = comBaseMedium.isOk();
|
---|
139 | if (!fSuccess)
|
---|
140 | UINotificationMessage::cannotAcquireMediumParameter(comBaseMedium);
|
---|
141 | else if (enmType == KMediumType_Immutable)
|
---|
142 | ++cAmountOfImmutableImages;
|
---|
143 | }
|
---|
144 | if (!fSuccess)
|
---|
145 | break;
|
---|
146 | }
|
---|
147 | }
|
---|
148 | }
|
---|
149 | }
|
---|
150 | if (fSuccess)
|
---|
151 | cAmount = cAmountOfImmutableImages;
|
---|
152 | return fSuccess;
|
---|
153 | }
|
---|
154 |
|
---|
155 | QString UIMediumTools::defaultFolderPathForType(UIMediumDeviceType enmMediumType)
|
---|
156 | {
|
---|
157 | QString strLastFolder;
|
---|
158 | switch (enmMediumType)
|
---|
159 | {
|
---|
160 | case UIMediumDeviceType_HardDisk:
|
---|
161 | strLastFolder = gEDataManager->recentFolderForHardDrives();
|
---|
162 | if (strLastFolder.isEmpty())
|
---|
163 | strLastFolder = gEDataManager->recentFolderForOpticalDisks();
|
---|
164 | if (strLastFolder.isEmpty())
|
---|
165 | strLastFolder = gEDataManager->recentFolderForFloppyDisks();
|
---|
166 | break;
|
---|
167 | case UIMediumDeviceType_DVD:
|
---|
168 | strLastFolder = gEDataManager->recentFolderForOpticalDisks();
|
---|
169 | if (strLastFolder.isEmpty())
|
---|
170 | strLastFolder = gEDataManager->recentFolderForFloppyDisks();
|
---|
171 | if (strLastFolder.isEmpty())
|
---|
172 | strLastFolder = gEDataManager->recentFolderForHardDrives();
|
---|
173 | break;
|
---|
174 | case UIMediumDeviceType_Floppy:
|
---|
175 | strLastFolder = gEDataManager->recentFolderForFloppyDisks();
|
---|
176 | if (strLastFolder.isEmpty())
|
---|
177 | strLastFolder = gEDataManager->recentFolderForOpticalDisks();
|
---|
178 | if (strLastFolder.isEmpty())
|
---|
179 | strLastFolder = gEDataManager->recentFolderForHardDrives();
|
---|
180 | break;
|
---|
181 | default:
|
---|
182 | break;
|
---|
183 | }
|
---|
184 |
|
---|
185 | if (strLastFolder.isEmpty())
|
---|
186 | return gpGlobalSession->virtualBox().GetSystemProperties().GetDefaultMachineFolder();
|
---|
187 |
|
---|
188 | return strLastFolder;
|
---|
189 | }
|
---|
190 |
|
---|
191 | QUuid UIMediumTools::openMedium(UIMediumDeviceType enmMediumType,
|
---|
192 | const QString &strMediumLocation,
|
---|
193 | QWidget *pParent /* = 0 */)
|
---|
194 | {
|
---|
195 | /* Convert to native separators: */
|
---|
196 | const QString strLocation = QDir::toNativeSeparators(strMediumLocation);
|
---|
197 |
|
---|
198 | /* Initialize variables: */
|
---|
199 | CVirtualBox comVBox = gpGlobalSession->virtualBox();
|
---|
200 |
|
---|
201 | /* Open corresponding medium: */
|
---|
202 | CMedium comMedium = comVBox.OpenMedium(strLocation, mediumTypeToGlobal(enmMediumType), KAccessMode_ReadWrite, false);
|
---|
203 |
|
---|
204 | if (comVBox.isOk())
|
---|
205 | {
|
---|
206 | /* Prepare vbox medium wrapper: */
|
---|
207 | UIMedium guiMedium = gpMediumEnumerator->medium(comMedium.GetId());
|
---|
208 |
|
---|
209 | /* First of all we should test if that medium already opened: */
|
---|
210 | if (guiMedium.isNull())
|
---|
211 | {
|
---|
212 | /* And create new otherwise: */
|
---|
213 | guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
|
---|
214 | gpMediumEnumerator->createMedium(guiMedium);
|
---|
215 | }
|
---|
216 |
|
---|
217 | /* Return guiMedium id: */
|
---|
218 | return guiMedium.id();
|
---|
219 | }
|
---|
220 | else
|
---|
221 | msgCenter().cannotOpenMedium(comVBox, strLocation, pParent);
|
---|
222 |
|
---|
223 | return QUuid();
|
---|
224 | }
|
---|
225 |
|
---|
226 | QUuid UIMediumTools::openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType,
|
---|
227 | QWidget *pParent,
|
---|
228 | const QString &strDefaultFolder /* = QString() */,
|
---|
229 | bool fUseLastFolder /* = false */)
|
---|
230 | {
|
---|
231 | /* Initialize variables: */
|
---|
232 | QList<QPair <QString, QString> > filters;
|
---|
233 | QStringList backends;
|
---|
234 | QStringList prefixes;
|
---|
235 | QString strFilter;
|
---|
236 | QString strTitle;
|
---|
237 | QString allType;
|
---|
238 | QString strLastFolder = defaultFolderPathForType(enmMediumType);
|
---|
239 |
|
---|
240 | /* For DVDs and Floppies always check first the last recently used medium folder.
|
---|
241 | * For hard disk use the caller's setting: */
|
---|
242 | fUseLastFolder = (enmMediumType == UIMediumDeviceType_DVD) || (enmMediumType == UIMediumDeviceType_Floppy);
|
---|
243 |
|
---|
244 | switch (enmMediumType)
|
---|
245 | {
|
---|
246 | case UIMediumDeviceType_HardDisk:
|
---|
247 | {
|
---|
248 | filters = HDDBackends(gpGlobalSession->virtualBox());
|
---|
249 | strTitle = QApplication::translate("UIMediumTools", "Please choose a virtual hard disk file");
|
---|
250 | allType = QApplication::translate("UIMediumTools", "All virtual hard disk files (%1)");
|
---|
251 | break;
|
---|
252 | }
|
---|
253 | case UIMediumDeviceType_DVD:
|
---|
254 | {
|
---|
255 | filters = DVDBackends(gpGlobalSession->virtualBox());
|
---|
256 | strTitle = QApplication::translate("UIMediumTools", "Please choose a virtual optical disk file");
|
---|
257 | allType = QApplication::translate("UIMediumTools", "All virtual optical disk files (%1)");
|
---|
258 | break;
|
---|
259 | }
|
---|
260 | case UIMediumDeviceType_Floppy:
|
---|
261 | {
|
---|
262 | filters = FloppyBackends(gpGlobalSession->virtualBox());
|
---|
263 | strTitle = QApplication::translate("UIMediumTools", "Please choose a virtual floppy disk file");
|
---|
264 | allType = QApplication::translate("UIMediumTools", "All virtual floppy disk files (%1)");
|
---|
265 | break;
|
---|
266 | }
|
---|
267 | default:
|
---|
268 | break;
|
---|
269 | }
|
---|
270 | QString strHomeFolder = fUseLastFolder && !strLastFolder.isEmpty() ? strLastFolder :
|
---|
271 | strDefaultFolder.isEmpty() ? gpGlobalSession->homeFolder() : strDefaultFolder;
|
---|
272 |
|
---|
273 | /* Prepare filters and backends: */
|
---|
274 | for (int i = 0; i < filters.count(); ++i)
|
---|
275 | {
|
---|
276 | /* Get iterated filter: */
|
---|
277 | QPair<QString, QString> item = filters.at(i);
|
---|
278 | /* Create one backend filter string: */
|
---|
279 | backends << QString("%1 (%2)").arg(item.first).arg(item.second);
|
---|
280 | /* Save the suffix's for the "All" entry: */
|
---|
281 | prefixes << item.second;
|
---|
282 | }
|
---|
283 | if (!prefixes.isEmpty())
|
---|
284 | backends.insert(0, allType.arg(prefixes.join(" ").trimmed()));
|
---|
285 | backends << QApplication::translate("UIMediumTools", "All files (*)");
|
---|
286 | strFilter = backends.join(";;").trimmed();
|
---|
287 |
|
---|
288 | /* Create open file dialog: */
|
---|
289 | QStringList files = QIFileDialog::getOpenFileNames(strHomeFolder, strFilter, pParent, strTitle, 0, true, true);
|
---|
290 |
|
---|
291 | /* If dialog has some result: */
|
---|
292 | if (!files.empty() && !files[0].isEmpty())
|
---|
293 | {
|
---|
294 | QUuid uMediumId = openMedium(enmMediumType, files[0], pParent);
|
---|
295 | if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy ||
|
---|
296 | (enmMediumType == UIMediumDeviceType_HardDisk && fUseLastFolder))
|
---|
297 | gpMediumEnumerator->updateRecentlyUsedMediumListAndFolder(enmMediumType, gpMediumEnumerator->medium(uMediumId).location());
|
---|
298 | return uMediumId;
|
---|
299 | }
|
---|
300 | return QUuid();
|
---|
301 | }
|
---|
302 |
|
---|
303 | QUuid UIMediumTools::openMediumCreatorDialog(UIActionPool *pActionPool,
|
---|
304 | QWidget *pParent,
|
---|
305 | UIMediumDeviceType enmMediumType,
|
---|
306 | const QString &strDefaultFolder /* = QString() */,
|
---|
307 | const QString &strMachineName /* = QString() */,
|
---|
308 | const QString &strMachineGuestOSTypeId /*= QString() */)
|
---|
309 | {
|
---|
310 | /* Depending on medium-type: */
|
---|
311 | QUuid uMediumId;
|
---|
312 | switch (enmMediumType)
|
---|
313 | {
|
---|
314 | case UIMediumDeviceType_HardDisk:
|
---|
315 | uMediumId = UIWizardNewVD::createVDWithWizard(pParent, strDefaultFolder, strMachineName, strMachineGuestOSTypeId);
|
---|
316 | break;
|
---|
317 | case UIMediumDeviceType_DVD:
|
---|
318 | uMediumId = UIVisoCreatorDialog::createViso(pActionPool, pParent, strDefaultFolder, strMachineName);
|
---|
319 | break;
|
---|
320 | case UIMediumDeviceType_Floppy:
|
---|
321 | uMediumId = UIFDCreationDialog::createFloppyDisk(pParent, strDefaultFolder, strMachineName);
|
---|
322 | break;
|
---|
323 | default:
|
---|
324 | break;
|
---|
325 | }
|
---|
326 | if (uMediumId.isNull())
|
---|
327 | return QUuid();
|
---|
328 |
|
---|
329 | /* Update the recent medium list only if the medium type is floppy since updating when a VISO is created is not optimal: */
|
---|
330 | if (enmMediumType == UIMediumDeviceType_Floppy)
|
---|
331 | gpMediumEnumerator->updateRecentlyUsedMediumListAndFolder(enmMediumType, gpMediumEnumerator->medium(uMediumId).location());
|
---|
332 | return uMediumId;
|
---|
333 | }
|
---|
334 |
|
---|
335 | void UIMediumTools::prepareStorageMenu(QMenu *pMenu,
|
---|
336 | QObject *pListener,
|
---|
337 | const char *pszSlotName,
|
---|
338 | const CMachine &comMachine,
|
---|
339 | const QString &strControllerName,
|
---|
340 | const StorageSlot &storageSlot)
|
---|
341 | {
|
---|
342 | /* Current attachment attributes: */
|
---|
343 | const CMediumAttachment comCurrentAttachment = comMachine.GetMediumAttachment(strControllerName,
|
---|
344 | storageSlot.port,
|
---|
345 | storageSlot.device);
|
---|
346 | const CMedium comCurrentMedium = comCurrentAttachment.GetMedium();
|
---|
347 | const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId();
|
---|
348 | const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation();
|
---|
349 |
|
---|
350 | /* Other medium-attachments of same machine: */
|
---|
351 | const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments();
|
---|
352 |
|
---|
353 | /* Determine device & medium types: */
|
---|
354 | const UIMediumDeviceType enmMediumType = mediumTypeToLocal(comCurrentAttachment.GetType());
|
---|
355 | AssertMsgReturnVoid(enmMediumType != UIMediumDeviceType_Invalid, ("Incorrect storage medium type!\n"));
|
---|
356 |
|
---|
357 | /* Prepare open-existing-medium action: */
|
---|
358 | QAction *pActionOpenExistingMedium = pMenu->addAction(UIIconPool::iconSet(":/select_file_16px.png"),
|
---|
359 | QString(), pListener, pszSlotName);
|
---|
360 | pActionOpenExistingMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
|
---|
361 | comCurrentAttachment.GetDevice(), enmMediumType)));
|
---|
362 | pActionOpenExistingMedium->setText(QApplication::translate("UIMediumTools", "Choose/Create a Disk Image..."));
|
---|
363 |
|
---|
364 | /* Prepare open medium file action: */
|
---|
365 | QAction *pActionFileSelector = pMenu->addAction(UIIconPool::iconSet(":/select_file_16px.png"),
|
---|
366 | QString(), pListener, pszSlotName);
|
---|
367 | pActionFileSelector->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
|
---|
368 | comCurrentAttachment.GetDevice(), enmMediumType,
|
---|
369 | UIMediumTarget::UIMediumTargetType_WithFileDialog)));
|
---|
370 | pActionFileSelector->setText(QApplication::translate("UIMediumTools", "Choose a Disk File..."));
|
---|
371 |
|
---|
372 | /* Insert separator: */
|
---|
373 | pMenu->addSeparator();
|
---|
374 |
|
---|
375 | /* Get existing-host-drive vector: */
|
---|
376 | CMediumVector comMedia;
|
---|
377 | switch (enmMediumType)
|
---|
378 | {
|
---|
379 | case UIMediumDeviceType_DVD: comMedia = gpGlobalSession->host().GetDVDDrives(); break;
|
---|
380 | case UIMediumDeviceType_Floppy: comMedia = gpGlobalSession->host().GetFloppyDrives(); break;
|
---|
381 | default: break;
|
---|
382 | }
|
---|
383 | /* Prepare choose-existing-host-drive actions: */
|
---|
384 | foreach (const CMedium &comMedium, comMedia)
|
---|
385 | {
|
---|
386 | /* Make sure host-drive usage is unique: */
|
---|
387 | bool fIsHostDriveUsed = false;
|
---|
388 | foreach (const CMediumAttachment &comOtherAttachment, comAttachments)
|
---|
389 | {
|
---|
390 | if (comOtherAttachment != comCurrentAttachment)
|
---|
391 | {
|
---|
392 | const CMedium &comOtherMedium = comOtherAttachment.GetMedium();
|
---|
393 | if (!comOtherMedium.isNull() && comOtherMedium.GetId() == comMedium.GetId())
|
---|
394 | {
|
---|
395 | fIsHostDriveUsed = true;
|
---|
396 | break;
|
---|
397 | }
|
---|
398 | }
|
---|
399 | }
|
---|
400 | /* If host-drives usage is unique: */
|
---|
401 | if (!fIsHostDriveUsed)
|
---|
402 | {
|
---|
403 | QAction *pActionChooseHostDrive = pMenu->addAction(UIMedium(comMedium, enmMediumType).name(), pListener, pszSlotName);
|
---|
404 | pActionChooseHostDrive->setCheckable(true);
|
---|
405 | pActionChooseHostDrive->setChecked(!comCurrentMedium.isNull() && comMedium.GetId() == uCurrentID);
|
---|
406 | pActionChooseHostDrive->setData(QVariant::fromValue(UIMediumTarget(strControllerName,
|
---|
407 | comCurrentAttachment.GetPort(),
|
---|
408 | comCurrentAttachment.GetDevice(),
|
---|
409 | enmMediumType,
|
---|
410 | UIMediumTarget::UIMediumTargetType_WithID,
|
---|
411 | comMedium.GetId().toString())));
|
---|
412 | }
|
---|
413 | }
|
---|
414 |
|
---|
415 | /* Get recent-medium list: */
|
---|
416 | QStringList recentMediumList;
|
---|
417 | QStringList recentMediumListUsed;
|
---|
418 | switch (enmMediumType)
|
---|
419 | {
|
---|
420 | case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break;
|
---|
421 | case UIMediumDeviceType_DVD: recentMediumList = gEDataManager->recentListOfOpticalDisks(); break;
|
---|
422 | case UIMediumDeviceType_Floppy: recentMediumList = gEDataManager->recentListOfFloppyDisks(); break;
|
---|
423 | default: break;
|
---|
424 | }
|
---|
425 | /* Prepare choose-recent-medium actions: */
|
---|
426 | foreach (const QString &strRecentMediumLocationBase, recentMediumList)
|
---|
427 | {
|
---|
428 | /* Confirm medium uniqueness: */
|
---|
429 | if (recentMediumListUsed.contains(strRecentMediumLocationBase))
|
---|
430 | continue;
|
---|
431 | /* Mark medium as known: */
|
---|
432 | recentMediumListUsed << strRecentMediumLocationBase;
|
---|
433 | /* Convert separators to native: */
|
---|
434 | const QString strRecentMediumLocation = QDir::toNativeSeparators(strRecentMediumLocationBase);
|
---|
435 | /* Confirm medium presence: */
|
---|
436 | if (!QFile::exists(strRecentMediumLocation))
|
---|
437 | continue;
|
---|
438 | /* Make sure recent-medium usage is unique: */
|
---|
439 | bool fIsRecentMediumUsed = false;
|
---|
440 | if (enmMediumType != UIMediumDeviceType_DVD)
|
---|
441 | {
|
---|
442 | foreach (const CMediumAttachment &otherAttachment, comAttachments)
|
---|
443 | {
|
---|
444 | if (otherAttachment != comCurrentAttachment)
|
---|
445 | {
|
---|
446 | const CMedium &comOtherMedium = otherAttachment.GetMedium();
|
---|
447 | if (!comOtherMedium.isNull() && comOtherMedium.GetLocation() == strRecentMediumLocation)
|
---|
448 | {
|
---|
449 | fIsRecentMediumUsed = true;
|
---|
450 | break;
|
---|
451 | }
|
---|
452 | }
|
---|
453 | }
|
---|
454 | }
|
---|
455 | /* If recent-medium usage is unique: */
|
---|
456 | if (!fIsRecentMediumUsed)
|
---|
457 | {
|
---|
458 | QAction *pActionChooseRecentMedium = pMenu->addAction(QFileInfo(strRecentMediumLocation).fileName(),
|
---|
459 | pListener, pszSlotName);
|
---|
460 | pActionChooseRecentMedium->setCheckable(true);
|
---|
461 | pActionChooseRecentMedium->setChecked(!comCurrentMedium.isNull() && strRecentMediumLocation == strCurrentLocation);
|
---|
462 | pActionChooseRecentMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName,
|
---|
463 | comCurrentAttachment.GetPort(),
|
---|
464 | comCurrentAttachment.GetDevice(),
|
---|
465 | enmMediumType,
|
---|
466 | UIMediumTarget::UIMediumTargetType_WithLocation,
|
---|
467 | strRecentMediumLocation)));
|
---|
468 | pActionChooseRecentMedium->setToolTip(strRecentMediumLocation);
|
---|
469 | }
|
---|
470 | }
|
---|
471 |
|
---|
472 | /* Last action for optical/floppy attachments only: */
|
---|
473 | if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy)
|
---|
474 | {
|
---|
475 | /* Insert separator: */
|
---|
476 | pMenu->addSeparator();
|
---|
477 |
|
---|
478 | /* Prepare unmount-current-medium action: */
|
---|
479 | QAction *pActionUnmountMedium = pMenu->addAction(QString(), pListener, pszSlotName);
|
---|
480 | pActionUnmountMedium->setEnabled(!comCurrentMedium.isNull());
|
---|
481 | pActionUnmountMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
|
---|
482 | comCurrentAttachment.GetDevice())));
|
---|
483 | pActionUnmountMedium->setText(QApplication::translate("UIMediumTools", "Remove Disk From Virtual Drive"));
|
---|
484 | if (enmMediumType == UIMediumDeviceType_DVD)
|
---|
485 | pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/cd_unmount_16px.png", ":/cd_unmount_disabled_16px.png"));
|
---|
486 | else if (enmMediumType == UIMediumDeviceType_Floppy)
|
---|
487 | pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/fd_unmount_16px.png", ":/fd_unmount_disabled_16px.png"));
|
---|
488 | }
|
---|
489 | }
|
---|
490 |
|
---|
491 | void UIMediumTools::updateMachineStorage(const CMachine &comConstMachine,
|
---|
492 | const UIMediumTarget &target,
|
---|
493 | UIActionPool *pActionPool)
|
---|
494 | {
|
---|
495 | /* Mount (by default): */
|
---|
496 | bool fMount = true;
|
---|
497 | /* Null medium (by default): */
|
---|
498 | CMedium comMedium;
|
---|
499 | /* With null ID (by default): */
|
---|
500 | QUuid uActualID;
|
---|
501 |
|
---|
502 | /* Current mount-target attributes: */
|
---|
503 | const CStorageController comCurrentController = comConstMachine.GetStorageControllerByName(target.name);
|
---|
504 | const KStorageBus enmCurrentStorageBus = comCurrentController.GetBus();
|
---|
505 | const CMediumAttachment comCurrentAttachment = comConstMachine.GetMediumAttachment(target.name, target.port, target.device);
|
---|
506 | const CMedium comCurrentMedium = comCurrentAttachment.GetMedium();
|
---|
507 | const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId();
|
---|
508 | const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation();
|
---|
509 |
|
---|
510 | /* Which additional info do we have? */
|
---|
511 | switch (target.type)
|
---|
512 | {
|
---|
513 | /* Do we have an exact ID or do we let the user open a medium? */
|
---|
514 | case UIMediumTarget::UIMediumTargetType_WithID:
|
---|
515 | case UIMediumTarget::UIMediumTargetType_WithFileDialog:
|
---|
516 | case UIMediumTarget::UIMediumTargetType_CreateAdHocVISO:
|
---|
517 | case UIMediumTarget::UIMediumTargetType_CreateFloppyDisk:
|
---|
518 | {
|
---|
519 | /* New mount-target attributes: */
|
---|
520 | QUuid uNewID;
|
---|
521 |
|
---|
522 | /* Invoke file-open dialog to choose medium ID: */
|
---|
523 | if (target.mediumType != UIMediumDeviceType_Invalid && target.data.isNull())
|
---|
524 | {
|
---|
525 | /* Keyboard can be captured by machine-view.
|
---|
526 | * So we should clear machine-view focus to let file-open dialog get it.
|
---|
527 | * That way the keyboard will be released too.. */
|
---|
528 | QWidget *pLastFocusedWidget = 0;
|
---|
529 | if (QApplication::focusWidget())
|
---|
530 | {
|
---|
531 | pLastFocusedWidget = QApplication::focusWidget();
|
---|
532 | pLastFocusedWidget->clearFocus();
|
---|
533 | }
|
---|
534 | /* Call for file-open dialog: */
|
---|
535 | const QString strMachineFolder(QFileInfo(comConstMachine.GetSettingsFilePath()).absolutePath());
|
---|
536 | QUuid uMediumID;
|
---|
537 | if (target.type == UIMediumTarget::UIMediumTargetType_WithID)
|
---|
538 | {
|
---|
539 | int iDialogReturn = UIMediumSelector::openMediumSelectorDialog(windowManager().mainWindowShown(), target.mediumType,
|
---|
540 | uCurrentID, uMediumID,
|
---|
541 | strMachineFolder, comConstMachine.GetName(),
|
---|
542 | comConstMachine.GetOSTypeId(), true /*fEnableCreate */,
|
---|
543 | comConstMachine.GetId(), pActionPool);
|
---|
544 | if (iDialogReturn == UIMediumSelector::ReturnCode_LeftEmpty &&
|
---|
545 | (target.mediumType == UIMediumDeviceType_DVD || target.mediumType == UIMediumDeviceType_Floppy))
|
---|
546 | fMount = false;
|
---|
547 | }
|
---|
548 | else if (target.type == UIMediumTarget::UIMediumTargetType_WithFileDialog)
|
---|
549 | {
|
---|
550 | uMediumID = openMediumWithFileOpenDialog(target.mediumType, windowManager().mainWindowShown(),
|
---|
551 | strMachineFolder, false /* fUseLastFolder */);
|
---|
552 | }
|
---|
553 | else if(target.type == UIMediumTarget::UIMediumTargetType_CreateAdHocVISO)
|
---|
554 | UIVisoCreatorDialog::createViso(pActionPool, windowManager().mainWindowShown(),
|
---|
555 | strMachineFolder, comConstMachine.GetName());
|
---|
556 |
|
---|
557 | else if(target.type == UIMediumTarget::UIMediumTargetType_CreateFloppyDisk)
|
---|
558 | uMediumID = UIFDCreationDialog::createFloppyDisk(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName());
|
---|
559 |
|
---|
560 | /* Return focus back: */
|
---|
561 | if (pLastFocusedWidget)
|
---|
562 | pLastFocusedWidget->setFocus();
|
---|
563 | /* Accept new medium ID: */
|
---|
564 | if (!uMediumID.isNull())
|
---|
565 | uNewID = uMediumID;
|
---|
566 | else
|
---|
567 | /* Else just exit in case left empty is not chosen in medium selector dialog: */
|
---|
568 | if (fMount)
|
---|
569 | return;
|
---|
570 | }
|
---|
571 | /* Use medium ID which was passed: */
|
---|
572 | else if (!target.data.isNull() && target.data != uCurrentID.toString())
|
---|
573 | uNewID = QUuid(target.data);
|
---|
574 |
|
---|
575 | /* Should we mount or unmount? */
|
---|
576 | fMount = !uNewID.isNull();
|
---|
577 |
|
---|
578 | /* Prepare target medium: */
|
---|
579 | const UIMedium guiMedium = gpMediumEnumerator->medium(uNewID);
|
---|
580 | comMedium = guiMedium.medium();
|
---|
581 | uActualID = fMount ? uNewID : uCurrentID;
|
---|
582 | break;
|
---|
583 | }
|
---|
584 | /* Do we have a recent location? */
|
---|
585 | case UIMediumTarget::UIMediumTargetType_WithLocation:
|
---|
586 | {
|
---|
587 | /* Open medium by location and get new medium ID if any: */
|
---|
588 | const QUuid uNewID = openMedium(target.mediumType, target.data);
|
---|
589 | /* Else just exit: */
|
---|
590 | if (uNewID.isNull())
|
---|
591 | return;
|
---|
592 |
|
---|
593 | /* Should we mount or unmount? */
|
---|
594 | fMount = uNewID != uCurrentID;
|
---|
595 |
|
---|
596 | /* Prepare target medium: */
|
---|
597 | const UIMedium guiMedium = fMount ? gpMediumEnumerator->medium(uNewID) : UIMedium();
|
---|
598 | comMedium = fMount ? guiMedium.medium() : CMedium();
|
---|
599 | uActualID = fMount ? uNewID : uCurrentID;
|
---|
600 | break;
|
---|
601 | }
|
---|
602 | }
|
---|
603 |
|
---|
604 | /* Do not unmount hard-drives: */
|
---|
605 | if (target.mediumType == UIMediumDeviceType_HardDisk && !fMount)
|
---|
606 | return;
|
---|
607 |
|
---|
608 | /* Get editable machine & session: */
|
---|
609 | CMachine comMachine = comConstMachine;
|
---|
610 | CSession comSession = tryToOpenSessionFor(comMachine);
|
---|
611 |
|
---|
612 | /* Remount medium to the predefined port/device: */
|
---|
613 | bool fWasMounted = false;
|
---|
614 | /* Hard drive case: */
|
---|
615 | if (target.mediumType == UIMediumDeviceType_HardDisk)
|
---|
616 | {
|
---|
617 | /* Detaching: */
|
---|
618 | comMachine.DetachDevice(target.name, target.port, target.device);
|
---|
619 | fWasMounted = comMachine.isOk();
|
---|
620 | if (!fWasMounted)
|
---|
621 | msgCenter().cannotDetachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation,
|
---|
622 | StorageSlot(enmCurrentStorageBus, target.port, target.device));
|
---|
623 | else
|
---|
624 | {
|
---|
625 | /* Attaching: */
|
---|
626 | comMachine.AttachDevice(target.name, target.port, target.device, KDeviceType_HardDisk, comMedium);
|
---|
627 | fWasMounted = comMachine.isOk();
|
---|
628 | if (!fWasMounted)
|
---|
629 | msgCenter().cannotAttachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation,
|
---|
630 | StorageSlot(enmCurrentStorageBus, target.port, target.device));
|
---|
631 | }
|
---|
632 | }
|
---|
633 | /* Optical/floppy drive case: */
|
---|
634 | else
|
---|
635 | {
|
---|
636 | /* Remounting: */
|
---|
637 | comMachine.MountMedium(target.name, target.port, target.device, comMedium, false /* force? */);
|
---|
638 | fWasMounted = comMachine.isOk();
|
---|
639 | if (!fWasMounted)
|
---|
640 | {
|
---|
641 | /* Ask for force remounting: */
|
---|
642 | if (msgCenter().cannotRemountMedium(comMachine, gpMediumEnumerator->medium(uActualID),
|
---|
643 | fMount, true /* retry? */))
|
---|
644 | {
|
---|
645 | /* Force remounting: */
|
---|
646 | comMachine.MountMedium(target.name, target.port, target.device, comMedium, true /* force? */);
|
---|
647 | fWasMounted = comMachine.isOk();
|
---|
648 | if (!fWasMounted)
|
---|
649 | msgCenter().cannotRemountMedium(comMachine, gpMediumEnumerator->medium(uActualID),
|
---|
650 | fMount, false /* retry? */);
|
---|
651 | }
|
---|
652 | }
|
---|
653 | }
|
---|
654 |
|
---|
655 | /* Save settings: */
|
---|
656 | if (fWasMounted)
|
---|
657 | {
|
---|
658 | comMachine.SaveSettings();
|
---|
659 | if (!comMachine.isOk())
|
---|
660 | msgCenter().cannotSaveMachineSettings(comMachine, windowManager().mainWindowShown());
|
---|
661 | }
|
---|
662 |
|
---|
663 | /* Close session to editable comMachine if necessary: */
|
---|
664 | if (!comSession.isNull())
|
---|
665 | comSession.UnlockMachine();
|
---|
666 | }
|
---|