VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox4/src/VBoxGlobal.cpp@ 14509

Last change on this file since 14509 was 14509, checked in by vboxsync, 16 years ago

Fe/Qt4: Global callback for tray icon code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 181.6 KB
Line 
1/** @file
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * VBoxGlobal class implementation
5 */
6
7/*
8 * Copyright (C) 2008 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include "VBoxGlobal.h"
24#include <VBox/VBoxHDD-new.h>
25
26#include "VBoxDefs.h"
27#include "VBoxSelectorWnd.h"
28#include "VBoxConsoleWnd.h"
29#include "VBoxProblemReporter.h"
30#include "QIHotKeyEdit.h"
31#include "QIMessageBox.h"
32#include "QIDialogButtonBox.h"
33
34#ifdef VBOX_WITH_REGISTRATION
35#include "VBoxRegistrationDlg.h"
36#endif
37#include "VBoxUpdateDlg.h"
38
39/* Qt includes */
40#include <QLibraryInfo>
41#include <QFileDialog>
42#include <QToolTip>
43#include <QTranslator>
44#include <QDesktopWidget>
45#include <QMutex>
46#include <QToolButton>
47#include <QProcess>
48#include <QThread>
49#include <QPainter>
50
51#ifdef Q_WS_X11
52#ifndef VBOX_OSE
53# include "VBoxLicenseViewer.h"
54#endif /* VBOX_OSE */
55
56#include <QTextBrowser>
57#include <QScrollBar>
58#include <QX11Info>
59#endif
60
61
62#if defined (Q_WS_MAC)
63#include "VBoxUtils.h"
64#include <Carbon/Carbon.h> // for HIToolbox/InternetConfig
65#endif
66
67#if defined (Q_WS_WIN)
68#include "shlobj.h"
69#include <QEventLoop>
70#endif
71
72#if defined (Q_WS_X11)
73#undef BOOL /* typedef CARD8 BOOL in Xmd.h conflicts with #define BOOL PRBool
74 * in COMDefs.h. A better fix would be to isolate X11-specific
75 * stuff by placing XX* helpers below to a separate source file. */
76#include <X11/X.h>
77#include <X11/Xmd.h>
78#include <X11/Xlib.h>
79#include <X11/Xatom.h>
80#define BOOL PRBool
81#endif
82
83#include <iprt/asm.h>
84#include <iprt/err.h>
85#include <iprt/param.h>
86#include <iprt/path.h>
87#include <iprt/env.h>
88#include <iprt/file.h>
89#include <iprt/ldr.h>
90
91#if defined (Q_WS_X11)
92#include <iprt/mem.h>
93#endif
94
95//#warning "port me: check this"
96/// @todo bird: Use (U)INT_PTR, (U)LONG_PTR, DWORD_PTR, or (u)intptr_t.
97#if defined(Q_OS_WIN64)
98typedef __int64 Q_LONG; /* word up to 64 bit signed */
99typedef unsigned __int64 Q_ULONG; /* word up to 64 bit unsigned */
100#else
101typedef long Q_LONG; /* word up to 64 bit signed */
102typedef unsigned long Q_ULONG; /* word up to 64 bit unsigned */
103#endif
104
105// VBoxMedium
106/////////////////////////////////////////////////////////////////////////////
107
108void VBoxMedium::init()
109{
110 AssertReturnVoid (!mMedium.isNull());
111
112 switch (mType)
113 {
114 case VBoxDefs::MediaType_HardDisk:
115 {
116 mHardDisk = mMedium;
117 AssertReturnVoid (!mHardDisk.isNull());
118 break;
119 }
120 case VBoxDefs::MediaType_DVD:
121 {
122 mDVDImage = mMedium;
123 AssertReturnVoid (!mDVDImage.isNull());
124 Assert (mParent == NULL);
125 break;
126 }
127 case VBoxDefs::MediaType_Floppy:
128 {
129 mFloppyImage = mMedium;
130 AssertReturnVoid (!mFloppyImage.isNull());
131 Assert (mParent == NULL);
132 break;
133 }
134 default:
135 AssertFailed();
136 }
137
138 refresh();
139}
140
141/**
142 * Queries the medium state. Call this and then read the state field instad
143 * of calling GetState() on medium directly as it will properly handle the
144 * situation when GetState() itself fails by setting state to Inaccessible
145 * and memorizing the error info describing why GetState() failed.
146 *
147 * As the last step, this method calls #refresh() to refresh all precomposed
148 * strings.
149 *
150 * @note This method blocks for the duration of the state check. Since this
151 * check may take quite a while (e.g. for a medium located on a
152 * network share), the calling thread must not be the UI thread. You
153 * have been warned.
154 */
155void VBoxMedium::blockAndQueryState()
156{
157 mState = mMedium.GetState();
158
159 /* save the result to distinguish between inaccessible and e.g.
160 * uninitialized objects */
161 mResult = COMResult (mMedium);
162
163 if (!mResult.isOk())
164 {
165 mState = KMediaState_Inaccessible;
166 mLastAccessError = QString::null;
167 }
168 else
169 mLastAccessError = mMedium.GetLastAccessError();
170
171 refresh();
172}
173
174/**
175 * Refreshes the precomposed strings containing such media parameters as
176 * location, size by querying the respective data from the associated
177 * media object.
178 *
179 * Note that some string such as #size() are meaningless if the media state is
180 * KMediaState_NotCreated (i.e. the medium has not yet been checked for
181 * accessibility).
182 */
183void VBoxMedium::refresh()
184{
185 mId = mMedium.GetId();
186 mLocation = mMedium.GetLocation();
187 mName = mMedium.GetName();
188
189 if (mType == VBoxDefs::MediaType_HardDisk)
190 {
191 /// @todo NEWMEDIA use CSystemProperties::GetHardDIskFormats to see if the
192 /// given hard disk format is a file
193 mLocation = QDir::toNativeSeparators (mLocation);
194 mHardDiskFormat = mHardDisk.GetFormat();
195 mHardDiskType = vboxGlobal().hardDiskTypeString (mHardDisk);
196
197 mIsReadOnly = mHardDisk.GetReadOnly();
198
199 /* adjust the parent if necessary (note that mParent must always point
200 * to an item from VBoxGlobal::currentMediaList()) */
201
202 CHardDisk2 parent = mHardDisk.GetParent();
203 Assert (!parent.isNull() || mParent == NULL);
204
205 if (!parent.isNull() &&
206 (mParent == NULL || mParent->mHardDisk != parent))
207 {
208 /* search for the parent (must be there) */
209 const VBoxMediaList &list = vboxGlobal().currentMediaList();
210 for (VBoxMediaList::const_iterator it = list.begin();
211 it != list.end(); ++ it)
212 {
213 if ((*it).mType != VBoxDefs::MediaType_HardDisk)
214 break;
215
216 if ((*it).mHardDisk == parent)
217 {
218 /* we unconst here because by the const list we don't mean
219 * const items */
220 mParent = unconst (&*it);
221 break;
222 }
223 }
224
225 Assert (mParent != NULL && mParent->mHardDisk == parent);
226 }
227 }
228 else
229 {
230 mLocation = QDir::toNativeSeparators (mLocation);
231 mHardDiskFormat = QString::null;
232 mHardDiskType = QString::null;
233
234 mIsReadOnly = false;
235 }
236
237 if (mState != KMediaState_Inaccessible &&
238 mState != KMediaState_NotCreated)
239 {
240 mSize = vboxGlobal().formatSize (mMedium.GetSize());
241 if (mType == VBoxDefs::MediaType_HardDisk)
242 mLogicalSize = vboxGlobal()
243 .formatSize (mHardDisk.GetLogicalSize() * _1M);
244 else
245 mLogicalSize = mSize;
246 }
247 else
248 {
249 mSize = mLogicalSize = QString ("--");
250 }
251
252 /* detect usage */
253
254 mUsage = QString::null; /* important: null means not used! */
255
256 mCurStateMachineIds.clear();
257
258 QVector <QUuid> machineIds = mMedium.GetMachineIds();
259 if (machineIds.size() > 0)
260 {
261 QString usage;
262
263 CVirtualBox vbox = vboxGlobal().virtualBox();
264
265 for (QVector <QUuid>::ConstIterator it = machineIds.begin();
266 it != machineIds.end(); ++ it)
267 {
268 CMachine machine = vbox.GetMachine (*it);
269
270 QString name = machine.GetName();
271 QString snapshots;
272
273 QVector <QUuid> snapIds = mMedium.GetSnapshotIds (*it);
274 for (QVector <QUuid>::ConstIterator jt = snapIds.begin();
275 jt != snapIds.end(); ++ jt)
276 {
277 if (*jt == *it)
278 {
279 /* the medium is attached to the machine in the current
280 * state, we don't distinguish this for now by always
281 * giving the VM name in front of snapshot names. */
282
283 mCurStateMachineIds.push_back (*jt);
284 continue;
285 }
286
287 CSnapshot snapshot = machine.GetSnapshot (*jt);
288 if (!snapshots.isNull())
289 snapshots += ", ";
290 snapshots += snapshot.GetName();
291 }
292
293 if (!usage.isNull())
294 usage += ", ";
295
296 usage += name;
297
298 if (!snapshots.isNull())
299 {
300 usage += QString (" (%2)").arg (snapshots);
301 mIsUsedInSnapshots = true;
302 }
303 else
304 mIsUsedInSnapshots = false;
305 }
306
307 Assert (!usage.isEmpty());
308 mUsage = usage;
309 }
310
311 /* compose the tooltip (makes sense to keep the format in sync with
312 * VBoxMediaManagerDlg::languageChangeImp() and
313 * VBoxMediaManagerDlg::processCurrentChanged()) */
314
315 mToolTip = QString ("<nobr><b>%1</b></nobr>").arg (mLocation);
316
317 if (mType == VBoxDefs::MediaType_HardDisk)
318 {
319 mToolTip += VBoxGlobal::tr (
320 "<br><nobr>Type&nbsp;(Format):&nbsp;&nbsp;%2&nbsp;(%3)</nobr>",
321 "hard disk")
322 .arg (mHardDiskType)
323 .arg (mHardDiskFormat);
324 }
325
326 mToolTip += VBoxGlobal::tr (
327 "<br><nobr>Attached to:&nbsp;&nbsp;%1</nobr>", "medium")
328 .arg (mUsage.isNull() ?
329 VBoxGlobal::tr ("<i>Not&nbsp;Attached</i>", "medium") :
330 mUsage);
331
332 switch (mState)
333 {
334 case KMediaState_NotCreated:
335 {
336 mToolTip += VBoxGlobal::tr ("<br><i>Checking accessibility...</i>",
337 "medium");
338 break;
339 }
340 case KMediaState_Inaccessible:
341 {
342 if (mResult.isOk())
343 {
344 /* not accessibile */
345 mToolTip += QString ("<hr>%1").
346 arg (VBoxGlobal::highlight (mLastAccessError,
347 true /* aToolTip */));
348 }
349 else
350 {
351 /* accessibility check (eg GetState()) itself failed */
352 mToolTip = VBoxGlobal::tr (
353 "<hr>Failed to check media accessibility.<br>%1.",
354 "medium").
355 arg (VBoxProblemReporter::formatErrorInfo (mResult));
356 }
357 break;
358 }
359 default:
360 break;
361 }
362
363 /* reset mNoDiffs */
364 mNoDiffs.isSet = false;
365}
366
367/**
368 * Returns a root medium of this medium. For non-hard disk media, this is always
369 * this medium itself.
370 */
371VBoxMedium &VBoxMedium::root() const
372{
373 VBoxMedium *root = unconst (this);
374 while (root->mParent != NULL)
375 root = root->mParent;
376
377 return *root;
378}
379
380/**
381 * Returns a tooltip for this medium.
382 *
383 * In "don't show diffs" mode (where the attributes of the base hard disk are
384 * shown instead of the attributes of the differencing hard disk), extra
385 * information will be added to the tooltip to give the user a hint that the
386 * medium is actually a differencing hard disk.
387 *
388 * @param aNoDiffs @c true to enable user-friendly "don't show diffs" mode.
389 * @param aCheckRO @c true to perform the #readOnly() check and add a notice
390 * accordingly.
391 */
392QString VBoxMedium::toolTip (bool aNoDiffs /*= false*/,
393 bool aCheckRO /*= false*/) const
394{
395 unconst (this)->checkNoDiffs (aNoDiffs);
396
397 QString tip = aNoDiffs ? mNoDiffs.toolTip : mToolTip;
398
399 if (aCheckRO && mIsReadOnly)
400 tip += VBoxGlobal::tr (
401 "<hr><img src=%1/>&nbsp;Attaching this hard disk will "
402 "be performed indirectly using a newly created "
403 "differencing hard disk.",
404 "medium").
405 arg (":/new_16px.png");
406
407 return tip;
408}
409
410/**
411 * Returns an icon corresponding to the media state. Distinguishes between
412 * the Inaccessible state and the situation when querying the state itself
413 * failed.
414 *
415 * In "don't show diffs" mode (where the attributes of the base hard disk are
416 * shown instead of the attributes of the differencing hard disk), the most
417 * worst media state on the given hard disk chain will be used to select the
418 * media icon.
419 *
420 * @param aNoDiffs @c true to enable user-friendly "don't show diffs" mode.
421 * @param aCheckRO @c true to perform the #readOnly() check and change the icon
422 * accordingly.
423 */
424QPixmap VBoxMedium::icon (bool aNoDiffs /*= false*/,
425 bool aCheckRO /*= false*/) const
426{
427 QPixmap icon;
428
429 if (state (aNoDiffs) == KMediaState_Inaccessible)
430 icon = result (aNoDiffs).isOk() ?
431 vboxGlobal().warningIcon() : vboxGlobal().errorIcon();
432
433 if (aCheckRO && mIsReadOnly)
434 icon = VBoxGlobal::
435 joinPixmaps (icon, QPixmap (":/new_16px.png"));
436
437 return icon;
438}
439
440/**
441 * Returns the details of this medium as a single-line string
442 *
443 * For hard disks, the details include the location, type and the logical size
444 * of the hard disk. Note that if @a aNoDiffs is @c true, these properties are
445 * queried on the root hard disk of the given hard disk because the primary
446 * purpose of the returned string is to be human readabile (so that seeing a
447 * complex diff hard disk name is usually not desirable).
448 *
449 * For other media types, the location and the actual size are returned.
450 * Arguments @a aPredictDiff and @a aNoRoot are ignored in this case.
451 *
452 * @param aNoDiffs @c true to enable user-friendly "don't show diffs" mode.
453 * @param aPredictDiff @c true to mark the hard disk as differencing if
454 * attaching it would create a differencing hard disk (not
455 * used when @a aNoRoot is true).
456 * @param aUseHTML @c true to allow for emphasizing using bold and italics.
457 *
458 * @note Use #detailsHTML() instead of passing @c true for @a aUseHTML.
459 *
460 * @note The media object may become uninitialized by a third party while this
461 * method is reading its properties. In this case, the method will return
462 * an empty string.
463 */
464QString VBoxMedium::details (bool aNoDiffs /*= false*/,
465 bool aPredictDiff /*= false*/,
466 bool aUseHTML /*= false */) const
467{
468 // @todo *** the below check is rough; if mMedium becomes uninitialized, any
469 // of getters called afterwards will also fail. The same relates to the
470 // root hard disk object (that will be the hard disk itself in case of
471 // non-differencing disks). However, this check was added to fix a
472 // particular use case: when the hard disk is a differencing hard disk and
473 // it happens to be discarded (and uninitialized) after this method is
474 // called but before we read all its properties (yes, it's possible!), the
475 // root object will be null and calling methods on it will assert in the
476 // debug builds. This check seems to be enough as a quick solution (fresh
477 // hard disk attachments will be re-read by a machine state change signal
478 // after the discard operation is finished, so the user will eventually see
479 // correct data), but in order to solve the problem properly we need to use
480 // exceptions everywhere (or check the result after every method call). See
481 // also Defect #2149.
482 if (!mMedium.isOk())
483 return QString::null;
484
485 QString details, str;
486
487 VBoxMedium *root = unconst (this);
488 KMediaState state = mState;
489
490 if (mType == VBoxDefs::MediaType_HardDisk)
491 {
492 if (aNoDiffs)
493 {
494 root = &this->root();
495
496 bool isDiff =
497 (!aPredictDiff && mParent != NULL) ||
498 (aPredictDiff && mIsReadOnly);
499
500 details = isDiff && aUseHTML ?
501 QString ("<i>%1</i>, ").arg (root->mHardDiskType) :
502 QString ("%1, ").arg (root->mHardDiskType);
503
504 /* overall (worst) state */
505 state = this->state (true /* aNoDiffs */);
506
507 /* we cannot get the logical size if the root is not checked yet */
508 if (root->mState == KMediaState_NotCreated)
509 state = KMediaState_NotCreated;
510 }
511 else
512 {
513 details = QString ("%1, ").arg (root->mHardDiskType);
514 }
515 }
516
517 /// @todo prepend the details with the warning/error
518 // icon when not accessible
519
520 switch (state)
521 {
522 case KMediaState_NotCreated:
523 str = VBoxGlobal::tr ("Checking...", "medium");
524 details += aUseHTML ? QString ("<i>%1</i>").arg (str) : str;
525 break;
526 case KMediaState_Inaccessible:
527 str = VBoxGlobal::tr ("Inaccessible", "medium");
528 details += aUseHTML ? QString ("<b>%1</b>").arg (str) : str;
529 break;
530 default:
531 details += mType == VBoxDefs::MediaType_HardDisk ?
532 root->mLogicalSize : root->mSize;
533 break;
534 }
535
536 details = aUseHTML ?
537 QString ("%1 (<nobr>%2</nobr>)").
538 arg (VBoxGlobal::locationForHTML (root->mName), details) :
539 QString ("%1 (%2)").
540 arg (VBoxGlobal::locationForHTML (root->mName), details);
541
542 return details;
543}
544
545/**
546 * Checks if mNoDiffs is filled in and does it if not.
547 *
548 * @param aNoDiffs @if false, this method immediately returns.
549 */
550void VBoxMedium::checkNoDiffs (bool aNoDiffs)
551{
552 if (!aNoDiffs || mNoDiffs.isSet)
553 return;
554
555 /* fill mNoDiffs */
556
557 mNoDiffs.toolTip = QString::null;
558
559 /* detect the overall (worst) state of the given hard disk chain */
560 mNoDiffs.state = mState;
561 for (VBoxMedium *cur = mParent; cur != NULL;
562 cur = cur->mParent)
563 {
564 if (cur->mState == KMediaState_Inaccessible)
565 {
566 mNoDiffs.state = cur->mState;
567
568 if (mNoDiffs.toolTip.isNull())
569 mNoDiffs.toolTip = VBoxGlobal::tr (
570 "<hr>Some of the media in this hard disk chain are "
571 "inaccessible. Please use the Virtual Media Manager "
572 "in <b>Show Differencing Hard Disks</b> mode to inspect "
573 "these media.");
574
575 if (!cur->mResult.isOk())
576 {
577 mNoDiffs.result = cur->mResult;
578 break;
579 }
580
581 /* comtinue looking for another !cur->mResult.isOk() */
582 }
583 }
584
585 if (mParent != NULL && !mIsReadOnly)
586 {
587 mNoDiffs.toolTip = VBoxGlobal::tr (
588 "%1"
589 "<hr>This base hard disk is indirectly attached using the "
590 "following differencing hard disk:<br>"
591 "%2%3").
592 arg (root().toolTip(), mToolTip, mNoDiffs.toolTip);
593 }
594
595 if (mNoDiffs.toolTip.isNull())
596 mNoDiffs.toolTip = mToolTip;
597
598 mNoDiffs.isSet = true;
599}
600
601// VBoxMediaEnumEvent
602/////////////////////////////////////////////////////////////////////////////
603
604class VBoxMediaEnumEvent : public QEvent
605{
606public:
607
608 /** Constructs a regular enum event */
609 VBoxMediaEnumEvent (const VBoxMedium &aMedium,
610 VBoxMediaList::iterator &aIterator)
611 : QEvent ((QEvent::Type) VBoxDefs::MediaEnumEventType)
612 , mMedium (aMedium), mIterator (aIterator), mLast (false)
613 {}
614 /** Constructs the last enum event */
615 VBoxMediaEnumEvent (VBoxMediaList::iterator &aIterator)
616 : QEvent ((QEvent::Type) VBoxDefs::MediaEnumEventType)
617 , mIterator (aIterator), mLast (true)
618 {}
619
620 /** Last enumerated medium (not valid when #last is true) */
621 const VBoxMedium mMedium;
622 /** Opaque iterator provided by the event sender (guaranteed to be
623 * the same variable for all media in the single enumeration procedure) */
624 VBoxMediaList::iterator &mIterator;
625 /** Whether this is the last event for the given enumeration or not */
626 const bool mLast;
627};
628
629#if defined (Q_WS_WIN)
630class VBoxShellExecuteEvent : public QEvent
631{
632public:
633
634 /** Constructs a regular enum event */
635 VBoxShellExecuteEvent (QThread *aThread, const QString &aURL,
636 bool aOk)
637 : QEvent ((QEvent::Type) VBoxDefs::ShellExecuteEventType)
638 , mThread (aThread), mURL (aURL), mOk (aOk)
639 {}
640
641 QThread *mThread;
642 QString mURL;
643 bool mOk;
644};
645#endif
646
647// VirtualBox callback class
648/////////////////////////////////////////////////////////////////////////////
649
650class VBoxCallback : public IVirtualBoxCallback
651{
652public:
653
654 VBoxCallback (VBoxGlobal &aGlobal)
655 : mGlobal (aGlobal)
656 , mIsRegDlgOwner (false), mIsUpdDlgOwner (false)
657 {
658#if defined (Q_OS_WIN32)
659 refcnt = 0;
660#endif
661 }
662
663 virtual ~VBoxCallback() {}
664
665 NS_DECL_ISUPPORTS
666
667#if defined (Q_OS_WIN32)
668 STDMETHOD_(ULONG, AddRef)()
669 {
670 return ::InterlockedIncrement (&refcnt);
671 }
672 STDMETHOD_(ULONG, Release)()
673 {
674 long cnt = ::InterlockedDecrement (&refcnt);
675 if (cnt == 0)
676 delete this;
677 return cnt;
678 }
679 STDMETHOD(QueryInterface) (REFIID riid , void **ppObj)
680 {
681 if (riid == IID_IUnknown) {
682 *ppObj = this;
683 AddRef();
684 return S_OK;
685 }
686 if (riid == IID_IVirtualBoxCallback) {
687 *ppObj = this;
688 AddRef();
689 return S_OK;
690 }
691 *ppObj = NULL;
692 return E_NOINTERFACE;
693 }
694#endif
695
696 // IVirtualBoxCallback methods
697
698 // Note: we need to post custom events to the GUI event queue
699 // instead of doing what we need directly from here because on Win32
700 // these callback methods are never called on the main GUI thread.
701 // Another reason to handle events asynchronously is that internally
702 // most callback interface methods are called from under the initiator
703 // object's lock, so accessing the initiator object (for example, reading
704 // some property) directly from the callback method will definitely cause
705 // a deadlock.
706
707 STDMETHOD(OnMachineStateChange) (IN_GUIDPARAM id, MachineState_T state)
708 {
709 postEvent (new VBoxMachineStateChangeEvent (COMBase::ToQUuid (id),
710 (KMachineState) state));
711 return S_OK;
712 }
713
714 STDMETHOD(OnMachineDataChange) (IN_GUIDPARAM id)
715 {
716 postEvent (new VBoxMachineDataChangeEvent (COMBase::ToQUuid (id)));
717 return S_OK;
718 }
719
720 STDMETHOD(OnExtraDataCanChange)(IN_GUIDPARAM id,
721 IN_BSTRPARAM key, IN_BSTRPARAM value,
722 BSTR *error, BOOL *allowChange)
723 {
724 if (!error || !allowChange)
725 return E_INVALIDARG;
726
727 if (COMBase::ToQUuid (id).isNull())
728 {
729 /* it's a global extra data key someone wants to change */
730 QString sKey = QString::fromUtf16 (key);
731 QString sVal = QString::fromUtf16 (value);
732 if (sKey.startsWith ("GUI/"))
733 {
734 if (sKey == VBoxDefs::GUI_RegistrationDlgWinID)
735 {
736 if (mIsRegDlgOwner)
737 {
738 if (sVal.isEmpty() ||
739 sVal == QString ("%1")
740 .arg ((qulonglong) vboxGlobal().mainWindow()->winId()))
741 *allowChange = TRUE;
742 else
743 *allowChange = FALSE;
744 }
745 else
746 *allowChange = TRUE;
747 return S_OK;
748 }
749
750 if (sKey == VBoxDefs::GUI_UpdateDlgWinID)
751 {
752 if (mIsUpdDlgOwner)
753 {
754 if (sVal.isEmpty() ||
755 sVal == QString ("%1")
756 .arg ((qulonglong) vboxGlobal().mainWindow()->winId()))
757 *allowChange = TRUE;
758 else
759 *allowChange = FALSE;
760 }
761 else
762 *allowChange = TRUE;
763 return S_OK;
764 }
765
766 /* try to set the global setting to check its syntax */
767 VBoxGlobalSettings gs (false /* non-null */);
768 if (gs.setPublicProperty (sKey, sVal))
769 {
770 /* this is a known GUI property key */
771 if (!gs)
772 {
773 /* disallow the change when there is an error*/
774 *error = SysAllocString ((const OLECHAR *)
775 (gs.lastError().isNull() ? 0 : gs.lastError().utf16()));
776 *allowChange = FALSE;
777 }
778 else
779 *allowChange = TRUE;
780 return S_OK;
781 }
782 }
783 }
784
785 /* not interested in this key -- never disagree */
786 *allowChange = TRUE;
787 return S_OK;
788 }
789
790 STDMETHOD(OnExtraDataChange) (IN_GUIDPARAM id,
791 IN_BSTRPARAM key, IN_BSTRPARAM value)
792 {
793 if (COMBase::ToQUuid (id).isNull())
794 {
795 QString sKey = QString::fromUtf16 (key);
796 QString sVal = QString::fromUtf16 (value);
797 if (sKey.startsWith ("GUI/"))
798 {
799 if (sKey == VBoxDefs::GUI_RegistrationDlgWinID)
800 {
801 if (sVal.isEmpty())
802 {
803 mIsRegDlgOwner = false;
804 QApplication::postEvent (&mGlobal, new VBoxCanShowRegDlgEvent (true));
805 }
806 else if (sVal == QString ("%1")
807 .arg ((qulonglong) vboxGlobal().mainWindow()->winId()))
808 {
809 mIsRegDlgOwner = true;
810 QApplication::postEvent (&mGlobal, new VBoxCanShowRegDlgEvent (true));
811 }
812 else
813 QApplication::postEvent (&mGlobal, new VBoxCanShowRegDlgEvent (false));
814 }
815 if (sKey == VBoxDefs::GUI_UpdateDlgWinID)
816 {
817 if (sVal.isEmpty())
818 {
819 mIsUpdDlgOwner = false;
820 QApplication::postEvent (&mGlobal, new VBoxCanShowUpdDlgEvent (true));
821 }
822 else if (sVal == QString ("%1")
823 .arg ((qulonglong) vboxGlobal().mainWindow()->winId()))
824 {
825 mIsUpdDlgOwner = true;
826 QApplication::postEvent (&mGlobal, new VBoxCanShowUpdDlgEvent (true));
827 }
828 else
829 QApplication::postEvent (&mGlobal, new VBoxCanShowUpdDlgEvent (false));
830 }
831 if (sKey == "GUI/LanguageID")
832 QApplication::postEvent (&mGlobal, new VBoxChangeGUILanguageEvent (sVal));
833 #ifdef VBOX_GUI_WITH_SYSTRAY
834 if (sKey == "GUI/TrayIcon/Enabled")
835 QApplication::postEvent (&mGlobal, new VBoxChangeGUITrayIconEvent ((sVal.toLower() == "true") ? true : false));
836 #endif
837
838 mMutex.lock();
839 mGlobal.gset.setPublicProperty (sKey, sVal);
840 mMutex.unlock();
841 Assert (!!mGlobal.gset);
842 }
843 }
844 return S_OK;
845 }
846
847 STDMETHOD(OnMediaRegistered) (IN_GUIDPARAM id, DeviceType_T type,
848 BOOL registered)
849 {
850 /** @todo */
851 Q_UNUSED (id);
852 Q_UNUSED (type);
853 Q_UNUSED (registered);
854 return S_OK;
855 }
856
857 STDMETHOD(OnMachineRegistered) (IN_GUIDPARAM id, BOOL registered)
858 {
859 postEvent (new VBoxMachineRegisteredEvent (COMBase::ToQUuid (id),
860 registered));
861 return S_OK;
862 }
863
864 STDMETHOD(OnSessionStateChange) (IN_GUIDPARAM id, SessionState_T state)
865 {
866 postEvent (new VBoxSessionStateChangeEvent (COMBase::ToQUuid (id),
867 (KSessionState) state));
868 return S_OK;
869 }
870
871 STDMETHOD(OnSnapshotTaken) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
872 {
873 postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
874 COMBase::ToQUuid (aSnapshotId),
875 VBoxSnapshotEvent::Taken));
876 return S_OK;
877 }
878
879 STDMETHOD(OnSnapshotDiscarded) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
880 {
881 postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
882 COMBase::ToQUuid (aSnapshotId),
883 VBoxSnapshotEvent::Discarded));
884 return S_OK;
885 }
886
887 STDMETHOD(OnSnapshotChange) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
888 {
889 postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
890 COMBase::ToQUuid (aSnapshotId),
891 VBoxSnapshotEvent::Changed));
892 return S_OK;
893 }
894
895 STDMETHOD(OnGuestPropertyChange) (IN_GUIDPARAM /* id */,
896 IN_BSTRPARAM /* key */,
897 IN_BSTRPARAM /* value */,
898 IN_BSTRPARAM /* flags */)
899 {
900 return S_OK;
901 }
902
903private:
904
905 void postEvent (QEvent *e)
906 {
907 // currently, we don't post events if we are in the VM execution
908 // console mode, to save some CPU ticks (so far, there was no need
909 // to handle VirtualBox callback events in the execution console mode)
910
911 if (!mGlobal.isVMConsoleProcess())
912 QApplication::postEvent (&mGlobal, e);
913 }
914
915 VBoxGlobal &mGlobal;
916
917 /** protects #OnExtraDataChange() */
918 QMutex mMutex;
919
920 bool mIsRegDlgOwner;
921 bool mIsUpdDlgOwner;
922
923#if defined (Q_OS_WIN32)
924private:
925 long refcnt;
926#endif
927};
928
929#if !defined (Q_OS_WIN32)
930NS_DECL_CLASSINFO (VBoxCallback)
931NS_IMPL_THREADSAFE_ISUPPORTS1_CI (VBoxCallback, IVirtualBoxCallback)
932#endif
933
934// Helpers for VBoxGlobal::getOpenFileName() & getExistingDirectory()
935/////////////////////////////////////////////////////////////////////////////
936
937#if defined Q_WS_WIN
938
939extern void qt_enter_modal (QWidget*);
940extern void qt_leave_modal (QWidget*);
941
942static QString extractFilter (const QString &aRawFilter)
943{
944 static const char qt_file_dialog_filter_reg_exp[] =
945 "([a-zA-Z0-9 ]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$";
946
947 QString result = aRawFilter;
948 QRegExp r (QString::fromLatin1 (qt_file_dialog_filter_reg_exp));
949 int index = r.indexIn (result);
950 if (index >= 0)
951 result = r.cap (2);
952 return result.replace (QChar (' '), QChar (';'));
953}
954
955/**
956 * Converts QFileDialog filter list to Win32 API filter list.
957 */
958static QString winFilter (const QString &aFilter)
959{
960 QStringList filterLst;
961
962 if (!aFilter.isEmpty())
963 {
964 int i = aFilter.indexOf (";;", 0);
965 QString sep (";;");
966 if (i == -1)
967 {
968 if (aFilter.indexOf ("\n", 0) != -1)
969 {
970 sep = "\n";
971 i = aFilter.indexOf (sep, 0);
972 }
973 }
974
975 filterLst = aFilter.split (sep);
976 }
977
978 QStringList::Iterator it = filterLst.begin();
979 QString winfilters;
980 for (; it != filterLst.end(); ++it)
981 {
982 winfilters += *it;
983 winfilters += QChar::Null;
984 winfilters += extractFilter (*it);
985 winfilters += QChar::Null;
986 }
987 winfilters += QChar::Null;
988 return winfilters;
989}
990
991/*
992 * Callback function to control the native Win32 API file dialog
993 */
994UINT_PTR CALLBACK OFNHookProc (HWND aHdlg, UINT aUiMsg, WPARAM aWParam, LPARAM aLParam)
995{
996 if (aUiMsg == WM_NOTIFY)
997 {
998 OFNOTIFY *notif = (OFNOTIFY*) aLParam;
999 if (notif->hdr.code == CDN_TYPECHANGE)
1000 {
1001 /* locate native dialog controls */
1002 HWND parent = GetParent (aHdlg);
1003 HWND button = GetDlgItem (parent, IDOK);
1004 HWND textfield = ::GetDlgItem (parent, cmb13);
1005 if (textfield == NULL)
1006 textfield = ::GetDlgItem (parent, edt1);
1007 if (textfield == NULL)
1008 return FALSE;
1009 HWND selector = ::GetDlgItem (parent, cmb1);
1010
1011 /* simulate filter change by pressing apply-key */
1012 int size = 256;
1013 TCHAR *buffer = (TCHAR*)malloc (size);
1014 SendMessage (textfield, WM_GETTEXT, size, (LPARAM)buffer);
1015 SendMessage (textfield, WM_SETTEXT, 0, (LPARAM)"\0");
1016 SendMessage (button, BM_CLICK, 0, 0);
1017 SendMessage (textfield, WM_SETTEXT, 0, (LPARAM)buffer);
1018 free (buffer);
1019
1020 /* make request for focus moving to filter selector combo-box */
1021 HWND curFocus = GetFocus();
1022 PostMessage (curFocus, WM_KILLFOCUS, (WPARAM)selector, 0);
1023 PostMessage (selector, WM_SETFOCUS, (WPARAM)curFocus, 0);
1024 WPARAM wParam = MAKEWPARAM (WA_ACTIVE, 0);
1025 PostMessage (selector, WM_ACTIVATE, wParam, (LPARAM)curFocus);
1026 }
1027 }
1028 return FALSE;
1029}
1030
1031/*
1032 * Callback function to control the native Win32 API folders dialog
1033 */
1034static int __stdcall winGetExistDirCallbackProc (HWND hwnd, UINT uMsg,
1035 LPARAM lParam, LPARAM lpData)
1036{
1037 if (uMsg == BFFM_INITIALIZED && lpData != 0)
1038 {
1039 QString *initDir = (QString *)(lpData);
1040 if (!initDir->isEmpty())
1041 {
1042 SendMessage (hwnd, BFFM_SETSELECTION, TRUE, Q_ULONG (
1043 initDir->isNull() ? 0 : initDir->utf16()));
1044 //SendMessage (hwnd, BFFM_SETEXPANDED, TRUE, Q_ULONG (initDir->utf16()));
1045 }
1046 }
1047 else if (uMsg == BFFM_SELCHANGED)
1048 {
1049 TCHAR path [MAX_PATH];
1050 SHGetPathFromIDList (LPITEMIDLIST (lParam), path);
1051 QString tmpStr = QString::fromUtf16 ((ushort*)path);
1052 if (!tmpStr.isEmpty())
1053 SendMessage (hwnd, BFFM_ENABLEOK, 1, 1);
1054 else
1055 SendMessage (hwnd, BFFM_ENABLEOK, 0, 0);
1056 SendMessage (hwnd, BFFM_SETSTATUSTEXT, 1, Q_ULONG (path));
1057 }
1058 return 0;
1059}
1060
1061/**
1062 * QEvent class to carry Win32 API native dialog's result information
1063 */
1064class OpenNativeDialogEvent : public QEvent
1065{
1066public:
1067
1068 OpenNativeDialogEvent (const QString &aResult, QEvent::Type aType)
1069 : QEvent (aType), mResult (aResult) {}
1070
1071 const QString& result() { return mResult; }
1072
1073private:
1074
1075 QString mResult;
1076};
1077
1078/**
1079 * QObject class reimplementation which is the target for OpenNativeDialogEvent
1080 * event. It receives OpenNativeDialogEvent event from another thread,
1081 * stores result information and exits the given local event loop.
1082 */
1083class LoopObject : public QObject
1084{
1085public:
1086
1087 LoopObject (QEvent::Type aType, QEventLoop &aLoop)
1088 : mType (aType), mLoop (aLoop), mResult (QString::null) {}
1089 const QString& result() { return mResult; }
1090
1091private:
1092
1093 bool event (QEvent *aEvent)
1094 {
1095 if (aEvent->type() == mType)
1096 {
1097 OpenNativeDialogEvent *ev = (OpenNativeDialogEvent*) aEvent;
1098 mResult = ev->result();
1099 mLoop.quit();
1100 return true;
1101 }
1102 return QObject::event (aEvent);
1103 }
1104
1105 QEvent::Type mType;
1106 QEventLoop &mLoop;
1107 QString mResult;
1108};
1109
1110#endif /* Q_WS_WIN */
1111
1112
1113// VBoxGlobal
1114////////////////////////////////////////////////////////////////////////////////
1115
1116static bool sVBoxGlobalInited = false;
1117static bool sVBoxGlobalInCleanup = false;
1118
1119/** @internal
1120 *
1121 * Special routine to do VBoxGlobal cleanup when the application is being
1122 * terminated. It is called before some essential Qt functionality (for
1123 * instance, QThread) becomes unavailable, allowing us to use it from
1124 * VBoxGlobal::cleanup() if necessary.
1125 */
1126static void vboxGlobalCleanup()
1127{
1128 Assert (!sVBoxGlobalInCleanup);
1129 sVBoxGlobalInCleanup = true;
1130 vboxGlobal().cleanup();
1131}
1132
1133/** @internal
1134 *
1135 * Determines the rendering mode from the argument. Sets the appropriate
1136 * default rendering mode if the argumen is NULL.
1137 */
1138static VBoxDefs::RenderMode vboxGetRenderMode (const char *aModeStr)
1139{
1140 VBoxDefs::RenderMode mode = VBoxDefs::InvalidRenderMode;
1141
1142#if defined (Q_WS_MAC) && defined (VBOX_GUI_USE_QUARTZ2D)
1143 mode = VBoxDefs::Quartz2DMode;
1144#elif (defined (Q_WS_WIN32) || defined (Q_WS_PM)) && defined (VBOX_GUI_USE_QIMAGE)
1145 mode = VBoxDefs::QImageMode;
1146#elif defined (Q_WS_X11) && defined (VBOX_GUI_USE_SDL)
1147 mode = VBoxDefs::SDLMode;
1148#elif defined (VBOX_GUI_USE_QIMAGE)
1149 mode = VBoxDefs::QImageMode;
1150#else
1151# error "Cannot determine the default render mode!"
1152#endif
1153
1154 if (aModeStr)
1155 {
1156 if (0) ;
1157#if defined (VBOX_GUI_USE_QIMAGE)
1158 else if (::strcmp (aModeStr, "image") == 0)
1159 mode = VBoxDefs::QImageMode;
1160#endif
1161#if defined (VBOX_GUI_USE_SDL)
1162 else if (::strcmp (aModeStr, "sdl") == 0)
1163 mode = VBoxDefs::SDLMode;
1164#endif
1165#if defined (VBOX_GUI_USE_DDRAW)
1166 else if (::strcmp (aModeStr, "ddraw") == 0)
1167 mode = VBoxDefs::DDRAWMode;
1168#endif
1169#if defined (VBOX_GUI_USE_QUARTZ2D)
1170 else if (::strcmp (aModeStr, "quartz2d") == 0)
1171 mode = VBoxDefs::Quartz2DMode;
1172#endif
1173 }
1174
1175 return mode;
1176}
1177
1178/** @class VBoxGlobal
1179 *
1180 * The VBoxGlobal class incapsulates the global VirtualBox data.
1181 *
1182 * There is only one instance of this class per VirtualBox application,
1183 * the reference to it is returned by the static instance() method, or by
1184 * the global vboxGlobal() function, that is just an inlined shortcut.
1185 */
1186
1187VBoxGlobal::VBoxGlobal()
1188 : mValid (false)
1189 , mSelectorWnd (NULL), mConsoleWnd (NULL)
1190 , mMainWindow (NULL)
1191#ifdef VBOX_WITH_REGISTRATION
1192 , mRegDlg (NULL)
1193#endif
1194 , mUpdDlg (NULL)
1195 , mMediaEnumThread (NULL)
1196 , verString ("1.0")
1197 , vm_state_color (KMachineState_COUNT)
1198 , machineStates (KMachineState_COUNT)
1199 , sessionStates (KSessionState_COUNT)
1200 , deviceTypes (KDeviceType_COUNT)
1201 , storageBuses (KStorageBus_COUNT)
1202 , storageBusDevices (2)
1203 , storageBusChannels (3)
1204 , diskTypes (KHardDiskType_COUNT)
1205 , vrdpAuthTypes (KVRDPAuthType_COUNT)
1206 , portModeTypes (KPortMode_COUNT)
1207 , usbFilterActionTypes (KUSBDeviceFilterAction_COUNT)
1208 , audioDriverTypes (KAudioDriverType_COUNT)
1209 , audioControllerTypes (KAudioControllerType_COUNT)
1210 , networkAdapterTypes (KNetworkAdapterType_COUNT)
1211 , networkAttachmentTypes (KNetworkAttachmentType_COUNT)
1212 , clipboardTypes (KClipboardMode_COUNT)
1213 , ideControllerTypes (KIDEControllerType_COUNT)
1214 , USBDeviceStates (KUSBDeviceState_COUNT)
1215 , detailReportTemplatesReady (false)
1216{
1217}
1218
1219//
1220// Public members
1221/////////////////////////////////////////////////////////////////////////////
1222
1223/**
1224 * Returns a reference to the global VirtualBox data, managed by this class.
1225 *
1226 * The main() function of the VBox GUI must call this function soon after
1227 * creating a QApplication instance but before opening any of the main windows
1228 * (to let the VBoxGlobal initialization procedure use various Qt facilities),
1229 * and continue execution only when the isValid() method of the returned
1230 * instancereturns true, i.e. do something like:
1231 *
1232 * @code
1233 * if ( !VBoxGlobal::instance().isValid() )
1234 * return 1;
1235 * @endcode
1236 * or
1237 * @code
1238 * if ( !vboxGlobal().isValid() )
1239 * return 1;
1240 * @endcode
1241 *
1242 * @note Some VBoxGlobal methods can be used on a partially constructed
1243 * VBoxGlobal instance, i.e. from constructors and methods called
1244 * from the VBoxGlobal::init() method, which obtain the instance
1245 * using this instance() call or the ::vboxGlobal() function. Currently, such
1246 * methods are:
1247 * #vmStateText, #vmTypeIcon, #vmTypeText, #vmTypeTextList, #vmTypeFromText.
1248 *
1249 * @see ::vboxGlobal
1250 */
1251VBoxGlobal &VBoxGlobal::instance()
1252{
1253 static VBoxGlobal vboxGlobal_instance;
1254
1255 if (!sVBoxGlobalInited)
1256 {
1257 /* check that a QApplication instance is created */
1258 if (qApp)
1259 {
1260 sVBoxGlobalInited = true;
1261 vboxGlobal_instance.init();
1262 /* add our cleanup handler to the list of Qt post routines */
1263 qAddPostRoutine (vboxGlobalCleanup);
1264 }
1265 else
1266 AssertMsgFailed (("Must construct a QApplication first!"));
1267 }
1268 return vboxGlobal_instance;
1269}
1270
1271VBoxGlobal::~VBoxGlobal()
1272{
1273 qDeleteAll (mOsTypeIcons);
1274 qDeleteAll (mStateIcons);
1275 qDeleteAll (vm_state_color);
1276}
1277
1278/**
1279 * Sets the new global settings and saves them to the VirtualBox server.
1280 */
1281bool VBoxGlobal::setSettings (const VBoxGlobalSettings &gs)
1282{
1283 gs.save (mVBox);
1284
1285 if (!mVBox.isOk())
1286 {
1287 vboxProblem().cannotSaveGlobalConfig (mVBox);
1288 return false;
1289 }
1290
1291 /* We don't assign gs to our gset member here, because VBoxCallback
1292 * will update gset as necessary when new settings are successfullly
1293 * sent to the VirtualBox server by gs.save(). */
1294
1295 return true;
1296}
1297
1298/**
1299 * Returns a reference to the main VBox VM Selector window.
1300 * The reference is valid until application termination.
1301 *
1302 * There is only one such a window per VirtualBox application.
1303 */
1304VBoxSelectorWnd &VBoxGlobal::selectorWnd()
1305{
1306#if defined (VBOX_GUI_SEPARATE_VM_PROCESS)
1307 AssertMsg (!vboxGlobal().isVMConsoleProcess(),
1308 ("Must NOT be a VM console process"));
1309#endif
1310
1311 Assert (mValid);
1312
1313 if (!mSelectorWnd)
1314 {
1315 /*
1316 * We pass the address of mSelectorWnd to the constructor to let it be
1317 * initialized right after the constructor is called. It is necessary
1318 * to avoid recursion, since this method may be (and will be) called
1319 * from the below constructor or from constructors/methods it calls.
1320 */
1321 VBoxSelectorWnd *w = new VBoxSelectorWnd (&mSelectorWnd, 0);
1322 Assert (w == mSelectorWnd);
1323 NOREF(w);
1324 }
1325
1326 return *mSelectorWnd;
1327}
1328
1329/**
1330 * Returns a reference to the main VBox VM Console window.
1331 * The reference is valid until application termination.
1332 *
1333 * There is only one such a window per VirtualBox application.
1334 */
1335VBoxConsoleWnd &VBoxGlobal::consoleWnd()
1336{
1337#if defined (VBOX_GUI_SEPARATE_VM_PROCESS)
1338 AssertMsg (vboxGlobal().isVMConsoleProcess(),
1339 ("Must be a VM console process"));
1340#endif
1341
1342 Assert (mValid);
1343
1344 if (!mConsoleWnd)
1345 {
1346 /*
1347 * We pass the address of mConsoleWnd to the constructor to let it be
1348 * initialized right after the constructor is called. It is necessary
1349 * to avoid recursion, since this method may be (and will be) called
1350 * from the below constructor or from constructors/methods it calls.
1351 */
1352 VBoxConsoleWnd *w = new VBoxConsoleWnd (&mConsoleWnd, 0);
1353 Assert (w == mConsoleWnd);
1354 NOREF(w);
1355 }
1356
1357 return *mConsoleWnd;
1358}
1359
1360/**
1361 * Returns the list of few guest OS types, queried from
1362 * IVirtualBox corresponding to every family id.
1363 */
1364QList <CGuestOSType> VBoxGlobal::vmGuestOSFamilyList() const
1365{
1366 QList <CGuestOSType> result;
1367 for (int i = 0 ; i < mFamilyIDs.size(); ++ i)
1368 result << mTypes [i][0];
1369 return result;
1370}
1371
1372/**
1373 * Returns the list of all guest OS types, queried from
1374 * IVirtualBox corresponding to passed family id.
1375 */
1376QList <CGuestOSType> VBoxGlobal::vmGuestOSTypeList (const QString &aFamilyId) const
1377{
1378 AssertMsg (mFamilyIDs.contains (aFamilyId), ("Family ID incorrect: '%s'.", aFamilyId.toLatin1().constData()));
1379 return mFamilyIDs.contains (aFamilyId) ?
1380 mTypes [mFamilyIDs.indexOf (aFamilyId)] : QList <CGuestOSType>();
1381}
1382
1383/**
1384 * Returns the icon corresponding to the given guest OS type id.
1385 */
1386QPixmap VBoxGlobal::vmGuestOSTypeIcon (const QString &aTypeId) const
1387{
1388 static const QPixmap none;
1389 QPixmap *p = mOsTypeIcons.value (aTypeId);
1390 AssertMsg (p, ("Icon for type '%s' must be defined.", aTypeId.toLatin1().constData()));
1391 return p ? *p : none;
1392}
1393
1394/**
1395 * Returns the guest OS type object corresponding to the given type id of list
1396 * containing OS types related to OS family determined by family id attribute.
1397 * If the index is invalid a null object is returned.
1398 */
1399CGuestOSType VBoxGlobal::vmGuestOSType (const QString &aTypeId,
1400 const QString &aFamilyId /* = QString::null */) const
1401{
1402 QList <CGuestOSType> list;
1403 if (mFamilyIDs.contains (aFamilyId))
1404 {
1405 list = mTypes [mFamilyIDs.indexOf (aFamilyId)];
1406 }
1407 else
1408 {
1409 for (int i = 0; i < mFamilyIDs.size(); ++ i)
1410 list += mTypes [i];
1411 }
1412 for (int j = 0; j < list.size(); ++ j)
1413 if (!list [j].GetId().compare (aTypeId))
1414 return list [j];
1415 AssertMsgFailed (("Type ID incorrect: '%s'.", aTypeId.toLatin1().constData()));
1416 return CGuestOSType();
1417}
1418
1419/**
1420 * Returns the description corresponding to the given guest OS type id.
1421 */
1422QString VBoxGlobal::vmGuestOSTypeDescription (const QString &aTypeId) const
1423{
1424 for (int i = 0; i < mFamilyIDs.size(); ++ i)
1425 {
1426 QList <CGuestOSType> list (mTypes [i]);
1427 for ( int j = 0; j < list.size(); ++ j)
1428 if (!list [j].GetId().compare (aTypeId))
1429 return list [j].GetDescription();
1430 }
1431 return QString::null;
1432}
1433
1434/**
1435 * Returns a string representation of the given channel number on the given
1436 * storage bus. Complementary to #toStorageChannel (KStorageBus, const
1437 * QString &) const.
1438 */
1439QString VBoxGlobal::toString (KStorageBus aBus, LONG aChannel) const
1440{
1441 Assert (storageBusChannels.count() == 3);
1442 QString channel;
1443
1444 switch (aBus)
1445 {
1446 case KStorageBus_IDE:
1447 {
1448 if (aChannel == 0 || aChannel == 1)
1449 {
1450 channel = storageBusChannels [aChannel];
1451 break;
1452 }
1453
1454 AssertMsgFailedBreak (("Invalid channel %d\n", aChannel));
1455 }
1456 case KStorageBus_SATA:
1457 {
1458 channel = storageBusChannels [2].arg (aChannel);
1459 break;
1460 }
1461 default:
1462 AssertFailedBreak();
1463 }
1464
1465 return channel;
1466}
1467
1468/**
1469 * Returns a channel number on the given storage bus corresponding to the given
1470 * string representation. Complementary to #toString (KStorageBus, LONG) const.
1471 */
1472LONG VBoxGlobal::toStorageChannel (KStorageBus aBus, const QString &aChannel) const
1473{
1474 LONG channel = 0;
1475
1476 switch (aBus)
1477 {
1478 case KStorageBus_IDE:
1479 {
1480 QStringVector::const_iterator it =
1481 qFind (storageBusChannels.begin(), storageBusChannels.end(),
1482 aChannel);
1483 AssertMsgBreak (it != storageBusChannels.end(),
1484 ("No value for {%s}\n", aChannel.toLatin1().constData()));
1485 channel = (LONG) (it - storageBusChannels.begin());
1486 break;
1487 }
1488 case KStorageBus_SATA:
1489 {
1490 /// @todo use regexp to properly extract the %1 text
1491 QString tpl = storageBusChannels [2].arg ("");
1492 if (aChannel.startsWith (tpl))
1493 {
1494 channel = aChannel.right (aChannel.length() - tpl.length()).toLong();
1495 break;
1496 }
1497
1498 AssertMsgFailedBreak (("Invalid channel {%s}\n", aChannel.toLatin1().constData()));
1499 break;
1500 }
1501 default:
1502 AssertFailedBreak();
1503 }
1504
1505 return channel;
1506}
1507
1508/**
1509 * Returns a string representation of the given device number of the given
1510 * channel on the given storage bus. Complementary to #toStorageDevice
1511 * (KStorageBus, LONG, const QString &) const.
1512 */
1513QString VBoxGlobal::toString (KStorageBus aBus, LONG aChannel, LONG aDevice) const
1514{
1515 NOREF (aChannel);
1516
1517 Assert (storageBusDevices.count() == 2);
1518 QString device;
1519
1520 switch (aBus)
1521 {
1522 case KStorageBus_IDE:
1523 {
1524 if (aDevice == 0 || aDevice == 1)
1525 {
1526 device = storageBusDevices [aDevice];
1527 break;
1528 }
1529
1530 AssertMsgFailedBreak (("Invalid device %d\n", aDevice));
1531 }
1532 case KStorageBus_SATA:
1533 {
1534 AssertMsgBreak (aDevice == 0, ("Invalid device %d\n", aDevice));
1535 /* always zero so far for SATA */
1536 break;
1537 }
1538 default:
1539 AssertFailedBreak();
1540 }
1541
1542 return device;
1543}
1544
1545/**
1546 * Returns a device number of the given channel on the given storage bus
1547 * corresponding to the given string representation. Complementary to #toString
1548 * (KStorageBus, LONG, LONG) const.
1549 */
1550LONG VBoxGlobal::toStorageDevice (KStorageBus aBus, LONG aChannel,
1551 const QString &aDevice) const
1552{
1553 NOREF (aChannel);
1554
1555 LONG device = 0;
1556
1557 switch (aBus)
1558 {
1559 case KStorageBus_IDE:
1560 {
1561 QStringVector::const_iterator it =
1562 qFind (storageBusDevices.begin(), storageBusDevices.end(),
1563 aDevice);
1564 AssertMsg (it != storageBusDevices.end(),
1565 ("No value for {%s}", aDevice.toLatin1().constData()));
1566 device = (LONG) (it - storageBusDevices.begin());
1567 break;
1568 }
1569 case KStorageBus_SATA:
1570 {
1571 AssertMsgBreak(aDevice.isEmpty(), ("Invalid device {%s}\n", aDevice.toLatin1().constData()));
1572 /* always zero for SATA so far. */
1573 break;
1574 }
1575 default:
1576 AssertFailedBreak();
1577 }
1578
1579 return device;
1580}
1581
1582/**
1583 * Returns a full string representation of the given device of the given channel
1584 * on the given storage bus. Complementary to #toStorageParams (KStorageBus,
1585 * LONG, LONG) const.
1586 */
1587QString VBoxGlobal::toFullString (KStorageBus aBus, LONG aChannel,
1588 LONG aDevice) const
1589{
1590 QString device;
1591
1592 switch (aBus)
1593 {
1594 case KStorageBus_IDE:
1595 {
1596 device = QString ("%1 %2 %3")
1597 .arg (vboxGlobal().toString (aBus))
1598 .arg (vboxGlobal().toString (aBus, aChannel))
1599 .arg (vboxGlobal().toString (aBus, aChannel, aDevice));
1600 break;
1601 }
1602 case KStorageBus_SATA:
1603 {
1604 /* we only have one SATA device so far which is always zero */
1605 device = QString ("%1 %2")
1606 .arg (vboxGlobal().toString (aBus))
1607 .arg (vboxGlobal().toString (aBus, aChannel));
1608 break;
1609 }
1610 default:
1611 AssertFailedBreak();
1612 }
1613
1614 return device;
1615}
1616
1617/**
1618 * Returns the list of all device types (VirtualBox::DeviceType COM enum).
1619 */
1620QStringList VBoxGlobal::deviceTypeStrings() const
1621{
1622 static QStringList list;
1623 if (list.empty())
1624 for (int i = 0; i < deviceTypes.count() - 1 /* usb=n/a */; i++)
1625 list += deviceTypes [i];
1626 return list;
1627}
1628
1629struct PortConfig
1630{
1631 const char *name;
1632 const ulong IRQ;
1633 const ulong IOBase;
1634};
1635
1636static const PortConfig comKnownPorts[] =
1637{
1638 { "COM1", 4, 0x3F8 },
1639 { "COM2", 3, 0x2F8 },
1640 { "COM3", 4, 0x3E8 },
1641 { "COM4", 3, 0x2E8 },
1642 /* must not contain an element with IRQ=0 and IOBase=0 used to cause
1643 * toCOMPortName() to return the "User-defined" string for these values. */
1644};
1645
1646static const PortConfig lptKnownPorts[] =
1647{
1648 { "LPT1", 7, 0x3BC },
1649 { "LPT2", 5, 0x378 },
1650 { "LPT3", 5, 0x278 },
1651 /* must not contain an element with IRQ=0 and IOBase=0 used to cause
1652 * toLPTPortName() to return the "User-defined" string for these values. */
1653};
1654
1655/**
1656 * Returns the list of the standard COM port names (i.e. "COMx").
1657 */
1658QStringList VBoxGlobal::COMPortNames() const
1659{
1660 QStringList list;
1661 for (size_t i = 0; i < RT_ELEMENTS (comKnownPorts); ++ i)
1662 list << comKnownPorts [i].name;
1663
1664 return list;
1665}
1666
1667/**
1668 * Returns the list of the standard LPT port names (i.e. "LPTx").
1669 */
1670QStringList VBoxGlobal::LPTPortNames() const
1671{
1672 QStringList list;
1673 for (size_t i = 0; i < RT_ELEMENTS (lptKnownPorts); ++ i)
1674 list << lptKnownPorts [i].name;
1675
1676 return list;
1677}
1678
1679/**
1680 * Returns the name of the standard COM port corresponding to the given
1681 * parameters, or "User-defined" (which is also returned when both
1682 * @a aIRQ and @a aIOBase are 0).
1683 */
1684QString VBoxGlobal::toCOMPortName (ulong aIRQ, ulong aIOBase) const
1685{
1686 for (size_t i = 0; i < RT_ELEMENTS (comKnownPorts); ++ i)
1687 if (comKnownPorts [i].IRQ == aIRQ &&
1688 comKnownPorts [i].IOBase == aIOBase)
1689 return comKnownPorts [i].name;
1690
1691 return mUserDefinedPortName;
1692}
1693
1694/**
1695 * Returns the name of the standard LPT port corresponding to the given
1696 * parameters, or "User-defined" (which is also returned when both
1697 * @a aIRQ and @a aIOBase are 0).
1698 */
1699QString VBoxGlobal::toLPTPortName (ulong aIRQ, ulong aIOBase) const
1700{
1701 for (size_t i = 0; i < RT_ELEMENTS (lptKnownPorts); ++ i)
1702 if (lptKnownPorts [i].IRQ == aIRQ &&
1703 lptKnownPorts [i].IOBase == aIOBase)
1704 return lptKnownPorts [i].name;
1705
1706 return mUserDefinedPortName;
1707}
1708
1709/**
1710 * Returns port parameters corresponding to the given standard COM name.
1711 * Returns @c true on success, or @c false if the given port name is not one
1712 * of the standard names (i.e. "COMx").
1713 */
1714bool VBoxGlobal::toCOMPortNumbers (const QString &aName, ulong &aIRQ,
1715 ulong &aIOBase) const
1716{
1717 for (size_t i = 0; i < RT_ELEMENTS (comKnownPorts); ++ i)
1718 if (strcmp (comKnownPorts [i].name, aName.toUtf8().data()) == 0)
1719 {
1720 aIRQ = comKnownPorts [i].IRQ;
1721 aIOBase = comKnownPorts [i].IOBase;
1722 return true;
1723 }
1724
1725 return false;
1726}
1727
1728/**
1729 * Returns port parameters corresponding to the given standard LPT name.
1730 * Returns @c true on success, or @c false if the given port name is not one
1731 * of the standard names (i.e. "LPTx").
1732 */
1733bool VBoxGlobal::toLPTPortNumbers (const QString &aName, ulong &aIRQ,
1734 ulong &aIOBase) const
1735{
1736 for (size_t i = 0; i < RT_ELEMENTS (lptKnownPorts); ++ i)
1737 if (strcmp (lptKnownPorts [i].name, aName.toUtf8().data()) == 0)
1738 {
1739 aIRQ = lptKnownPorts [i].IRQ;
1740 aIOBase = lptKnownPorts [i].IOBase;
1741 return true;
1742 }
1743
1744 return false;
1745}
1746
1747/**
1748 * Searches for the given hard disk in the list of known media descriptors and
1749 * calls VBoxMedium::details() on the found desriptor.
1750 *
1751 * If the requeststed hard disk is not found (for example, it's a new hard disk
1752 * for a new VM created outside our UI), then media enumeration is requested and
1753 * the search is repeated. We assume that the secont attempt always succeeds and
1754 * assert otherwise.
1755 *
1756 * @note Technically, the second attempt may fail if, for example, the new hard
1757 * passed to this method disk gets removed before #startEnumeratingMedia()
1758 * succeeds. This (unexpected object uninitialization) is a generic
1759 * problem though and needs to be addressed using exceptions (see also the
1760 * @todo in VBoxMedium::details()).
1761 */
1762QString VBoxGlobal::details (const CHardDisk2 &aHD,
1763 bool aPredictDiff)
1764{
1765 CMedium cmedium (aHD);
1766 VBoxMedium medium;
1767
1768 if (!findMedium (cmedium, medium))
1769 {
1770 /* media may be new and not alredy in the media list, request refresh */
1771 startEnumeratingMedia();
1772 if (!findMedium (cmedium, medium))
1773 AssertFailedReturn (QString::null);
1774 }
1775
1776 return medium.detailsHTML (true /* aNoDiffs */, aPredictDiff);
1777}
1778
1779/**
1780 * Returns the details of the given USB device as a single-line string.
1781 */
1782QString VBoxGlobal::details (const CUSBDevice &aDevice) const
1783{
1784 QString details;
1785 QString m = aDevice.GetManufacturer().trimmed();
1786 QString p = aDevice.GetProduct().trimmed();
1787 if (m.isEmpty() && p.isEmpty())
1788 {
1789 details =
1790 tr ("Unknown device %1:%2", "USB device details")
1791 .arg (QString().sprintf ("%04hX", aDevice.GetVendorId()))
1792 .arg (QString().sprintf ("%04hX", aDevice.GetProductId()));
1793 }
1794 else
1795 {
1796 if (p.toUpper().startsWith (m.toUpper()))
1797 details = p;
1798 else
1799 details = m + " " + p;
1800 }
1801 ushort r = aDevice.GetRevision();
1802 if (r != 0)
1803 details += QString().sprintf (" [%04hX]", r);
1804
1805 return details.trimmed();
1806}
1807
1808/**
1809 * Returns the multi-line description of the given USB device.
1810 */
1811QString VBoxGlobal::toolTip (const CUSBDevice &aDevice) const
1812{
1813 QString tip =
1814 tr ("<nobr>Vendor ID: %1</nobr><br>"
1815 "<nobr>Product ID: %2</nobr><br>"
1816 "<nobr>Revision: %3</nobr>", "USB device tooltip")
1817 .arg (QString().sprintf ("%04hX", aDevice.GetVendorId()))
1818 .arg (QString().sprintf ("%04hX", aDevice.GetProductId()))
1819 .arg (QString().sprintf ("%04hX", aDevice.GetRevision()));
1820
1821 QString ser = aDevice.GetSerialNumber();
1822 if (!ser.isEmpty())
1823 tip += QString (tr ("<br><nobr>Serial No. %1</nobr>", "USB device tooltip"))
1824 .arg (ser);
1825
1826 /* add the state field if it's a host USB device */
1827 CHostUSBDevice hostDev (aDevice);
1828 if (!hostDev.isNull())
1829 {
1830 tip += QString (tr ("<br><nobr>State: %1</nobr>", "USB device tooltip"))
1831 .arg (vboxGlobal().toString (hostDev.GetState()));
1832 }
1833
1834 return tip;
1835}
1836
1837/**
1838 * Returns the multi-line description of the given USB filter
1839 */
1840QString VBoxGlobal::toolTip (const CUSBDeviceFilter &aFilter) const
1841{
1842 QString tip;
1843
1844 QString vendorId = aFilter.GetVendorId();
1845 if (!vendorId.isEmpty())
1846 tip += tr ("<nobr>Vendor ID: %1</nobr>", "USB filter tooltip")
1847 .arg (vendorId);
1848
1849 QString productId = aFilter.GetProductId();
1850 if (!productId.isEmpty())
1851 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>Product ID: %2</nobr>", "USB filter tooltip")
1852 .arg (productId);
1853
1854 QString revision = aFilter.GetRevision();
1855 if (!revision.isEmpty())
1856 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>Revision: %3</nobr>", "USB filter tooltip")
1857 .arg (revision);
1858
1859 QString product = aFilter.GetProduct();
1860 if (!product.isEmpty())
1861 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>Product: %4</nobr>", "USB filter tooltip")
1862 .arg (product);
1863
1864 QString manufacturer = aFilter.GetManufacturer();
1865 if (!manufacturer.isEmpty())
1866 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>Manufacturer: %5</nobr>", "USB filter tooltip")
1867 .arg (manufacturer);
1868
1869 QString serial = aFilter.GetSerialNumber();
1870 if (!serial.isEmpty())
1871 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>Serial No.: %1</nobr>", "USB filter tooltip")
1872 .arg (serial);
1873
1874 QString port = aFilter.GetPort();
1875 if (!port.isEmpty())
1876 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>Port: %1</nobr>", "USB filter tooltip")
1877 .arg (port);
1878
1879 /* add the state field if it's a host USB device */
1880 CHostUSBDevice hostDev (aFilter);
1881 if (!hostDev.isNull())
1882 {
1883 tip += tip.isEmpty() ? "":"<br/>" + tr ("<nobr>State: %1</nobr>", "USB filter tooltip")
1884 .arg (vboxGlobal().toString (hostDev.GetState()));
1885 }
1886
1887 return tip;
1888}
1889
1890/**
1891 * Returns a details report on a given VM represented as a HTML table.
1892 *
1893 * @param aMachine Machine to create a report for.
1894 * @param aIsNewVM @c true when called by the New VM Wizard.
1895 * @param aWithLinks @c true if section titles should be hypertext links.
1896 */
1897QString VBoxGlobal::detailsReport (const CMachine &aMachine, bool aIsNewVM,
1898 bool aWithLinks)
1899{
1900 static const char *sTableTpl =
1901 "<table border=0 cellspacing=1 cellpadding=0>%1</table>";
1902 static const char *sSectionHrefTpl =
1903 "<tr><td width=22 rowspan=%1 align=left><img src='%2'></td>"
1904 "<td colspan=2><b><a href='%3'><nobr>%4</nobr></a></b></td></tr>"
1905 "%5"
1906 "<tr><td colspan=2><font size=1>&nbsp;</font></td></tr>";
1907 static const char *sSectionBoldTpl =
1908 "<tr><td width=22 rowspan=%1 align=left><img src='%2'></td>"
1909 "<td colspan=2><!-- %3 --><b><nobr>%4</nobr></b></td></tr>"
1910 "%5"
1911 "<tr><td colspan=2><font size=1>&nbsp;</font></td></tr>";
1912 static const char *sSectionItemTpl =
1913 "<tr><td width=40%><nobr>%1</nobr></td><td>%2</td></tr>";
1914
1915 static QString sGeneralBasicHrefTpl, sGeneralBasicBoldTpl;
1916 static QString sGeneralFullHrefTpl, sGeneralFullBoldTpl;
1917
1918 /* generate templates after every language change */
1919
1920 if (!detailReportTemplatesReady)
1921 {
1922 detailReportTemplatesReady = true;
1923
1924 QString generalItems
1925 = QString (sSectionItemTpl).arg (tr ("Name", "details report"), "%1")
1926 + QString (sSectionItemTpl).arg (tr ("OS Type", "details report"), "%2")
1927 + QString (sSectionItemTpl).arg (tr ("Base Memory", "details report"),
1928 tr ("<nobr>%3 MB</nobr>", "details report"));
1929 sGeneralBasicHrefTpl = QString (sSectionHrefTpl)
1930 .arg (2 + 3) /* rows */
1931 .arg (":/machine_16px.png", /* icon */
1932 "#general", /* link */
1933 tr ("General", "details report"), /* title */
1934 generalItems); /* items */
1935 sGeneralBasicBoldTpl = QString (sSectionBoldTpl)
1936 .arg (2 + 3) /* rows */
1937 .arg (":/machine_16px.png", /* icon */
1938 "#general", /* link */
1939 tr ("General", "details report"), /* title */
1940 generalItems); /* items */
1941
1942 generalItems
1943 += QString (sSectionItemTpl).arg (tr ("Video Memory", "details report"),
1944 tr ("<nobr>%4 MB</nobr>", "details report"))
1945 + QString (sSectionItemTpl).arg (tr ("Boot Order", "details report"), "%5")
1946 + QString (sSectionItemTpl).arg (tr ("ACPI", "details report"), "%6")
1947 + QString (sSectionItemTpl).arg (tr ("IO APIC", "details report"), "%7")
1948 + QString (sSectionItemTpl).arg (tr ("VT-x/AMD-V", "details report"), "%8")
1949 + QString (sSectionItemTpl).arg (tr ("PAE/NX", "details report"), "%9")
1950 + QString (sSectionItemTpl).arg (tr ("3D Acceleration", "details report"), "%10");
1951
1952 sGeneralFullHrefTpl = QString (sSectionHrefTpl)
1953 .arg (2 + 10) /* rows */
1954 .arg (":/machine_16px.png", /* icon */
1955 "#general", /* link */
1956 tr ("General", "details report"), /* title */
1957 generalItems); /* items */
1958 sGeneralFullBoldTpl = QString (sSectionBoldTpl)
1959 .arg (2 + 10) /* rows */
1960 .arg (":/machine_16px.png", /* icon */
1961 "#general", /* link */
1962 tr ("General", "details report"), /* title */
1963 generalItems); /* items */
1964 }
1965
1966 /* common generated content */
1967
1968 const QString &sectionTpl = aWithLinks
1969 ? sSectionHrefTpl
1970 : sSectionBoldTpl;
1971
1972 QString hardDisks;
1973 {
1974 int rows = 2; /* including section header and footer */
1975
1976 CHardDisk2AttachmentVector vec = aMachine.GetHardDisk2Attachments();
1977 for (size_t i = 0; i < (size_t) vec.size(); ++ i)
1978 {
1979 CHardDisk2Attachment hda = vec [i];
1980 CHardDisk2 hd = hda.GetHardDisk();
1981
1982 /// @todo for the explaination of the below isOk() checks, see ***
1983 /// in #details (const CHardDisk &, bool).
1984 if (hda.isOk())
1985 {
1986 KStorageBus bus = hda.GetBus();
1987 LONG channel = hda.GetChannel();
1988 LONG device = hda.GetDevice();
1989 hardDisks += QString (sSectionItemTpl)
1990 .arg (toFullString (bus, channel, device))
1991 .arg (details (hd, aIsNewVM));
1992 ++ rows;
1993 }
1994 }
1995
1996 if (hardDisks.isNull())
1997 {
1998 hardDisks = QString (sSectionItemTpl)
1999 .arg (tr ("Not Attached", "details report (HDDs)")).arg ("");
2000 ++ rows;
2001 }
2002
2003 hardDisks = sectionTpl
2004 .arg (rows) /* rows */
2005 .arg (":/hd_16px.png", /* icon */
2006 "#hdds", /* link */
2007 tr ("Hard Disks", "details report"), /* title */
2008 hardDisks); /* items */
2009 }
2010
2011 /* compose details report */
2012
2013 const QString &generalBasicTpl = aWithLinks
2014 ? sGeneralBasicHrefTpl
2015 : sGeneralBasicBoldTpl;
2016
2017 const QString &generalFullTpl = aWithLinks
2018 ? sGeneralFullHrefTpl
2019 : sGeneralFullBoldTpl;
2020
2021 QString detailsReport;
2022
2023 if (aIsNewVM)
2024 {
2025 detailsReport
2026 = generalBasicTpl
2027 .arg (aMachine.GetName())
2028 .arg (vmGuestOSTypeDescription (aMachine.GetOSTypeId()))
2029 .arg (aMachine.GetMemorySize())
2030 + hardDisks;
2031 }
2032 else
2033 {
2034 /* boot order */
2035 QString bootOrder;
2036 for (ulong i = 1; i <= mVBox.GetSystemProperties().GetMaxBootPosition(); i++)
2037 {
2038 KDeviceType device = aMachine.GetBootOrder (i);
2039 if (device == KDeviceType_Null)
2040 continue;
2041 if (!bootOrder.isEmpty())
2042 bootOrder += ", ";
2043 bootOrder += toString (device);
2044 }
2045 if (bootOrder.isEmpty())
2046 bootOrder = toString (KDeviceType_Null);
2047
2048 CBIOSSettings biosSettings = aMachine.GetBIOSSettings();
2049
2050 /* ACPI */
2051 QString acpi = biosSettings.GetACPIEnabled()
2052 ? tr ("Enabled", "details report (ACPI)")
2053 : tr ("Disabled", "details report (ACPI)");
2054
2055 /* IO APIC */
2056 QString ioapic = biosSettings.GetIOAPICEnabled()
2057 ? tr ("Enabled", "details report (IO APIC)")
2058 : tr ("Disabled", "details report (IO APIC)");
2059
2060 /* VT-x/AMD-V */
2061 QString virt = aMachine.GetHWVirtExEnabled() == KTSBool_True ?
2062 tr ("Enabled", "details report (VT-x/AMD-V)") :
2063 tr ("Disabled", "details report (VT-x/AMD-V)");
2064
2065 /* PAE/NX */
2066 QString pae = aMachine.GetPAEEnabled()
2067 ? tr ("Enabled", "details report (PAE/NX)")
2068 : tr ("Disabled", "details report (PAE/NX)");
2069
2070 /* 3D Acceleration */
2071 QString acc3d = aMachine.GetAccelerate3DEnabled()
2072 ? tr ("Enabled", "details report (3D Acceleration)")
2073 : tr ("Disabled", "details report (3D Acceleration)");
2074
2075 /* General + Hard Disks */
2076 detailsReport
2077 = generalFullTpl
2078 .arg (aMachine.GetName())
2079 .arg (vmGuestOSTypeDescription (aMachine.GetOSTypeId()))
2080 .arg (aMachine.GetMemorySize())
2081 .arg (aMachine.GetVRAMSize())
2082 .arg (bootOrder)
2083 .arg (acpi)
2084 .arg (ioapic)
2085 .arg (virt)
2086 .arg (pae)
2087 .arg (acc3d)
2088 + hardDisks;
2089
2090 QString item;
2091
2092 /* DVD */
2093 CDVDDrive dvd = aMachine.GetDVDDrive();
2094 item = QString (sSectionItemTpl);
2095 switch (dvd.GetState())
2096 {
2097 case KDriveState_NotMounted:
2098 item = item.arg (tr ("Not mounted", "details report (DVD)"), "");
2099 break;
2100 case KDriveState_ImageMounted:
2101 {
2102 CDVDImage2 img = dvd.GetImage();
2103 item = item.arg (tr ("Image", "details report (DVD)"),
2104 locationForHTML (img.GetName()));
2105 break;
2106 }
2107 case KDriveState_HostDriveCaptured:
2108 {
2109 CHostDVDDrive drv = dvd.GetHostDrive();
2110 QString drvName = drv.GetName();
2111 QString description = drv.GetDescription();
2112 QString fullName = description.isEmpty() ?
2113 drvName :
2114 QString ("%1 (%2)").arg (description, drvName);
2115 item = item.arg (tr ("Host Drive", "details report (DVD)"),
2116 fullName);
2117 break;
2118 }
2119 default:
2120 AssertMsgFailed (("Invalid DVD state: %d", dvd.GetState()));
2121 }
2122 detailsReport += sectionTpl
2123 .arg (2 + 1) /* rows */
2124 .arg (":/cd_16px.png", /* icon */
2125 "#dvd", /* link */
2126 tr ("CD/DVD-ROM", "details report"), /* title */
2127 item); // items
2128
2129 /* Floppy */
2130 CFloppyDrive floppy = aMachine.GetFloppyDrive();
2131 item = QString (sSectionItemTpl);
2132 switch (floppy.GetState())
2133 {
2134 case KDriveState_NotMounted:
2135 item = item.arg (tr ("Not mounted", "details report (floppy)"), "");
2136 break;
2137 case KDriveState_ImageMounted:
2138 {
2139 CFloppyImage2 img = floppy.GetImage();
2140 item = item.arg (tr ("Image", "details report (floppy)"),
2141 locationForHTML (img.GetName()));
2142 break;
2143 }
2144 case KDriveState_HostDriveCaptured:
2145 {
2146 CHostFloppyDrive drv = floppy.GetHostDrive();
2147 QString drvName = drv.GetName();
2148 QString description = drv.GetDescription();
2149 QString fullName = description.isEmpty() ?
2150 drvName :
2151 QString ("%1 (%2)").arg (description, drvName);
2152 item = item.arg (tr ("Host Drive", "details report (floppy)"),
2153 fullName);
2154 break;
2155 }
2156 default:
2157 AssertMsgFailed (("Invalid floppy state: %d", floppy.GetState()));
2158 }
2159 detailsReport += sectionTpl
2160 .arg (2 + 1) /* rows */
2161 .arg (":/fd_16px.png", /* icon */
2162 "#floppy", /* link */
2163 tr ("Floppy", "details report"), /* title */
2164 item); /* items */
2165
2166 /* audio */
2167 {
2168 CAudioAdapter audio = aMachine.GetAudioAdapter();
2169 int rows = audio.GetEnabled() ? 3 : 2;
2170 if (audio.GetEnabled())
2171 item = QString (sSectionItemTpl)
2172 .arg (tr ("Host Driver", "details report (audio)"),
2173 toString (audio.GetAudioDriver())) +
2174 QString (sSectionItemTpl)
2175 .arg (tr ("Controller", "details report (audio)"),
2176 toString (audio.GetAudioController()));
2177 else
2178 item = QString (sSectionItemTpl)
2179 .arg (tr ("Disabled", "details report (audio)"), "");
2180
2181 detailsReport += sectionTpl
2182 .arg (rows + 1) /* rows */
2183 .arg (":/sound_16px.png", /* icon */
2184 "#audio", /* link */
2185 tr ("Audio", "details report"), /* title */
2186 item); /* items */
2187 }
2188 /* network */
2189 {
2190 item = QString::null;
2191 ulong count = mVBox.GetSystemProperties().GetNetworkAdapterCount();
2192 int rows = 2; /* including section header and footer */
2193 for (ulong slot = 0; slot < count; slot ++)
2194 {
2195 CNetworkAdapter adapter = aMachine.GetNetworkAdapter (slot);
2196 if (adapter.GetEnabled())
2197 {
2198 KNetworkAttachmentType type = adapter.GetAttachmentType();
2199 QString attType = toString (adapter.GetAdapterType())
2200 .replace (QRegExp ("\\s\\(.+\\)"), " (%1)");
2201 /* don't use the adapter type string for types that have
2202 * an additional symbolic network/interface name field, use
2203 * this name instead */
2204 if (type == KNetworkAttachmentType_HostInterface)
2205 attType = attType.arg (tr ("host interface, %1",
2206 "details report (network)").arg (adapter.GetHostInterface()));
2207 else if (type == KNetworkAttachmentType_Internal)
2208 attType = attType.arg (tr ("internal network, '%1'",
2209 "details report (network)").arg (adapter.GetInternalNetwork()));
2210 else
2211 attType = attType.arg (vboxGlobal().toString (type));
2212
2213 item += QString (sSectionItemTpl)
2214 .arg (tr ("Adapter %1", "details report (network)")
2215 .arg (adapter.GetSlot() + 1))
2216 .arg (attType);
2217 ++ rows;
2218 }
2219 }
2220 if (item.isNull())
2221 {
2222 item = QString (sSectionItemTpl)
2223 .arg (tr ("Disabled", "details report (network)"), "");
2224 ++ rows;
2225 }
2226
2227 detailsReport += sectionTpl
2228 .arg (rows) /* rows */
2229 .arg (":/nw_16px.png", /* icon */
2230 "#network", /* link */
2231 tr ("Network", "details report"), /* title */
2232 item); /* items */
2233 }
2234 /* serial ports */
2235 {
2236 item = QString::null;
2237 ulong count = mVBox.GetSystemProperties().GetSerialPortCount();
2238 int rows = 2; /* including section header and footer */
2239 for (ulong slot = 0; slot < count; slot ++)
2240 {
2241 CSerialPort port = aMachine.GetSerialPort (slot);
2242 if (port.GetEnabled())
2243 {
2244 KPortMode mode = port.GetHostMode();
2245 QString data =
2246 toCOMPortName (port.GetIRQ(), port.GetIOBase()) + ", ";
2247 if (mode == KPortMode_HostPipe ||
2248 mode == KPortMode_HostDevice)
2249 data += QString ("%1 (<nobr>%2</nobr>)")
2250 .arg (vboxGlobal().toString (mode))
2251 .arg (QDir::toNativeSeparators (port.GetPath()));
2252 else
2253 data += toString (mode);
2254
2255 item += QString (sSectionItemTpl)
2256 .arg (tr ("Port %1", "details report (serial ports)")
2257 .arg (port.GetSlot() + 1))
2258 .arg (data);
2259 ++ rows;
2260 }
2261 }
2262 if (item.isNull())
2263 {
2264 item = QString (sSectionItemTpl)
2265 .arg (tr ("Disabled", "details report (serial ports)"), "");
2266 ++ rows;
2267 }
2268
2269 detailsReport += sectionTpl
2270 .arg (rows) /* rows */
2271 .arg (":/serial_port_16px.png", /* icon */
2272 "#serialPorts", /* link */
2273 tr ("Serial Ports", "details report"), /* title */
2274 item); /* items */
2275 }
2276 /* parallel ports */
2277 {
2278 item = QString::null;
2279 ulong count = mVBox.GetSystemProperties().GetParallelPortCount();
2280 int rows = 2; /* including section header and footer */
2281 for (ulong slot = 0; slot < count; slot ++)
2282 {
2283 CParallelPort port = aMachine.GetParallelPort (slot);
2284 if (port.GetEnabled())
2285 {
2286 QString data =
2287 toLPTPortName (port.GetIRQ(), port.GetIOBase()) +
2288 QString (" (<nobr>%1</nobr>)")
2289 .arg (QDir::toNativeSeparators (port.GetPath()));
2290
2291 item += QString (sSectionItemTpl)
2292 .arg (tr ("Port %1", "details report (parallel ports)")
2293 .arg (port.GetSlot() + 1))
2294 .arg (data);
2295 ++ rows;
2296 }
2297 }
2298 if (item.isNull())
2299 {
2300 item = QString (sSectionItemTpl)
2301 .arg (tr ("Disabled", "details report (parallel ports)"), "");
2302 ++ rows;
2303 }
2304
2305 /* Temporary disabled */
2306 QString dummy = sectionTpl /* detailsReport += sectionTpl */
2307 .arg (rows) /* rows */
2308 .arg (":/parallel_port_16px.png", /* icon */
2309 "#parallelPorts", /* link */
2310 tr ("Parallel Ports", "details report"), /* title */
2311 item); /* items */
2312 }
2313 /* USB */
2314 {
2315 CUSBController ctl = aMachine.GetUSBController();
2316 if (!ctl.isNull())
2317 {
2318 /* the USB controller may be unavailable (i.e. in VirtualBox OSE) */
2319
2320 if (ctl.GetEnabled())
2321 {
2322 CUSBDeviceFilterCollection coll = ctl.GetDeviceFilters();
2323 CUSBDeviceFilterEnumerator en = coll.Enumerate();
2324 uint active = 0;
2325 while (en.HasMore())
2326 if (en.GetNext().GetActive())
2327 active ++;
2328
2329 item = QString (sSectionItemTpl)
2330 .arg (tr ("Device Filters", "details report (USB)"),
2331 tr ("%1 (%2 active)", "details report (USB)")
2332 .arg (coll.GetCount()).arg (active));
2333 }
2334 else
2335 item = QString (sSectionItemTpl)
2336 .arg (tr ("Disabled", "details report (USB)"), "");
2337
2338 detailsReport += sectionTpl
2339 .arg (2 + 1) /* rows */
2340 .arg (":/usb_16px.png", /* icon */
2341 "#usb", /* link */
2342 tr ("USB", "details report"), /* title */
2343 item); /* items */
2344 }
2345 }
2346 /* Shared folders */
2347 {
2348 ulong count = aMachine.GetSharedFolders().GetCount();
2349 if (count > 0)
2350 {
2351 item = QString (sSectionItemTpl)
2352 .arg (tr ("Shared Folders", "details report (shared folders)"),
2353 tr ("%1", "details report (shadef folders)")
2354 .arg (count));
2355 }
2356 else
2357 item = QString (sSectionItemTpl)
2358 .arg (tr ("None", "details report (shared folders)"), "");
2359
2360 detailsReport += sectionTpl
2361 .arg (2 + 1) /* rows */
2362 .arg (":/shared_folder_16px.png", /* icon */
2363 "#sfolders", /* link */
2364 tr ("Shared Folders", "details report"), /* title */
2365 item); /* items */
2366 }
2367 /* VRDP */
2368 {
2369 CVRDPServer srv = aMachine.GetVRDPServer();
2370 if (!srv.isNull())
2371 {
2372 /* the VRDP server may be unavailable (i.e. in VirtualBox OSE) */
2373
2374 if (srv.GetEnabled())
2375 item = QString (sSectionItemTpl)
2376 .arg (tr ("VRDP Server Port", "details report (VRDP)"),
2377 tr ("%1", "details report (VRDP)")
2378 .arg (srv.GetPort()));
2379 else
2380 item = QString (sSectionItemTpl)
2381 .arg (tr ("Disabled", "details report (VRDP)"), "");
2382
2383 detailsReport += sectionTpl
2384 .arg (2 + 1) /* rows */
2385 .arg (":/vrdp_16px.png", /* icon */
2386 "#vrdp", /* link */
2387 tr ("Remote Display", "details report"), /* title */
2388 item); /* items */
2389 }
2390 }
2391 }
2392
2393 return QString (sTableTpl). arg (detailsReport);
2394}
2395
2396QString VBoxGlobal::platformInfo()
2397{
2398 QString platform;
2399
2400#if defined (Q_OS_WIN)
2401 platform = "win";
2402#elif defined (Q_OS_LINUX)
2403 platform = "linux";
2404#elif defined (Q_OS_MACX)
2405 platform = "macosx";
2406#elif defined (Q_OS_OS2)
2407 platform = "os2";
2408#elif defined (Q_OS_FREEBSD)
2409 platform = "freebsd";
2410#elif defined (Q_OS_SOLARIS)
2411 platform = "solaris";
2412#else
2413 platform = "unknown";
2414#endif
2415
2416 /* The format is <system>.<bitness> */
2417 platform += QString (".%1").arg (ARCH_BITS);
2418
2419 /* Add more system information */
2420#if defined (Q_OS_WIN)
2421 OSVERSIONINFO versionInfo;
2422 ZeroMemory (&versionInfo, sizeof (OSVERSIONINFO));
2423 versionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
2424 GetVersionEx (&versionInfo);
2425 int major = versionInfo.dwMajorVersion;
2426 int minor = versionInfo.dwMinorVersion;
2427 int build = versionInfo.dwBuildNumber;
2428 QString sp = QString::fromUtf16 ((ushort*)versionInfo.szCSDVersion);
2429
2430 QString distrib;
2431 if (major == 6)
2432 distrib = QString ("Windows Vista %1");
2433 else if (major == 5)
2434 {
2435 if (minor == 2)
2436 distrib = QString ("Windows Server 2003 %1");
2437 else if (minor == 1)
2438 distrib = QString ("Windows XP %1");
2439 else if (minor == 0)
2440 distrib = QString ("Windows 2000 %1");
2441 else
2442 distrib = QString ("Unknown %1");
2443 }
2444 else if (major == 4)
2445 {
2446 if (minor == 90)
2447 distrib = QString ("Windows Me %1");
2448 else if (minor == 10)
2449 distrib = QString ("Windows 98 %1");
2450 else if (minor == 0)
2451 distrib = QString ("Windows 95 %1");
2452 else
2453 distrib = QString ("Unknown %1");
2454 }
2455 else
2456 distrib = QString ("Unknown %1");
2457 distrib = distrib.arg (sp);
2458 QString version = QString ("%1.%2").arg (major).arg (minor);
2459 QString kernel = QString ("%1").arg (build);
2460 platform += QString (" [Distribution: %1 | Version: %2 | Build: %3]")
2461 .arg (distrib).arg (version).arg (kernel);
2462#elif defined (Q_OS_OS2)
2463 // TODO: add sys info for os2 if any...
2464#elif defined (Q_OS_LINUX) || defined (Q_OS_MACX) || defined (Q_OS_FREEBSD) || defined (Q_OS_SOLARIS)
2465 /* Get script path */
2466 char szAppPrivPath [RTPATH_MAX];
2467 int rc = RTPathAppPrivateNoArch (szAppPrivPath, sizeof (szAppPrivPath)); NOREF(rc);
2468 AssertRC (rc);
2469 /* Run script */
2470 QByteArray result =
2471 Process::singleShot (QString (szAppPrivPath) + "/VBoxSysInfo.sh");
2472 if (!result.isNull())
2473 platform += QString (" [%1]").arg (QString (result).trimmed());
2474#endif
2475
2476 return platform;
2477}
2478
2479#if defined(Q_WS_X11) && !defined(VBOX_OSE)
2480double VBoxGlobal::findLicenseFile (const QStringList &aFilesList, QRegExp aPattern, QString &aLicenseFile) const
2481{
2482 double maxVersionNumber = 0;
2483 aLicenseFile = "";
2484 for (int index = 0; index < aFilesList.count(); ++ index)
2485 {
2486 aPattern.indexIn (aFilesList [index]);
2487 QString version = aPattern.cap (1);
2488 if (maxVersionNumber < version.toDouble())
2489 {
2490 maxVersionNumber = version.toDouble();
2491 aLicenseFile = aFilesList [index];
2492 }
2493 }
2494 return maxVersionNumber;
2495}
2496
2497bool VBoxGlobal::showVirtualBoxLicense()
2498{
2499 /* get the apps doc path */
2500 int size = 256;
2501 char *buffer = (char*) RTMemTmpAlloc (size);
2502 RTPathAppDocs (buffer, size);
2503 QString path (buffer);
2504 RTMemTmpFree (buffer);
2505 QDir docDir (path);
2506 docDir.setFilter (QDir::Files);
2507 docDir.setNameFilters (QStringList ("License-*.html"));
2508
2509 /* Make sure that the language is in two letter code.
2510 * Note: if languageId() returns an empty string lang.name() will
2511 * return "C" which is an valid language code. */
2512 QLocale lang (VBoxGlobal::languageId());
2513
2514 QStringList filesList = docDir.entryList();
2515 QString licenseFile;
2516 /* First try to find a localized version of the license file. */
2517 double versionNumber = findLicenseFile (filesList, QRegExp (QString ("License-([\\d\\.]+)-%1.html").arg (lang.name())), licenseFile);
2518 /* If there wasn't a localized version of the currently selected language,
2519 * search for the generic one. */
2520 if (versionNumber == 0)
2521 versionNumber = findLicenseFile (filesList, QRegExp ("License-([\\d\\.]+).html"), licenseFile);
2522 /* Check the version again. */
2523 if (!versionNumber)
2524 {
2525 vboxProblem().cannotFindLicenseFiles (path);
2526 return false;
2527 }
2528
2529 /* compose the latest license file full path */
2530 QString latestVersion = QString::number (versionNumber);
2531 QString latestFilePath = docDir.absoluteFilePath (licenseFile);
2532
2533 /* check for the agreed license version */
2534 QString licenseAgreed = virtualBox().GetExtraData (VBoxDefs::GUI_LicenseKey);
2535 if (licenseAgreed == latestVersion)
2536 return true;
2537
2538 VBoxLicenseViewer licenseDialog (latestFilePath);
2539 bool result = licenseDialog.exec() == QDialog::Accepted;
2540 if (result)
2541 virtualBox().SetExtraData (VBoxDefs::GUI_LicenseKey, latestVersion);
2542 return result;
2543}
2544#endif /* defined(Q_WS_X11) && !defined(VBOX_OSE) */
2545
2546/**
2547 * Checks if any of the settings files were auto-converted and informs the user
2548 * if so. Returns @c false if the user select to exit the application.
2549 *
2550 * @param aAfterRefresh @c true to suppress the first simple dialog aExit
2551 * button. Used when calling after the VM refresh.
2552 */
2553bool VBoxGlobal::checkForAutoConvertedSettings (bool aAfterRefresh /*= false*/)
2554{
2555 QString formatVersion = mVBox.GetSettingsFormatVersion();
2556
2557 bool isGlobalConverted = false;
2558 QList <CMachine> machines;
2559 QString fileList;
2560 QString version;
2561
2562 CMachineVector vec = mVBox.GetMachines2();
2563 for (CMachineVector::ConstIterator m = vec.begin();
2564 m != vec.end(); ++ m)
2565 {
2566 if (!m->GetAccessible())
2567 continue;
2568
2569 version = m->GetSettingsFileVersion();
2570 if (version != formatVersion)
2571 {
2572 machines.append (*m);
2573 fileList += QString ("<tr><td><nobr>%1</nobr></td><td>&nbsp;&nbsp;</td>"
2574 "</td><td><nobr><i>%2</i></nobr></td></tr>")
2575 .arg (m->GetSettingsFilePath())
2576 .arg (version);
2577 }
2578 }
2579
2580 if (!aAfterRefresh)
2581 {
2582 version = mVBox.GetSettingsFileVersion();
2583 if (version != formatVersion)
2584 {
2585 isGlobalConverted = true;
2586 fileList += QString ("<tr><td><nobr>%1</nobr></td><td>&nbsp;&nbsp;</td>"
2587 "</td><td><nobr><i>%2</i></nobr></td></tr>")
2588 .arg (mVBox.GetSettingsFilePath())
2589 .arg (version);
2590 }
2591 }
2592
2593 if (!fileList.isNull())
2594 {
2595 fileList = QString ("<table cellspacing=0 cellpadding=0>%1</table>")
2596 .arg (fileList);
2597
2598 int rc = vboxProblem()
2599 .warnAboutAutoConvertedSettings (formatVersion, fileList,
2600 aAfterRefresh);
2601
2602 if (rc == QIMessageBox::Cancel)
2603 return false;
2604
2605 Assert (rc == QIMessageBox::No || rc == QIMessageBox::Yes);
2606
2607 /* backup (optionally) and save all settings files
2608 * (QIMessageBox::No = Backup, QIMessageBox::Yes = Save) */
2609
2610 foreach (CMachine m, machines)
2611 {
2612 CSession session = openSession (m.GetId());
2613 if (!session.isNull())
2614 {
2615 CMachine sm = session.GetMachine();
2616 if (rc == QIMessageBox::No)
2617 sm.SaveSettingsWithBackup();
2618 else
2619 sm.SaveSettings();
2620
2621 if (!sm.isOk())
2622 vboxProblem().cannotSaveMachineSettings (sm);
2623 session.Close();
2624 }
2625 }
2626
2627 if (isGlobalConverted)
2628 {
2629 if (rc == QIMessageBox::No)
2630 mVBox.SaveSettingsWithBackup();
2631 else
2632 mVBox.SaveSettings();
2633
2634 if (!mVBox.isOk())
2635 vboxProblem().cannotSaveGlobalSettings (mVBox);
2636 }
2637 }
2638
2639 return true;
2640}
2641
2642/**
2643 * Opens a direct session for a machine with the given ID.
2644 * This method does user-friendly error handling (display error messages, etc.).
2645 * and returns a null CSession object in case of any error.
2646 * If this method succeeds, don't forget to close the returned session when
2647 * it is no more necessary.
2648 *
2649 * @param aId Machine ID.
2650 * @param aExisting @c true to open an existing session with the machine
2651 * which is already running, @c false to open a new direct
2652 * session.
2653 */
2654CSession VBoxGlobal::openSession (const QUuid &aId, bool aExisting /* = false */)
2655{
2656 CSession session;
2657 session.createInstance (CLSID_Session);
2658 if (session.isNull())
2659 {
2660 vboxProblem().cannotOpenSession (session);
2661 return session;
2662 }
2663
2664 if (aExisting)
2665 mVBox.OpenExistingSession (session, aId);
2666 else
2667 {
2668 mVBox.OpenSession (session, aId);
2669 CMachine machine = session.GetMachine ();
2670 /* Make sure that the language is in two letter code.
2671 * Note: if languageId() returns an empty string lang.name() will
2672 * return "C" which is an valid language code. */
2673 QLocale lang (VBoxGlobal::languageId());
2674 machine.SetGuestPropertyValue ("/VirtualBox/HostInfo/GUI/LanguageID", lang.name());
2675 }
2676
2677 if (!mVBox.isOk())
2678 {
2679 CMachine machine = CVirtualBox (mVBox).GetMachine (aId);
2680 vboxProblem().cannotOpenSession (mVBox, machine);
2681 session.detach();
2682 }
2683
2684 return session;
2685}
2686
2687/**
2688 * Starts a machine with the given ID.
2689 */
2690bool VBoxGlobal::startMachine (const QUuid &id)
2691{
2692 AssertReturn (mValid, false);
2693
2694 CSession session = vboxGlobal().openSession (id);
2695 if (session.isNull())
2696 return false;
2697
2698 return consoleWnd().openView (session);
2699}
2700
2701/**
2702 * Appends the given list of hard disks and all their children to the media
2703 * list. To be called only from VBoxGlobal::startEnumeratingMedia().
2704 */
2705static
2706void AddHardDisksToList (const CHardDisk2Vector &aVector,
2707 VBoxMediaList &aList,
2708 VBoxMediaList::iterator aWhere,
2709 VBoxMedium *aParent = 0)
2710{
2711 VBoxMediaList::iterator first = aWhere;
2712
2713 /* First pass: Add siblings sorted */
2714 for (CHardDisk2Vector::ConstIterator it = aVector.begin();
2715 it != aVector.end(); ++ it)
2716 {
2717 CMedium cmedium (*it);
2718 VBoxMedium medium (cmedium, VBoxDefs::MediaType_HardDisk, aParent);
2719
2720 /* Search for a proper alphabetic position */
2721 VBoxMediaList::iterator jt = first;
2722 for (; jt != aWhere; ++ jt)
2723 if ((*jt).name().localeAwareCompare (medium.name()) > 0)
2724 break;
2725
2726 aList.insert (jt, medium);
2727
2728 /* Adjust the first item if inserted before it */
2729 if (jt == first)
2730 -- first;
2731 }
2732
2733 /* Second pass: Add children */
2734 for (VBoxMediaList::iterator it = first; it != aWhere;)
2735 {
2736 CHardDisk2Vector children = (*it).hardDisk().GetChildren();
2737 VBoxMedium *parent = &(*it);
2738
2739 ++ it; /* go to the next sibling before inserting children */
2740 AddHardDisksToList (children, aList, it, parent);
2741 }
2742}
2743
2744/**
2745 * Starts a thread that asynchronously enumerates all currently registered
2746 * media.
2747 *
2748 * Before the enumeration is started, the current media list (a list returned by
2749 * #currentMediaList()) is populated with all registered media and the
2750 * #mediumEnumStarted() signal is emitted. The enumeration thread then walks this
2751 * list, checks for media acessiblity and emits #mediumEnumerated() signals of
2752 * each checked medium. When all media are checked, the enumeration thread is
2753 * stopped and the #mediumEnumFinished() signal is emitted.
2754 *
2755 * If the enumeration is already in progress, no new thread is started.
2756 *
2757 * The media list returned by #currentMediaList() is always sorted
2758 * alphabetically by the location attribute and comes in the following order:
2759 * <ol>
2760 * <li>All hard disks. If a hard disk has children, these children
2761 * (alphabetically sorted) immediately follow their parent and terefore
2762 * appear before its next sibling hard disk.</li>
2763 * <li>All CD/DVD images.</li>
2764 * <li>All Floppy images.</li>
2765 * </ol>
2766 *
2767 * Note that #mediumEnumerated() signals are emitted in the same order as
2768 * described above.
2769 *
2770 * @sa #currentMediaList()
2771 * @sa #isMediaEnumerationStarted()
2772 */
2773void VBoxGlobal::startEnumeratingMedia()
2774{
2775 AssertReturnVoid (mValid);
2776
2777 /* check if already started but not yet finished */
2778 if (mMediaEnumThread != NULL)
2779 return;
2780
2781 /* ignore the request during application termination */
2782 if (sVBoxGlobalInCleanup)
2783 return;
2784
2785 /* composes a list of all currently known media & their children */
2786 mMediaList.clear();
2787 {
2788 AddHardDisksToList (mVBox.GetHardDisks2(), mMediaList, mMediaList.end());
2789 }
2790 {
2791 VBoxMediaList::iterator first = mMediaList.end();
2792
2793 CDVDImage2Vector vec = mVBox.GetDVDImages();
2794 for (CDVDImage2Vector::ConstIterator it = vec.begin();
2795 it != vec.end(); ++ it)
2796 {
2797 CMedium cmedium (*it);
2798 VBoxMedium medium (cmedium, VBoxDefs::MediaType_DVD);
2799
2800 /* Search for a proper alphabetic position */
2801 VBoxMediaList::iterator jt = first;
2802 for (; jt != mMediaList.end(); ++ jt)
2803 if ((*jt).name().localeAwareCompare (medium.name()) > 0)
2804 break;
2805
2806 mMediaList.insert (jt, medium);
2807
2808 /* Adjust the first item if inserted before it */
2809 if (jt == first)
2810 -- first;
2811 }
2812 }
2813 {
2814 VBoxMediaList::iterator first = mMediaList.end();
2815
2816 CFloppyImage2Vector vec = mVBox.GetFloppyImages();
2817 for (CFloppyImage2Vector::ConstIterator it = vec.begin();
2818 it != vec.end(); ++ it)
2819 {
2820 CMedium cmedium (*it);
2821 VBoxMedium medium (cmedium, VBoxDefs::MediaType_Floppy);
2822
2823 /* Search for a proper alphabetic position */
2824 VBoxMediaList::iterator jt = first;
2825 for (; jt != mMediaList.end(); ++ jt)
2826 if ((*jt).name().localeAwareCompare (medium.name()) > 0)
2827 break;
2828
2829 mMediaList.insert (jt, medium);
2830
2831 /* Adjust the first item if inserted before it */
2832 if (jt == first)
2833 -- first;
2834 }
2835 }
2836
2837 /* enumeration thread class */
2838 class MediaEnumThread : public QThread
2839 {
2840 public:
2841
2842 MediaEnumThread (VBoxMediaList &aList)
2843 : mVector (aList.size())
2844 , mSavedIt (aList.begin())
2845 {
2846 int i = 0;
2847 for (VBoxMediaList::const_iterator it = aList.begin();
2848 it != aList.end(); ++ it)
2849 mVector [i ++] = *it;
2850 }
2851
2852 virtual void run()
2853 {
2854 LogFlow (("MediaEnumThread started.\n"));
2855 COMBase::InitializeCOM();
2856
2857 CVirtualBox mVBox = vboxGlobal().virtualBox();
2858 QObject *self = &vboxGlobal();
2859
2860 /* Enumerate the list */
2861 for (int i = 0; i < mVector.size() && !sVBoxGlobalInCleanup; ++ i)
2862 {
2863 mVector [i].blockAndQueryState();
2864 QApplication::
2865 postEvent (self,
2866 new VBoxMediaEnumEvent (mVector [i], mSavedIt));
2867 }
2868
2869 /* Post the end-of-enumeration event */
2870 if (!sVBoxGlobalInCleanup)
2871 QApplication::postEvent (self, new VBoxMediaEnumEvent (mSavedIt));
2872
2873 COMBase::CleanupCOM();
2874 LogFlow (("MediaEnumThread finished.\n"));
2875 }
2876
2877 private:
2878
2879 QVector <VBoxMedium> mVector;
2880 VBoxMediaList::iterator mSavedIt;
2881 };
2882
2883 mMediaEnumThread = new MediaEnumThread (mMediaList);
2884 AssertReturnVoid (mMediaEnumThread);
2885
2886 /* emit mediumEnumStarted() after we set mMediaEnumThread to != NULL
2887 * to cause isMediaEnumerationStarted() to return TRUE from slots */
2888 emit mediumEnumStarted();
2889
2890 mMediaEnumThread->start();
2891}
2892
2893/**
2894 * Adds a new medium to the current media list and emits the #mediumAdded()
2895 * signal.
2896 *
2897 * @sa #currentMediaList()
2898 */
2899void VBoxGlobal::addMedium (const VBoxMedium &aMedium)
2900{
2901 /* Note that we maitain the same order here as #startEnumeratingMedia() */
2902
2903 VBoxMediaList::iterator it = mMediaList.begin();
2904
2905 if (aMedium.type() == VBoxDefs::MediaType_HardDisk)
2906 {
2907 VBoxMediaList::iterator parent = mMediaList.end();
2908
2909 for (; it != mMediaList.end(); ++ it)
2910 {
2911 if ((*it).type() != VBoxDefs::MediaType_HardDisk)
2912 break;
2913
2914 if (aMedium.parent() != NULL && parent == mMediaList.end())
2915 {
2916 if (&*it == aMedium.parent())
2917 parent = it;
2918 }
2919 else
2920 {
2921 /* break if met a parent's sibling (will insert before it) */
2922 if (aMedium.parent() != NULL &&
2923 (*it).parent() == (*parent).parent())
2924 break;
2925
2926 /* compare to aMedium's siblings */
2927 if ((*it).parent() == aMedium.parent() &&
2928 (*it).name().localeAwareCompare (aMedium.name()) > 0)
2929 break;
2930 }
2931 }
2932
2933 AssertReturnVoid (aMedium.parent() == NULL || parent != mMediaList.end());
2934 }
2935 else
2936 {
2937 for (; it != mMediaList.end(); ++ it)
2938 {
2939 /* skip HardDisks that come first */
2940 if ((*it).type() == VBoxDefs::MediaType_HardDisk)
2941 continue;
2942
2943 /* skip DVD when inserting Floppy */
2944 if (aMedium.type() == VBoxDefs::MediaType_Floppy &&
2945 (*it).type() == VBoxDefs::MediaType_DVD)
2946 continue;
2947
2948 if ((*it).name().localeAwareCompare (aMedium.name()) > 0 ||
2949 (aMedium.type() == VBoxDefs::MediaType_DVD &&
2950 (*it).type() == VBoxDefs::MediaType_Floppy))
2951 break;
2952 }
2953 }
2954
2955 it = mMediaList.insert (it, aMedium);
2956
2957 emit mediumAdded (*it);
2958}
2959
2960/**
2961 * Updates the medium in the current media list and emits the #mediumUpdated()
2962 * signal.
2963 *
2964 * @sa #currentMediaList()
2965 */
2966void VBoxGlobal::updateMedium (const VBoxMedium &aMedium)
2967{
2968 VBoxMediaList::Iterator it;
2969 for (it = mMediaList.begin(); it != mMediaList.end(); ++ it)
2970 if ((*it).id() == aMedium.id())
2971 break;
2972
2973 AssertReturnVoid (it != mMediaList.end());
2974
2975 if (&*it != &aMedium)
2976 *it = aMedium;
2977
2978 emit mediumUpdated (*it);
2979}
2980
2981/**
2982 * Removes the medium from the current media list and emits the #mediumRemoved()
2983 * signal.
2984 *
2985 * @sa #currentMediaList()
2986 */
2987void VBoxGlobal::removeMedium (VBoxDefs::MediaType aType, const QUuid &aId)
2988{
2989 VBoxMediaList::Iterator it;
2990 for (it = mMediaList.begin(); it != mMediaList.end(); ++ it)
2991 if ((*it).id() == aId)
2992 break;
2993
2994 AssertReturnVoid (it != mMediaList.end());
2995
2996#if DEBUG
2997 /* sanity: must be no children */
2998 {
2999 VBoxMediaList::Iterator jt = it;
3000 ++ jt;
3001 AssertReturnVoid (jt == mMediaList.end() || (*jt).parent() != &*it);
3002 }
3003#endif
3004
3005 VBoxMedium *parent = (*it).parent();
3006
3007 /* remove the medium from the list to keep it in sync with the server "for
3008 * free" when the medium is deleted from one of our UIs */
3009 mMediaList.erase (it);
3010
3011 emit mediumRemoved (aType, aId);
3012
3013 /* also emit the parent update signal because some attributes like
3014 * isReadOnly() may have been changed after child removal */
3015 if (parent != NULL)
3016 {
3017 parent->refresh();
3018 emit mediumUpdated (*parent);
3019 }
3020}
3021
3022/**
3023 * Searches for a VBoxMedum object representing the given COM medium object.
3024 *
3025 * @return true if found and false otherwise.
3026 */
3027bool VBoxGlobal::findMedium (const CMedium &aObj, VBoxMedium &aMedium) const
3028{
3029 for (VBoxMediaList::ConstIterator it = mMediaList.begin();
3030 it != mMediaList.end(); ++ it)
3031 {
3032 if ((*it).medium() == aObj)
3033 {
3034 aMedium = (*it);
3035 return true;
3036 }
3037 }
3038
3039 return false;
3040}
3041
3042/**
3043 * Native language name of the currently installed translation.
3044 * Returns "English" if no translation is installed
3045 * or if the translation file is invalid.
3046 */
3047QString VBoxGlobal::languageName() const
3048{
3049
3050 return qApp->translate ("@@@", "English",
3051 "Native language name");
3052}
3053
3054/**
3055 * Native language country name of the currently installed translation.
3056 * Returns "--" if no translation is installed or if the translation file is
3057 * invalid, or if the language is independent on the country.
3058 */
3059QString VBoxGlobal::languageCountry() const
3060{
3061 return qApp->translate ("@@@", "--",
3062 "Native language country name "
3063 "(empty if this language is for all countries)");
3064}
3065
3066/**
3067 * Language name of the currently installed translation, in English.
3068 * Returns "English" if no translation is installed
3069 * or if the translation file is invalid.
3070 */
3071QString VBoxGlobal::languageNameEnglish() const
3072{
3073
3074 return qApp->translate ("@@@", "English",
3075 "Language name, in English");
3076}
3077
3078/**
3079 * Language country name of the currently installed translation, in English.
3080 * Returns "--" if no translation is installed or if the translation file is
3081 * invalid, or if the language is independent on the country.
3082 */
3083QString VBoxGlobal::languageCountryEnglish() const
3084{
3085 return qApp->translate ("@@@", "--",
3086 "Language country name, in English "
3087 "(empty if native country name is empty)");
3088}
3089
3090/**
3091 * Comma-separated list of authors of the currently installed translation.
3092 * Returns "Sun Microsystems, Inc." if no translation is installed or if the
3093 * translation file is invalid, or if the translation is supplied by Sun
3094 * Microsystems, inc.
3095 */
3096QString VBoxGlobal::languageTranslators() const
3097{
3098 return qApp->translate ("@@@", "Sun Microsystems, Inc.",
3099 "Comma-separated list of translators");
3100}
3101
3102/**
3103 * Changes the language of all global string constants according to the
3104 * currently installed translations tables.
3105 */
3106void VBoxGlobal::retranslateUi()
3107{
3108 machineStates [KMachineState_PoweredOff] = tr ("Powered Off", "MachineState");
3109 machineStates [KMachineState_Saved] = tr ("Saved", "MachineState");
3110 machineStates [KMachineState_Aborted] = tr ("Aborted", "MachineState");
3111 machineStates [KMachineState_Running] = tr ("Running", "MachineState");
3112 machineStates [KMachineState_Paused] = tr ("Paused", "MachineState");
3113 machineStates [KMachineState_Stuck] = tr ("Stuck", "MachineState");
3114 machineStates [KMachineState_Starting] = tr ("Starting", "MachineState");
3115 machineStates [KMachineState_Stopping] = tr ("Stopping", "MachineState");
3116 machineStates [KMachineState_Saving] = tr ("Saving", "MachineState");
3117 machineStates [KMachineState_Restoring] = tr ("Restoring", "MachineState");
3118 machineStates [KMachineState_Discarding] = tr ("Discarding", "MachineState");
3119 machineStates [KMachineState_SettingUp] = tr ("Setting Up", "MachineState");
3120
3121 sessionStates [KSessionState_Closed] = tr ("Closed", "SessionState");
3122 sessionStates [KSessionState_Open] = tr ("Open", "SessionState");
3123 sessionStates [KSessionState_Spawning] = tr ("Spawning", "SessionState");
3124 sessionStates [KSessionState_Closing] = tr ("Closing", "SessionState");
3125
3126 deviceTypes [KDeviceType_Null] = tr ("None", "DeviceType");
3127 deviceTypes [KDeviceType_Floppy] = tr ("Floppy", "DeviceType");
3128 deviceTypes [KDeviceType_DVD] = tr ("CD/DVD-ROM", "DeviceType");
3129 deviceTypes [KDeviceType_HardDisk] = tr ("Hard Disk", "DeviceType");
3130 deviceTypes [KDeviceType_Network] = tr ("Network", "DeviceType");
3131 deviceTypes [KDeviceType_USB] = tr ("USB", "DeviceType");
3132 deviceTypes [KDeviceType_SharedFolder] = tr ("Shared Folder", "DeviceType");
3133
3134 storageBuses [KStorageBus_IDE] =
3135 tr ("IDE", "StorageBus");
3136 storageBuses [KStorageBus_SATA] =
3137 tr ("SATA", "StorageBus");
3138
3139 Assert (storageBusChannels.count() == 3);
3140 storageBusChannels [0] =
3141 tr ("Primary", "StorageBusChannel");
3142 storageBusChannels [1] =
3143 tr ("Secondary", "StorageBusChannel");
3144 storageBusChannels [2] =
3145 tr ("Port %1", "StorageBusChannel");
3146
3147 Assert (storageBusDevices.count() == 2);
3148 storageBusDevices [0] = tr ("Master", "StorageBusDevice");
3149 storageBusDevices [1] = tr ("Slave", "StorageBusDevice");
3150
3151 diskTypes [KHardDiskType_Normal] =
3152 tr ("Normal", "DiskType");
3153 diskTypes [KHardDiskType_Immutable] =
3154 tr ("Immutable", "DiskType");
3155 diskTypes [KHardDiskType_Writethrough] =
3156 tr ("Writethrough", "DiskType");
3157 diskTypes_Differencing =
3158 tr ("Differencing", "DiskType");
3159
3160 vrdpAuthTypes [KVRDPAuthType_Null] =
3161 tr ("Null", "VRDPAuthType");
3162 vrdpAuthTypes [KVRDPAuthType_External] =
3163 tr ("External", "VRDPAuthType");
3164 vrdpAuthTypes [KVRDPAuthType_Guest] =
3165 tr ("Guest", "VRDPAuthType");
3166
3167 portModeTypes [KPortMode_Disconnected] =
3168 tr ("Disconnected", "PortMode");
3169 portModeTypes [KPortMode_HostPipe] =
3170 tr ("Host Pipe", "PortMode");
3171 portModeTypes [KPortMode_HostDevice] =
3172 tr ("Host Device", "PortMode");
3173
3174 usbFilterActionTypes [KUSBDeviceFilterAction_Ignore] =
3175 tr ("Ignore", "USBFilterActionType");
3176 usbFilterActionTypes [KUSBDeviceFilterAction_Hold] =
3177 tr ("Hold", "USBFilterActionType");
3178
3179 audioDriverTypes [KAudioDriverType_Null] =
3180 tr ("Null Audio Driver", "AudioDriverType");
3181 audioDriverTypes [KAudioDriverType_WinMM] =
3182 tr ("Windows Multimedia", "AudioDriverType");
3183 audioDriverTypes [KAudioDriverType_SolAudio] =
3184 tr ("Solaris Audio", "AudioDriverType");
3185 audioDriverTypes [KAudioDriverType_OSS] =
3186 tr ("OSS Audio Driver", "AudioDriverType");
3187 audioDriverTypes [KAudioDriverType_ALSA] =
3188 tr ("ALSA Audio Driver", "AudioDriverType");
3189 audioDriverTypes [KAudioDriverType_DirectSound] =
3190 tr ("Windows DirectSound", "AudioDriverType");
3191 audioDriverTypes [KAudioDriverType_CoreAudio] =
3192 tr ("CoreAudio", "AudioDriverType");
3193 audioDriverTypes [KAudioDriverType_Pulse] =
3194 tr ("PulseAudio", "AudioDriverType");
3195
3196 audioControllerTypes [KAudioControllerType_AC97] =
3197 tr ("ICH AC97", "AudioControllerType");
3198 audioControllerTypes [KAudioControllerType_SB16] =
3199 tr ("SoundBlaster 16", "AudioControllerType");
3200
3201 networkAdapterTypes [KNetworkAdapterType_Am79C970A] =
3202 tr ("PCnet-PCI II (Am79C970A)", "NetworkAdapterType");
3203 networkAdapterTypes [KNetworkAdapterType_Am79C973] =
3204 tr ("PCnet-FAST III (Am79C973)", "NetworkAdapterType");
3205 networkAdapterTypes [KNetworkAdapterType_I82540EM] =
3206 tr ("Intel PRO/1000 MT Desktop (82540EM)", "NetworkAdapterType");
3207 networkAdapterTypes [KNetworkAdapterType_I82543GC] =
3208 tr ("Intel PRO/1000 T Server (82543GC)", "NetworkAdapterType");
3209
3210 networkAttachmentTypes [KNetworkAttachmentType_Null] =
3211 tr ("Not attached", "NetworkAttachmentType");
3212 networkAttachmentTypes [KNetworkAttachmentType_NAT] =
3213 tr ("NAT", "NetworkAttachmentType");
3214 networkAttachmentTypes [KNetworkAttachmentType_HostInterface] =
3215 tr ("Host Interface", "NetworkAttachmentType");
3216 networkAttachmentTypes [KNetworkAttachmentType_Internal] =
3217 tr ("Internal Network", "NetworkAttachmentType");
3218
3219 clipboardTypes [KClipboardMode_Disabled] =
3220 tr ("Disabled", "ClipboardType");
3221 clipboardTypes [KClipboardMode_HostToGuest] =
3222 tr ("Host To Guest", "ClipboardType");
3223 clipboardTypes [KClipboardMode_GuestToHost] =
3224 tr ("Guest To Host", "ClipboardType");
3225 clipboardTypes [KClipboardMode_Bidirectional] =
3226 tr ("Bidirectional", "ClipboardType");
3227
3228 ideControllerTypes [KIDEControllerType_PIIX3] =
3229 tr ("PIIX3", "IDEControllerType");
3230 ideControllerTypes [KIDEControllerType_PIIX4] =
3231 tr ("PIIX4", "IDEControllerType");
3232
3233 USBDeviceStates [KUSBDeviceState_NotSupported] =
3234 tr ("Not supported", "USBDeviceState");
3235 USBDeviceStates [KUSBDeviceState_Unavailable] =
3236 tr ("Unavailable", "USBDeviceState");
3237 USBDeviceStates [KUSBDeviceState_Busy] =
3238 tr ("Busy", "USBDeviceState");
3239 USBDeviceStates [KUSBDeviceState_Available] =
3240 tr ("Available", "USBDeviceState");
3241 USBDeviceStates [KUSBDeviceState_Held] =
3242 tr ("Held", "USBDeviceState");
3243 USBDeviceStates [KUSBDeviceState_Captured] =
3244 tr ("Captured", "USBDeviceState");
3245
3246 mUserDefinedPortName = tr ("User-defined", "serial port");
3247
3248 mWarningIcon = standardIcon (QStyle::SP_MessageBoxWarning, 0).pixmap (16, 16);
3249 Assert (!mWarningIcon.isNull());
3250
3251 mErrorIcon = standardIcon (QStyle::SP_MessageBoxCritical, 0).pixmap (16, 16);
3252 Assert (!mErrorIcon.isNull());
3253
3254 detailReportTemplatesReady = false;
3255
3256#if defined (Q_WS_PM) || defined (Q_WS_X11)
3257 /* As PM and X11 do not (to my knowledge) have functionality for providing
3258 * human readable key names, we keep a table of them, which must be
3259 * updated when the language is changed. */
3260 QIHotKeyEdit::retranslateUi();
3261#endif
3262}
3263
3264// public static stuff
3265////////////////////////////////////////////////////////////////////////////////
3266
3267/* static */
3268bool VBoxGlobal::isDOSType (const QString &aOSTypeId)
3269{
3270 if (aOSTypeId.left (3) == "dos" ||
3271 aOSTypeId.left (3) == "win" ||
3272 aOSTypeId.left (3) == "os2")
3273 return true;
3274
3275 return false;
3276}
3277
3278/**
3279 * Sets the QLabel background and frame colors according tho the pixmap
3280 * contents. The bottom right pixel of the label pixmap defines the
3281 * background color of the label, the top right pixel defines the color of
3282 * the one-pixel frame around it. This function also sets the alignment of
3283 * the pixmap to AlignVTop (to correspond to the color choosing logic).
3284 *
3285 * This method is useful to provide nice scaling of pixmal labels without
3286 * scaling pixmaps themselves. To see th eeffect, the size policy of the
3287 * label in the corresponding direction (vertical, for now) should be set to
3288 * something like MinimumExpanding.
3289 *
3290 * @todo Parametrize corners to select pixels from and set the alignment
3291 * accordingly.
3292 */
3293/* static */
3294void VBoxGlobal::adoptLabelPixmap (QLabel *aLabel)
3295{
3296 AssertReturnVoid (aLabel);
3297
3298 aLabel->setAlignment (Qt::AlignTop);
3299 aLabel->setFrameShape (QFrame::Box);
3300 aLabel->setFrameShadow (QFrame::Plain);
3301
3302 const QPixmap *pix = aLabel->pixmap();
3303 QImage img = pix->toImage();
3304 QRgb rgbBack = img.pixel (img.width() - 1, img.height() - 1);
3305 QRgb rgbFrame = img.pixel (img.width() - 1, 0);
3306
3307 QPalette pal = aLabel->palette();
3308 pal.setColor (QPalette::Window, rgbBack);
3309 pal.setColor (QPalette::WindowText, rgbFrame);
3310 aLabel->setPalette (pal);
3311}
3312
3313extern const char *gVBoxLangSubDir = "/nls";
3314extern const char *gVBoxLangFileBase = "VirtualBox_";
3315extern const char *gVBoxLangFileExt = ".qm";
3316extern const char *gVBoxLangIDRegExp = "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
3317extern const char *gVBoxBuiltInLangName = "C";
3318
3319class VBoxTranslator : public QTranslator
3320{
3321public:
3322
3323 VBoxTranslator (QObject *aParent = 0)
3324 : QTranslator (aParent) {}
3325
3326 bool loadFile (const QString &aFileName)
3327 {
3328 QFile file (aFileName);
3329 if (!file.open (QIODevice::ReadOnly))
3330 return false;
3331 mData = file.readAll();
3332 return load ((uchar*) mData.data(), mData.size());
3333 }
3334
3335private:
3336
3337 QByteArray mData;
3338};
3339
3340static VBoxTranslator *sTranslator = 0;
3341static QString sLoadedLangId = gVBoxBuiltInLangName;
3342
3343/**
3344 * Returns the loaded (active) language ID.
3345 * Note that it may not match with VBoxGlobalSettings::languageId() if the
3346 * specified language cannot be loaded.
3347 * If the built-in language is active, this method returns "C".
3348 *
3349 * @note "C" is treated as the built-in language for simplicity -- the C
3350 * locale is used in unix environments as a fallback when the requested
3351 * locale is invalid. This way we don't need to process both the "built_in"
3352 * language and the "C" language (which is a valid environment setting)
3353 * separately.
3354 */
3355/* static */
3356QString VBoxGlobal::languageId()
3357{
3358 return sLoadedLangId;
3359}
3360
3361/**
3362 * Loads the language by language ID.
3363 *
3364 * @param aLangId Language ID in in form of xx_YY. QString::null means the
3365 * system default language.
3366 */
3367/* static */
3368void VBoxGlobal::loadLanguage (const QString &aLangId)
3369{
3370 QString langId = aLangId.isNull() ?
3371 VBoxGlobal::systemLanguageId() : aLangId;
3372 QString languageFileName;
3373 QString selectedLangId = gVBoxBuiltInLangName;
3374
3375 char szNlsPath[RTPATH_MAX];
3376 int rc;
3377
3378 rc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
3379 AssertRC (rc);
3380
3381 QString nlsPath = QString(szNlsPath) + gVBoxLangSubDir;
3382 QDir nlsDir (nlsPath);
3383
3384 Assert (!langId.isEmpty());
3385 if (!langId.isEmpty() && langId != gVBoxBuiltInLangName)
3386 {
3387 QRegExp regExp (gVBoxLangIDRegExp);
3388 int pos = regExp.indexIn (langId);
3389 /* the language ID should match the regexp completely */
3390 AssertReturnVoid (pos == 0);
3391
3392 QString lang = regExp.cap (2);
3393
3394 if (nlsDir.exists (gVBoxLangFileBase + langId + gVBoxLangFileExt))
3395 {
3396 languageFileName = nlsDir.absoluteFilePath (gVBoxLangFileBase + langId +
3397 gVBoxLangFileExt);
3398 selectedLangId = langId;
3399 }
3400 else if (nlsDir.exists (gVBoxLangFileBase + lang + gVBoxLangFileExt))
3401 {
3402 languageFileName = nlsDir.absoluteFilePath (gVBoxLangFileBase + lang +
3403 gVBoxLangFileExt);
3404 selectedLangId = lang;
3405 }
3406 else
3407 {
3408 /* Never complain when the default language is requested. In any
3409 * case, if no explicit language file exists, we will simply
3410 * fall-back to English (built-in). */
3411 if (!aLangId.isNull())
3412 vboxProblem().cannotFindLanguage (langId, nlsPath);
3413 /* selectedLangId remains built-in here */
3414 AssertReturnVoid (selectedLangId == gVBoxBuiltInLangName);
3415 }
3416 }
3417
3418 /* delete the old translator if there is one */
3419 if (sTranslator)
3420 {
3421 /* QTranslator destructor will call qApp->removeTranslator() for
3422 * us. It will also delete all its child translations we attach to it
3423 * below, so we don't have to care about them specially. */
3424 delete sTranslator;
3425 }
3426
3427 /* load new language files */
3428 sTranslator = new VBoxTranslator (qApp);
3429 Assert (sTranslator);
3430 bool loadOk = true;
3431 if (sTranslator)
3432 {
3433 if (selectedLangId != gVBoxBuiltInLangName)
3434 {
3435 Assert (!languageFileName.isNull());
3436 loadOk = sTranslator->loadFile (languageFileName);
3437 }
3438 /* we install the translator in any case: on failure, this will
3439 * activate an empty translator that will give us English
3440 * (built-in) */
3441 qApp->installTranslator (sTranslator);
3442 }
3443 else
3444 loadOk = false;
3445
3446 if (loadOk)
3447 sLoadedLangId = selectedLangId;
3448 else
3449 {
3450 vboxProblem().cannotLoadLanguage (languageFileName);
3451 sLoadedLangId = gVBoxBuiltInLangName;
3452 }
3453
3454 /* Try to load the corresponding Qt translation */
3455 if (sLoadedLangId != gVBoxBuiltInLangName)
3456 {
3457#ifdef Q_OS_UNIX
3458 /* We use system installations of Qt on Linux systems, so first, try
3459 * to load the Qt translation from the system location. */
3460 languageFileName = QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" +
3461 sLoadedLangId + gVBoxLangFileExt;
3462 QTranslator *qtSysTr = new QTranslator (sTranslator);
3463 Assert (qtSysTr);
3464 if (qtSysTr && qtSysTr->load (languageFileName))
3465 qApp->installTranslator (qtSysTr);
3466 /* Note that the Qt translation supplied by Sun is always loaded
3467 * afterwards to make sure it will take precedence over the system
3468 * translation (it may contain more decent variants of translation
3469 * that better correspond to VirtualBox UI). We need to load both
3470 * because a newer version of Qt may be installed on the user computer
3471 * and the Sun version may not fully support it. We don't do it on
3472 * Win32 because we supply a Qt library there and therefore the
3473 * Sun translation is always the best one. */
3474#endif
3475 languageFileName = nlsDir.absoluteFilePath (QString ("qt_") +
3476 sLoadedLangId +
3477 gVBoxLangFileExt);
3478 QTranslator *qtTr = new QTranslator (sTranslator);
3479 Assert (qtTr);
3480 if (qtTr && (loadOk = qtTr->load (languageFileName)))
3481 qApp->installTranslator (qtTr);
3482 /* The below message doesn't fit 100% (because it's an additonal
3483 * language and the main one won't be reset to built-in on failure)
3484 * but the load failure is so rare here that it's not worth a separate
3485 * message (but still, having something is better than having none) */
3486 if (!loadOk && !aLangId.isNull())
3487 vboxProblem().cannotLoadLanguage (languageFileName);
3488 }
3489}
3490
3491QString VBoxGlobal::helpFile() const
3492{
3493#if defined (Q_WS_WIN32) || defined (Q_WS_X11)
3494 const QString name = "VirtualBox";
3495 const QString suffix = "chm";
3496#elif defined (Q_WS_MAC)
3497 const QString name = "UserManual";
3498 const QString suffix = "pdf";
3499#endif
3500 /* Where are the docs located? */
3501 char szDocsPath[RTPATH_MAX];
3502 int rc = RTPathAppDocs (szDocsPath, sizeof (szDocsPath));
3503 AssertRC (rc);
3504 /* Make sure that the language is in two letter code.
3505 * Note: if languageId() returns an empty string lang.name() will
3506 * return "C" which is an valid language code. */
3507 QLocale lang (VBoxGlobal::languageId());
3508
3509 /* Construct the path and the filename */
3510 QString manual = QString ("%1/%2_%3.%4").arg (szDocsPath)
3511 .arg (name)
3512 .arg (lang.name())
3513 .arg (suffix);
3514 /* Check if a help file with that name exists */
3515 QFileInfo fi (manual);
3516 if (fi.exists())
3517 return manual;
3518
3519 /* Fall back to the standard */
3520 manual = QString ("%1/%2.%4").arg (szDocsPath)
3521 .arg (name)
3522 .arg (suffix);
3523 return manual;
3524}
3525
3526/* static */
3527QIcon VBoxGlobal::iconSet (const char *aNormal,
3528 const char *aDisabled /* = NULL */,
3529 const char *aActive /* = NULL */)
3530{
3531 QIcon iconSet;
3532
3533 iconSet.addFile (aNormal, QSize(),
3534 QIcon::Normal);
3535 if (aDisabled != NULL)
3536 iconSet.addFile (aDisabled, QSize(),
3537 QIcon::Disabled);
3538 if (aActive != NULL)
3539 iconSet.addFile (aActive, QSize(),
3540 QIcon::Active);
3541 return iconSet;
3542}
3543
3544/* static */
3545QIcon VBoxGlobal::iconSetFull (const QSize &aNormalSize, const QSize &aSmallSize,
3546 const char *aNormal, const char *aSmallNormal,
3547 const char *aDisabled /* = NULL */,
3548 const char *aSmallDisabled /* = NULL */,
3549 const char *aActive /* = NULL */,
3550 const char *aSmallActive /* = NULL */)
3551{
3552 QIcon iconSet;
3553
3554 iconSet.addFile (aNormal, aNormalSize, QIcon::Normal);
3555 iconSet.addFile (aSmallNormal, aSmallSize, QIcon::Normal);
3556 if (aSmallDisabled != NULL)
3557 {
3558 iconSet.addFile (aDisabled, aNormalSize, QIcon::Disabled);
3559 iconSet.addFile (aSmallDisabled, aSmallSize, QIcon::Disabled);
3560 }
3561 if (aSmallActive != NULL)
3562 {
3563 iconSet.addFile (aActive, aNormalSize, QIcon::Active);
3564 iconSet.addFile (aSmallActive, aSmallSize, QIcon::Active);
3565 }
3566
3567 return iconSet;
3568}
3569
3570QIcon VBoxGlobal::standardIcon (QStyle::StandardPixmap aStandard, QWidget *aWidget /* = NULL */)
3571{
3572 QStyle *style = aWidget ? aWidget->style(): QApplication::style();
3573#ifdef Q_WS_MAC
3574 /* At least in Qt 4.3.4/4.4 RC1 SP_MessageBoxWarning is the application
3575 * icon. So change this to the critical icon. (Maybe this would be
3576 * fixed in a later Qt version) */
3577 if (aStandard == QStyle::SP_MessageBoxWarning)
3578 return style->standardIcon (QStyle::SP_MessageBoxCritical, 0, aWidget);
3579#endif /* Q_WS_MAC */
3580 return style->standardIcon (aStandard, 0, aWidget);
3581}
3582
3583/**
3584 * Replacement for QToolButton::setTextLabel() that handles the shortcut
3585 * letter (if it is present in the argument string) as if it were a setText()
3586 * call: the shortcut letter is used to automatically assign an "Alt+<letter>"
3587 * accelerator key sequence to the given tool button.
3588 *
3589 * @note This method preserves the icon set if it was assigned before. Only
3590 * the text label and the accelerator are changed.
3591 *
3592 * @param aToolButton Tool button to set the text label on.
3593 * @param aTextLabel Text label to set.
3594 */
3595/* static */
3596void VBoxGlobal::setTextLabel (QToolButton *aToolButton,
3597 const QString &aTextLabel)
3598{
3599 AssertReturnVoid (aToolButton != NULL);
3600
3601 /* remember the icon set as setText() will kill it */
3602 QIcon iset = aToolButton->icon();
3603 /* re-use the setText() method to detect and set the accelerator */
3604 aToolButton->setText (aTextLabel);
3605 QKeySequence accel = aToolButton->shortcut();
3606 aToolButton->setText (aTextLabel);
3607 aToolButton->setIcon (iset);
3608 /* set the accel last as setIconSet() would kill it */
3609 aToolButton->setShortcut (accel);
3610}
3611
3612/**
3613 * Ensures that the given rectangle \a aRect is fully contained within the
3614 * rectangle \a aBoundRect by moving \a aRect if necessary. If \a aRect is
3615 * larger than \a aBoundRect, its top left corner is simply aligned with the
3616 * top left corner of \a aRect and, if \a aCanResize is true, \a aRect is
3617 * shrinked to become fully visible.
3618 */
3619/* static */
3620QRect VBoxGlobal::normalizeGeometry (const QRect &aRect, const QRect &aBoundRect,
3621 bool aCanResize /* = true */)
3622{
3623 QRect fr = aRect;
3624
3625 /* make the bottom right corner visible */
3626 int rd = aBoundRect.right() - fr.right();
3627 int bd = aBoundRect.bottom() - fr.bottom();
3628 fr.translate (rd < 0 ? rd : 0, bd < 0 ? bd : 0);
3629
3630 /* ensure the top left corner is visible */
3631 int ld = fr.left() - aBoundRect.left();
3632 int td = fr.top() - aBoundRect.top();
3633 fr.translate (ld < 0 ? -ld : 0, td < 0 ? -td : 0);
3634
3635 if (aCanResize)
3636 {
3637 /* adjust the size to make the rectangle fully contained */
3638 rd = aBoundRect.right() - fr.right();
3639 bd = aBoundRect.bottom() - fr.bottom();
3640 if (rd < 0)
3641 fr.setRight (fr.right() + rd);
3642 if (bd < 0)
3643 fr.setBottom (fr.bottom() + bd);
3644 }
3645
3646 return fr;
3647}
3648
3649/**
3650 * Aligns the center of \a aWidget with the center of \a aRelative.
3651 *
3652 * If necessary, \a aWidget's position is adjusted to make it fully visible
3653 * within the available desktop area. If \a aWidget is bigger then this area,
3654 * it will also be resized unless \a aCanResize is false or there is an
3655 * inappropriate minimum size limit (in which case the top left corner will be
3656 * simply aligned with the top left corner of the available desktop area).
3657 *
3658 * \a aWidget must be a top-level widget. \a aRelative may be any widget, but
3659 * if it's not top-level itself, its top-level widget will be used for
3660 * calculations. \a aRelative can also be NULL, in which case \a aWidget will
3661 * be centered relative to the available desktop area.
3662 */
3663/* static */
3664void VBoxGlobal::centerWidget (QWidget *aWidget, QWidget *aRelative,
3665 bool aCanResize /* = true */)
3666{
3667 AssertReturnVoid (aWidget);
3668 AssertReturnVoid (aWidget->isTopLevel());
3669
3670 QRect deskGeo, parentGeo;
3671 QWidget *w = aRelative;
3672 if (w)
3673 {
3674 w = w->window();
3675 deskGeo = QApplication::desktop()->availableGeometry (w);
3676 parentGeo = w->frameGeometry();
3677 /* On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level
3678 * widgets with parents, what a shame. Use mapToGlobal() to workaround. */
3679 QPoint d = w->mapToGlobal (QPoint (0, 0));
3680 d.rx() -= w->geometry().x() - w->x();
3681 d.ry() -= w->geometry().y() - w->y();
3682 parentGeo.moveTopLeft (d);
3683 }
3684 else
3685 {
3686 deskGeo = QApplication::desktop()->availableGeometry();
3687 parentGeo = deskGeo;
3688 }
3689
3690 /* On X11, there is no way to determine frame geometry (including WM
3691 * decorations) before the widget is shown for the first time. Stupidly
3692 * enumerate other top level widgets to find the thickest frame. The code
3693 * is based on the idea taken from QDialog::adjustPositionInternal(). */
3694
3695 int extraw = 0, extrah = 0;
3696
3697 QWidgetList list = QApplication::topLevelWidgets();
3698 QListIterator<QWidget*> it (list);
3699 while ((extraw == 0 || extrah == 0) && it.hasNext())
3700 {
3701 int framew, frameh;
3702 QWidget *current = it.next();
3703 if (!current->isVisible())
3704 continue;
3705
3706 framew = current->frameGeometry().width() - current->width();
3707 frameh = current->frameGeometry().height() - current->height();
3708
3709 extraw = qMax (extraw, framew);
3710 extrah = qMax (extrah, frameh);
3711 }
3712
3713 /// @todo (r=dmik) not sure if we really need this
3714#if 0
3715 /* sanity check for decoration frames. With embedding, we
3716 * might get extraordinary values */
3717 if (extraw == 0 || extrah == 0 || extraw > 20 || extrah > 50)
3718 {
3719 extrah = 50;
3720 extraw = 20;
3721 }
3722#endif
3723
3724 /* On non-X11 platforms, the following would be enough instead of the
3725 * above workaround: */
3726 // QRect geo = frameGeometry();
3727 QRect geo = QRect (0, 0, aWidget->width() + extraw,
3728 aWidget->height() + extrah);
3729
3730 geo.moveCenter (QPoint (parentGeo.x() + (parentGeo.width() - 1) / 2,
3731 parentGeo.y() + (parentGeo.height() - 1) / 2));
3732
3733 /* ensure the widget is within the available desktop area */
3734 QRect newGeo = normalizeGeometry (geo, deskGeo, aCanResize);
3735
3736 aWidget->move (newGeo.topLeft());
3737
3738 if (aCanResize &&
3739 (geo.width() != newGeo.width() || geo.height() != newGeo.height()))
3740 aWidget->resize (newGeo.width() - extraw, newGeo.height() - extrah);
3741}
3742
3743/**
3744 * Returns the decimal separator for the current locale.
3745 */
3746/* static */
3747QChar VBoxGlobal::decimalSep()
3748{
3749 return QLocale::system().decimalPoint();
3750}
3751
3752/**
3753 * Returns the regexp string that defines the format of the human-readable
3754 * size representation, <tt>####[.##] B|KB|MB|GB|TB|PB</tt>.
3755 *
3756 * This regexp will capture 5 groups of text:
3757 * - cap(1): integer number in case when no decimal point is present
3758 * (if empty, it means that decimal point is present)
3759 * - cap(2): size suffix in case when no decimal point is present (may be empty)
3760 * - cap(3): integer number in case when decimal point is present (may be empty)
3761 * - cap(4): fraction number (hundredth) in case when decimal point is present
3762 * - cap(5): size suffix in case when decimal point is present (note that
3763 * B cannot appear there)
3764 */
3765/* static */
3766QString VBoxGlobal::sizeRegexp()
3767{
3768 QString regexp =
3769 QString ("^(?:(?:(\\d+)(?:\\s?([KMGTP]?B))?)|(?:(\\d*)%1(\\d{1,2})(?:\\s?([KMGTP]B))))$")
3770 .arg (decimalSep());
3771 return regexp;
3772}
3773
3774/**
3775 * Parses the given size string that should be in form of
3776 * <tt>####[.##] B|KB|MB|GB|TB|PB</tt> and returns the size value
3777 * in bytes. Zero is returned on error.
3778 */
3779/* static */
3780quint64 VBoxGlobal::parseSize (const QString &aText)
3781{
3782 QRegExp regexp (sizeRegexp());
3783 int pos = regexp.indexIn (aText);
3784 if (pos != -1)
3785 {
3786 QString intgS = regexp.cap (1);
3787 QString hundS;
3788 QString suff = regexp.cap (2);
3789 if (intgS.isEmpty())
3790 {
3791 intgS = regexp.cap (3);
3792 hundS = regexp.cap (4);
3793 suff = regexp.cap (5);
3794 }
3795
3796 quint64 denom = 0;
3797 if (suff.isEmpty() || suff == "B")
3798 denom = 1;
3799 else if (suff == "KB")
3800 denom = _1K;
3801 else if (suff == "MB")
3802 denom = _1M;
3803 else if (suff == "GB")
3804 denom = _1G;
3805 else if (suff == "TB")
3806 denom = _1T;
3807 else if (suff == "PB")
3808 denom = _1P;
3809
3810 quint64 intg = intgS.toULongLong();
3811 if (denom == 1)
3812 return intg;
3813
3814 quint64 hund = hundS.leftJustified (2, '0').toULongLong();
3815 hund = hund * denom / 100;
3816 intg = intg * denom + hund;
3817 return intg;
3818 }
3819 else
3820 return 0;
3821}
3822
3823/**
3824 * Formats the given \a size value in bytes to a human readable string
3825 * in form of <tt>####[.##] B|KB|MB|GB|TB|PB</tt>.
3826 *
3827 * The \a mode parameter is used for resulting numbers that get a fractional
3828 * part after converting the \a size to KB, MB etc:
3829 * <ul>
3830 * <li>When \a mode is 0, the result is rounded to the closest number
3831 * containing two decimal digits.
3832 * </li>
3833 * <li>When \a mode is -1, the result is rounded to the largest two decimal
3834 * digit number that is not greater than the result. This guarantees that
3835 * converting the resulting string back to the integer value in bytes
3836 * will not produce a value greater that the initial \a size parameter.
3837 * </li>
3838 * <li>When \a mode is 1, the result is rounded to the smallest two decimal
3839 * digit number that is not less than the result. This guarantees that
3840 * converting the resulting string back to the integer value in bytes
3841 * will not produce a value less that the initial \a size parameter.
3842 * </li>
3843 * </ul>
3844 *
3845 * @param aSize size value in bytes
3846 * @param aMode convertion mode (-1, 0 or 1)
3847 * @return human-readable size string
3848 */
3849/* static */
3850QString VBoxGlobal::formatSize (quint64 aSize, int aMode /* = 0 */)
3851{
3852 static const char *Suffixes [] = { "B", "KB", "MB", "GB", "TB", "PB", NULL };
3853
3854 quint64 denom = 0;
3855 int suffix = 0;
3856
3857 if (aSize < _1K)
3858 {
3859 denom = 1;
3860 suffix = 0;
3861 }
3862 else if (aSize < _1M)
3863 {
3864 denom = _1K;
3865 suffix = 1;
3866 }
3867 else if (aSize < _1G)
3868 {
3869 denom = _1M;
3870 suffix = 2;
3871 }
3872 else if (aSize < _1T)
3873 {
3874 denom = _1G;
3875 suffix = 3;
3876 }
3877 else if (aSize < _1P)
3878 {
3879 denom = _1T;
3880 suffix = 4;
3881 }
3882 else
3883 {
3884 denom = _1P;
3885 suffix = 5;
3886 }
3887
3888 quint64 intg = aSize / denom;
3889 quint64 hund = aSize % denom;
3890
3891 QString number;
3892 if (denom > 1)
3893 {
3894 if (hund)
3895 {
3896 hund *= 100;
3897 /* not greater */
3898 if (aMode < 0) hund = hund / denom;
3899 /* not less */
3900 else if (aMode > 0) hund = (hund + denom - 1) / denom;
3901 /* nearest */
3902 else hund = (hund + denom / 2) / denom;
3903 }
3904 /* check for the fractional part overflow due to rounding */
3905 if (hund == 100)
3906 {
3907 hund = 0;
3908 ++ intg;
3909 /* check if we've got 1024 XB after rounding and scale down if so */
3910 if (intg == 1024 && Suffixes [suffix + 1] != NULL)
3911 {
3912 intg /= 1024;
3913 ++ suffix;
3914 }
3915 }
3916 number = QString ("%1%2%3").arg (intg).arg (decimalSep())
3917 .arg (QString::number (hund).rightJustified (2, '0'));
3918 }
3919 else
3920 {
3921 number = QString::number (intg);
3922 }
3923
3924 return QString ("%1 %2").arg (number).arg (Suffixes [suffix]);
3925}
3926
3927/**
3928 * Returns the required video memory in bytes for the current desktop
3929 * resolution at maximum possible screen depth in bpp.
3930 */
3931/* static */
3932quint64 VBoxGlobal::requiredVideoMemory (CMachine *aMachine)
3933{
3934 QSize desktopRes = QApplication::desktop()->screenGeometry().size();
3935 /* Calculate summary required memory amount in bits */
3936 quint64 needBits = (desktopRes.width() /* display width */ *
3937 desktopRes.height() /* display height */ *
3938 32 /* we will take the maximum possible bpp for now */ +
3939 8 * _1M /* current cache per screen - may be changed in future */) *
3940 (!aMachine || aMachine->isNull() ? 1 : aMachine->GetMonitorCount()) +
3941 8 * 4096 /* adapter info */;
3942 /* Translate value into megabytes with rounding to highest side */
3943 quint64 needMBytes = needBits % (8 * _1M) ? needBits / (8 * _1M) + 1 :
3944 needBits / (8 * _1M) /* convert to megabytes */;
3945
3946 return needMBytes * _1M;
3947}
3948
3949/**
3950 * Puts soft hyphens after every path component in the given file name.
3951 *
3952 * @param aFileName File name (must be a full path name).
3953 */
3954/* static */
3955QString VBoxGlobal::locationForHTML (const QString &aFileName)
3956{
3957/// @todo (dmik) remove?
3958// QString result = QDir::toNativeSeparators (fn);
3959//#ifdef Q_OS_LINUX
3960// result.replace ('/', "/<font color=red>&shy;</font>");
3961//#else
3962// result.replace ('\\', "\\<font color=red>&shy;</font>");
3963//#endif
3964// return result;
3965 QFileInfo fi (aFileName);
3966 return fi.fileName();
3967}
3968
3969/**
3970 * Reformats the input string @a aStr so that:
3971 * - strings in single quotes will be put inside <nobr> and marked
3972 * with blue color;
3973 * - UUIDs be put inside <nobr> and marked
3974 * with green color;
3975 * - replaces new line chars with </p><p> constructs to form paragraphs
3976 * (note that <p> and </p> are not appended to the beginnign and to the
3977 * end of the string respectively, to allow the result be appended
3978 * or prepended to the existing paragraph).
3979 *
3980 * If @a aToolTip is true, colouring is not applied, only the <nobr> tag
3981 * is added. Also, new line chars are replaced with <br> instead of <p>.
3982 */
3983/* static */
3984QString VBoxGlobal::highlight (const QString &aStr, bool aToolTip /* = false */)
3985{
3986 QString strFont;
3987 QString uuidFont;
3988 QString endFont;
3989 if (!aToolTip)
3990 {
3991 strFont = "<font color=#0000CC>";
3992 uuidFont = "<font color=#008000>";
3993 endFont = "</font>";
3994 }
3995
3996 QString text = aStr;
3997
3998 /* replace special entities, '&' -- first! */
3999 text.replace ('&', "&amp;");
4000 text.replace ('<', "&lt;");
4001 text.replace ('>', "&gt;");
4002 text.replace ('\"', "&quot;");
4003
4004 /* mark strings in single quotes with color */
4005 QRegExp rx = QRegExp ("((?:^|\\s)[(]?)'([^']*)'(?=[:.-!);]?(?:\\s|$))");
4006 rx.setMinimal (true);
4007 text.replace (rx,
4008 QString ("\\1%1<nobr>'\\2'</nobr>%2")
4009 .arg (strFont). arg (endFont));
4010
4011 /* mark UUIDs with color */
4012 text.replace (QRegExp (
4013 "((?:^|\\s)[(]?)"
4014 "(\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\})"
4015 "(?=[:.-!);]?(?:\\s|$))"),
4016 QString ("\\1%1<nobr>\\2</nobr>%2")
4017 .arg (uuidFont). arg (endFont));
4018
4019 /* split to paragraphs at \n chars */
4020 if (!aToolTip)
4021 text.replace ('\n', "</p><p>");
4022 else
4023 text.replace ('\n', "<br>");
4024
4025 return text;
4026}
4027
4028/**
4029 * This does exactly the same as QLocale::system().name() but corrects its
4030 * wrong behavior on Linux systems (LC_NUMERIC for some strange reason takes
4031 * precedence over any other locale setting in the QLocale::system()
4032 * implementation). This implementation first looks at LC_ALL (as defined by
4033 * SUS), then looks at LC_MESSAGES which is designed to define a language for
4034 * program messages in case if it differs from the language for other locale
4035 * categories. Then it looks for LANG and finally falls back to
4036 * QLocale::system().name().
4037 *
4038 * The order of precedence is well defined here:
4039 * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
4040 *
4041 * @note This method will return "C" when the requested locale is invalid or
4042 * when the "C" locale is set explicitly.
4043 */
4044/* static */
4045QString VBoxGlobal::systemLanguageId()
4046{
4047#if defined (Q_WS_MAC)
4048 /* QLocale return the right id only if the user select the format of the
4049 * language also. So we use our own implementation */
4050 return ::darwinSystemLanguage();
4051#elif defined (Q_OS_UNIX)
4052 const char *s = RTEnvGet ("LC_ALL");
4053 if (s == 0)
4054 s = RTEnvGet ("LC_MESSAGES");
4055 if (s == 0)
4056 s = RTEnvGet ("LANG");
4057 if (s != 0)
4058 return QLocale (s).name();
4059#endif
4060 return QLocale::system().name();
4061}
4062
4063/**
4064 * Reimplementation of QFileDialog::getExistingDirectory() that removes some
4065 * oddities and limitations.
4066 *
4067 * On Win32, this function makes sure a native dialog is launched in
4068 * another thread to avoid dialog visualization errors occuring due to
4069 * multi-threaded COM apartment initialization on the main UI thread while
4070 * the appropriate native dialog function expects a single-threaded one.
4071 *
4072 * On all other platforms, this function is equivalent to
4073 * QFileDialog::getExistingDirectory().
4074 */
4075QString VBoxGlobal::getExistingDirectory (const QString &aDir,
4076 QWidget *aParent,
4077 const QString &aCaption,
4078 bool aDirOnly,
4079 bool aResolveSymlinks)
4080{
4081#if defined Q_WS_WIN
4082
4083 /**
4084 * QEvent class reimplementation to carry Win32 API native dialog's
4085 * result folder information
4086 */
4087 class GetExistDirectoryEvent : public OpenNativeDialogEvent
4088 {
4089 public:
4090
4091 enum { TypeId = QEvent::User + 300 };
4092
4093 GetExistDirectoryEvent (const QString &aResult)
4094 : OpenNativeDialogEvent (aResult, (QEvent::Type) TypeId) {}
4095 };
4096
4097 /**
4098 * QThread class reimplementation to open Win32 API native folder's dialog
4099 */
4100 class Thread : public QThread
4101 {
4102 public:
4103
4104 Thread (QWidget *aParent, QObject *aTarget,
4105 const QString &aDir, const QString &aCaption)
4106 : mParent (aParent), mTarget (aTarget), mDir (aDir), mCaption (aCaption) {}
4107
4108 virtual void run()
4109 {
4110 QString result;
4111
4112 QWidget *topParent = mParent ? mParent->window() : vboxGlobal().mainWindow();
4113 QString title = mCaption.isNull() ? tr ("Select a directory") : mCaption;
4114
4115 TCHAR path[MAX_PATH];
4116 path [0] = 0;
4117 TCHAR initPath [MAX_PATH];
4118 initPath [0] = 0;
4119
4120 BROWSEINFO bi;
4121 bi.hwndOwner = topParent ? topParent->winId() : 0;
4122 bi.pidlRoot = NULL;
4123 bi.lpszTitle = (TCHAR*)(title.isNull() ? 0 : title.utf16());
4124 bi.pszDisplayName = initPath;
4125 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
4126 bi.lpfn = winGetExistDirCallbackProc;
4127 bi.lParam = Q_ULONG (&mDir);
4128
4129 /* Qt is uncapable to properly handle modal state if the modal
4130 * window is not a QWidget. For example, if we have the W1->W2->N
4131 * ownership where Wx are QWidgets (W2 is modal), and N is a
4132 * native modal window, cliking on the title bar of W1 will still
4133 * activate W2 and redirect keyboard/mouse to it. The dirty hack
4134 * to prevent it is to disable the entire widget... */
4135 if (mParent)
4136 mParent->setEnabled (false);
4137
4138 LPITEMIDLIST itemIdList = SHBrowseForFolder (&bi);
4139 if (itemIdList)
4140 {
4141 SHGetPathFromIDList (itemIdList, path);
4142 IMalloc *pMalloc;
4143 if (SHGetMalloc (&pMalloc) != NOERROR)
4144 result = QString::null;
4145 else
4146 {
4147 pMalloc->Free (itemIdList);
4148 pMalloc->Release();
4149 result = QString::fromUtf16 ((ushort*)path);
4150 }
4151 }
4152 else
4153 result = QString::null;
4154 QApplication::postEvent (mTarget, new GetExistDirectoryEvent (result));
4155
4156 /* Enable the parent widget again. */
4157 if (mParent)
4158 mParent->setEnabled (true);
4159 }
4160
4161 private:
4162
4163 QWidget *mParent;
4164 QObject *mTarget;
4165 QString mDir;
4166 QString mCaption;
4167 };
4168
4169 /* Local event loop to run while waiting for the result from another
4170 * thread */
4171 QEventLoop loop;
4172
4173 QString dir = QDir::toNativeSeparators (aDir);
4174 LoopObject loopObject ((QEvent::Type) GetExistDirectoryEvent::TypeId, loop);
4175
4176 Thread openDirThread (aParent, &loopObject, dir, aCaption);
4177 openDirThread.start();
4178 loop.exec();
4179 openDirThread.wait();
4180
4181 return loopObject.result();
4182
4183#elif defined (Q_WS_X11) && (QT_VERSION < 0x040400)
4184
4185 /* Here is workaround for Qt4.3 bug with QFileDialog which crushes when
4186 * gets initial path as hidden directory if no hidden files are shown.
4187 * See http://trolltech.com/developer/task-tracker/index_html?method=entry&id=193483
4188 * for details */
4189 QFileDialog dlg (aParent);
4190 dlg.setWindowTitle (aCaption);
4191 dlg.setDirectory (aDir);
4192 dlg.setResolveSymlinks (aResolveSymlinks);
4193 dlg.setFileMode (aDirOnly ? QFileDialog::DirectoryOnly : QFileDialog::Directory);
4194 QAction *hidden = dlg.findChild <QAction*> ("qt_show_hidden_action");
4195 if (hidden)
4196 {
4197 hidden->trigger();
4198 hidden->setVisible (false);
4199 }
4200 return dlg.exec() ? dlg.selectedFiles() [0] : QString::null;
4201
4202#else
4203
4204 QFileDialog::Options o;
4205 if (aDirOnly)
4206 o = QFileDialog::ShowDirsOnly;
4207 if (!aResolveSymlinks)
4208 o |= QFileDialog::DontResolveSymlinks;
4209 return QFileDialog::getExistingDirectory (aParent, aCaption, aDir, o);
4210
4211#endif
4212}
4213
4214/**
4215 * Reimplementation of QFileDialog::getOpenFileName() that removes some
4216 * oddities and limitations.
4217 *
4218 * On Win32, this function makes sure a file filter is applied automatically
4219 * right after it is selected from the drop-down list, to conform to common
4220 * experience in other applications. Note that currently, @a selectedFilter
4221 * is always set to null on return.
4222 *
4223 * On all other platforms, this function is equivalent to
4224 * QFileDialog::getOpenFileName().
4225 */
4226/* static */
4227QString VBoxGlobal::getOpenFileName (const QString &aStartWith,
4228 const QString &aFilters,
4229 QWidget *aParent,
4230 const QString &aCaption,
4231 QString *aSelectedFilter /* = NULL */,
4232 bool aResolveSymlinks /* = true */)
4233{
4234 return getOpenFileNames (aStartWith,
4235 aFilters,
4236 aParent,
4237 aCaption,
4238 aSelectedFilter,
4239 aResolveSymlinks,
4240 true /* aSingleFile */).value (0, "");
4241}
4242
4243/**
4244 * Reimplementation of QFileDialog::getOpenFileNames() that removes some
4245 * oddities and limitations.
4246 *
4247 * On Win32, this function makes sure a file filter is applied automatically
4248 * right after it is selected from the drop-down list, to conform to common
4249 * experience in other applications. Note that currently, @a selectedFilter
4250 * is always set to null on return.
4251 * @todo: implement the multiple file selection on win
4252 * @todo: is this extra handling on win still necessary with Qt4?
4253 *
4254 * On all other platforms, this function is equivalent to
4255 * QFileDialog::getOpenFileNames().
4256 */
4257/* static */
4258QStringList VBoxGlobal::getOpenFileNames (const QString &aStartWith,
4259 const QString &aFilters,
4260 QWidget *aParent,
4261 const QString &aCaption,
4262 QString *aSelectedFilter /* = NULL */,
4263 bool aResolveSymlinks /* = true */,
4264 bool aSingleFile /* = false */)
4265{
4266#if defined Q_WS_WIN
4267
4268 /**
4269 * QEvent class reimplementation to carry Win32 API native dialog's
4270 * result folder information
4271 */
4272 class GetOpenFileNameEvent : public OpenNativeDialogEvent
4273 {
4274 public:
4275
4276 enum { TypeId = QEvent::User + 301 };
4277
4278 GetOpenFileNameEvent (const QString &aResult)
4279 : OpenNativeDialogEvent (aResult, (QEvent::Type) TypeId) {}
4280 };
4281
4282 /**
4283 * QThread class reimplementation to open Win32 API native file dialog
4284 */
4285 class Thread : public QThread
4286 {
4287 public:
4288
4289 Thread (QWidget *aParent, QObject *aTarget,
4290 const QString &aStartWith, const QString &aFilters,
4291 const QString &aCaption) :
4292 mParent (aParent), mTarget (aTarget),
4293 mStartWith (aStartWith), mFilters (aFilters),
4294 mCaption (aCaption) {}
4295
4296 virtual void run()
4297 {
4298 QString result;
4299
4300 QString workDir;
4301 QString initSel;
4302 QFileInfo fi (mStartWith);
4303
4304 if (fi.isDir())
4305 workDir = mStartWith;
4306 else
4307 {
4308 workDir = fi.absolutePath();
4309 initSel = fi.fileName();
4310 }
4311
4312 workDir = QDir::toNativeSeparators (workDir);
4313 if (!workDir.endsWith ("\\"))
4314 workDir += "\\";
4315
4316 QString title = mCaption.isNull() ? tr ("Select a file") : mCaption;
4317
4318 QWidget *topParent = mParent ? mParent->window() : vboxGlobal().mainWindow();
4319 QString winFilters = winFilter (mFilters);
4320 AssertCompile (sizeof (TCHAR) == sizeof (QChar));
4321 TCHAR buf [1024];
4322 if (initSel.length() > 0 && initSel.length() < sizeof (buf))
4323 memcpy (buf, initSel.isNull() ? 0 : initSel.utf16(),
4324 (initSel.length() + 1) * sizeof (TCHAR));
4325 else
4326 buf [0] = 0;
4327
4328 OPENFILENAME ofn;
4329 memset (&ofn, 0, sizeof (OPENFILENAME));
4330
4331 ofn.lStructSize = sizeof (OPENFILENAME);
4332 ofn.hwndOwner = topParent ? topParent->winId() : 0;
4333 ofn.lpstrFilter = (TCHAR *) winFilters.isNull() ? 0 : winFilters.utf16();
4334 ofn.lpstrFile = buf;
4335 ofn.nMaxFile = sizeof (buf) - 1;
4336 ofn.lpstrInitialDir = (TCHAR *) workDir.isNull() ? 0 : workDir.utf16();
4337 ofn.lpstrTitle = (TCHAR *) title.isNull() ? 0 : title.utf16();
4338 ofn.Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY |
4339 OFN_EXPLORER | OFN_ENABLEHOOK |
4340 OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
4341 ofn.lpfnHook = OFNHookProc;
4342
4343 if (GetOpenFileName (&ofn))
4344 {
4345 result = QString::fromUtf16 ((ushort *) ofn.lpstrFile);
4346 }
4347
4348 // qt_win_eatMouseMove();
4349 MSG msg = {0, 0, 0, 0, 0, 0, 0};
4350 while (PeekMessage (&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE));
4351 if (msg.message == WM_MOUSEMOVE)
4352 PostMessage (msg.hwnd, msg.message, 0, msg.lParam);
4353
4354 result = result.isEmpty() ? result : QFileInfo (result).absoluteFilePath();
4355
4356 QApplication::postEvent (mTarget, new GetOpenFileNameEvent (result));
4357 }
4358
4359 private:
4360
4361 QWidget *mParent;
4362 QObject *mTarget;
4363 QString mStartWith;
4364 QString mFilters;
4365 QString mCaption;
4366 };
4367
4368 if (aSelectedFilter)
4369 *aSelectedFilter = QString::null;
4370
4371 /* Local event loop to run while waiting for the result from another
4372 * thread */
4373 QEventLoop loop;
4374
4375 QString startWith = QDir::toNativeSeparators (aStartWith);
4376 LoopObject loopObject ((QEvent::Type) GetOpenFileNameEvent::TypeId, loop);
4377
4378//#warning check me!
4379 if (aParent)
4380 aParent->setWindowModality (Qt::WindowModal);
4381
4382 Thread openDirThread (aParent, &loopObject, startWith, aFilters, aCaption);
4383 openDirThread.start();
4384 loop.exec();
4385 openDirThread.wait();
4386
4387//#warning check me!
4388 if (aParent)
4389 aParent->setWindowModality (Qt::NonModal);
4390
4391 return QStringList() << loopObject.result();
4392
4393#elif defined (Q_WS_X11) && (QT_VERSION < 0x040400)
4394
4395 /* Here is workaround for Qt4.3 bug with QFileDialog which crushes when
4396 * gets initial path as hidden directory if no hidden files are shown.
4397 * See http://trolltech.com/developer/task-tracker/index_html?method=entry&id=193483
4398 * for details */
4399 QFileDialog dlg (aParent);
4400 dlg.setWindowTitle (aCaption);
4401 dlg.setDirectory (aStartWith);
4402 dlg.setFilter (aFilters);
4403 if (aSingleFile)
4404 dlg.setFileMode (QFileDialog::ExistingFile);
4405 else
4406 dlg.setFileMode (QFileDialog::ExistingFiles);
4407 if (aSelectedFilter)
4408 dlg.selectFilter (*aSelectedFilter);
4409 dlg.setResolveSymlinks (aResolveSymlinks);
4410 QAction *hidden = dlg.findChild <QAction*> ("qt_show_hidden_action");
4411 if (hidden)
4412 {
4413 hidden->trigger();
4414 hidden->setVisible (false);
4415 }
4416 return dlg.exec() == QDialog::Accepted ? dlg.selectedFiles() : QStringList() << QString::null;
4417
4418#else
4419
4420 QFileDialog::Options o;
4421 if (!aResolveSymlinks)
4422 o |= QFileDialog::DontResolveSymlinks;
4423 if (aSingleFile)
4424 return QStringList() << QFileDialog::getOpenFileName (aParent, aCaption, aStartWith,
4425 aFilters, aSelectedFilter, o);
4426 else
4427 return QFileDialog::getOpenFileNames (aParent, aCaption, aStartWith,
4428 aFilters, aSelectedFilter, o);
4429#endif
4430}
4431
4432/**
4433 * Search for the first directory that exists starting from the passed one
4434 * and going up through its parents. In case if none of the directories
4435 * exist (except the root one), the function returns QString::null.
4436 */
4437/* static */
4438QString VBoxGlobal::getFirstExistingDir (const QString &aStartDir)
4439{
4440 QString result = QString::null;
4441 QDir dir (aStartDir);
4442 while (!dir.exists() && !dir.isRoot())
4443 {
4444 QFileInfo dirInfo (dir.absolutePath());
4445 dir = dirInfo.absolutePath();
4446 }
4447 if (dir.exists() && !dir.isRoot())
4448 result = dir.absolutePath();
4449 return result;
4450}
4451
4452#if defined (Q_WS_X11)
4453
4454static char *XXGetProperty (Display *aDpy, Window aWnd,
4455 Atom aPropType, const char *aPropName)
4456{
4457 Atom propNameAtom = XInternAtom (aDpy, aPropName,
4458 True /* only_if_exists */);
4459 if (propNameAtom == None)
4460 return NULL;
4461
4462 Atom actTypeAtom = None;
4463 int actFmt = 0;
4464 unsigned long nItems = 0;
4465 unsigned long nBytesAfter = 0;
4466 unsigned char *propVal = NULL;
4467 int rc = XGetWindowProperty (aDpy, aWnd, propNameAtom,
4468 0, LONG_MAX, False /* delete */,
4469 aPropType, &actTypeAtom, &actFmt,
4470 &nItems, &nBytesAfter, &propVal);
4471 if (rc != Success)
4472 return NULL;
4473
4474 return reinterpret_cast <char *> (propVal);
4475}
4476
4477static Bool XXSendClientMessage (Display *aDpy, Window aWnd, const char *aMsg,
4478 unsigned long aData0 = 0, unsigned long aData1 = 0,
4479 unsigned long aData2 = 0, unsigned long aData3 = 0,
4480 unsigned long aData4 = 0)
4481{
4482 Atom msgAtom = XInternAtom (aDpy, aMsg, True /* only_if_exists */);
4483 if (msgAtom == None)
4484 return False;
4485
4486 XEvent ev;
4487
4488 ev.xclient.type = ClientMessage;
4489 ev.xclient.serial = 0;
4490 ev.xclient.send_event = True;
4491 ev.xclient.display = aDpy;
4492 ev.xclient.window = aWnd;
4493 ev.xclient.message_type = msgAtom;
4494
4495 /* always send as 32 bit for now */
4496 ev.xclient.format = 32;
4497 ev.xclient.data.l [0] = aData0;
4498 ev.xclient.data.l [1] = aData1;
4499 ev.xclient.data.l [2] = aData2;
4500 ev.xclient.data.l [3] = aData3;
4501 ev.xclient.data.l [4] = aData4;
4502
4503 return XSendEvent (aDpy, DefaultRootWindow (aDpy), False,
4504 SubstructureRedirectMask, &ev) != 0;
4505}
4506
4507#endif
4508
4509/**
4510 * Activates the specified window. If necessary, the window will be
4511 * de-iconified activation.
4512 *
4513 * @note On X11, it is implied that @a aWid represents a window of the same
4514 * display the application was started on.
4515 *
4516 * @param aWId Window ID to activate.
4517 * @param aSwitchDesktop @c true to switch to the window's desktop before
4518 * activation.
4519 *
4520 * @return @c true on success and @c false otherwise.
4521 */
4522/* static */
4523bool VBoxGlobal::activateWindow (WId aWId, bool aSwitchDesktop /* = true */)
4524{
4525 bool result = true;
4526
4527#if defined (Q_WS_WIN32)
4528
4529 if (IsIconic (aWId))
4530 result &= !!ShowWindow (aWId, SW_RESTORE);
4531 else if (!IsWindowVisible (aWId))
4532 result &= !!ShowWindow (aWId, SW_SHOW);
4533
4534 result &= !!SetForegroundWindow (aWId);
4535
4536#elif defined (Q_WS_X11)
4537
4538 Display *dpy = QX11Info::display();
4539
4540 if (aSwitchDesktop)
4541 {
4542 /* try to find the desktop ID using the NetWM property */
4543 CARD32 *desktop = (CARD32 *) XXGetProperty (dpy, aWId, XA_CARDINAL,
4544 "_NET_WM_DESKTOP");
4545 if (desktop == NULL)
4546 /* if the NetWM propery is not supported try to find the desktop
4547 * ID using the GNOME WM property */
4548 desktop = (CARD32 *) XXGetProperty (dpy, aWId, XA_CARDINAL,
4549 "_WIN_WORKSPACE");
4550
4551 if (desktop != NULL)
4552 {
4553 Bool ok = XXSendClientMessage (dpy, DefaultRootWindow (dpy),
4554 "_NET_CURRENT_DESKTOP",
4555 *desktop);
4556 if (!ok)
4557 {
4558 LogWarningFunc (("Couldn't switch to desktop=%08X\n",
4559 desktop));
4560 result = false;
4561 }
4562 XFree (desktop);
4563 }
4564 else
4565 {
4566 LogWarningFunc (("Couldn't find a desktop ID for aWId=%08X\n",
4567 aWId));
4568 result = false;
4569 }
4570 }
4571
4572 Bool ok = XXSendClientMessage (dpy, aWId, "_NET_ACTIVE_WINDOW");
4573 result &= !!ok;
4574
4575 XRaiseWindow (dpy, aWId);
4576
4577#else
4578
4579 NOREF (aSwitchDesktop);
4580 AssertFailed();
4581 result = false;
4582
4583#endif
4584
4585 if (!result)
4586 LogWarningFunc (("Couldn't activate aWId=%08X\n", aWId));
4587
4588 return result;
4589}
4590
4591/**
4592 * Removes the acceletartor mark (the ampersand symbol) from the given string
4593 * and returns the result. The string is supposed to be a menu item's text
4594 * that may (or may not) contain the accelerator mark.
4595 *
4596 * In order to support accelerators used in non-alphabet languages
4597 * (e.g. Japanese) that has a form of "(&<L>)" (where <L> is a latin letter),
4598 * this method first searches for this pattern and, if found, removes it as a
4599 * whole. If such a pattern is not found, then the '&' character is simply
4600 * removed from the string.
4601 *
4602 * @note This function removes only the first occurense of the accelerator
4603 * mark.
4604 *
4605 * @param aText Menu item's text to remove the acceletaror mark from.
4606 *
4607 * @return The resulting string.
4608 */
4609/* static */
4610QString VBoxGlobal::removeAccelMark (const QString &aText)
4611{
4612 QString result = aText;
4613
4614 QRegExp accel ("\\(&[a-zA-Z]\\)");
4615 int pos = accel.indexIn (result);
4616 if (pos >= 0)
4617 result.remove (pos, accel.cap().length());
4618 else
4619 {
4620 pos = result.indexOf ('&');
4621 if (pos >= 0)
4622 result.remove (pos, 1);
4623 }
4624
4625 return result;
4626}
4627
4628/* static */
4629QString VBoxGlobal::insertKeyToActionText (const QString &aText, const QString &aKey)
4630{
4631#ifdef Q_WS_MAC
4632 QString key ("%1 (Host+%2)");
4633#else
4634 QString key ("%1 \tHost+%2");
4635#endif
4636 return key.arg (aText).arg (QKeySequence (aKey).toString (QKeySequence::NativeText));
4637}
4638
4639/* static */
4640QString VBoxGlobal::extractKeyFromActionText (const QString &aText)
4641{
4642 QString key;
4643#ifdef Q_WS_MAC
4644 QRegExp re (".* \\(Host\\+(.+)\\)");
4645#else
4646 QRegExp re (".* \\t\\Host\\+(.+)");
4647#endif
4648 if (re.exactMatch (aText))
4649 key = re.cap (1);
4650 return key;
4651}
4652
4653/**
4654 * Joins two pixmaps horizontally with 2px space between them and returns the
4655 * result.
4656 *
4657 * @param aPM1 Left pixmap.
4658 * @param aPM2 Right pixmap.
4659 */
4660/* static */
4661QPixmap VBoxGlobal::joinPixmaps (const QPixmap &aPM1, const QPixmap &aPM2)
4662{
4663 if (aPM1.isNull())
4664 return aPM2;
4665 if (aPM2.isNull())
4666 return aPM1;
4667
4668 QPixmap result (aPM1.width() + aPM2.width() + 2,
4669 qMax (aPM1.height(), aPM2.height()));
4670 result.fill (Qt::transparent);
4671
4672 QPainter painter (&result);
4673 painter.drawPixmap (0, 0, aPM1);
4674 painter.drawPixmap (aPM1.width() + 2, result.height() - aPM2.height(), aPM2);
4675 painter.end();
4676
4677 return result;
4678}
4679
4680/**
4681 * Searches for a widget that with @a aName (if it is not NULL) which inherits
4682 * @a aClassName (if it is not NULL) and among children of @a aParent. If @a
4683 * aParent is NULL, all top-level widgets are searched. If @a aRecursive is
4684 * true, child widgets are recursively searched as well.
4685 */
4686/* static */
4687QWidget *VBoxGlobal::findWidget (QWidget *aParent, const char *aName,
4688 const char *aClassName /* = NULL */,
4689 bool aRecursive /* = false */)
4690{
4691 if (aParent == NULL)
4692 {
4693 QWidgetList list = QApplication::topLevelWidgets();
4694 QWidget* w = NULL;
4695 foreach(w, list)
4696 {
4697 if ((!aName || strcmp (w->objectName().toAscii().constData(), aName) == 0) &&
4698 (!aClassName || strcmp (w->metaObject()->className(), aClassName) == 0))
4699 break;
4700 if (aRecursive)
4701 {
4702 w = findWidget (w, aName, aClassName, aRecursive);
4703 if (w)
4704 break;
4705 }
4706 }
4707 return w;
4708 }
4709
4710 /* Find the first children of aParent with the appropriate properties.
4711 * Please note that this call is recursivly. */
4712 QList<QWidget *> list = qFindChildren<QWidget *> (aParent, aName);
4713 QWidget *child = NULL;
4714 foreach(child, list)
4715 {
4716 if (!aClassName || strcmp (child->metaObject()->className(), aClassName) == 0)
4717 break;
4718 }
4719 return child;
4720}
4721
4722/**
4723 * Figures out which hard disk formats are currently supported by VirtualBox.
4724 * Returned is a list of pairs with the form
4725 * <tt>{"Backend Name", "*.suffix1 .suffix2 ..."}</tt>.
4726 */
4727/* static */
4728QList <QPair <QString, QString> > VBoxGlobal::HDDBackends()
4729{
4730 CSystemProperties systemProperties = vboxGlobal().virtualBox().GetSystemProperties();
4731 QVector<CHardDiskFormat> hardDiskFormats = systemProperties.GetHardDiskFormats();
4732 QList< QPair<QString, QString> > backendPropList;
4733 for (int i = 0; i < hardDiskFormats.size(); ++ i)
4734 {
4735 /* File extensions */
4736 QVector <QString> fileExtensions = hardDiskFormats [i].GetFileExtensions();
4737 QStringList f;
4738 for (int a = 0; a < fileExtensions.size(); ++ a)
4739 f << QString ("*.%1").arg (fileExtensions [a]);
4740 /* Create a pair out of the backend description and all suffix's. */
4741 if (!f.isEmpty())
4742 backendPropList << QPair<QString, QString> (hardDiskFormats [i].GetName(), f.join(" "));
4743 }
4744 return backendPropList;
4745}
4746
4747// Public slots
4748////////////////////////////////////////////////////////////////////////////////
4749
4750/**
4751 * Opens the specified URL using OS/Desktop capabilities.
4752 *
4753 * @param aURL URL to open
4754 *
4755 * @return true on success and false otherwise
4756 */
4757bool VBoxGlobal::openURL (const QString &aURL)
4758{
4759#if defined (Q_WS_WIN)
4760 /* We cannot use ShellExecute() on the main UI thread because we've
4761 * initialized COM with CoInitializeEx(COINIT_MULTITHREADED). See
4762 * http://support.microsoft.com/default.aspx?scid=kb;en-us;287087
4763 * for more details. */
4764 class Thread : public QThread
4765 {
4766 public:
4767
4768 Thread (const QString &aURL, QObject *aObject)
4769 : mObject (aObject), mURL (aURL) {}
4770
4771 void run()
4772 {
4773 int rc = (int) ShellExecute (NULL, NULL, mURL.isNull() ? 0 : mURL.utf16(),
4774 NULL, NULL, SW_SHOW);
4775 bool ok = rc > 32;
4776 QApplication::postEvent
4777 (mObject,
4778 new VBoxShellExecuteEvent (this, mURL, ok));
4779 }
4780
4781 QString mURL;
4782 QObject *mObject;
4783 };
4784
4785 Thread *thread = new Thread (aURL, this);
4786 thread->start();
4787 /* thread will be deleted in the VBoxShellExecuteEvent handler */
4788
4789 return true;
4790
4791#elif defined (Q_WS_X11)
4792
4793 static const char * const commands[] =
4794 { "kfmclient:exec", "gnome-open", "x-www-browser", "firefox", "konqueror" };
4795
4796 for (size_t i = 0; i < RT_ELEMENTS (commands); ++ i)
4797 {
4798 QStringList args = QString(commands [i]).split (':');
4799 args += aURL;
4800 QString command = args.takeFirst();
4801 if (QProcess::startDetached (command, args))
4802 return true;
4803 }
4804
4805#elif defined (Q_WS_MAC)
4806
4807 /* The code below is taken from Psi 0.10 sources
4808 * (http://www.psi-im.org) */
4809
4810 /* Use Internet Config to hand the URL to the appropriate application, as
4811 * set by the user in the Internet Preferences pane.
4812 * NOTE: ICStart could be called once at Psi startup, saving the
4813 * ICInstance in a global variable, as a minor optimization.
4814 * ICStop should then be called at Psi shutdown if ICStart
4815 * succeeded. */
4816 ICInstance icInstance;
4817 OSType psiSignature = 'psi ';
4818 OSStatus error = ::ICStart (&icInstance, psiSignature);
4819 if (error == noErr)
4820 {
4821 ConstStr255Param hint (0x0);
4822 QByteArray cs = aURL.toLocal8Bit();
4823 const char* data = cs.data();
4824 long length = cs.length();
4825 long start (0);
4826 long end (length);
4827 /* Don't bother testing return value (error); launched application
4828 * will report problems. */
4829 ::ICLaunchURL (icInstance, hint, data, length, &start, &end);
4830 ICStop (icInstance);
4831 return true;
4832 }
4833
4834#else
4835 vboxProblem().message
4836 (NULL, VBoxProblemReporter::Error,
4837 tr ("Opening URLs is not implemented yet."));
4838 return false;
4839#endif
4840
4841 /* if we go here it means we couldn't open the URL */
4842 vboxProblem().cannotOpenURL (aURL);
4843
4844 return false;
4845}
4846
4847/**
4848 * Shows the VirtualBox registration dialog.
4849 *
4850 * @note that this method is not part of VBoxProblemReporter (like e.g.
4851 * VBoxProblemReporter::showHelpAboutDialog()) because it is tied to
4852 * VBoxCallback::OnExtraDataChange() handling performed by VBoxGlobal.
4853 *
4854 * @param aForce
4855 */
4856void VBoxGlobal::showRegistrationDialog (bool aForce)
4857{
4858#ifdef VBOX_WITH_REGISTRATION
4859 if (!aForce && !VBoxRegistrationDlg::hasToBeShown())
4860 return;
4861
4862 if (mRegDlg)
4863 {
4864 /* Show the already opened registration dialog */
4865 mRegDlg->setWindowState (mRegDlg->windowState() & ~Qt::WindowMinimized);
4866 mRegDlg->raise();
4867 mRegDlg->activateWindow();
4868 }
4869 else
4870 {
4871 /* Store the ID of the main window to ensure that only one
4872 * registration dialog is shown at a time. Due to manipulations with
4873 * OnExtraDataCanChange() and OnExtraDataChange() signals, this extra
4874 * data item acts like an inter-process mutex, so the first process
4875 * that attempts to set it will win, the rest will get a failure from
4876 * the SetExtraData() call. */
4877 mVBox.SetExtraData (VBoxDefs::GUI_RegistrationDlgWinID,
4878 QString ("%1").arg ((qulonglong) mMainWindow->winId()));
4879
4880 if (mVBox.isOk())
4881 {
4882 /* We've got the "mutex", create a new registration dialog */
4883 VBoxRegistrationDlg *dlg =
4884 new VBoxRegistrationDlg (&mRegDlg, 0);
4885 dlg->setAttribute (Qt::WA_DeleteOnClose);
4886 Assert (dlg == mRegDlg);
4887 mRegDlg->show();
4888 }
4889 }
4890#endif
4891}
4892
4893/**
4894 * Shows the VirtualBox version check & update dialog.
4895 *
4896 * @note that this method is not part of VBoxProblemReporter (like e.g.
4897 * VBoxProblemReporter::showHelpAboutDialog()) because it is tied to
4898 * VBoxCallback::OnExtraDataChange() handling performed by VBoxGlobal.
4899 *
4900 * @param aForce
4901 */
4902void VBoxGlobal::showUpdateDialog (bool aForce)
4903{
4904 bool isNecessary = VBoxUpdateDlg::isNecessary();
4905
4906 if (!aForce && !isNecessary)
4907 return;
4908
4909 if (mUpdDlg)
4910 {
4911 if (!mUpdDlg->isHidden())
4912 {
4913 mUpdDlg->setWindowState (mUpdDlg->windowState() & ~Qt::WindowMinimized);
4914 mUpdDlg->raise();
4915 mUpdDlg->activateWindow();
4916 }
4917 }
4918 else
4919 {
4920 /* Store the ID of the main window to ensure that only one
4921 * update dialog is shown at a time. Due to manipulations with
4922 * OnExtraDataCanChange() and OnExtraDataChange() signals, this extra
4923 * data item acts like an inter-process mutex, so the first process
4924 * that attempts to set it will win, the rest will get a failure from
4925 * the SetExtraData() call. */
4926 mVBox.SetExtraData (VBoxDefs::GUI_UpdateDlgWinID,
4927 QString ("%1").arg ((qulonglong) mMainWindow->winId()));
4928
4929 if (mVBox.isOk())
4930 {
4931 /* We've got the "mutex", create a new update dialog */
4932 VBoxUpdateDlg *dlg = new VBoxUpdateDlg (&mUpdDlg, aForce, 0);
4933 dlg->setAttribute (Qt::WA_DeleteOnClose);
4934 Assert (dlg == mUpdDlg);
4935
4936 /* Update dialog always in background mode for now.
4937 * if (!aForce && isAutomatic) */
4938 mUpdDlg->search();
4939 /* else mUpdDlg->show(); */
4940 }
4941 }
4942}
4943
4944// Protected members
4945////////////////////////////////////////////////////////////////////////////////
4946
4947bool VBoxGlobal::event (QEvent *e)
4948{
4949 switch (e->type())
4950 {
4951#if defined (Q_WS_WIN)
4952 case VBoxDefs::ShellExecuteEventType:
4953 {
4954 VBoxShellExecuteEvent *ev = (VBoxShellExecuteEvent *) e;
4955 if (!ev->mOk)
4956 vboxProblem().cannotOpenURL (ev->mURL);
4957 /* wait for the thread and free resources */
4958 ev->mThread->wait();
4959 delete ev->mThread;
4960 return true;
4961 }
4962#endif
4963
4964 case VBoxDefs::AsyncEventType:
4965 {
4966 VBoxAsyncEvent *ev = (VBoxAsyncEvent *) e;
4967 ev->handle();
4968 return true;
4969 }
4970
4971 case VBoxDefs::MediaEnumEventType:
4972 {
4973 VBoxMediaEnumEvent *ev = (VBoxMediaEnumEvent*) e;
4974
4975 if (!ev->mLast)
4976 {
4977 if (ev->mMedium.state() == KMediaState_Inaccessible &&
4978 !ev->mMedium.result().isOk())
4979 vboxProblem().cannotGetMediaAccessibility (ev->mMedium);
4980 Assert (ev->mIterator != mMediaList.end());
4981 *(ev->mIterator) = ev->mMedium;
4982 emit mediumEnumerated (*ev->mIterator);
4983 ++ ev->mIterator;
4984 }
4985 else
4986 {
4987 /* the thread has posted the last message, wait for termination */
4988 mMediaEnumThread->wait();
4989 delete mMediaEnumThread;
4990 mMediaEnumThread = 0;
4991 emit mediumEnumFinished (mMediaList);
4992 }
4993
4994 return true;
4995 }
4996
4997 /* VirtualBox callback events */
4998
4999 case VBoxDefs::MachineStateChangeEventType:
5000 {
5001 emit machineStateChanged (*(VBoxMachineStateChangeEvent *) e);
5002 return true;
5003 }
5004 case VBoxDefs::MachineDataChangeEventType:
5005 {
5006 emit machineDataChanged (*(VBoxMachineDataChangeEvent *) e);
5007 return true;
5008 }
5009 case VBoxDefs::MachineRegisteredEventType:
5010 {
5011 emit machineRegistered (*(VBoxMachineRegisteredEvent *) e);
5012 return true;
5013 }
5014 case VBoxDefs::SessionStateChangeEventType:
5015 {
5016 emit sessionStateChanged (*(VBoxSessionStateChangeEvent *) e);
5017 return true;
5018 }
5019 case VBoxDefs::SnapshotEventType:
5020 {
5021 emit snapshotChanged (*(VBoxSnapshotEvent *) e);
5022 return true;
5023 }
5024 case VBoxDefs::CanShowRegDlgEventType:
5025 {
5026 emit canShowRegDlg (((VBoxCanShowRegDlgEvent *) e)->mCanShow);
5027 return true;
5028 }
5029 case VBoxDefs::CanShowUpdDlgEventType:
5030 {
5031 emit canShowUpdDlg (((VBoxCanShowUpdDlgEvent *) e)->mCanShow);
5032 return true;
5033 }
5034 case VBoxDefs::ChangeGUILanguageEventType:
5035 {
5036 loadLanguage (static_cast<VBoxChangeGUILanguageEvent*> (e)->mLangId);
5037 return true;
5038 }
5039 case VBoxDefs::ChangeGUITrayIconEventType:
5040 {
5041 emit systrayIconChanged (*(VBoxChangeGUITrayIconEvent *) e);
5042 return true;
5043 }
5044
5045 default:
5046 break;
5047 }
5048
5049 return QObject::event (e);
5050}
5051
5052bool VBoxGlobal::eventFilter (QObject *aObject, QEvent *aEvent)
5053{
5054 if (aEvent->type() == QEvent::LanguageChange &&
5055 aObject->isWidgetType() &&
5056 static_cast <QWidget *> (aObject)->isTopLevel())
5057 {
5058 /* Catch the language change event before any other widget gets it in
5059 * order to invalidate cached string resources (like the details view
5060 * templates) that may be used by other widgets. */
5061 QWidgetList list = QApplication::topLevelWidgets();
5062 if (list.first() == aObject)
5063 {
5064 /* call this only once per every language change (see
5065 * QApplication::installTranslator() for details) */
5066 retranslateUi();
5067 }
5068 }
5069
5070 return QObject::eventFilter (aObject, aEvent);
5071}
5072
5073// Private members
5074////////////////////////////////////////////////////////////////////////////////
5075
5076void VBoxGlobal::init()
5077{
5078#ifdef DEBUG
5079 verString += " [DEBUG]";
5080#endif
5081
5082#ifdef Q_WS_WIN
5083 /* COM for the main thread is initialized in main() */
5084#else
5085 HRESULT rc = COMBase::InitializeCOM();
5086 if (FAILED (rc))
5087 {
5088 vboxProblem().cannotInitCOM (rc);
5089 return;
5090 }
5091#endif
5092
5093 mVBox.createInstance (CLSID_VirtualBox);
5094 if (!mVBox.isOk())
5095 {
5096 vboxProblem().cannotCreateVirtualBox (mVBox);
5097 return;
5098 }
5099
5100 /* Initialize guest OS Type list */
5101 CGuestOSTypeCollection coll = mVBox.GetGuestOSTypes();
5102 int osTypeCount = coll.GetCount();
5103 AssertMsg (osTypeCount > 0, ("Number of OS types must not be zero"));
5104 if (osTypeCount > 0)
5105 {
5106 CGuestOSTypeEnumerator en = coll.Enumerate();
5107 while (en.HasMore())
5108 {
5109 CGuestOSType os (en.GetNext());
5110 QString familyId (os.GetFamilyId());
5111 if (!mFamilyIDs.contains (familyId))
5112 {
5113 mFamilyIDs << familyId;
5114 mTypes << QList <CGuestOSType> ();
5115 }
5116 mTypes [mFamilyIDs.indexOf (familyId)].append (os);
5117 }
5118 }
5119
5120 /* Fill in OS type icon dictionary */
5121 static const char *kOSTypeIcons [][2] =
5122 {
5123 {"Other", ":/os_other.png"},
5124 {"DOS", ":/os_dos.png"},
5125 {"Netware", ":/os_netware.png"},
5126 {"L4", ":/os_l4.png"},
5127 {"Windows31", ":/os_win31.png"},
5128 {"Windows95", ":/os_win95.png"},
5129 {"Windows98", ":/os_win98.png"},
5130 {"WindowsMe", ":/os_winme.png"},
5131 {"WindowsNT4", ":/os_winnt4.png"},
5132 {"Windows2000", ":/os_win2k.png"},
5133 {"WindowsXP", ":/os_winxp.png"},
5134 {"WindowsXP_64", ":/os_winxp_64.png"},
5135 {"Windows2003", ":/os_win2k3.png"},
5136 {"Windows2003_64", ":/os_win2k3_64.png"},
5137 {"WindowsVista", ":/os_winvista.png"},
5138 {"WindowsVista_64", ":/os_winvista_64.png"},
5139 {"Windows2008", ":/os_win2k8.png"},
5140 {"Windows2008_64", ":/os_win2k8_64.png"},
5141 {"WindowsNT", ":/os_win_other.png"},
5142 {"OS2Warp3", ":/os_os2warp3.png"},
5143 {"OS2Warp4", ":/os_os2warp4.png"},
5144 {"OS2Warp45", ":/os_os2warp45.png"},
5145 {"OS2eCS", ":/os_os2ecs.png"},
5146 {"OS2", ":/os_os2_other.png"},
5147 {"Linux22", ":/os_linux22.png"},
5148 {"Linux24", ":/os_linux24.png"},
5149 {"Linux24_64", ":/os_linux24_64.png"},
5150 {"Linux26", ":/os_linux26.png"},
5151 {"Linux26_64", ":/os_linux26_64.png"},
5152 {"ArchLinux", ":/os_archlinux.png"},
5153 {"ArchLinux_64", ":/os_archlinux_64.png"},
5154 {"Debian", ":/os_debian.png"},
5155 {"Debian_64", ":/os_debian_64.png"},
5156 {"OpenSUSE", ":/os_opensuse.png"},
5157 {"OpenSUSE_64", ":/os_opensuse_64.png"},
5158 {"Fedora", ":/os_fedora.png"},
5159 {"Fedora_64", ":/os_fedora_64.png"},
5160 {"Gentoo", ":/os_gentoo.png"},
5161 {"Gentoo_64", ":/os_gentoo_64.png"},
5162 {"Mandriva", ":/os_mandriva.png"},
5163 {"Mandriva_64", ":/os_mandriva_64.png"},
5164 {"RedHat", ":/os_redhat.png"},
5165 {"RedHat_64", ":/os_redhat_64.png"},
5166 {"Ubuntu", ":/os_ubuntu.png"},
5167 {"Ubuntu_64", ":/os_ubuntu_64.png"},
5168 {"Xandros", ":/os_xandros.png"},
5169 {"Xandros_64", ":/os_xandros_64.png"},
5170 {"Linux", ":/os_linux_other.png"},
5171 {"FreeBSD", ":/os_freebsd.png"},
5172 {"FreeBSD_64", ":/os_freebsd_64.png"},
5173 {"OpenBSD", ":/os_openbsd.png"},
5174 {"OpenBSD_64", ":/os_openbsd_64.png"},
5175 {"NetBSD", ":/os_netbsd.png"},
5176 {"NetBSD_64", ":/os_netbsd_64.png"},
5177 {"Solaris", ":/os_solaris.png"},
5178 {"Solaris_64", ":/os_solaris_64.png"},
5179 {"OpenSolaris", ":/os_opensolaris.png"},
5180 {"OpenSolaris_64", ":/os_opensolaris_64.png"},
5181 };
5182 for (uint n = 0; n < SIZEOF_ARRAY (kOSTypeIcons); ++ n)
5183 {
5184 mOsTypeIcons.insert (kOSTypeIcons [n][0],
5185 new QPixmap (kOSTypeIcons [n][1]));
5186 }
5187
5188 /* fill in VM state icon dictionary */
5189 static struct
5190 {
5191 KMachineState state;
5192 const char *name;
5193 }
5194 vmStateIcons[] =
5195 {
5196 {KMachineState_Null, NULL},
5197 {KMachineState_PoweredOff, ":/state_powered_off_16px.png"},
5198 {KMachineState_Saved, ":/state_saved_16px.png"},
5199 {KMachineState_Aborted, ":/state_aborted_16px.png"},
5200 {KMachineState_Running, ":/state_running_16px.png"},
5201 {KMachineState_Paused, ":/state_paused_16px.png"},
5202 {KMachineState_Stuck, ":/state_stuck_16px.png"},
5203 {KMachineState_Starting, ":/state_running_16px.png"}, /// @todo (dmik) separate icon?
5204 {KMachineState_Stopping, ":/state_running_16px.png"}, /// @todo (dmik) separate icon?
5205 {KMachineState_Saving, ":/state_saving_16px.png"},
5206 {KMachineState_Restoring, ":/state_restoring_16px.png"},
5207 {KMachineState_Discarding, ":/state_discarding_16px.png"},
5208 {KMachineState_SettingUp, ":/settings_16px.png"},
5209 };
5210 for (uint n = 0; n < SIZEOF_ARRAY (vmStateIcons); n ++)
5211 {
5212 mStateIcons.insert (vmStateIcons [n].state,
5213 new QPixmap (vmStateIcons [n].name));
5214 }
5215
5216 /* online/offline snapshot icons */
5217 mOfflineSnapshotIcon = QPixmap (":/offline_snapshot_16px.png");
5218 mOnlineSnapshotIcon = QPixmap (":/online_snapshot_16px.png");
5219
5220 /* initialize state colors vector */
5221 vm_state_color.insert (KMachineState_Null, new QColor(Qt::red));
5222 vm_state_color.insert (KMachineState_PoweredOff, new QColor(Qt::gray));
5223 vm_state_color.insert (KMachineState_Saved, new QColor(Qt::yellow));
5224 vm_state_color.insert (KMachineState_Aborted, new QColor(Qt::darkRed));
5225 vm_state_color.insert (KMachineState_Running, new QColor(Qt::green));
5226 vm_state_color.insert (KMachineState_Paused, new QColor(Qt::darkGreen));
5227 vm_state_color.insert (KMachineState_Stuck, new QColor(Qt::darkMagenta));
5228 vm_state_color.insert (KMachineState_Starting, new QColor(Qt::green));
5229 vm_state_color.insert (KMachineState_Stopping, new QColor(Qt::green));
5230 vm_state_color.insert (KMachineState_Saving, new QColor(Qt::green));
5231 vm_state_color.insert (KMachineState_Restoring, new QColor(Qt::green));
5232 vm_state_color.insert (KMachineState_Discarding, new QColor(Qt::green));
5233 vm_state_color.insert (KMachineState_SettingUp, new QColor(Qt::green));
5234
5235 qApp->installEventFilter (this);
5236
5237 /* create default non-null global settings */
5238 gset = VBoxGlobalSettings (false);
5239
5240 /* try to load global settings */
5241 gset.load (mVBox);
5242 if (!mVBox.isOk() || !gset)
5243 {
5244 vboxProblem().cannotLoadGlobalConfig (mVBox, gset.lastError());
5245 return;
5246 }
5247
5248 /* Load customized language if any */
5249 QString languageId = gset.languageId();
5250 if (!languageId.isNull())
5251 loadLanguage (languageId);
5252
5253 retranslateUi();
5254
5255 /* process command line */
5256
5257 vm_render_mode_str = 0;
5258#ifdef VBOX_WITH_DEBUGGER_GUI
5259# ifdef VBOX_WITH_DEBUGGER_GUI_MENU
5260 mDbgEnabled = true;
5261# else
5262 mDbgEnabled = RTEnvExist("VBOX_GUI_DBG_ENABLED");
5263# endif
5264 mDbgAutoShow = RTEnvExist("VBOX_GUI_DBG_AUTO_SHOW");
5265#endif
5266
5267 int argc = qApp->argc();
5268 int i = 1;
5269 while (i < argc)
5270 {
5271 const char *arg = qApp->argv() [i];
5272 if ( !::strcmp (arg, "-startvm"))
5273 {
5274 if (++i < argc)
5275 {
5276 QString param = QString (qApp->argv() [i]);
5277 QUuid uuid = QUuid (param);
5278 if (!uuid.isNull())
5279 {
5280 vmUuid = uuid;
5281 }
5282 else
5283 {
5284 CMachine m = mVBox.FindMachine (param);
5285 if (m.isNull())
5286 {
5287 vboxProblem().cannotFindMachineByName (mVBox, param);
5288 return;
5289 }
5290 vmUuid = m.GetId();
5291 }
5292 }
5293 }
5294 else if (!::strcmp (arg, "-comment"))
5295 {
5296 ++i;
5297 }
5298 else if (!::strcmp (arg, "-rmode"))
5299 {
5300 if (++i < argc)
5301 vm_render_mode_str = qApp->argv() [i];
5302 }
5303#ifdef VBOX_WITH_DEBUGGER_GUI
5304 else if (!::strcmp (arg, "-dbg") || !::strcmp (arg, "--dbg"))
5305 {
5306 mDbgEnabled = true;
5307 }
5308 else if (!::strcmp( arg, "-debug") || !::strcmp( arg, "--debug"))
5309 {
5310 mDbgEnabled = true;
5311 mDbgAutoShow = true;
5312 }
5313 else if (!::strcmp (arg, "-no-debug") || !::strcmp (arg, "--no-debug"))
5314 {
5315 mDbgEnabled = false;
5316 mDbgAutoShow = false;
5317 }
5318#endif
5319 /** @todo add an else { msgbox(syntax error); exit(1); } here, pretty please... */
5320 i++;
5321 }
5322
5323 vm_render_mode = vboxGetRenderMode( vm_render_mode_str );
5324
5325 /* setup the callback */
5326 callback = CVirtualBoxCallback (new VBoxCallback (*this));
5327 mVBox.RegisterCallback (callback);
5328 AssertWrapperOk (mVBox);
5329 if (!mVBox.isOk())
5330 return;
5331
5332#ifdef VBOX_WITH_DEBUGGER_GUI
5333 /* setup the debugger gui. */
5334 if (RTEnvExist("VBOX_GUI_NO_DEBUGGER"))
5335 mDbgEnabled = mDbgAutoShow = false;
5336 if (mDbgEnabled)
5337 {
5338 int rc = SUPR3HardenedLdrLoadAppPriv("VBoxDbg", &mhVBoxDbg);
5339 if (RT_FAILURE(rc))
5340 {
5341 mhVBoxDbg = NIL_RTLDRMOD;
5342 mDbgAutoShow = false;
5343 LogRel(("Failed to load VBoxDbg, rc=%Rrc\n", rc));
5344 }
5345 }
5346#endif
5347
5348 mValid = true;
5349}
5350
5351/** @internal
5352 *
5353 * This method should be never called directly. It is called automatically
5354 * when the application terminates.
5355 */
5356void VBoxGlobal::cleanup()
5357{
5358 /* sanity check */
5359 if (!sVBoxGlobalInCleanup)
5360 {
5361 AssertMsgFailed (("Should never be called directly\n"));
5362 return;
5363 }
5364
5365 if (!callback.isNull())
5366 {
5367 mVBox.UnregisterCallback (callback);
5368 AssertWrapperOk (mVBox);
5369 callback.detach();
5370 }
5371
5372 if (mMediaEnumThread)
5373 {
5374 /* sVBoxGlobalInCleanup is true here, so just wait for the thread */
5375 mMediaEnumThread->wait();
5376 delete mMediaEnumThread;
5377 mMediaEnumThread = 0;
5378 }
5379
5380#ifdef VBOX_WITH_REGISTRATION
5381 if (mRegDlg)
5382 mRegDlg->close();
5383#endif
5384
5385 if (mConsoleWnd)
5386 delete mConsoleWnd;
5387 if (mSelectorWnd)
5388 delete mSelectorWnd;
5389
5390 /* ensure CGuestOSType objects are no longer used */
5391 mFamilyIDs.clear();
5392 mTypes.clear();
5393
5394 /* media list contains a lot of CUUnknown, release them */
5395 mMediaList.clear();
5396 /* the last step to ensure we don't use COM any more */
5397 mVBox.detach();
5398
5399 /* There may be VBoxMediaEnumEvent instances still in the message
5400 * queue which reference COM objects. Remove them to release those objects
5401 * before uninitializing the COM subsystem. */
5402 QApplication::removePostedEvents (this);
5403
5404#ifdef Q_WS_WIN
5405 /* COM for the main thread is shutdown in main() */
5406#else
5407 COMBase::CleanupCOM();
5408#endif
5409
5410 mValid = false;
5411}
5412
5413/** @fn vboxGlobal
5414 *
5415 * Shortcut to the static VBoxGlobal::instance() method, for convenience.
5416 */
5417
5418
5419/**
5420 * USB Popup Menu class methods
5421 * This class provides the list of USB devices attached to the host.
5422 */
5423VBoxUSBMenu::VBoxUSBMenu (QWidget *aParent) : QMenu (aParent)
5424{
5425 connect (this, SIGNAL (aboutToShow()),
5426 this, SLOT (processAboutToShow()));
5427// connect (this, SIGNAL (hovered (QAction *)),
5428// this, SLOT (processHighlighted (QAction *)));
5429}
5430
5431const CUSBDevice& VBoxUSBMenu::getUSB (QAction *aAction)
5432{
5433 return mUSBDevicesMap [aAction];
5434}
5435
5436void VBoxUSBMenu::setConsole (const CConsole &aConsole)
5437{
5438 mConsole = aConsole;
5439}
5440
5441void VBoxUSBMenu::processAboutToShow()
5442{
5443 clear();
5444 mUSBDevicesMap.clear();
5445
5446 CHost host = vboxGlobal().virtualBox().GetHost();
5447
5448 bool isUSBEmpty = host.GetUSBDevices().GetCount() == 0;
5449 if (isUSBEmpty)
5450 {
5451 QAction *action = addAction (tr ("<no available devices>", "USB devices"));
5452 action->setEnabled (false);
5453 action->setToolTip (tr ("No supported devices connected to the host PC",
5454 "USB device tooltip"));
5455 }
5456 else
5457 {
5458 CHostUSBDeviceEnumerator en = host.GetUSBDevices().Enumerate();
5459 while (en.HasMore())
5460 {
5461 CHostUSBDevice dev = en.GetNext();
5462 CUSBDevice usb (dev);
5463 QAction *action = addAction (vboxGlobal().details (usb));
5464 action->setCheckable (true);
5465 mUSBDevicesMap [action] = usb;
5466 /* check if created item was alread attached to this session */
5467 if (!mConsole.isNull())
5468 {
5469 CUSBDevice attachedUSB =
5470 mConsole.GetUSBDevices().FindById (usb.GetId());
5471 action->setChecked (!attachedUSB.isNull());
5472 action->setEnabled (dev.GetState() !=
5473 KUSBDeviceState_Unavailable);
5474 }
5475 }
5476 }
5477}
5478
5479bool VBoxUSBMenu::event(QEvent *aEvent)
5480{
5481 /* We provide dynamic tooltips for the usb devices */
5482 if (aEvent->type() == QEvent::ToolTip)
5483 {
5484 QHelpEvent *helpEvent = static_cast<QHelpEvent *> (aEvent);
5485 QAction *action = actionAt (helpEvent->pos());
5486 if (action)
5487 {
5488 CUSBDevice usb = mUSBDevicesMap [action];
5489 if (!usb.isNull())
5490 {
5491 QToolTip::showText (helpEvent->globalPos(), vboxGlobal().toolTip (usb));
5492 return true;
5493 }
5494 }
5495 }
5496 return QMenu::event (aEvent);
5497}
5498
5499/**
5500 * Enable/Disable Menu class.
5501 * This class provides enable/disable menu items.
5502 */
5503VBoxSwitchMenu::VBoxSwitchMenu (QWidget *aParent, QAction *aAction,
5504 bool aInverted)
5505 : QMenu (aParent), mAction (aAction), mInverted (aInverted)
5506{
5507 /* this menu works only with toggle action */
5508 Assert (aAction->isCheckable());
5509 addAction(aAction);
5510 connect (this, SIGNAL (aboutToShow()),
5511 this, SLOT (processAboutToShow()));
5512}
5513
5514void VBoxSwitchMenu::setToolTip (const QString &aTip)
5515{
5516 mAction->setToolTip (aTip);
5517}
5518
5519void VBoxSwitchMenu::processAboutToShow()
5520{
5521 QString text = mAction->isChecked() ^ mInverted ? tr ("Disable") : tr ("Enable");
5522 mAction->setText (text);
5523}
5524
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