VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/VBoxMedium.cpp@ 35740

Last change on this file since 35740 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/* $Id: VBoxMedium.cpp 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 *
4 * VBox frontends: Qt GUI ("VirtualBox"):
5 * VBoxMedium class implementation
6 */
7
8/*
9 * Copyright (C) 2009-2010 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#ifdef VBOX_WITH_PRECOMPILED_HEADERS
21# include "precomp.h"
22#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
23/* Global includes */
24#include <QDir>
25
26/* Local includes */
27#include "VBoxMedium.h"
28#include "VBoxGlobal.h"
29#include "VBoxProblemReporter.h"
30#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
31
32QString VBoxMedium::mTable = QString ("<table>%1</table>");
33QString VBoxMedium::mRow = QString ("<tr><td>%1</td></tr>");
34
35VBoxMedium& VBoxMedium::operator= (const VBoxMedium &aOther)
36{
37 mMedium = aOther.medium();
38 mType = aOther.type();
39 mState = aOther.state();
40 mLastAccessError = aOther.lastAccessError();
41 mResult = aOther.result();
42
43 mId = aOther.id();
44 mName = aOther.name();
45 mLocation = aOther.location();
46
47 mSize = aOther.size();
48 mLogicalSize = aOther.logicalSize();
49
50 mHardDiskFormat = aOther.hardDiskFormat();
51 mHardDiskType = aOther.hardDiskType();
52
53 mUsage = aOther.usage();
54 mToolTip = aOther.tip();
55
56 mIsReadOnly = aOther.isReadOnly();
57 mIsUsedInSnapshots = aOther.isUsedInSnapshots();
58 mIsHostDrive = aOther.isHostDrive();
59
60 mCurStateMachineIds = aOther.curStateMachineIds();
61
62 mParent = aOther.parent();
63
64 mNoDiffs = aOther.cache();
65
66 return *this;
67}
68
69/**
70 * Queries the medium state. Call this and then read the state field instead
71 * of calling GetState() on medium directly as it will properly handle the
72 * situation when GetState() itself fails by setting state to Inaccessible
73 * and memorizing the error info describing why GetState() failed.
74 *
75 * As the last step, this method calls #refresh() to refresh all precomposed
76 * strings.
77 *
78 * @note This method blocks for the duration of the state check. Since this
79 * check may take quite a while (e.g. for a medium located on a
80 * network share), the calling thread must not be the UI thread. You
81 * have been warned.
82 */
83void VBoxMedium::blockAndQueryState()
84{
85 if (mMedium.isNull()) return;
86
87 mState = mMedium.RefreshState();
88
89 /* Save the result to distinguish between inaccessible and e.g. uninitialized objects */
90 mResult = COMResult (mMedium);
91
92 if (!mResult.isOk())
93 {
94 mState = KMediumState_Inaccessible;
95 mLastAccessError = QString::null;
96 }
97 else
98 mLastAccessError = mMedium.GetLastAccessError();
99
100 refresh();
101}
102
103/**
104 * Refreshes the precomposed strings containing such media parameters as
105 * location, size by querying the respective data from the associated
106 * media object.
107 *
108 * Note that some string such as #size() are meaningless if the media state is
109 * KMediumState_NotCreated (i.e. the medium has not yet been checked for
110 * accessibility).
111 */
112void VBoxMedium::refresh()
113{
114 /* Detect basic parameters */
115 mId = mMedium.isNull() ? QUuid().toString().remove ('{').remove ('}') : mMedium.GetId();
116
117 mIsHostDrive = mMedium.isNull() ? false : mMedium.GetHostDrive();
118
119 if (mMedium.isNull())
120 mName = VBoxGlobal::tr ("Empty", "medium");
121 else if (!mIsHostDrive)
122 mName = mMedium.GetName();
123 else if (mMedium.GetDescription().isEmpty())
124 mName = VBoxGlobal::tr ("Host Drive '%1'", "medium").arg (QDir::toNativeSeparators (mMedium.GetLocation()));
125 else
126 mName = VBoxGlobal::tr ("Host Drive %1 (%2)", "medium").arg (mMedium.GetDescription(), mMedium.GetName());
127
128 mLocation = mMedium.isNull() || mIsHostDrive ? QString ("--") :
129 QDir::toNativeSeparators (mMedium.GetLocation());
130
131 if (mType == VBoxDefs::MediumType_HardDisk)
132 {
133 mHardDiskFormat = mMedium.GetFormat();
134 mHardDiskType = vboxGlobal().mediumTypeString (mMedium);
135 mIsReadOnly = mMedium.GetReadOnly();
136
137 /* Adjust the parent if its possible */
138 CMedium parentMedium = mMedium.GetParent();
139 Assert (!parentMedium.isNull() || mParent == NULL);
140
141 if (!parentMedium.isNull() && (mParent == NULL || mParent->mMedium != parentMedium))
142 {
143 /* Search for the parent (might be there) */
144 const VBoxMediaList &list = vboxGlobal().currentMediaList();
145 for (VBoxMediaList::const_iterator it = list.begin(); it != list.end(); ++ it)
146 {
147 if ((*it).mType != VBoxDefs::MediumType_HardDisk)
148 break;
149
150 if ((*it).mMedium == parentMedium)
151 {
152 mParent = unconst (&*it);
153 break;
154 }
155 }
156 }
157 }
158 else
159 {
160 mHardDiskFormat = QString::null;
161 mHardDiskType = QString::null;
162 mIsReadOnly = false;
163 }
164
165 /* Detect sizes */
166 if (mState != KMediumState_Inaccessible && mState != KMediumState_NotCreated && !mIsHostDrive)
167 {
168 mSize = vboxGlobal().formatSize (mMedium.GetSize());
169 if (mType == VBoxDefs::MediumType_HardDisk)
170 mLogicalSize = vboxGlobal().formatSize(mMedium.GetLogicalSize());
171 else
172 mLogicalSize = mSize;
173 }
174 else
175 {
176 mSize = mLogicalSize = QString ("--");
177 }
178
179 /* Detect usage */
180 mUsage = QString::null;
181 if (!mMedium.isNull())
182 {
183 mCurStateMachineIds.clear();
184 QVector <QString> machineIds = mMedium.GetMachineIds();
185 if (machineIds.size() > 0)
186 {
187 QString sUsage;
188
189 CVirtualBox vbox = vboxGlobal().virtualBox();
190
191 for (QVector <QString>::ConstIterator it = machineIds.begin(); it != machineIds.end(); ++ it)
192 {
193 CMachine machine = vbox.FindMachine(*it);
194
195 QString sName = machine.GetName();
196 QString sSnapshots;
197
198 QVector <QString> snapIds = mMedium.GetSnapshotIds (*it);
199 for (QVector <QString>::ConstIterator jt = snapIds.begin(); jt != snapIds.end(); ++ jt)
200 {
201 if (*jt == *it)
202 {
203 /* The medium is attached to the machine in the current
204 * state, we don't distinguish this for now by always
205 * giving the VM name in front of snapshot names. */
206 mCurStateMachineIds.push_back (*jt);
207 continue;
208 }
209
210 CSnapshot snapshot = machine.FindSnapshot(*jt);
211 if (!snapshot.isNull()) // can be NULL while takeSnaphot is in progress
212 {
213 if (!sSnapshots.isNull())
214 sSnapshots += ", ";
215 sSnapshots += snapshot.GetName();
216 }
217 }
218
219 if (!sUsage.isNull())
220 sUsage += ", ";
221
222 sUsage += sName;
223
224 if (!sSnapshots.isNull())
225 {
226 sUsage += QString (" (%2)").arg (sSnapshots);
227 mIsUsedInSnapshots = true;
228 }
229 else
230 mIsUsedInSnapshots = false;
231 }
232
233 Assert (!sUsage.isEmpty());
234 mUsage = sUsage;
235 }
236 }
237
238 /* Compose the tooltip */
239 if (!mMedium.isNull())
240 {
241 mToolTip = mRow.arg (QString ("<p style=white-space:pre><b>%1</b></p>").arg (mIsHostDrive ? mName : mLocation));
242
243 if (mType == VBoxDefs::MediumType_HardDisk)
244 {
245 mToolTip += mRow.arg (VBoxGlobal::tr ("<p style=white-space:pre>Type (Format): %1 (%2)</p>", "medium")
246 .arg (mHardDiskType).arg (mHardDiskFormat));
247 }
248
249 mToolTip += mRow.arg (VBoxGlobal::tr ("<p>Attached to: %1</p>", "image")
250 .arg (mUsage.isNull() ? VBoxGlobal::tr ("<i>Not Attached</i>", "image") : mUsage));
251
252 switch (mState)
253 {
254 case KMediumState_NotCreated:
255 {
256 mToolTip += mRow.arg (VBoxGlobal::tr ("<i>Checking accessibility...</i>", "medium"));
257 break;
258 }
259 case KMediumState_Inaccessible:
260 {
261 if (mResult.isOk())
262 {
263 /* Not Accessible */
264 mToolTip += mRow.arg ("<hr>") + mRow.arg (VBoxGlobal::highlight (mLastAccessError, true /* aToolTip */));
265 }
266 else
267 {
268 /* Accessibility check (eg GetState()) itself failed */
269 mToolTip += mRow.arg ("<hr>") + mRow.arg (VBoxGlobal::tr ("Failed to check media accessibility.", "medium")) +
270 mRow.arg (VBoxProblemReporter::formatErrorInfo (mResult) + ".");
271 }
272 break;
273 }
274 default:
275 break;
276 }
277 }
278
279 /* Reset mNoDiffs */
280 mNoDiffs.isSet = false;
281}
282
283/**
284 * Returns a root medium of this medium. For non-hard disk media, this is always
285 * this medium itself.
286 */
287VBoxMedium &VBoxMedium::root() const
288{
289 VBoxMedium *pRoot = unconst (this);
290 while (pRoot->mParent != NULL)
291 pRoot = pRoot->mParent;
292
293 return *pRoot;
294}
295
296/**
297 * Returns generated tooltip for this medium.
298 *
299 * In "don't show diffs" mode (where the attributes of the base hard disk are
300 * shown instead of the attributes of the differencing hard disk), extra
301 * information will be added to the tooltip to give the user a hint that the
302 * medium is actually a differencing hard disk.
303 *
304 * @param aNoDiffs @c true to enable user-friendly "don't show diffs" mode.
305 * @param aCheckRO @c true to perform the #readOnly() check and add a notice
306 * accordingly.
307 */
308QString VBoxMedium::toolTip (bool aNoDiffs /* = false */, bool aCheckRO /* = false */, bool aNullAllowed /* = false */) const
309{
310 QString sTip;
311
312 if (mMedium.isNull())
313 {
314 sTip = aNullAllowed ? mRow.arg (VBoxGlobal::tr ("<b>No medium selected</b>", "medium")) +
315 mRow.arg (VBoxGlobal::tr ("You can also change this while the machine is running.")) :
316 mRow.arg (VBoxGlobal::tr ("<b>No media available</b>", "medium")) +
317 mRow.arg (VBoxGlobal::tr ("You can create media images using the virtual media manager."));
318 }
319 else
320 {
321 unconst (this)->checkNoDiffs (aNoDiffs);
322
323 sTip = aNoDiffs ? mNoDiffs.toolTip : mToolTip;
324
325 if (aCheckRO && mIsReadOnly)
326 sTip += mRow.arg ("<hr>") +
327 mRow.arg (VBoxGlobal::tr ("Attaching this hard disk will be performed indirectly using "
328 "a newly created differencing hard disk.", "medium"));
329 }
330
331 return mTable.arg (sTip);
332}
333
334/**
335 * Returns an icon corresponding to the media state. Distinguishes between
336 * the Inaccessible state and the situation when querying the state itself
337 * failed.
338 *
339 * In "don't show diffs" mode (where the attributes of the base hard disk are
340 * shown instead of the attributes of the differencing hard disk), the most
341 * worst media state on the given hard disk chain will be used to select the
342 * media icon.
343 *
344 * @param aNoDiffs @c true to enable user-friendly "don't show diffs" mode.
345 * @param aCheckRO @c true to perform the #readOnly() check and change the icon
346 * accordingly.
347 */
348QPixmap VBoxMedium::icon (bool aNoDiffs /* = false */, bool aCheckRO /* = false */) const
349{
350 QPixmap pixmap;
351
352 if (state (aNoDiffs) == KMediumState_Inaccessible)
353 pixmap = result (aNoDiffs).isOk() ? vboxGlobal().warningIcon() : vboxGlobal().errorIcon();
354
355 if (aCheckRO && mIsReadOnly)
356 pixmap = VBoxGlobal::joinPixmaps (pixmap, QPixmap (":/new_16px.png"));
357
358 return pixmap;
359}
360
361/**
362 * Returns the details of this medium as a single-line string
363 *
364 * For hard disks, the details include the location, type and the logical size
365 * of the hard disk. Note that if @a aNoDiffs is @c true, these properties are
366 * queried on the root hard disk of the given hard disk because the primary
367 * purpose of the returned string is to be human readable (so that seeing a
368 * complex diff hard disk name is usually not desirable).
369 *
370 * For other media types, the location and the actual size are returned.
371 * Arguments @a aPredictDiff and @a aNoRoot are ignored in this case.
372 *
373 * @param aNoDiffs @c true to enable user-friendly "don't show diffs" mode.
374 * @param aPredictDiff @c true to mark the hard disk as differencing if
375 * attaching it would create a differencing hard disk (not
376 * used when @a aNoRoot is true).
377 * @param aUseHTML @c true to allow for emphasizing using bold and italics.
378 *
379 * @note Use #detailsHTML() instead of passing @c true for @a aUseHTML.
380 *
381 * @note The media object may become uninitialized by a third party while this
382 * method is reading its properties. In this case, the method will return
383 * an empty string.
384 */
385QString VBoxMedium::details (bool aNoDiffs /* = false */,
386 bool aPredictDiff /* = false */,
387 bool aUseHTML /* = false */) const
388{
389 // @todo the below check is rough; if mMedium becomes uninitialized, any
390 // of getters called afterwards will also fail. The same relates to the
391 // root hard disk object (that will be the hard disk itself in case of
392 // non-differencing disks). However, this check was added to fix a
393 // particular use case: when the hard disk is a differencing hard disk and
394 // it happens to be discarded (and uninitialized) after this method is
395 // called but before we read all its properties (yes, it's possible!), the
396 // root object will be null and calling methods on it will assert in the
397 // debug builds. This check seems to be enough as a quick solution (fresh
398 // hard disk attachments will be re-read by a machine state change signal
399 // after the discard operation is finished, so the user will eventually see
400 // correct data), but in order to solve the problem properly we need to use
401 // exceptions everywhere (or check the result after every method call). See
402 // also Defect #2149.
403
404 if (mMedium.isNull() || mIsHostDrive)
405 return mName;
406
407 if (!mMedium.isOk())
408 return QString::null;
409
410 QString sDetails, sStr;
411
412 VBoxMedium *pRoot = unconst (this);
413 KMediumState eState = mState;
414
415 if (mType == VBoxDefs::MediumType_HardDisk)
416 {
417 if (aNoDiffs)
418 {
419 pRoot = &this->root();
420
421 bool isDiff = (!aPredictDiff && mParent != NULL) || (aPredictDiff && mIsReadOnly);
422
423 sDetails = isDiff && aUseHTML ?
424 QString ("<i>%1</i>, ").arg (pRoot->mHardDiskType) :
425 QString ("%1, ").arg (pRoot->mHardDiskType);
426
427 eState = this->state (true /* aNoDiffs */);
428
429 if (pRoot->mState == KMediumState_NotCreated)
430 eState = KMediumState_NotCreated;
431 }
432 else
433 {
434 sDetails = QString ("%1, ").arg (pRoot->mHardDiskType);
435 }
436 }
437
438 // @todo prepend the details with the warning/error icon when not accessible
439
440 switch (eState)
441 {
442 case KMediumState_NotCreated:
443 sStr = VBoxGlobal::tr ("Checking...", "medium");
444 sDetails += aUseHTML ? QString ("<i>%1</i>").arg (sStr) : sStr;
445 break;
446 case KMediumState_Inaccessible:
447 sStr = VBoxGlobal::tr ("Inaccessible", "medium");
448 sDetails += aUseHTML ? QString ("<b>%1</b>").arg (sStr) : sStr;
449 break;
450 default:
451 sDetails += mType == VBoxDefs::MediumType_HardDisk ? pRoot->mLogicalSize : pRoot->mSize;
452 break;
453 }
454
455 sDetails = aUseHTML ?
456 QString ("%1 (<nobr>%2</nobr>)").arg (VBoxGlobal::locationForHTML (pRoot->mName), sDetails) :
457 QString ("%1 (%2)").arg (VBoxGlobal::locationForHTML (pRoot->mName), sDetails);
458
459 return sDetails;
460}
461
462/**
463 * Checks if mNoDiffs is filled in and does it if not.
464 *
465 * @param aNoDiffs @if false, this method immediately returns.
466 */
467void VBoxMedium::checkNoDiffs (bool aNoDiffs)
468{
469 if (!aNoDiffs || mNoDiffs.isSet)
470 return;
471
472 mNoDiffs.toolTip = QString::null;
473
474 mNoDiffs.state = mState;
475 for (VBoxMedium *cur = mParent; cur != NULL; cur = cur->mParent)
476 {
477 if (cur->mState == KMediumState_Inaccessible)
478 {
479 mNoDiffs.state = cur->mState;
480
481 if (mNoDiffs.toolTip.isNull())
482 mNoDiffs.toolTip = mRow.arg (VBoxGlobal::tr ("Some of the media in this hard disk chain "
483 "are inaccessible. Please use the Virtual Media "
484 "Manager in <b>Show Differencing Hard Disks</b> "
485 "mode to inspect these media.", "medium"));
486
487 if (!cur->mResult.isOk())
488 {
489 mNoDiffs.result = cur->mResult;
490 break;
491 }
492 }
493 }
494
495 if (mParent != NULL && !mIsReadOnly)
496 {
497 mNoDiffs.toolTip = root().tip() +
498 mRow.arg ("<hr>") +
499 mRow.arg (VBoxGlobal::tr ("This base hard disk is indirectly attached using "
500 "the following differencing hard disk:", "medium")) +
501 mToolTip + mNoDiffs.toolTip;
502 }
503
504 if (mNoDiffs.toolTip.isNull())
505 mNoDiffs.toolTip = mToolTip;
506
507 mNoDiffs.isSet = true;
508}
509
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use