VirtualBox

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

Last change on this file was 104915, checked in by vboxsync, 3 months ago

FE/Qt: UIMediumEnumerator: Moving some unrelated stuff to UIMediumTools namespace as that's more suitable place for this one.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.7 KB
Line 
1/* $Id: UIMediumEnumerator.cpp 104915 2024-06-13 13:18:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMediumEnumerator class implementation.
4 */
5
6/*
7 * Copyright (C) 2013-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 <QFileInfo>
30#include <QSet>
31
32/* GUI includes: */
33#include "UICommon.h"
34#include "UIErrorString.h"
35#include "UIExtraDataManager.h"
36#include "UIGlobalSession.h"
37#include "UILoggingDefs.h"
38#include "UIMediumEnumerator.h"
39#include "UINotificationCenter.h"
40#include "UITask.h"
41#include "UITranslationEventListener.h"
42#include "UIThreadPool.h"
43#include "UIVirtualBoxEventHandler.h"
44
45/* COM includes: */
46#include "CMachine.h"
47#include "CMediumAttachment.h"
48#include "CSnapshot.h"
49
50
51/** Template function to convert a list of
52 * abstract objects to a human readable string list.
53 * @note T should have .toString() member implemented. */
54template<class T> static QStringList toStringList(const QList<T> &list)
55{
56 QStringList l;
57 foreach(const T &t, list)
58 l << t.toString();
59 return l;
60}
61
62
63/** UITask extension used for medium-enumeration purposes.
64 * @note We made setting/getting medium a thread-safe stuff. But this wasn't
65 * dangerous for us before since setter/getter calls are splitted in time
66 * by enumeration logic. Previously we were even using
67 * property/setProperty API for that but latest Qt versions prohibits
68 * property/setProperty API usage from other than the GUI thread so we
69 * had to rework that stuff to be thread-safe for Qt >= 5.11. */
70class UITaskMediumEnumeration : public UITask
71{
72 Q_OBJECT;
73
74public:
75
76 /** Constructs @a guiMedium enumeration task. */
77 UITaskMediumEnumeration(const UIMedium &guiMedium)
78 : UITask(UITask::Type_MediumEnumeration)
79 , m_guiMedium(guiMedium)
80 {}
81
82 /** Returns GUI medium. */
83 UIMedium medium() const
84 {
85 /* Acquire under a proper lock: */
86 m_mutex.lock();
87 const UIMedium guiMedium = m_guiMedium;
88 m_mutex.unlock();
89 return guiMedium;
90 }
91
92private:
93
94 /** Contains medium-enumeration task body. */
95 virtual void run() RT_OVERRIDE
96 {
97 /* Enumerate under a proper lock: */
98 m_mutex.lock();
99 m_guiMedium.blockAndQueryState();
100 m_mutex.unlock();
101 }
102
103 /** Holds the mutex to access m_guiMedium member. */
104 mutable QMutex m_mutex;
105 /** Holds the medium being enumerated. */
106 UIMedium m_guiMedium;
107};
108
109
110/*********************************************************************************************************************************
111* Class UIMediumEnumerator implementation. *
112*********************************************************************************************************************************/
113
114/* static */
115UIMediumEnumerator *UIMediumEnumerator::s_pInstance = 0;
116
117/* static */
118QReadWriteLock UIMediumEnumerator::s_guiCleanupProtectionToken = QReadWriteLock();
119
120/* static */
121void UIMediumEnumerator::create()
122{
123 AssertReturnVoid(!s_pInstance);
124 s_pInstance = new UIMediumEnumerator;
125}
126
127/* static */
128void UIMediumEnumerator::destroy()
129{
130 AssertPtrReturnVoid(s_pInstance);
131
132 s_guiCleanupProtectionToken.lockForWrite();
133 delete s_pInstance;
134 s_pInstance = 0;
135 s_guiCleanupProtectionToken.unlock();
136}
137
138/* static */
139UIMediumEnumerator *UIMediumEnumerator::instance()
140{
141 /* This is the fallback behavior, we need the lazy-init here
142 * only to make sure gpMediumEnumerator is never NULL. */
143 AssertPtr(s_pInstance);
144 if (!s_pInstance)
145 create();
146 return s_pInstance;
147}
148
149/* static */
150bool UIMediumEnumerator::exists()
151{
152 return !!s_pInstance;
153}
154
155UIMediumEnumerator::UIMediumEnumerator()
156 : m_fFullMediumEnumerationRequested(false)
157 , m_fMediumEnumerationInProgress(false)
158{
159 /* Allow UIMedium to be used in inter-thread signals: */
160 qRegisterMetaType<UIMedium>();
161
162 /* Prepare Main event handlers: */
163 /* Machine related events: */
164 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineDataChange,
165 this, &UIMediumEnumerator::sltHandleMachineDataChange);
166 /* Medium related events: */
167 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigStorageControllerChange,
168 this, &UIMediumEnumerator::sltHandleStorageControllerChange);
169 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigStorageDeviceChange,
170 this, &UIMediumEnumerator::sltHandleStorageDeviceChange);
171 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMediumChange,
172 this, &UIMediumEnumerator::sltHandleMediumChange);
173 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMediumConfigChange,
174 this, &UIMediumEnumerator::sltHandleMediumConfigChange);
175 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMediumRegistered,
176 this, &UIMediumEnumerator::sltHandleMediumRegistered);
177
178 /* Prepare global thread-pool listener: */
179 connect(uiCommon().threadPool(), &UIThreadPool::sigTaskComplete,
180 this, &UIMediumEnumerator::sltHandleMediumEnumerationTaskComplete);
181
182 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
183 this, &UIMediumEnumerator::sltRetranslateUI);
184
185 /* We should make sure media map contains at least NULL medium object: */
186 addNullMediumToMap(m_media);
187 /* Notify listener about initial enumeration started/finished instantly: */
188 LogRel(("GUI: UIMediumEnumerator: Initial medium-enumeration finished!\n"));
189 emit sigMediumEnumerationStarted();
190 emit sigMediumEnumerationFinished();
191
192 /* Populate the list of medium names to be excluded from the recently used media extra data: */
193#if 0 /* bird: This is counter productive as it is _frequently_ necessary to re-insert the
194 viso to refresh the files (like after you rebuilt them on the host).
195 The guest caches ISOs aggressively and files sizes may change. */
196 m_recentMediaExcludeList << "ad-hoc.viso";
197#endif
198}
199
200QList<QUuid> UIMediumEnumerator::mediumIDs() const
201{
202 /* Redirect request to subroutine under proper lock: */
203 if (s_guiCleanupProtectionToken.tryLockForRead())
204 {
205 const QList<QUuid> mediaList = mediumIDsSub();
206 s_guiCleanupProtectionToken.unlock();
207 return mediaList;
208 }
209 return QList<QUuid>();
210}
211
212UIMedium UIMediumEnumerator::medium(const QUuid &uMediumID) const
213{
214 /* Redirect request to subroutine under proper lock: */
215 if (s_guiCleanupProtectionToken.tryLockForRead())
216 {
217 const UIMedium guiMedium = mediumSub(uMediumID);
218 s_guiCleanupProtectionToken.unlock();
219 return guiMedium;
220 }
221 return UIMedium();
222}
223
224void UIMediumEnumerator::createMedium(const UIMedium &guiMedium)
225{
226 /* Redirect request to subroutine under proper lock: */
227 if (s_guiCleanupProtectionToken.tryLockForRead())
228 {
229 createMediumSub(guiMedium);
230 s_guiCleanupProtectionToken.unlock();
231 }
232}
233
234void UIMediumEnumerator::enumerateMedia(const CMediumVector &comMedia /* = CMediumVector() */)
235{
236 /* Make sure UICommon is already valid: */
237 AssertReturnVoid(uiCommon().isValid());
238 /* Ignore the request during UICommon cleanup: */
239 if (uiCommon().isCleaningUp())
240 return;
241 /* Ignore the request during startup snapshot restoring: */
242 if (uiCommon().shouldRestoreCurrentSnapshot())
243 return;
244
245 /* Redirect request to subroutine under proper lock: */
246 if (s_guiCleanupProtectionToken.tryLockForRead())
247 {
248 enumerateMediaSub(comMedia);
249 s_guiCleanupProtectionToken.unlock();
250 }
251}
252
253void UIMediumEnumerator::refreshMedia()
254{
255 /* Make sure UICommon is already valid: */
256 AssertReturnVoid(uiCommon().isValid());
257 /* Ignore the request during UICommon cleanup: */
258 if (uiCommon().isCleaningUp())
259 return;
260 /* Ignore the request during startup snapshot restoring: */
261 if (uiCommon().shouldRestoreCurrentSnapshot())
262 return;
263
264 /* Make sure enumeration is not already started: */
265 if (isMediumEnumerationInProgress())
266 return;
267
268 /* We assume it's safe to call it without locking,
269 * since we are performing blocking operation here. */
270 gpMediumEnumerator->refreshMediaSub();
271}
272
273void UIMediumEnumerator::updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation)
274{
275 /* Don't add the medium to extra data if its name is in exclude list, m_recentMediaExcludeList: */
276 foreach (const QString &strExcludeName, m_recentMediaExcludeList)
277 if (strMediumLocation.contains(strExcludeName))
278 return;
279
280 /* Remember the path of the last chosen medium: */
281 switch (enmMediumType)
282 {
283 case UIMediumDeviceType_HardDisk:
284 gEDataManager->setRecentFolderForHardDrives(QFileInfo(strMediumLocation).absolutePath());
285 break;
286 case UIMediumDeviceType_DVD:
287 gEDataManager->setRecentFolderForOpticalDisks(QFileInfo(strMediumLocation).absolutePath());
288 break;
289 case UIMediumDeviceType_Floppy:
290 gEDataManager->setRecentFolderForFloppyDisks(QFileInfo(strMediumLocation).absolutePath());
291 break;
292 default:
293 break;
294 }
295
296 /* Update recently used list: */
297 QStringList recentMediumList;
298 switch (enmMediumType)
299 {
300 case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break;
301 case UIMediumDeviceType_DVD: recentMediumList = gEDataManager->recentListOfOpticalDisks(); break;
302 case UIMediumDeviceType_Floppy: recentMediumList = gEDataManager->recentListOfFloppyDisks(); break;
303 default: break;
304 }
305 if (recentMediumList.contains(strMediumLocation))
306 recentMediumList.removeAll(strMediumLocation);
307 recentMediumList.prepend(strMediumLocation);
308 while(recentMediumList.size() > 5)
309 recentMediumList.removeLast();
310 switch (enmMediumType)
311 {
312 case UIMediumDeviceType_HardDisk: gEDataManager->setRecentListOfHardDrives(recentMediumList); break;
313 case UIMediumDeviceType_DVD: gEDataManager->setRecentListOfOpticalDisks(recentMediumList); break;
314 case UIMediumDeviceType_Floppy: gEDataManager->setRecentListOfFloppyDisks(recentMediumList); break;
315 default: break;
316 }
317 emit sigRecentMediaListUpdated(enmMediumType);
318}
319
320void UIMediumEnumerator::sltHandleMediumCreated(const CMedium &comMedium)
321{
322 /* Acquire device type: */
323 const KDeviceType enmDeviceType = comMedium.GetDeviceType();
324 if (!comMedium.isOk())
325 UINotificationMessage::cannotAcquireMediumParameter(comMedium);
326 else
327 {
328 /* Convert to medium type: */
329 const UIMediumDeviceType enmMediumType = mediumTypeToLocal(enmDeviceType);
330
331 /* Make sure we cached created medium in GUI: */
332 createMedium(UIMedium(comMedium, enmMediumType, KMediumState_Created));
333 }
334}
335
336void UIMediumEnumerator::sltRetranslateUI()
337{
338 /* Translating NULL UIMedium by recreating it: */
339 if (m_media.contains(UIMedium::nullID()))
340 m_media[UIMedium::nullID()] = UIMedium();
341}
342
343void UIMediumEnumerator::sltHandleMachineDataChange(const QUuid &uMachineId)
344{
345 //printf("MachineDataChange: machine-id=%s\n",
346 // uMachineId.toString().toUtf8().constData());
347 LogRel2(("GUI: UIMediumEnumerator: MachineDataChange event received, Machine ID = {%s}\n",
348 uMachineId.toString().toUtf8().constData()));
349
350 /* Enumerate all the media of machine with this ID: */
351 QList<QUuid> result;
352 enumerateAllMediaOfMachineWithId(uMachineId, result);
353}
354
355void UIMediumEnumerator::sltHandleStorageControllerChange(const QUuid &uMachineId, const QString &strControllerName)
356{
357 //printf("StorageControllerChanged: machine-id=%s, controller-name=%s\n",
358 // uMachineId.toString().toUtf8().constData(), strControllerName.toUtf8().constData());
359 LogRel2(("GUI: UIMediumEnumerator: StorageControllerChanged event received, Medium ID = {%s}, Controller Name = {%s}\n",
360 uMachineId.toString().toUtf8().constData(), strControllerName.toUtf8().constData()));
361}
362
363void UIMediumEnumerator::sltHandleStorageDeviceChange(CMediumAttachment comAttachment, bool fRemoved, bool fSilent)
364{
365 //printf("StorageDeviceChanged: removed=%d, silent=%d\n",
366 // fRemoved, fSilent);
367 LogRel2(("GUI: UIMediumEnumerator: StorageDeviceChanged event received, Removed = {%d}, Silent = {%d}\n",
368 fRemoved, fSilent));
369
370 /* Parse attachment: */
371 QList<QUuid> result;
372 parseAttachment(comAttachment, result);
373}
374
375void UIMediumEnumerator::sltHandleMediumChange(CMediumAttachment comAttachment)
376{
377 //printf("MediumChanged\n");
378 LogRel2(("GUI: UIMediumEnumerator: MediumChanged event received\n"));
379
380 /* Parse attachment: */
381 QList<QUuid> result;
382 parseAttachment(comAttachment, result);
383}
384
385void UIMediumEnumerator::sltHandleMediumConfigChange(CMedium comMedium)
386{
387 //printf("MediumConfigChanged\n");
388 LogRel2(("GUI: UIMediumEnumerator: MediumConfigChanged event received\n"));
389
390 /* Parse medium: */
391 QList<QUuid> result;
392 parseMedium(comMedium, result);
393}
394
395void UIMediumEnumerator::sltHandleMediumRegistered(const QUuid &uMediumId, KDeviceType enmMediumType, bool fRegistered)
396{
397 //printf("MediumRegistered: medium-id=%s, medium-type=%d, registered=%d\n",
398 // uMediumId.toString().toUtf8().constData(), enmMediumType, fRegistered);
399 //printf(" Medium to recache: %s\n",
400 // uMediumId.toString().toUtf8().constData());
401 LogRel2(("GUI: UIMediumEnumerator: MediumRegistered event received, Medium ID = {%s}, Medium type = {%d}, Registered = {%d}\n",
402 uMediumId.toString().toUtf8().constData(), enmMediumType, fRegistered));
403
404 /* New medium registered: */
405 if (fRegistered)
406 {
407 /* Make sure this medium isn't already cached: */
408 if (!mediumSub(uMediumId).isNull())
409 {
410 /* This medium can be known because of async event nature. Currently medium registration event comes
411 * very late and other even unrelated events can come before it and request for this particular medium
412 * enumeration, so we just ignore repetitive events but enumerate this UIMedium at least once if it
413 * wasn't registered before. */
414 if (!m_registeredMediaIds.contains(uMediumId))
415 {
416 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} is cached but not registered already, so will be enumerated..\n",
417 uMediumId.toString().toUtf8().constData()));
418 createMediumEnumerationTask(m_media.value(uMediumId));
419
420 /* Mark medium registered: */
421 m_registeredMediaIds << uMediumId;
422 }
423 }
424 else
425 {
426 /* Get VBox for temporary usage, it will cache the error info: */
427 CVirtualBox comVBox = gpGlobalSession->virtualBox();
428 /* Open existing medium, this API can be used to open known medium as well, using ID as location for that: */
429 CMedium comMedium = comVBox.OpenMedium(uMediumId.toString(), enmMediumType, KAccessMode_ReadWrite, false);
430 if (!comVBox.isOk())
431 LogRel(("GUI: UIMediumEnumerator: Unable to open registered medium! %s\n",
432 UIErrorString::simplifiedErrorInfo(comVBox).toUtf8().constData()));
433 else
434 {
435 /* Create new UIMedium: */
436 const UIMedium guiMedium(comMedium, UIMediumDefs::mediumTypeToLocal(comMedium.GetDeviceType()));
437 const QUuid &uUIMediumKey = guiMedium.key();
438
439 /* Cache corresponding UIMedium: */
440 m_media.insert(uUIMediumKey, guiMedium);
441 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} is now cached and will be enumerated..\n",
442 uUIMediumKey.toString().toUtf8().constData()));
443
444 /* And notify listeners: */
445 emit sigMediumCreated(uUIMediumKey);
446
447 /* Enumerate corresponding UIMedium: */
448 createMediumEnumerationTask(m_media.value(uMediumId));
449
450 /* Mark medium registered: */
451 m_registeredMediaIds << uMediumId;
452 }
453 }
454 }
455 /* Old medium unregistered: */
456 else
457 {
458 /* Make sure this medium is still cached: */
459 if (mediumSub(uMediumId).isNull())
460 {
461 /* This medium can be wiped out already because of async event nature. Currently
462 * medium unregistration event comes very late and other even unrealted events
463 * can come before it and request for this particular medium enumeration. If medium
464 * enumeration is performed fast enough (before medium unregistration event comes),
465 * medium will be wiped out already, so we just ignore it. */
466 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} was not currently cached!\n",
467 uMediumId.toString().toUtf8().constData()));
468 }
469 else
470 {
471 /* Forget corresponding UIMedium: */
472 m_media.remove(uMediumId);
473 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} is no more cached!\n",
474 uMediumId.toString().toUtf8().constData()));
475
476 /* And notify listeners: */
477 emit sigMediumDeleted(uMediumId);
478
479 /* Besides that we should enumerate all the
480 * 1st level children of deleted medium: */
481 QList<QUuid> result;
482 enumerateAllMediaOfMediumWithId(uMediumId, result);
483 }
484
485 /* Mark medium unregistered: */
486 m_registeredMediaIds.remove(uMediumId);
487 }
488}
489
490void UIMediumEnumerator::sltHandleMediumEnumerationTaskComplete(UITask *pTask)
491{
492 /* Make sure that is one of our tasks: */
493 if (pTask->type() != UITask::Type_MediumEnumeration)
494 return;
495 AssertReturnVoid(m_tasks.contains(pTask));
496
497 /* Get enumerated UIMedium: */
498 const UIMedium guiMedium = qobject_cast<UITaskMediumEnumeration*>(pTask)->medium();
499 const QUuid uMediumKey = guiMedium.key();
500 LogRel2(("GUI: UIMediumEnumerator: Medium with key={%s} enumerated\n",
501 uMediumKey.toString().toUtf8().constData()));
502
503 /* Remove task from internal set: */
504 m_tasks.remove(pTask);
505
506 /* Make sure such UIMedium still exists: */
507 if (!m_media.contains(uMediumKey))
508 {
509 LogRel2(("GUI: UIMediumEnumerator: Medium with key={%s} already deleted by a third party\n",
510 uMediumKey.toString().toUtf8().constData()));
511 return;
512 }
513
514 /* Check if UIMedium ID was changed: */
515 const QUuid uMediumID = guiMedium.id();
516 /* UIMedium ID was changed to nullID: */
517 if (uMediumID == UIMedium::nullID())
518 {
519 /* Delete this UIMedium: */
520 m_media.remove(uMediumKey);
521 LogRel2(("GUI: UIMediumEnumerator: Medium with key={%s} closed and deleted (after enumeration)\n",
522 uMediumKey.toString().toUtf8().constData()));
523
524 /* And notify listener about delete: */
525 emit sigMediumDeleted(uMediumKey);
526 }
527 /* UIMedium ID was changed to something proper: */
528 else if (uMediumID != uMediumKey)
529 {
530 /* We have to reinject enumerated UIMedium: */
531 m_media.remove(uMediumKey);
532 m_media[uMediumID] = guiMedium;
533 m_media[uMediumID].setKey(uMediumID);
534 LogRel2(("GUI: UIMediumEnumerator: Medium with key={%s} has it changed to {%s}\n",
535 uMediumKey.toString().toUtf8().constData(),
536 uMediumID.toString().toUtf8().constData()));
537
538 /* And notify listener about delete/create: */
539 emit sigMediumDeleted(uMediumKey);
540 emit sigMediumCreated(uMediumID);
541 }
542 /* UIMedium ID was not changed: */
543 else
544 {
545 /* Just update enumerated UIMedium: */
546 m_media[uMediumID] = guiMedium;
547 LogRel2(("GUI: UIMediumEnumerator: Medium with key={%s} updated\n",
548 uMediumID.toString().toUtf8().constData()));
549
550 /* And notify listener about update: */
551 emit sigMediumEnumerated(uMediumID);
552 }
553
554 /* If there are no more tasks we know about: */
555 if (m_tasks.isEmpty())
556 {
557 /* Notify listener: */
558 LogRel(("GUI: UIMediumEnumerator: Medium-enumeration finished!\n"));
559 m_fMediumEnumerationInProgress = false;
560 emit sigMediumEnumerationFinished();
561 }
562}
563
564QList<QUuid> UIMediumEnumerator::mediumIDsSub() const
565{
566 /* Return keys of current media map: */
567 return m_media.keys();
568}
569
570UIMedium UIMediumEnumerator::mediumSub(const QUuid &uMediumID) const
571{
572 /* Search through current media map
573 * for the UIMedium with passed ID: */
574 if (m_media.contains(uMediumID))
575 return m_media.value(uMediumID);
576 /* Return NULL UIMedium otherwise: */
577 return UIMedium();
578}
579
580void UIMediumEnumerator::createMediumSub(const UIMedium &guiMedium)
581{
582 /* Get UIMedium ID: */
583 const QUuid uMediumID = guiMedium.id();
584
585 /* Do not create UIMedium(s) with incorrect ID: */
586 AssertReturnVoid(!uMediumID.isNull());
587 /* Make sure UIMedium doesn't exist already: */
588 if (m_media.contains(uMediumID))
589 return;
590
591 /* Insert UIMedium: */
592 m_media[uMediumID] = guiMedium;
593 LogRel(("GUI: UIMediumEnumerator: Medium with key={%s} created\n", uMediumID.toString().toUtf8().constData()));
594
595 /* Notify listener: */
596 emit sigMediumCreated(uMediumID);
597}
598
599void UIMediumEnumerator::enumerateMediaSub(const CMediumVector &comMedia /* = CMediumVector() */)
600{
601 /* Compose new map of currently cached media & their children.
602 * While composing we are using data from already cached media. */
603 UIMediumMap guiMedia;
604 addNullMediumToMap(guiMedia);
605 if (comMedia.isEmpty())
606 {
607 /* Compose new map of all known media & their children: */
608 addMediaToMap(gpGlobalSession->virtualBox().GetHardDisks(), guiMedia);
609 addMediaToMap(gpGlobalSession->host().GetDVDDrives(), guiMedia);
610 addMediaToMap(gpGlobalSession->virtualBox().GetDVDImages(), guiMedia);
611 addMediaToMap(gpGlobalSession->host().GetFloppyDrives(), guiMedia);
612 addMediaToMap(gpGlobalSession->virtualBox().GetFloppyImages(), guiMedia);
613 }
614 else
615 {
616 /* Compose new map of passed media & their children: */
617 addMediaToMap(comMedia, guiMedia);
618 }
619
620 /* UICommon is cleaning up, abort immediately: */
621 if (uiCommon().isCleaningUp())
622 return;
623
624 if (comMedia.isEmpty())
625 {
626 /* Replace existing media map since
627 * we have full medium enumeration: */
628 m_fFullMediumEnumerationRequested = true;
629 m_media = guiMedia;
630 }
631 else
632 {
633 /* Throw the media to existing map: */
634 foreach (const QUuid &uMediumId, guiMedia.keys())
635 m_media[uMediumId] = guiMedia.value(uMediumId);
636 }
637
638 /* If enumeration hasn't yet started: */
639 if (!m_fMediumEnumerationInProgress)
640 {
641 /* Notify listener about enumeration started: */
642 LogRel(("GUI: UIMediumEnumerator: Medium-enumeration started...\n"));
643 m_fMediumEnumerationInProgress = true;
644 emit sigMediumEnumerationStarted();
645
646 /* Make sure we really have more than one UIMedium (which is NULL): */
647 if ( guiMedia.size() == 1
648 && guiMedia.first().id() == UIMedium::nullID())
649 {
650 /* Notify listener about enumeration finished instantly: */
651 LogRel(("GUI: UIMediumEnumerator: Medium-enumeration finished!\n"));
652 m_fMediumEnumerationInProgress = false;
653 emit sigMediumEnumerationFinished();
654 }
655 }
656
657 /* Start enumeration for media with non-NULL ID: */
658 foreach (const QUuid &uMediumID, guiMedia.keys())
659 if (!uMediumID.isNull())
660 createMediumEnumerationTask(guiMedia[uMediumID]);
661}
662
663void UIMediumEnumerator::refreshMediaSub()
664{
665 /* Make sure we are not already in progress: */
666 AssertReturnVoid(!m_fMediumEnumerationInProgress);
667
668 /* Refresh all cached media we have: */
669 foreach (const QUuid &uMediumID, m_media.keys())
670 m_media[uMediumID].refresh();
671}
672
673void UIMediumEnumerator::createMediumEnumerationTask(const UIMedium &guiMedium)
674{
675 /* Prepare medium-enumeration task: */
676 UITask *pTask = new UITaskMediumEnumeration(guiMedium);
677 /* Append to internal set: */
678 m_tasks << pTask;
679 /* Post into global thread-pool: */
680 uiCommon().threadPool()->enqueueTask(pTask);
681}
682
683void UIMediumEnumerator::addNullMediumToMap(UIMediumMap &media)
684{
685 /* Insert NULL UIMedium to the passed media map.
686 * Get existing one from the previous map if any. */
687 const UIMedium guiMedium = m_media.contains(UIMedium::nullID())
688 ? m_media[UIMedium::nullID()]
689 : UIMedium();
690 media.insert(UIMedium::nullID(), guiMedium);
691}
692
693void UIMediumEnumerator::addMediaToMap(const CMediumVector &inputMedia, UIMediumMap &outputMedia)
694{
695 /* Iterate through passed inputMedia vector: */
696 foreach (const CMedium &comMedium, inputMedia)
697 {
698 /* If UICommon is cleaning up, abort immediately: */
699 if (uiCommon().isCleaningUp())
700 break;
701
702 /* Insert UIMedium to the passed media map.
703 * Get existing one from the previous map if any.
704 * Create on the basis of comMedium otherwise. */
705 const QUuid uMediumID = comMedium.GetId();
706 const UIMedium guiMedium = m_media.contains(uMediumID)
707 ? m_media.value(uMediumID)
708 : UIMedium(comMedium, UIMediumDefs::mediumTypeToLocal(comMedium.GetDeviceType()));
709 outputMedia.insert(guiMedium.id(), guiMedium);
710
711 /* Insert comMedium children into map as well: */
712 addMediaToMap(comMedium.GetChildren(), outputMedia);
713 }
714}
715
716void UIMediumEnumerator::parseAttachment(CMediumAttachment comAttachment, QList<QUuid> &result)
717{
718 /* Make sure attachment is valid: */
719 if (comAttachment.isNull())
720 {
721 LogRel2(("GUI: UIMediumEnumerator: Attachment is NULL!\n"));
722 /// @todo is this possible case?
723 AssertFailed();
724 }
725 else
726 {
727 /* Acquire attachment medium: */
728 CMedium comMedium = comAttachment.GetMedium();
729 if (!comAttachment.isOk())
730 LogRel(("GUI: UIMediumEnumerator: Unable to acquire attachment medium! %s\n",
731 UIErrorString::simplifiedErrorInfo(comAttachment).toUtf8().constData()));
732 else
733 {
734 /* Parse medium: */
735 parseMedium(comMedium, result);
736
737 // WORKAROUND:
738 // In current architecture there is no way to determine medium previously mounted
739 // to this attachment, so we will have to enumerate all other cached media which
740 // belongs to the same VM, since they may no longer belong to it.
741
742 /* Acquire parent VM: */
743 CMachine comMachine = comAttachment.GetMachine();
744 if (!comAttachment.isOk())
745 LogRel(("GUI: UIMediumEnumerator: Unable to acquire attachment parent machine! %s\n",
746 UIErrorString::simplifiedErrorInfo(comAttachment).toUtf8().constData()));
747 else
748 {
749 /* Acquire machine ID: */
750 const QUuid uMachineId = comMachine.GetId();
751 if (!comMachine.isOk())
752 LogRel(("GUI: UIMediumEnumerator: Unable to acquire machine ID! %s\n",
753 UIErrorString::simplifiedErrorInfo(comMachine).toUtf8().constData()));
754 else
755 {
756 /* Enumerate all the media of machine with this ID: */
757 enumerateAllMediaOfMachineWithId(uMachineId, result);
758 }
759 }
760 }
761 }
762}
763
764void UIMediumEnumerator::parseMedium(CMedium comMedium, QList<QUuid> &result)
765{
766 /* Make sure medium is valid: */
767 if (comMedium.isNull())
768 {
769 /* This medium is NULL by some reason, the obvious case when this
770 * can happen is when optical/floppy device is created empty. */
771 LogRel2(("GUI: UIMediumEnumerator: Medium is NULL!\n"));
772 }
773 else
774 {
775 /* Acquire medium ID: */
776 const QUuid uMediumId = comMedium.GetId();
777 if (!comMedium.isOk())
778 LogRel(("GUI: UIMediumEnumerator: Unable to acquire medium ID! %s\n",
779 UIErrorString::simplifiedErrorInfo(comMedium).toUtf8().constData()));
780 else
781 {
782 //printf(" Medium to recache: %s\n", uMediumId.toString().toUtf8().constData());
783
784 /* Make sure this medium is already cached: */
785 if (mediumSub(uMediumId).isNull())
786 {
787 /* This medium isn't cached by some reason, which can be different.
788 * One of such reasons is when config-changed event comes earlier than
789 * corresponding registration event. For now we are ignoring that at all. */
790 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} isn't cached yet!\n",
791 uMediumId.toString().toUtf8().constData()));
792 }
793 else
794 {
795 /* Enumerate corresponding UIMedium: */
796 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} will be enumerated..\n",
797 uMediumId.toString().toUtf8().constData()));
798 createMediumEnumerationTask(m_media.value(uMediumId));
799 result << uMediumId;
800 }
801 }
802 }
803}
804
805void UIMediumEnumerator::enumerateAllMediaOfMachineWithId(const QUuid &uMachineId, QList<QUuid> &result)
806{
807 /* For each the cached UIMedium we have: */
808 foreach (const QUuid &uMediumId, mediumIDsSub())
809 {
810 /* Check if medium isn't NULL, used by our
811 * machine and wasn't already enumerated. */
812 const UIMedium guiMedium = mediumSub(uMediumId);
813 if ( !guiMedium.isNull()
814 && guiMedium.machineIds().contains(uMachineId)
815 && !result.contains(uMediumId))
816 {
817 /* Enumerate corresponding UIMedium: */
818 //printf(" Medium to recache: %s\n",
819 // uMediumId.toString().toUtf8().constData());
820 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} of machine {%s} will be enumerated..\n",
821 uMediumId.toString().toUtf8().constData(),
822 uMachineId.toString().toUtf8().constData()));
823 createMediumEnumerationTask(guiMedium);
824 result << uMediumId;
825 }
826 }
827}
828
829void UIMediumEnumerator::enumerateAllMediaOfMediumWithId(const QUuid &uParentMediumId, QList<QUuid> &result)
830{
831 /* For each the cached UIMedium we have: */
832 foreach (const QUuid &uMediumId, mediumIDsSub())
833 {
834 /* Check if medium isn't NULL, and is
835 * a child of specified parent medium. */
836 const UIMedium guiMedium = mediumSub(uMediumId);
837 if ( !guiMedium.isNull()
838 && guiMedium.parentID() == uParentMediumId)
839 {
840 /* Enumerate corresponding UIMedium: */
841 //printf(" Medium to recache: %s\n",
842 // uMediumId.toString().toUtf8().constData());
843 LogRel2(("GUI: UIMediumEnumerator: Medium {%s} a child of medium {%s} will be enumerated..\n",
844 uMediumId.toString().toUtf8().constData(),
845 uParentMediumId.toString().toUtf8().constData()));
846 createMediumEnumerationTask(guiMedium);
847 result << uMediumId;
848 }
849 }
850}
851
852
853#include "UIMediumEnumerator.moc"
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