VirtualBox

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

Last change on this file was 103771, checked in by vboxsync, 2 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: 23.6 KB
Line 
1/* $Id: UIMedium.cpp 103771 2024-03-11 15:16:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMedium 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 "UICommon.h"
34#include "UIConverter.h"
35#include "UIErrorString.h"
36#include "UIExtraDataManager.h"
37#include "UIGlobalSession.h"
38#include "UIIconPool.h"
39#include "UIMedium.h"
40#include "UITranslator.h"
41
42/* COM includes: */
43#include "CMachine.h"
44#include "CSnapshot.h"
45
46/* Other VBox includes: */
47#include "iprt/cpp/utils.h" // for unconst stuff
48
49QUuid UIMedium::m_uNullID;
50QString UIMedium::m_sstrTable = QString("<table>%1</table>");
51QString UIMedium::m_sstrRow = QString("<tr><td>%1</td></tr>");
52
53UIMedium::UIMedium()
54 : m_type(UIMediumDeviceType_Invalid)
55 , m_medium(CMedium())
56 , m_state(KMediumState_NotCreated)
57 , m_enmMediumType(KMediumType_Max)
58 , m_enmMediumVariant(KMediumVariant_Max)
59{
60 refresh();
61}
62
63UIMedium::UIMedium(const CMedium &medium, UIMediumDeviceType type)
64 : m_type(type)
65 , m_medium(medium)
66 , m_state(KMediumState_NotCreated)
67 , m_enmMediumType(KMediumType_Max)
68 , m_enmMediumVariant(KMediumVariant_Max)
69{
70 refresh();
71}
72
73UIMedium::UIMedium(const CMedium &medium, UIMediumDeviceType type, KMediumState state)
74 : m_type(type)
75 , m_medium(medium)
76 , m_state(state)
77 , m_enmMediumType(KMediumType_Max)
78 , m_enmMediumVariant(KMediumVariant_Max)
79{
80 refresh();
81}
82
83UIMedium::UIMedium(const UIMedium &other)
84{
85 *this = other;
86}
87
88UIMedium& UIMedium::operator=(const UIMedium &other)
89{
90 m_type = other.type();
91
92 m_medium = other.medium();
93
94 m_state = other.state();
95 m_result = other.result();
96 m_strLastAccessError = other.lastAccessError();
97
98 m_uId = other.id();
99 m_uRootId = other.rootID();
100 m_uParentId = other.parentID();
101
102 m_uKey = other.key();
103
104 m_strName = other.name();
105 m_strLocation = other.location();
106 m_strDescription = other.description();
107
108 m_uSize = other.sizeInBytes();
109 m_uLogicalSize = other.logicalSizeInBytes();
110 m_strSize = other.size();
111 m_strLogicalSize = other.logicalSize();
112
113 m_enmMediumType = other.mediumType();
114 m_enmMediumVariant = other.mediumVariant();
115
116 m_strHardDiskType = other.hardDiskType();
117 m_strHardDiskFormat = other.hardDiskFormat();
118 m_fHasChildren = other.hasChildren();
119 m_strStorageDetails = other.storageDetails();
120 m_strEncryptionPasswordID = other.encryptionPasswordID();
121
122 m_strUsage = other.usage();
123 m_strToolTip = other.tip();
124 m_machineIds = other.machineIds();
125 m_curStateMachineIds = other.curStateMachineIds();
126
127 m_noDiffs = other.cache();
128
129 m_fHidden = other.m_fHidden;
130 m_fUsedByHiddenMachinesOnly = other.m_fUsedByHiddenMachinesOnly;
131 m_fReadOnly = other.isReadOnly();
132 m_fUsedInSnapshots = other.isUsedInSnapshots();
133 m_fHostDrive = other.isHostDrive();
134 m_fEncrypted = other.isEncrypted();
135
136 return *this;
137}
138
139void UIMedium::blockAndQueryState()
140{
141 /* Ignore for NULL medium: */
142 if (m_medium.isNull())
143 return;
144
145 /* Acquire actual medium state: */
146 m_state = m_medium.RefreshState();
147
148 /* Save the result to distinguish between
149 * inaccessible and e.g. uninitialized objects: */
150 m_result = COMResult(m_medium);
151 if (!m_result.isOk())
152 {
153 m_state = KMediumState_Inaccessible;
154 m_strLastAccessError = QString();
155 }
156 else
157 m_strLastAccessError = m_medium.GetLastAccessError();
158
159 /* Refresh finally: */
160 refresh();
161}
162
163void UIMedium::refresh()
164{
165 /* Reset ID parameters: */
166 m_uId = nullID();
167 m_uRootId = nullID();
168 m_uParentId = nullID();
169
170 /* Reset cache parameters: */
171 //m_strKey = nullID();
172
173 /* Reset name/location/description/size parameters: */
174 m_strName = QApplication::translate("UICommon", "Empty", "medium");
175 m_strLocation = m_strSize = m_strLogicalSize = QString("--");
176 m_strDescription = QString();
177 m_uSize = m_uLogicalSize = 0;
178
179 /* Reset medium type & variant parameter: */
180 m_enmMediumType = KMediumType_Max;
181 m_enmMediumVariant = KMediumVariant_Max;
182
183 /* Reset hard drive related parameters: */
184 m_strHardDiskType = QString();
185 m_strHardDiskFormat = QString();
186 m_fHasChildren = false;
187 m_strStorageDetails = QString();
188 m_strEncryptionPasswordID = QString();
189
190 /* Reset data parameters: */
191 m_strUsage = QString();
192 m_strToolTip = QString();
193 m_machineIds.clear();
194 m_curStateMachineIds.clear();
195
196 /* Reset m_noDiffs: */
197 m_noDiffs.isSet = false;
198
199 /* Reset flags: */
200 m_fHidden = false;
201 m_fUsedByHiddenMachinesOnly = false;
202 m_fReadOnly = false;
203 m_fUsedInSnapshots = false;
204 m_fHostDrive = false;
205 m_fEncrypted = false;
206
207 /* For non NULL medium: */
208 if (!m_medium.isNull())
209 {
210 /* Refresh medium ID: */
211 m_uId = normalizedID(m_medium.GetId());
212 /* Refresh root medium ID: */
213 m_uRootId = m_uId;
214
215 /* Init medium key if necessary: */
216 if (m_uKey.isNull())
217 m_uKey = m_uId;
218
219 /* Check whether this is host-drive medium: */
220 m_fHostDrive = m_medium.GetHostDrive();
221
222 /* Refresh medium description: */
223 m_strDescription = m_medium.GetDescription();
224
225 /* Refresh medium name: */
226 if (!m_fHostDrive)
227 m_strName = m_medium.GetName();
228 else if (m_strDescription.isEmpty())
229 m_strName = QApplication::translate("UICommon", "Host Drive '%1'", "medium").arg(QDir::toNativeSeparators(m_medium.GetLocation()));
230 else
231 m_strName = QApplication::translate("UICommon", "Host Drive %1 (%2)", "medium").arg(m_strDescription, m_medium.GetName());
232 /* Refresh medium location: */
233 if (!m_fHostDrive)
234 m_strLocation = QDir::toNativeSeparators(m_medium.GetLocation());
235
236 /* Refresh medium size and logical size: */
237 if (!m_fHostDrive)
238 {
239 /* Only for created and accessible media: */
240 if (m_state != KMediumState_Inaccessible && m_state != KMediumState_NotCreated)
241 {
242 m_uSize = m_medium.GetSize();
243 m_strSize = UITranslator::formatSize(m_uSize);
244 if (m_type == UIMediumDeviceType_HardDisk)
245 {
246 m_uLogicalSize = m_medium.GetLogicalSize();
247 m_strLogicalSize = UITranslator::formatSize(m_uLogicalSize);
248 }
249 else
250 {
251 m_uLogicalSize = m_uSize;
252 m_strLogicalSize = m_strSize;
253 }
254 }
255 }
256
257 /* Refresh medium type & variant: */
258 m_enmMediumType = m_medium.GetType();
259 qlonglong iMediumVariant = 0;
260 foreach (const KMediumVariant &enmVariant, m_medium.GetVariant())
261 iMediumVariant |= enmVariant;
262 m_enmMediumVariant = (KMediumVariant)iMediumVariant;
263
264 /* For hard drive medium: */
265 if (m_type == UIMediumDeviceType_HardDisk)
266 {
267 /* Refresh hard drive disk type: */
268 m_strHardDiskType = mediumTypeToString(m_medium);
269 /* Refresh hard drive format: */
270 m_strHardDiskFormat = m_medium.GetFormat();
271
272 /* Refresh hard drive parental status: */
273 m_fHasChildren = m_medium.GetChildren().size();
274
275 /* Refresh hard drive storage details: */
276 m_strStorageDetails = gpConverter->toString(m_enmMediumVariant);
277
278 /* Check whether this is read-only hard drive: */
279 m_fReadOnly = m_medium.GetReadOnly();
280
281 /* Refresh parent hard drive ID: */
282 CMedium parentMedium = m_medium.GetParent();
283 if (!parentMedium.isNull())
284 m_uParentId = normalizedID(parentMedium.GetId());
285
286 /* Only for created and accessible media: */
287 if (m_state != KMediumState_Inaccessible && m_state != KMediumState_NotCreated)
288 {
289 /* Refresh root hard drive ID: */
290 while (!parentMedium.isNull())
291 {
292 m_uRootId = normalizedID(parentMedium.GetId());
293 parentMedium = parentMedium.GetParent();
294 }
295
296 /* Refresh encryption attributes: */
297 if (m_uRootId != m_uId)
298 {
299 m_strEncryptionPasswordID = root().encryptionPasswordID();
300 m_fEncrypted = root().isEncrypted();
301 }
302 else
303 {
304 QString strCipher;
305 CMedium medium(m_medium);
306 const QString strEncryptionPasswordID = medium.GetEncryptionSettings(strCipher);
307 if (medium.isOk())
308 {
309 m_strEncryptionPasswordID = strEncryptionPasswordID;
310 m_fEncrypted = true;
311 }
312 }
313 }
314 }
315
316 /* Check whether this is hidden medium: */
317 QString strHints = m_medium.GetProperty("Special/GUI/Hints");
318 if (!strHints.isEmpty())
319 {
320 QStringList hints(strHints.split(','));
321 if (hints.contains("Hide", Qt::CaseInsensitive))
322 m_fHidden = true;
323 }
324
325 /* Refresh usage data: */
326 m_curStateMachineIds.clear();
327 m_machineIds = m_medium.GetMachineIds().toList();
328 if (m_machineIds.size() > 0)
329 {
330 /* Get CVirtualBox object: */
331 CVirtualBox vbox = gpGlobalSession->virtualBox();
332
333 /* By default we assuming that this medium is attached
334 * to 'hidden' machines only, if at least one machine present: */
335 m_fUsedByHiddenMachinesOnly = true;
336
337 /* Prepare machine usage: */
338 QString strMachineUsage;
339 /* Walk through all the machines this medium attached to: */
340 foreach (const QUuid &uMachineID, m_machineIds)
341 {
342 /* Look for the corresponding machine: */
343 CMachine machine = vbox.FindMachine(uMachineID.toString());
344
345 /* UIMedium object can wrap newly created CMedium object
346 * which belongs to not yet registered machine, like while creating VM clone.
347 * We can skip such a machines in usage string. */
348 if (machine.isNull())
349 {
350 /* Since we can't precisely check 'hidden' status for that machine in such case,
351 * we have to assume that medium attached not only to 'hidden' machines: */
352 m_fUsedByHiddenMachinesOnly = false;
353 continue;
354 }
355
356 /* Finally we can precisely check if current machine is 'hidden': */
357 if (gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineID))
358 m_fUsedByHiddenMachinesOnly = false;
359
360 /* Prepare snapshot usage: */
361 QString strSnapshotUsage;
362 /* Walk through all the snapshots this medium attached to: */
363 foreach (const QUuid &uSnapshotID, m_medium.GetSnapshotIds(uMachineID))
364 {
365 if (uSnapshotID == uMachineID)
366 {
367 /* The medium is attached to the machine in the current
368 * state, we don't distinguish this for now by always
369 * giving the VM name in front of snapshot names. */
370 m_curStateMachineIds.push_back(uSnapshotID);
371 continue;
372 }
373
374 /* Look for the corresponding snapshot: */
375 CSnapshot snapshot = machine.FindSnapshot(uSnapshotID.toString());
376
377 /* Snapshot can be NULL while takeSnaphot is in progress: */
378 if (snapshot.isNull())
379 continue;
380
381 /* Refresh snapshot usage flag: */
382 m_fUsedInSnapshots = true;
383
384 /* Append snapshot usage: */
385 if (!strSnapshotUsage.isNull())
386 strSnapshotUsage += ", ";
387 strSnapshotUsage += snapshot.GetName();
388 }
389
390 /* Append machine usage: */
391 if (!strMachineUsage.isNull())
392 strMachineUsage += ", ";
393 strMachineUsage += machine.GetName();
394
395 /* Append snapshot usage: */
396 if (!strSnapshotUsage.isNull())
397 strMachineUsage += QString(" (%2)").arg(strSnapshotUsage);
398 }
399
400 /* Append machine usage: */
401 if (!strMachineUsage.isEmpty())
402 m_strUsage += strMachineUsage;
403 }
404
405 /* Refresh tool-tip: */
406 m_strToolTip = m_sstrRow.arg(QString("<p style=white-space:pre><b>%1</b></p>").arg(m_fHostDrive ? m_strName : m_strLocation));
407 if (m_type == UIMediumDeviceType_HardDisk)
408 {
409 m_strToolTip += m_sstrRow.arg(QApplication::translate("UICommon", "<p style=white-space:pre>Type (Format): %1 (%2)</p>", "medium")
410 .arg(m_strHardDiskType).arg(m_strHardDiskFormat));
411 }
412 m_strToolTip += m_sstrRow.arg(QApplication::translate("UICommon", "<p>Attached to: %1</p>", "image")
413 .arg(m_strUsage.isNull() ? QApplication::translate("UICommon", "<i>Not Attached</i>", "image") : m_strUsage));
414 switch (m_state)
415 {
416 case KMediumState_NotCreated:
417 {
418 m_strToolTip += m_sstrRow.arg(QApplication::translate("UICommon", "<i>Checking accessibility...</i>", "medium"));
419 break;
420 }
421 case KMediumState_Inaccessible:
422 {
423 if (m_result.isOk())
424 {
425 /* Not Accessible: */
426 m_strToolTip += m_sstrRow.arg("<hr>") + m_sstrRow.arg(UITranslator::highlight(m_strLastAccessError, true /* aToolTip */));
427 }
428 else
429 {
430 /* Accessibility check (eg GetState()) itself failed: */
431 m_strToolTip += m_sstrRow.arg("<hr>") + m_sstrRow.arg(QApplication::translate("UICommon", "Failed to check accessibility of disk image files.", "medium")) +
432 m_sstrRow.arg(UIErrorString::formatErrorInfo(m_result) + ".");
433 }
434 break;
435 }
436 default:
437 break;
438 }
439 }
440}
441
442KMediumState UIMedium::state(bool fNoDiffs /* = false */) const
443{
444 unconst(this)->checkNoDiffs(fNoDiffs);
445 return fNoDiffs ? m_noDiffs.state : m_state;
446}
447
448const COMResult &UIMedium::result(bool fNoDiffs /* = false */) const
449{
450 unconst(this)->checkNoDiffs(fNoDiffs);
451 return fNoDiffs ? m_noDiffs.result : m_result;
452}
453
454void UIMedium::updateParentID()
455{
456 m_uParentId = nullID();
457 if (m_type == UIMediumDeviceType_HardDisk)
458 {
459 CMedium parentMedium = m_medium.GetParent();
460 if (!parentMedium.isNull())
461 m_uParentId = normalizedID(parentMedium.GetId());
462 }
463}
464
465QString UIMedium::toolTip(bool fNoDiffs /* = false */, bool fCheckRO /* = false */, bool fNullAllowed /* = false */) const
466{
467 QString strTip;
468
469 if (m_medium.isNull())
470 {
471 strTip = fNullAllowed ? m_sstrRow.arg(QApplication::translate("UICommon", "<b>No disk image file selected</b>", "medium")) +
472 m_sstrRow.arg(QApplication::translate("UICommon", "You can also change this while the machine is running.")) :
473 m_sstrRow.arg(QApplication::translate("UICommon", "<b>No disk image files available</b>", "medium")) +
474 m_sstrRow.arg(QApplication::translate("UICommon", "You can create or add disk image files in the virtual machine settings."));
475 }
476 else
477 {
478 unconst(this)->checkNoDiffs(fNoDiffs);
479
480 strTip = fNoDiffs ? m_noDiffs.toolTip : m_strToolTip;
481
482 if (fCheckRO && m_fReadOnly)
483 strTip += m_sstrRow.arg("<hr>") +
484 m_sstrRow.arg(QApplication::translate("UICommon",
485 "Attaching this hard disk will be performed indirectly using "
486 "a newly created differencing hard disk.", "medium"));
487 }
488
489 return m_sstrTable.arg(strTip);
490}
491
492QPixmap UIMedium::icon(bool fNoDiffs /* = false */, bool fCheckRO /* = false */) const
493{
494 QPixmap pixmap;
495
496 if (state(fNoDiffs) == KMediumState_Inaccessible)
497 pixmap = result(fNoDiffs).isOk() ? generalIconPool().warningIcon() : generalIconPool().errorIcon();
498
499 if (fCheckRO && m_fReadOnly)
500 {
501 QIcon icon = UIIconPool::iconSet(":/hd_create_16px.png");
502 pixmap = UIIconPool::joinPixmaps(pixmap, icon.pixmap(icon.availableSizes().value(0, QSize(16, 16))));
503 }
504
505 return pixmap;
506}
507
508QString UIMedium::details(bool fNoDiffs /* = false */,
509 bool fPredictDiff /* = false */,
510 bool fUseHTML /* = false */) const
511{
512 /// @todo the below check is rough; if m_medium becomes uninitialized, any
513 // of getters called afterwards will also fail. The same relates to the
514 // root hard drive object (that will be the hard drive itself in case of
515 // non-differencing disks). However, this check was added to fix a
516 // particular use case: when the hard drive is a differencing hard drive and
517 // it happens to be discarded (and uninitialized) after this method is
518 // called but before we read all its properties (yes, it's possible!), the
519 // root object will be null and calling methods on it will assert in the
520 // debug builds. This check seems to be enough as a quick solution (fresh
521 // hard drive attachments will be re-read by a machine state change signal
522 // after the discard operation is finished, so the user will eventually see
523 // correct data), but in order to solve the problem properly we need to use
524 // exceptions everywhere (or check the result after every method call). See
525 // @bugref{2149}.
526
527 if (m_medium.isNull() || m_fHostDrive)
528 return m_strName;
529
530 if (!m_medium.isOk())
531 return QString();
532
533 QString strDetails, strText;
534
535 /* Note: root accessible only if medium enumerated: */
536 UIMedium rootMedium = root();
537 KMediumState eState = m_state;
538
539 if (m_type == UIMediumDeviceType_HardDisk)
540 {
541 if (fNoDiffs)
542 {
543 bool isDiff = (!fPredictDiff && parentID() != nullID()) || (fPredictDiff && m_fReadOnly);
544
545 strDetails = isDiff && fUseHTML ?
546 QString("<i>%1</i>, ").arg(rootMedium.m_strHardDiskType) :
547 QString("%1, ").arg(rootMedium.m_strHardDiskType);
548
549 eState = this->state(true /* fNoDiffs */);
550
551 if (rootMedium.m_state == KMediumState_NotCreated)
552 eState = KMediumState_NotCreated;
553 }
554 else
555 {
556 strDetails = QString("%1, ").arg(rootMedium.m_strHardDiskType);
557 }
558
559 /* Add encryption status: */
560 if (m_fEncrypted)
561 strDetails += QString("%1, ").arg(QApplication::translate("UICommon", "Encrypted", "medium"));
562 }
563
564 /// @todo prepend the details with the warning/error icon when not accessible
565
566 switch (eState)
567 {
568 case KMediumState_NotCreated:
569 strText = QApplication::translate("UICommon", "Checking...", "medium");
570 strDetails += fUseHTML ? QString("<i>%1</i>").arg(strText) : strText;
571 break;
572 case KMediumState_Inaccessible:
573 strText = QApplication::translate("UICommon", "Inaccessible", "medium");
574 strDetails += fUseHTML ? QString("<b>%1</b>").arg(strText) : strText;
575 break;
576 default:
577 strDetails += m_type == UIMediumDeviceType_HardDisk ? rootMedium.m_strLogicalSize : rootMedium.m_strSize;
578 break;
579 }
580
581 strDetails = fUseHTML ?
582 QString("%1 (<nobr>%2</nobr>)").arg(QFileInfo(rootMedium.m_strName).fileName(), strDetails) :
583 QString("%1 (%2)").arg(QFileInfo(rootMedium.m_strName).fileName(), strDetails);
584
585 return strDetails;
586}
587
588/* static */
589QUuid UIMedium::nullID()
590{
591 return m_uNullID;
592}
593
594/* static */
595QUuid UIMedium::normalizedID(const QUuid &uID)
596{
597 /// @todo wipe out!
598 return uID;
599}
600
601/* static */
602bool UIMedium::isMediumAttachedToHiddenMachinesOnly(const UIMedium &medium)
603{
604 /* Iterate till the root: */
605 UIMedium mediumIterator = medium;
606 do
607 {
608 /* Ignore medium if its hidden
609 * or attached to hidden machines only: */
610 if (mediumIterator.isHidden())
611 return true;
612 /* Move iterator to parent: */
613 mediumIterator = mediumIterator.parent();
614 }
615 while (!mediumIterator.isNull());
616 /* False by default: */
617 return false;
618}
619
620UIMedium UIMedium::root() const
621{
622 /* Redirect call to UICommon: */
623 return uiCommon().medium(m_uRootId);
624}
625
626UIMedium UIMedium::parent() const
627{
628 /* Redirect call to UICommon: */
629 return uiCommon().medium(m_uParentId);
630}
631
632void UIMedium::checkNoDiffs(bool fNoDiffs)
633{
634 if (!fNoDiffs || m_noDiffs.isSet)
635 return;
636
637 m_noDiffs.toolTip = QString();
638
639 m_noDiffs.state = m_state;
640 for (UIMedium parentMedium = parent(); !parentMedium.isNull(); parentMedium = parentMedium.parent())
641 {
642 if (parentMedium.m_state == KMediumState_Inaccessible)
643 {
644 m_noDiffs.state = parentMedium.m_state;
645
646 if (m_noDiffs.toolTip.isNull())
647 m_noDiffs.toolTip = m_sstrRow.arg(QApplication::translate("UICommon",
648 "Some of the files in this hard disk chain "
649 "are inaccessible. Please use the Virtual Medium "
650 "Manager to inspect these files.", "medium"));
651
652 if (!parentMedium.m_result.isOk())
653 {
654 m_noDiffs.result = parentMedium.m_result;
655 break;
656 }
657 }
658 }
659
660 if (parentID() != nullID() && !m_fReadOnly)
661 {
662 m_noDiffs.toolTip = root().tip() +
663 m_sstrRow.arg("<hr>") +
664 m_sstrRow.arg(QApplication::translate("UICommon",
665 "This base hard disk is indirectly attached using "
666 "the following differencing hard disk:", "medium")) +
667 m_strToolTip + m_noDiffs.toolTip;
668 }
669
670 if (m_noDiffs.toolTip.isNull())
671 m_noDiffs.toolTip = m_strToolTip;
672
673 m_noDiffs.isSet = true;
674}
675
676/* static */
677QString UIMedium::mediumTypeToString(const CMedium &comMedium)
678{
679 if (!comMedium.GetParent().isNull())
680 {
681 Assert(comMedium.GetType() == KMediumType_Normal);
682 return QApplication::translate("UICommon", "Differencing", "MediumType");
683 }
684 return gpConverter->toString(comMedium.GetType());
685}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use