VirtualBox

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

Last change on this file since 7308 was 7308, checked in by vboxsync, 17 years ago

Removed several Q3* classes in the selector window.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 137.1 KB
Line 
1/** @file
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * VBoxGlobal class implementation
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
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
19#include "VBoxGlobal.h"
20
21#include "VBoxDefs.h"
22#include "VBoxSelectorWnd.h"
23#include "VBoxConsoleWnd.h"
24#include "VBoxProblemReporter.h"
25#include "QIHotKeyEdit.h"
26//Added by qt3to4:
27#include <QDesktopWidget>
28#include <Q3CString>
29#include <q3mimefactory.h>
30#include <QTranslator>
31#include <Q3VBoxLayout>
32#include <Q3Frame>
33#include <QEvent>
34#include <QShowEvent>
35#include <Q3PopupMenu>
36#include <Q3HBoxLayout>
37
38#ifdef VBOX_WITH_REGISTRATION
39#include "VBoxRegistrationDlg.h"
40#endif
41
42#include <qapplication.h>
43#include <qmessagebox.h>
44#include <qpixmap.h>
45#include <qicon.h>
46#include <qwidget.h>
47#include <q3filedialog.h>
48#include <qimage.h>
49#include <qlabel.h>
50#include <qtoolbutton.h>
51
52#ifdef Q_WS_X11
53#include <q3textbrowser.h>
54#include <qpushbutton.h>
55#include <qlayout.h>
56#endif
57
58#include <qfileinfo.h>
59#include <qdir.h>
60#include <qmutex.h>
61#include <qregexp.h>
62#include <qlocale.h>
63#include <q3process.h>
64
65#if defined (Q_WS_MAC)
66#include <Carbon/Carbon.h> // for HIToolbox/InternetConfig
67#endif
68
69#if defined (Q_WS_WIN)
70#include "shlobj.h"
71#include <qeventloop.h>
72#endif
73
74#if defined (Q_WS_X11)
75#undef BOOL /* typedef CARD8 BOOL in Xmd.h conflicts with #define BOOL PRBool
76 * in COMDefs.h. A better fix would be to isolate X11-specific
77 * stuff by placing XX* helpers below to a separate source file. */
78#include <X11/X.h>
79#include <X11/Xmd.h>
80#include <X11/Xlib.h>
81#include <X11/Xatom.h>
82#define BOOL PRBool
83#endif
84
85#include <iprt/err.h>
86#include <iprt/param.h>
87#include <iprt/path.h>
88#include <iprt/env.h>
89
90#if defined (Q_WS_X11)
91#include <iprt/mem.h>
92#endif
93
94#if defined (VBOX_GUI_DEBUG)
95uint64_t VMCPUTimer::ticks_per_msec = (uint64_t) -1LL; // declared in VBoxDefs.h
96#endif
97
98// VBoxEnumerateMediaEvent
99/////////////////////////////////////////////////////////////////////////////
100
101class VBoxEnumerateMediaEvent : public QEvent
102{
103public:
104
105 /** Constructs a regular enum event */
106 VBoxEnumerateMediaEvent (const VBoxMedia &aMedia, int aIndex)
107 : QEvent ((QEvent::Type) VBoxDefs::EnumerateMediaEventType)
108 , mMedia (aMedia), mLast (false), mIndex (aIndex)
109 {}
110 /** Constructs the last enum event */
111 VBoxEnumerateMediaEvent()
112 : QEvent ((QEvent::Type) VBoxDefs::EnumerateMediaEventType)
113 , mLast (true), mIndex (-1)
114 {}
115
116 /** the last enumerated media (not valid when #last is true) */
117 const VBoxMedia mMedia;
118 /** whether this is the last event for the given enumeration or not */
119 const bool mLast;
120 /** last enumerated media index (-1 when #last is true) */
121 const int mIndex;
122};
123
124#if defined (Q_WS_WIN)
125class VBoxShellExecuteEvent : public QEvent
126{
127public:
128
129 /** Constructs a regular enum event */
130 VBoxShellExecuteEvent (QThread *aThread, const QString &aURL,
131 bool aOk)
132 : QEvent ((QEvent::Type) VBoxDefs::ShellExecuteEventType)
133 , mThread (aThread), mURL (aURL), mOk (aOk)
134 {}
135
136 QThread *mThread;
137 QString mURL;
138 bool mOk;
139};
140#endif
141
142// VirtualBox callback class
143/////////////////////////////////////////////////////////////////////////////
144
145class VBoxCallback : public IVirtualBoxCallback
146{
147public:
148
149 VBoxCallback (VBoxGlobal &aGlobal)
150 : mGlobal (aGlobal), mIsRegDlgOwner (false)
151 {
152#if defined (Q_OS_WIN32)
153 refcnt = 0;
154#endif
155 }
156
157 virtual ~VBoxCallback() {}
158
159 NS_DECL_ISUPPORTS
160
161#if defined (Q_OS_WIN32)
162 STDMETHOD_(ULONG, AddRef)()
163 {
164 return ::InterlockedIncrement (&refcnt);
165 }
166 STDMETHOD_(ULONG, Release)()
167 {
168 long cnt = ::InterlockedDecrement (&refcnt);
169 if (cnt == 0)
170 delete this;
171 return cnt;
172 }
173 STDMETHOD(QueryInterface) (REFIID riid , void **ppObj)
174 {
175 if (riid == IID_IUnknown) {
176 *ppObj = this;
177 AddRef();
178 return S_OK;
179 }
180 if (riid == IID_IVirtualBoxCallback) {
181 *ppObj = this;
182 AddRef();
183 return S_OK;
184 }
185 *ppObj = NULL;
186 return E_NOINTERFACE;
187 }
188#endif
189
190 // IVirtualBoxCallback methods
191
192 // Note: we need to post custom events to the GUI event queue
193 // instead of doing what we need directly from here because on Win32
194 // these callback methods are never called on the main GUI thread.
195 // Another reason to handle events asynchronously is that internally
196 // most callback interface methods are called from under the initiator
197 // object's lock, so accessing the initiator object (for example, reading
198 // some property) directly from the callback method will definitely cause
199 // a deadlock.
200
201 STDMETHOD(OnMachineStateChange) (IN_GUIDPARAM id, MachineState_T state)
202 {
203 postEvent (new VBoxMachineStateChangeEvent (COMBase::ToQUuid (id),
204 (KMachineState) state));
205 return S_OK;
206 }
207
208 STDMETHOD(OnMachineDataChange) (IN_GUIDPARAM id)
209 {
210 postEvent (new VBoxMachineDataChangeEvent (COMBase::ToQUuid (id)));
211 return S_OK;
212 }
213
214 STDMETHOD(OnExtraDataCanChange)(IN_GUIDPARAM id,
215 IN_BSTRPARAM key, IN_BSTRPARAM value,
216 BSTR *error, BOOL *allowChange)
217 {
218 if (!error || !allowChange)
219 return E_INVALIDARG;
220
221 if (COMBase::ToQUuid (id).isNull())
222 {
223 /* it's a global extra data key someone wants to change */
224 QString sKey = QString::fromUcs2 (key);
225 QString sVal = QString::fromUcs2 (value);
226 if (sKey.startsWith ("GUI/"))
227 {
228 if (sKey == VBoxDefs::GUI_RegistrationDlgWinID)
229 {
230 if (mIsRegDlgOwner)
231 {
232 if (sVal.isEmpty() ||
233 sVal == QString ("%1").arg ((long)qApp->mainWidget()->winId()))
234 *allowChange = TRUE;
235 else
236 *allowChange = FALSE;
237 }
238 else
239 *allowChange = TRUE;
240 return S_OK;
241 }
242
243 /* try to set the global setting to check its syntax */
244 VBoxGlobalSettings gs (false /* non-null */);
245 if (gs.setPublicProperty (sKey, sVal))
246 {
247 /* this is a known GUI property key */
248 if (!gs)
249 {
250 /* disallow the change when there is an error*/
251 *error = SysAllocString ((const OLECHAR *)
252 gs.lastError().ucs2());
253 *allowChange = FALSE;
254 }
255 else
256 *allowChange = TRUE;
257 return S_OK;
258 }
259 }
260 }
261
262 /* not interested in this key -- never disagree */
263 *allowChange = TRUE;
264 return S_OK;
265 }
266
267 STDMETHOD(OnExtraDataChange) (IN_GUIDPARAM id,
268 IN_BSTRPARAM key, IN_BSTRPARAM value)
269 {
270 if (COMBase::ToQUuid (id).isNull())
271 {
272 QString sKey = QString::fromUcs2 (key);
273 QString sVal = QString::fromUcs2 (value);
274 if (sKey.startsWith ("GUI/"))
275 {
276 if (sKey == VBoxDefs::GUI_RegistrationDlgWinID)
277 {
278 if (sVal.isEmpty())
279 {
280 mIsRegDlgOwner = false;
281 QApplication::postEvent (&mGlobal, new VBoxCanShowRegDlgEvent (true));
282 }
283 else if (sVal == QString ("%1").arg ((long) qApp->mainWidget()->winId()))
284 {
285 mIsRegDlgOwner = true;
286 QApplication::postEvent (&mGlobal, new VBoxCanShowRegDlgEvent (true));
287 }
288 else
289 QApplication::postEvent (&mGlobal, new VBoxCanShowRegDlgEvent (false));
290 }
291
292 mMutex.lock();
293 mGlobal.gset.setPublicProperty (sKey, sVal);
294 mMutex.unlock();
295 Assert (!!mGlobal.gset);
296 }
297 }
298 return S_OK;
299 }
300
301 STDMETHOD(OnMediaRegistered) (IN_GUIDPARAM id, DeviceType_T type,
302 BOOL registered)
303 {
304 /** @todo */
305 Q_UNUSED (id);
306 Q_UNUSED (type);
307 Q_UNUSED (registered);
308 return S_OK;
309 }
310
311 STDMETHOD(OnMachineRegistered) (IN_GUIDPARAM id, BOOL registered)
312 {
313 postEvent (new VBoxMachineRegisteredEvent (COMBase::ToQUuid (id),
314 registered));
315 return S_OK;
316 }
317
318 STDMETHOD(OnSessionStateChange) (IN_GUIDPARAM id, SessionState_T state)
319 {
320 postEvent (new VBoxSessionStateChangeEvent (COMBase::ToQUuid (id),
321 (KSessionState) state));
322 return S_OK;
323 }
324
325 STDMETHOD(OnSnapshotTaken) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
326 {
327 postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
328 COMBase::ToQUuid (aSnapshotId),
329 VBoxSnapshotEvent::Taken));
330 return S_OK;
331 }
332
333 STDMETHOD(OnSnapshotDiscarded) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
334 {
335 postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
336 COMBase::ToQUuid (aSnapshotId),
337 VBoxSnapshotEvent::Discarded));
338 return S_OK;
339 }
340
341 STDMETHOD(OnSnapshotChange) (IN_GUIDPARAM aMachineId, IN_GUIDPARAM aSnapshotId)
342 {
343 postEvent (new VBoxSnapshotEvent (COMBase::ToQUuid (aMachineId),
344 COMBase::ToQUuid (aSnapshotId),
345 VBoxSnapshotEvent::Changed));
346 return S_OK;
347 }
348
349private:
350
351 void postEvent (QEvent *e)
352 {
353 // currently, we don't post events if we are in the VM execution
354 // console mode, to save some CPU ticks (so far, there was no need
355 // to handle VirtualBox callback events in the execution console mode)
356
357 if (!mGlobal.isVMConsoleProcess())
358 QApplication::postEvent (&mGlobal, e);
359 }
360
361 VBoxGlobal &mGlobal;
362
363 /** protects #OnExtraDataChange() */
364 QMutex mMutex;
365
366 bool mIsRegDlgOwner;
367
368#if defined (Q_OS_WIN32)
369private:
370 long refcnt;
371#endif
372};
373
374#if !defined (Q_OS_WIN32)
375NS_DECL_CLASSINFO (VBoxCallback)
376NS_IMPL_THREADSAFE_ISUPPORTS1_CI (VBoxCallback, IVirtualBoxCallback)
377#endif
378
379// Helpers for VBoxGlobal::getOpenFileName() & getExistingDirectory()
380/////////////////////////////////////////////////////////////////////////////
381
382#if defined Q_WS_WIN
383
384extern void qt_enter_modal (QWidget*);
385extern void qt_leave_modal (QWidget*);
386
387static QString extractFilter (const QString &aRawFilter)
388{
389 static const char qt_file_dialog_filter_reg_exp[] =
390 "([a-zA-Z0-9 ]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$";
391
392 QString result = aRawFilter;
393 QRegExp r (QString::fromLatin1 (qt_file_dialog_filter_reg_exp));
394 int index = r.search (result);
395 if (index >= 0)
396 result = r.cap (2);
397 return result.replace (QChar (' '), QChar (';'));
398}
399
400/**
401 * Converts QFileDialog filter list to Win32 API filter list.
402 */
403static QString winFilter (const QString &aFilter)
404{
405 QStringList filterLst;
406
407 if (!aFilter.isEmpty())
408 {
409 int i = aFilter.find (";;", 0);
410 QString sep (";;");
411 if (i == -1)
412 {
413 if (aFilter.find ("\n", 0) != -1)
414 {
415 sep = "\n";
416 i = aFilter.find (sep, 0);
417 }
418 }
419
420 filterLst = QStringList::split (sep, aFilter);
421 }
422
423 QStringList::Iterator it = filterLst.begin();
424 QString winfilters;
425 for (; it != filterLst.end(); ++it)
426 {
427 winfilters += *it;
428 winfilters += QChar::Null;
429 winfilters += extractFilter (*it);
430 winfilters += QChar::Null;
431 }
432 winfilters += QChar::Null;
433 return winfilters;
434}
435
436/*
437 * Callback function to control the native Win32 API file dialog
438 */
439UINT_PTR CALLBACK OFNHookProc (HWND aHdlg, UINT aUiMsg, WPARAM aWParam, LPARAM aLParam)
440{
441 if (aUiMsg == WM_NOTIFY)
442 {
443 OFNOTIFY *notif = (OFNOTIFY*) aLParam;
444 if (notif->hdr.code == CDN_TYPECHANGE)
445 {
446 /* locate native dialog controls */
447 HWND parent = GetParent (aHdlg);
448 HWND button = GetDlgItem (parent, IDOK);
449 HWND textfield = ::GetDlgItem (parent, cmb13);
450 if (textfield == NULL)
451 textfield = ::GetDlgItem (parent, edt1);
452 if (textfield == NULL)
453 return FALSE;
454 HWND selector = ::GetDlgItem (parent, cmb1);
455
456 /* simulate filter change by pressing apply-key */
457 int size = 256;
458 TCHAR *buffer = (TCHAR*)malloc (size);
459 SendMessage (textfield, WM_GETTEXT, size, (LPARAM)buffer);
460 SendMessage (textfield, WM_SETTEXT, 0, (LPARAM)"\0");
461 SendMessage (button, BM_CLICK, 0, 0);
462 SendMessage (textfield, WM_SETTEXT, 0, (LPARAM)buffer);
463 free (buffer);
464
465 /* make request for focus moving to filter selector combo-box */
466 HWND curFocus = GetFocus();
467 PostMessage (curFocus, WM_KILLFOCUS, (WPARAM)selector, 0);
468 PostMessage (selector, WM_SETFOCUS, (WPARAM)curFocus, 0);
469 WPARAM wParam = MAKEWPARAM (WA_ACTIVE, 0);
470 PostMessage (selector, WM_ACTIVATE, wParam, (LPARAM)curFocus);
471 }
472 }
473 return FALSE;
474}
475
476/*
477 * Callback function to control the native Win32 API folders dialog
478 */
479static int __stdcall winGetExistDirCallbackProc (HWND hwnd, UINT uMsg,
480 LPARAM lParam, LPARAM lpData)
481{
482 if (uMsg == BFFM_INITIALIZED && lpData != 0)
483 {
484 QString *initDir = (QString *)(lpData);
485 if (!initDir->isEmpty())
486 {
487 SendMessage (hwnd, BFFM_SETSELECTION, TRUE, Q_ULONG (initDir->ucs2()));
488 //SendMessage (hwnd, BFFM_SETEXPANDED, TRUE, Q_ULONG (initDir->ucs2()));
489 }
490 }
491 else if (uMsg == BFFM_SELCHANGED)
492 {
493 TCHAR path [MAX_PATH];
494 SHGetPathFromIDList (LPITEMIDLIST (lParam), path);
495 QString tmpStr = QString::fromUcs2 ((ushort*)path);
496 if (!tmpStr.isEmpty())
497 SendMessage (hwnd, BFFM_ENABLEOK, 1, 1);
498 else
499 SendMessage (hwnd, BFFM_ENABLEOK, 0, 0);
500 SendMessage (hwnd, BFFM_SETSTATUSTEXT, 1, Q_ULONG (path));
501 }
502 return 0;
503}
504
505/**
506 * QEvent class to carry Win32 API native dialog's result information
507 */
508class OpenNativeDialogEvent : public QEvent
509{
510public:
511
512 OpenNativeDialogEvent (const QString &aResult, QEvent::Type aType)
513 : QEvent (aType), mResult (aResult) {}
514
515 const QString& result() { return mResult; }
516
517private:
518
519 QString mResult;
520};
521
522/**
523 * QObject class reimplementation which is the target for OpenNativeDialogEvent
524 * event. It receives OpenNativeDialogEvent event from another thread,
525 * stores result information and exits event processing loop.
526 */
527class LoopObject : public QObject
528{
529public:
530
531 LoopObject (QEvent::Type aType) : mType (aType), mResult (QString::null) {}
532 const QString& result() { return mResult; }
533
534private:
535
536 bool event (QEvent *aEvent)
537 {
538 if (aEvent->type() == mType)
539 {
540 OpenNativeDialogEvent *ev = (OpenNativeDialogEvent*) aEvent;
541 mResult = ev->result();
542 qApp->eventLoop()->exitLoop();
543 return true;
544 }
545 return QObject::event (aEvent);
546 }
547
548 QEvent::Type mType;
549 QString mResult;
550};
551
552#endif /* Q_WS_WIN */
553
554#ifdef Q_WS_X11
555/**
556 * This class is used to show a user license under linux.
557 */
558class VBoxLicenseViewer : public QDialog
559{
560 Q_OBJECT
561
562public:
563
564 VBoxLicenseViewer (const QString &aFilePath)
565 : QDialog (0, "VBoxLicenseViewerObject")
566 , mFilePath (aFilePath)
567 , mLicenseText (0), mAgreeButton (0), mDisagreeButton (0)
568 {
569 setCaption ("VirtualBox License");
570 setIcon (QPixmap (":/ico40x01.png"));
571
572 mLicenseText = new Q3TextBrowser (this);
573 mAgreeButton = new QPushButton (tr ("I &Agree"), this);
574 mDisagreeButton = new QPushButton (tr ("I &Disagree"), this);
575
576 mLicenseText->setTextFormat (Qt::RichText);
577
578 connect (mLicenseText->verticalScrollBar(), SIGNAL (valueChanged (int)),
579 SLOT (onScrollBarMoving (int)));
580 connect (mAgreeButton, SIGNAL (clicked()), SLOT (accept()));
581 connect (mDisagreeButton, SIGNAL (clicked()), SLOT (reject()));
582
583 Q3VBoxLayout *mainLayout = new Q3VBoxLayout (this, 10, 10);
584 mainLayout->addWidget (mLicenseText);
585
586 Q3HBoxLayout *buttonLayout = new Q3HBoxLayout (mainLayout, 10);
587 buttonLayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding,
588 QSizePolicy::Preferred));
589 buttonLayout->addWidget (mAgreeButton);
590 buttonLayout->addWidget (mDisagreeButton);
591
592 mLicenseText->verticalScrollBar()->installEventFilter (this);
593
594 resize (600, 450);
595 }
596
597public slots:
598
599 int exec()
600 {
601 /* read & show the license file */
602 QFile file (mFilePath);
603 if (file.open (QIODevice::ReadOnly))
604 {
605 mLicenseText->setText (file.readAll());
606 return QDialog::exec();
607 }
608 else
609 {
610 vboxProblem().cannotOpenLicenseFile (this, mFilePath);
611 return QDialog::Rejected;
612 }
613 }
614
615private slots:
616
617 void onScrollBarMoving (int aValue)
618 {
619 if (aValue == mLicenseText->verticalScrollBar()->maxValue())
620 unlockButtons();
621 }
622
623 void unlockButtons()
624 {
625 mAgreeButton->setEnabled (true);
626 mDisagreeButton->setEnabled (true);
627 }
628
629private:
630
631 void showEvent (QShowEvent *aEvent)
632 {
633 QDialog::showEvent (aEvent);
634 bool isScrollBarHidden = mLicenseText->verticalScrollBar()->isHidden()
635 && !(windowState() & Qt::WindowMinimized);
636 mAgreeButton->setEnabled (isScrollBarHidden);
637 mDisagreeButton->setEnabled (isScrollBarHidden);
638 }
639
640 bool eventFilter (QObject *aObject, QEvent *aEvent)
641 {
642 switch (aEvent->type())
643 {
644 case QEvent::Hide:
645 if (aObject == mLicenseText->verticalScrollBar() &&
646 (windowState() & Qt::WindowActive))
647 unlockButtons();
648 default:
649 break;
650 }
651 return QDialog::eventFilter (aObject, aEvent);
652 }
653
654 QString mFilePath;
655 Q3TextBrowser *mLicenseText;
656 QPushButton *mAgreeButton;
657 QPushButton *mDisagreeButton;
658};
659#endif
660
661
662// VBoxGlobal
663////////////////////////////////////////////////////////////////////////////////
664
665static bool sVBoxGlobalInited = false;
666static bool sVBoxGlobalInCleanup = false;
667
668/** @internal
669 *
670 * Special routine to do VBoxGlobal cleanup when the application is being
671 * terminated. It is called before some essential Qt functionality (for
672 * instance, QThread) becomes unavailable, allowing us to use it from
673 * VBoxGlobal::cleanup() if necessary.
674 */
675static void vboxGlobalCleanup()
676{
677 Assert (!sVBoxGlobalInCleanup);
678 sVBoxGlobalInCleanup = true;
679 vboxGlobal().cleanup();
680}
681
682/** @internal
683 *
684 * Determines the rendering mode from the argument. Sets the appropriate
685 * default rendering mode if the argumen is NULL.
686 */
687static VBoxDefs::RenderMode vboxGetRenderMode (const char *aModeStr)
688{
689 VBoxDefs::RenderMode mode = VBoxDefs::InvalidRenderMode;
690
691#if defined (Q_WS_MAC) && defined (VBOX_GUI_USE_QUARTZ2D)
692 mode = VBoxDefs::Quartz2DMode;
693#elif (defined (Q_WS_WIN32) || defined (Q_WS_PM)) && defined (VBOX_GUI_USE_QIMAGE)
694 mode = VBoxDefs::QImageMode;
695#elif defined (Q_WS_X11) && defined (VBOX_GUI_USE_SDL)
696 mode = VBoxDefs::SDLMode;
697#elif defined (VBOX_GUI_USE_QIMAGE)
698 mode = VBoxDefs::QImageMode;
699#else
700# error "Cannot determine the default render mode!"
701#endif
702
703 if (aModeStr)
704 {
705 if (0) ;
706#if defined (VBOX_GUI_USE_REFRESH_TIMER)
707 else if (::strcmp (aModeStr, "timer") == 0)
708 mode = VBoxDefs::TimerMode;
709#endif
710#if defined (VBOX_GUI_USE_QIMAGE)
711 else if (::strcmp (aModeStr, "image") == 0)
712 mode = VBoxDefs::QImageMode;
713#endif
714#if defined (VBOX_GUI_USE_SDL)
715 else if (::strcmp (aModeStr, "sdl") == 0)
716 mode = VBoxDefs::SDLMode;
717#endif
718#if defined (VBOX_GUI_USE_DDRAW)
719 else if (::strcmp (aModeStr, "ddraw") == 0)
720 mode = VBoxDefs::DDRAWMode;
721#endif
722#if defined (VBOX_GUI_USE_QUARTZ2D)
723 else if (::strcmp (aModeStr, "quartz2d") == 0)
724 mode = VBoxDefs::Quartz2DMode;
725#endif
726 }
727
728 return mode;
729}
730
731/** @class VBoxGlobal
732 *
733 * The VBoxGlobal class incapsulates the global VirtualBox data.
734 *
735 * There is only one instance of this class per VirtualBox application,
736 * the reference to it is returned by the static instance() method, or by
737 * the global vboxGlobal() function, that is just an inlined shortcut.
738 */
739
740VBoxGlobal::VBoxGlobal()
741 : mValid (false)
742 , mSelectorWnd (NULL), mConsoleWnd (NULL)
743#ifdef VBOX_WITH_REGISTRATION
744 , mRegDlg (NULL)
745#endif
746 , media_enum_thread (NULL)
747 , verString ("1.0")
748 , vm_state_color (KMachineState_COUNT)
749 , machineStates (KMachineState_COUNT)
750 , sessionStates (KSessionState_COUNT)
751 , deviceTypes (KDeviceType_COUNT)
752 , diskControllerTypes (KDiskControllerType_COUNT)
753 , diskTypes (KHardDiskType_COUNT)
754 , diskStorageTypes (KHardDiskStorageType_COUNT)
755 , vrdpAuthTypes (KVRDPAuthType_COUNT)
756 , portModeTypes (KPortMode_COUNT)
757 , usbFilterActionTypes (KUSBDeviceFilterAction_COUNT)
758 , diskControllerDevices (3)
759 , audioDriverTypes (KAudioDriverType_COUNT)
760 , audioControllerTypes (KAudioControllerType_COUNT)
761 , networkAdapterTypes (KNetworkAdapterType_COUNT)
762 , networkAttachmentTypes (KNetworkAttachmentType_COUNT)
763 , clipboardTypes (KClipboardMode_COUNT)
764 , ideControllerTypes (KIDEControllerType_COUNT)
765 , USBDeviceStates (KUSBDeviceState_COUNT)
766 , detailReportTemplatesReady (false)
767{
768}
769
770//
771// Public members
772/////////////////////////////////////////////////////////////////////////////
773
774/**
775 * Returns a reference to the global VirtualBox data, managed by this class.
776 *
777 * The main() function of the VBox GUI must call this function soon after
778 * creating a QApplication instance but before opening any of the main windows
779 * (to let the VBoxGlobal initialization procedure use various Qt facilities),
780 * and continue execution only when the isValid() method of the returned
781 * instancereturns true, i.e. do something like:
782 *
783 * @code
784 * if ( !VBoxGlobal::instance().isValid() )
785 * return 1;
786 * @endcode
787 * or
788 * @code
789 * if ( !vboxGlobal().isValid() )
790 * return 1;
791 * @endcode
792 *
793 * @note Some VBoxGlobal methods can be used on a partially constructed
794 * VBoxGlobal instance, i.e. from constructors and methods called
795 * from the VBoxGlobal::init() method, which obtain the instance
796 * using this instance() call or the ::vboxGlobal() function. Currently, such
797 * methods are:
798 * #vmStateText, #vmTypeIcon, #vmTypeText, #vmTypeTextList, #vmTypeFromText.
799 *
800 * @see ::vboxGlobal
801 */
802VBoxGlobal &VBoxGlobal::instance()
803{
804 static VBoxGlobal vboxGlobal_instance;
805
806 if (!sVBoxGlobalInited)
807 {
808 /* check that a QApplication instance is created */
809 if (qApp)
810 {
811 sVBoxGlobalInited = true;
812 vboxGlobal_instance.init();
813 /* add our cleanup handler to the list of Qt post routines */
814 qAddPostRoutine (vboxGlobalCleanup);
815 }
816 else
817 AssertMsgFailed (("Must construct a QApplication first!"));
818 }
819 return vboxGlobal_instance;
820}
821
822/**
823 * Sets the new global settings and saves them to the VirtualBox server.
824 */
825bool VBoxGlobal::setSettings (const VBoxGlobalSettings &gs)
826{
827 gs.save (mVBox);
828
829 if (!mVBox.isOk())
830 {
831 vboxProblem().cannotSaveGlobalConfig (mVBox);
832 return false;
833 }
834
835 /* We don't assign gs to our gset member here, because VBoxCallback
836 * will update gset as necessary when new settings are successfullly
837 * sent to the VirtualBox server by gs.save(). */
838
839 return true;
840}
841
842/**
843 * Returns a reference to the main VBox VM Selector window.
844 * The reference is valid until application termination.
845 *
846 * There is only one such a window per VirtualBox application.
847 */
848VBoxSelectorWnd &VBoxGlobal::selectorWnd()
849{
850#if defined (VBOX_GUI_SEPARATE_VM_PROCESS)
851 AssertMsg (!vboxGlobal().isVMConsoleProcess(),
852 ("Must NOT be a VM console process"));
853#endif
854
855 Assert (mValid);
856
857 if (!mSelectorWnd)
858 {
859 /*
860 * We pass the address of mSelectorWnd to the constructor to let it be
861 * initialized right after the constructor is called. It is necessary
862 * to avoid recursion, since this method may be (and will be) called
863 * from the below constructor or from constructors/methods it calls.
864 */
865 VBoxSelectorWnd *w = new VBoxSelectorWnd (&mSelectorWnd, 0);
866 Assert (w == mSelectorWnd);
867 NOREF(w);
868 }
869
870 return *mSelectorWnd;
871}
872
873/**
874 * Returns a reference to the main VBox VM Console window.
875 * The reference is valid until application termination.
876 *
877 * There is only one such a window per VirtualBox application.
878 */
879VBoxConsoleWnd &VBoxGlobal::consoleWnd()
880{
881#if defined (VBOX_GUI_SEPARATE_VM_PROCESS)
882 AssertMsg (vboxGlobal().isVMConsoleProcess(),
883 ("Must be a VM console process"));
884#endif
885
886 Assert (mValid);
887
888 if (!mConsoleWnd)
889 {
890 /*
891 * We pass the address of mConsoleWnd to the constructor to let it be
892 * initialized right after the constructor is called. It is necessary
893 * to avoid recursion, since this method may be (and will be) called
894 * from the below constructor or from constructors/methods it calls.
895 */
896 VBoxConsoleWnd *w = new VBoxConsoleWnd (&mConsoleWnd, 0, "consoleWnd");
897 Assert (w == mConsoleWnd);
898 NOREF(w);
899 }
900
901 return *mConsoleWnd;
902}
903
904/**
905 * Returns the list of all guest OS type descriptions, queried from
906 * IVirtualBox.
907 */
908QStringList VBoxGlobal::vmGuestOSTypeDescriptions() const
909{
910 static QStringList list;
911 if (list.empty()) {
912 for (uint i = 0; i < vm_os_types.count(); i++) {
913 list += vm_os_types [i].GetDescription();
914 }
915 }
916 return list;
917}
918
919/**
920 * Returns the guest OS type object corresponding to the given index.
921 * The index argument corresponds to the index in the list of OS type
922 * descriptions as returnded by #vmGuestOSTypeDescriptions().
923 *
924 * If the index is invalid a null object is returned.
925 */
926CGuestOSType VBoxGlobal::vmGuestOSType (int aIndex) const
927{
928 CGuestOSType type;
929 if (aIndex >= 0 && aIndex < (int) vm_os_types.count())
930 type = vm_os_types [aIndex];
931 AssertMsg (!type.isNull(), ("Index for OS type must be valid: %d", aIndex));
932 return type;
933}
934
935/**
936 * Returns the index corresponding to the given guest OS type ID.
937 * The returned index corresponds to the index in the list of OS type
938 * descriptions as returnded by #vmGuestOSTypeDescriptions().
939 *
940 * If the guest OS type ID is invalid, -1 is returned.
941 */
942int VBoxGlobal::vmGuestOSTypeIndex (const QString &aId) const
943{
944 for (int i = 0; i < (int) vm_os_types.count(); i++) {
945 if (!vm_os_types [i].GetId().compare (aId))
946 return i;
947 }
948 return -1;
949}
950
951/**
952 * Returns the icon corresponding to the given guest OS type ID.
953 */
954QPixmap VBoxGlobal::vmGuestOSTypeIcon (const QString &aId) const
955{
956 static const QPixmap none;
957 QPixmap *p = vm_os_type_icons [aId];
958 AssertMsg (p, ("Icon for type `%s' must be defined", aId.latin1()));
959 return p ? *p : none;
960}
961
962/**
963 * Returns the description corresponding to the given guest OS type ID.
964 */
965QString VBoxGlobal::vmGuestOSTypeDescription (const QString &aId) const
966{
967 for (int i = 0; i < (int) vm_os_types.count(); i++) {
968 if (!vm_os_types [i].GetId().compare (aId))
969 return vm_os_types [i].GetDescription();
970 }
971 return QString::null;
972}
973
974QString VBoxGlobal::toString (KDiskControllerType t, LONG d) const
975{
976 Assert (diskControllerDevices.count() == 3);
977 QString dev;
978 switch (t)
979 {
980 case KDiskControllerType_IDE0:
981 case KDiskControllerType_IDE1:
982 {
983 if (d == 0 || d == 1)
984 {
985 dev = diskControllerDevices [d];
986 break;
987 }
988 // fall through
989 }
990 default:
991 dev = diskControllerDevices [2].arg (d);
992 }
993 return dev;
994}
995
996/**
997 * Returns the list of all device types (VurtialBox::DeviceType COM enum).
998 */
999QStringList VBoxGlobal::deviceTypeStrings() const
1000{
1001 static QStringList list;
1002 if (list.empty())
1003 for (uint i = 0; i < deviceTypes.count() - 1 /* usb=n/a */; i++)
1004 list += deviceTypes [i];
1005 return list;
1006}
1007
1008struct PortConfig
1009{
1010 const char *name;
1011 const ulong IRQ;
1012 const ulong IOBase;
1013};
1014
1015static const PortConfig comKnownPorts[] =
1016{
1017 { "COM1", 4, 0x3F8 },
1018 { "COM2", 3, 0x2F8 },
1019 { "COM3", 4, 0x3E8 },
1020 { "COM4", 3, 0x2E8 },
1021 /* must not contain an element with IRQ=0 and IOBase=0 used to cause
1022 * toCOMPortName() to return the "User-defined" string for these values. */
1023};
1024
1025static const PortConfig lptKnownPorts[] =
1026{
1027 { "LPT1", 7, 0x3BC },
1028 { "LPT2", 5, 0x378 },
1029 { "LPT3", 5, 0x278 },
1030 /* must not contain an element with IRQ=0 and IOBase=0 used to cause
1031 * toLPTPortName() to return the "User-defined" string for these values. */
1032};
1033
1034/**
1035 * Returns the list of the standard COM port names (i.e. "COMx").
1036 */
1037QStringList VBoxGlobal::COMPortNames() const
1038{
1039 QStringList list;
1040 for (size_t i = 0; i < ELEMENTS (comKnownPorts); ++ i)
1041 list << comKnownPorts [i].name;
1042
1043 return list;
1044}
1045
1046/**
1047 * Returns the list of the standard LPT port names (i.e. "LPTx").
1048 */
1049QStringList VBoxGlobal::LPTPortNames() const
1050{
1051 QStringList list;
1052 for (size_t i = 0; i < ELEMENTS (lptKnownPorts); ++ i)
1053 list << lptKnownPorts [i].name;
1054
1055 return list;
1056}
1057
1058/**
1059 * Returns the name of the standard COM port corresponding to the given
1060 * parameters, or "User-defined" (which is also returned when both
1061 * @a aIRQ and @a aIOBase are 0).
1062 */
1063QString VBoxGlobal::toCOMPortName (ulong aIRQ, ulong aIOBase) const
1064{
1065 for (size_t i = 0; i < ELEMENTS (comKnownPorts); ++ i)
1066 if (comKnownPorts [i].IRQ == aIRQ &&
1067 comKnownPorts [i].IOBase == aIOBase)
1068 return comKnownPorts [i].name;
1069
1070 return mUserDefinedPortName;
1071}
1072
1073/**
1074 * Returns the name of the standard LPT port corresponding to the given
1075 * parameters, or "User-defined" (which is also returned when both
1076 * @a aIRQ and @a aIOBase are 0).
1077 */
1078QString VBoxGlobal::toLPTPortName (ulong aIRQ, ulong aIOBase) const
1079{
1080 for (size_t i = 0; i < ELEMENTS (lptKnownPorts); ++ i)
1081 if (lptKnownPorts [i].IRQ == aIRQ &&
1082 lptKnownPorts [i].IOBase == aIOBase)
1083 return lptKnownPorts [i].name;
1084
1085 return mUserDefinedPortName;
1086}
1087
1088/**
1089 * Returns port parameters corresponding to the given standard COM name.
1090 * Returns @c true on success, or @c false if the given port name is not one
1091 * of the standard names (i.e. "COMx").
1092 */
1093bool VBoxGlobal::toCOMPortNumbers (const QString &aName, ulong &aIRQ,
1094 ulong &aIOBase) const
1095{
1096 for (size_t i = 0; i < ELEMENTS (comKnownPorts); ++ i)
1097 if (strcmp (comKnownPorts [i].name, aName.utf8().data()) == 0)
1098 {
1099 aIRQ = comKnownPorts [i].IRQ;
1100 aIOBase = comKnownPorts [i].IOBase;
1101 return true;
1102 }
1103
1104 return false;
1105}
1106
1107/**
1108 * Returns port parameters corresponding to the given standard LPT name.
1109 * Returns @c true on success, or @c false if the given port name is not one
1110 * of the standard names (i.e. "LPTx").
1111 */
1112bool VBoxGlobal::toLPTPortNumbers (const QString &aName, ulong &aIRQ,
1113 ulong &aIOBase) const
1114{
1115 for (size_t i = 0; i < ELEMENTS (lptKnownPorts); ++ i)
1116 if (strcmp (lptKnownPorts [i].name, aName.utf8().data()) == 0)
1117 {
1118 aIRQ = lptKnownPorts [i].IRQ;
1119 aIOBase = lptKnownPorts [i].IOBase;
1120 return true;
1121 }
1122
1123 return false;
1124}
1125
1126/**
1127 * Returns the details of the given hard disk as a single-line string
1128 * to be used in the VM details view.
1129 *
1130 * The details include the type and the virtual size of the hard disk.
1131 * Note that for differencing hard disks based on immutable hard disks,
1132 * the Immutable hard disk type is returned.
1133 *
1134 * @param aHD hard disk image (when predict = true, must be a top-level image)
1135 * @param aPredict when true, the function predicts the type of the resulting
1136 * image after attaching the given image to the machine.
1137 * Otherwise, a real type of the given image is returned
1138 * (with the exception mentioned above).
1139 *
1140 * @note The hard disk object may become uninitialized by a third party
1141 * while this method is reading its properties. In this case, the method will
1142 * return an empty string.
1143 */
1144QString VBoxGlobal::details (const CHardDisk &aHD, bool aPredict /* = false */,
1145 bool aDoRefresh)
1146{
1147 Assert (!aPredict || aHD.GetParent().isNull());
1148
1149 VBoxMedia media;
1150 if (!aDoRefresh)
1151 media = VBoxMedia (CUnknown (aHD), VBoxDefs::HD, VBoxMedia::Ok);
1152 else if (!findMedia (CUnknown (aHD), media))
1153 {
1154 /* media may be new and not alredy in the media list, request refresh */
1155 startEnumeratingMedia();
1156 if (!findMedia (CUnknown (aHD), media))
1157 AssertFailed();
1158 }
1159
1160 CHardDisk root = aHD.GetRoot();
1161
1162 // @todo *** this check is rough; if aHD becomes uninitialized, any of aHD
1163 // getters called afterwards will also fail. The same relates to the root
1164 // object (that will be aHD itself in case of non-differencing
1165 // disks). However, this check was added to fix a particular use case:
1166 // when aHD is a differencing hard disk and it happens to be discarded
1167 // (and uninitialized) after this method is called but before we read all
1168 // its properties (yes, it's possible!), the root object will be null and
1169 // calling methods on it will assert in the debug builds. This check seems
1170 // to be enough as a quick solution (fresh hard disk attachments will be
1171 // re-read by a state change signal after the discard operation is
1172 // finished, so the user will eventually see correct data), but in order
1173 // to solve the problem properly we need to use exceptions everywhere (or
1174 // check the result after every method call). See also Comment #17 and
1175 // below in Defect #2126.
1176 if (!aHD.isOk())
1177 return QString::null;
1178
1179 QString details;
1180
1181 KHardDiskType type = root.GetType();
1182
1183 if (type == KHardDiskType_Normal &&
1184 (aHD != root || (aPredict && root.GetChildren().GetCount() != 0)))
1185 details = tr ("Differencing", "hard disk");
1186 else
1187 details = hardDiskTypeString (root);
1188
1189 details += ", ";
1190
1191 /// @todo prepend the details with the warning/error
1192 // icon when not accessible
1193
1194 switch (media.status)
1195 {
1196 case VBoxMedia::Unknown:
1197 details += tr ("<i>Checking...</i>", "hard disk");
1198 break;
1199 case VBoxMedia::Ok:
1200 details += formatSize (root.GetSize() * _1M);
1201 break;
1202 case VBoxMedia::Error:
1203 case VBoxMedia::Inaccessible:
1204 details += tr ("<i>Inaccessible</i>", "hard disk");
1205 break;
1206 }
1207
1208 return details;
1209}
1210
1211/**
1212 * Returns the details of the given USB device as a single-line string.
1213 */
1214QString VBoxGlobal::details (const CUSBDevice &aDevice) const
1215{
1216 QString details;
1217 QString m = aDevice.GetManufacturer().stripWhiteSpace();
1218 QString p = aDevice.GetProduct().stripWhiteSpace();
1219 if (m.isEmpty() && p.isEmpty())
1220 {
1221 details =
1222 tr ("Unknown device %1:%2", "USB device details")
1223 .arg (QString().sprintf ("%04hX", aDevice.GetVendorId()))
1224 .arg (QString().sprintf ("%04hX", aDevice.GetProductId()));
1225 }
1226 else
1227 {
1228 if (p.upper().startsWith (m.upper()))
1229 details = p;
1230 else
1231 details = m + " " + p;
1232 }
1233 ushort r = aDevice.GetRevision();
1234 if (r != 0)
1235 details += QString().sprintf (" [%04hX]", r);
1236
1237 return details.stripWhiteSpace();
1238}
1239
1240/**
1241 * Returns the multi-line description of the given USB device.
1242 */
1243QString VBoxGlobal::toolTip (const CUSBDevice &aDevice) const
1244{
1245 QString tip =
1246 tr ("<nobr>Vendor ID: %1</nobr><br>"
1247 "<nobr>Product ID: %2</nobr><br>"
1248 "<nobr>Revision: %3</nobr>", "USB device tooltip")
1249 .arg (QString().sprintf ("%04hX", aDevice.GetVendorId()))
1250 .arg (QString().sprintf ("%04hX", aDevice.GetProductId()))
1251 .arg (QString().sprintf ("%04hX", aDevice.GetRevision()));
1252
1253 QString ser = aDevice.GetSerialNumber();
1254 if (!ser.isEmpty())
1255 tip += QString (tr ("<br><nobr>Serial No. %1</nobr>", "USB device tooltip"))
1256 .arg (ser);
1257
1258 /* add the state field if it's a host USB device */
1259 CHostUSBDevice hostDev = CUnknown (aDevice);
1260 if (!hostDev.isNull())
1261 {
1262 tip += QString (tr ("<br><nobr>State: %1</nobr>", "USB device tooltip"))
1263 .arg (vboxGlobal().toString (hostDev.GetState()));
1264 }
1265
1266 return tip;
1267}
1268
1269/**
1270 * Puts soft hyphens after every path component in the given file name.
1271 * @param fn file name (must be a full path name)
1272 */
1273QString VBoxGlobal::prepareFileNameForHTML (const QString &fn) const
1274{
1275/// @todo (dmik) remove?
1276// QString result = QDir::convertSeparators (fn);
1277//#ifdef Q_OS_LINUX
1278// result.replace ('/', "/<font color=red>&shy;</font>");
1279//#else
1280// result.replace ('\\', "\\<font color=red>&shy;</font>");
1281//#endif
1282// return result;
1283 QFileInfo fi (fn);
1284 return fi.fileName();
1285}
1286
1287/**
1288 * Returns a details report on a given VM enclosed in a HTML table.
1289 *
1290 * @param m machine to create a report for
1291 * @param isNewVM true when called by the New VM Wizard
1292 * @param withLinks true if section titles should be hypertext links
1293 */
1294QString VBoxGlobal::detailsReport (const CMachine &m, bool isNewVM,
1295 bool withLinks, bool aDoRefresh)
1296{
1297 static const char *sTableTpl =
1298 "<table border=0 cellspacing=0 cellpadding=0>%1</table>";
1299 static const char *sSectionHrefTpl =
1300 "<tr><td rowspan=%1 align=left><img src='%2'></td>"
1301 "<td colspan=2><b><a href='%3'><nobr>%4</nobr></a></b></td></tr>"
1302 "%5"
1303 "<tr><td colspan=2><font size=1>&nbsp;</font></td></tr>";
1304 static const char *sSectionBoldTpl =
1305 "<tr><td rowspan=%1 align=left><img src='%2'></td>"
1306 "<td colspan=2><!-- %3 --><b><nobr>%4</nobr></b></td></tr>"
1307 "%5"
1308 "<tr><td colspan=2><font size=1>&nbsp;</font></td></tr>";
1309 static const char *sSectionItemTpl =
1310 "<tr><td width=30%><nobr>%1</nobr></td><td>%2</td></tr>";
1311
1312 static QString sGeneralBasicHrefTpl, sGeneralBasicBoldTpl;
1313 static QString sGeneralFullHrefTpl, sGeneralFullBoldTpl;
1314
1315 /* generate templates after every language change */
1316
1317 if (!detailReportTemplatesReady)
1318 {
1319 detailReportTemplatesReady = true;
1320
1321 QString generalItems
1322 = QString (sSectionItemTpl).arg (tr ("Name", "details report"), "%1")
1323 + QString (sSectionItemTpl).arg (tr ("OS Type", "details report"), "%2")
1324 + QString (sSectionItemTpl).arg (tr ("Base Memory", "details report"),
1325 tr ("<nobr>%3 MB</nobr>", "details report"));
1326 sGeneralBasicHrefTpl = QString (sSectionHrefTpl)
1327 .arg (2 + 3) /* rows */
1328 .arg (":/machine_16px.png", /* icon */
1329 "#general", /* link */
1330 tr ("General", "details report"), /* title */
1331 generalItems); /* items */
1332 sGeneralBasicBoldTpl = QString (sSectionBoldTpl)
1333 .arg (2 + 3) /* rows */
1334 .arg (":/machine_16px.png", /* icon */
1335 "#general", /* link */
1336 tr ("General", "details report"), /* title */
1337 generalItems); /* items */
1338
1339 generalItems
1340 += QString (sSectionItemTpl).arg (tr ("Video Memory", "details report"),
1341 tr ("<nobr>%4 MB</nobr>", "details report"))
1342 + QString (sSectionItemTpl).arg (tr ("Boot Order", "details report"), "%5")
1343 + QString (sSectionItemTpl).arg (tr ("ACPI", "details report"), "%6")
1344 + QString (sSectionItemTpl).arg (tr ("IO APIC", "details report"), "%7")
1345 + QString (sSectionItemTpl).arg (tr ("VT-x/AMD-V", "details report"), "%8");
1346
1347 sGeneralFullHrefTpl = QString (sSectionHrefTpl)
1348 .arg (2 + 8) /* rows */
1349 .arg (":/machine_16px.png", /* icon */
1350 "#general", /* link */
1351 tr ("General", "details report"), /* title */
1352 generalItems); /* items */
1353 sGeneralFullBoldTpl = QString (sSectionBoldTpl)
1354 .arg (2 + 8) /* rows */
1355 .arg (":/machine_16px.png", /* icon */
1356 "#general", /* link */
1357 tr ("General", "details report"), /* title */
1358 generalItems); /* items */
1359 }
1360
1361 /* common generated content */
1362
1363 const QString &sectionTpl = withLinks
1364 ? sSectionHrefTpl
1365 : sSectionBoldTpl;
1366
1367 QString hardDisks;
1368 {
1369 int rows = 2; /* including section header and footer */
1370
1371 CHardDiskAttachmentEnumerator aen = m.GetHardDiskAttachments().Enumerate();
1372 while (aen.HasMore())
1373 {
1374 CHardDiskAttachment hda = aen.GetNext();
1375 CHardDisk hd = hda.GetHardDisk();
1376 /// @todo for the explaination of the below isOk() checks, see
1377 /// @todo *** in #details (const CHardDisk &, bool).
1378 if (hda.isOk())
1379 {
1380 CHardDisk root = hd.GetRoot();
1381 if (hd.isOk())
1382 {
1383 QString src = root.GetLocation();
1384 hardDisks += QString (sSectionItemTpl)
1385 .arg (QString ("%1 %2")
1386 .arg (toString (hda.GetController()))
1387 .arg (toString (hda.GetController(),
1388 hda.GetDeviceNumber())))
1389 .arg (QString ("%1 [<nobr>%2</nobr>]")
1390 .arg (prepareFileNameForHTML (src))
1391 .arg (details (hd, isNewVM /* predict */, aDoRefresh)));
1392 ++ rows;
1393 }
1394 }
1395 }
1396
1397 if (hardDisks.isNull())
1398 {
1399 hardDisks = QString (sSectionItemTpl)
1400 .arg (tr ("Not Attached", "details report (HDDs)")).arg ("");
1401 ++ rows;
1402 }
1403
1404 hardDisks = sectionTpl
1405 .arg (rows) /* rows */
1406 .arg (":/hd_16px.png", /* icon */
1407 "#hdds", /* link */
1408 tr ("Hard Disks", "details report"), /* title */
1409 hardDisks); /* items */
1410 }
1411
1412 /* compose details report */
1413
1414 const QString &generalBasicTpl = withLinks
1415 ? sGeneralBasicHrefTpl
1416 : sGeneralBasicBoldTpl;
1417
1418 const QString &generalFullTpl = withLinks
1419 ? sGeneralFullHrefTpl
1420 : sGeneralFullBoldTpl;
1421
1422 QString detailsReport;
1423
1424 if (isNewVM)
1425 {
1426 detailsReport
1427 = generalBasicTpl
1428 .arg (m.GetName())
1429 .arg (vmGuestOSTypeDescription (m.GetOSTypeId()))
1430 .arg (m.GetMemorySize())
1431 + hardDisks;
1432 }
1433 else
1434 {
1435 /* boot order */
1436 QString bootOrder;
1437 for (ulong i = 1; i <= mVBox.GetSystemProperties().GetMaxBootPosition(); i++)
1438 {
1439 KDeviceType device = m.GetBootOrder (i);
1440 if (device == KDeviceType_Null)
1441 continue;
1442 if (!bootOrder.isEmpty())
1443 bootOrder += ", ";
1444 bootOrder += toString (device);
1445 }
1446 if (bootOrder.isEmpty())
1447 bootOrder = toString (KDeviceType_Null);
1448
1449 CBIOSSettings biosSettings = m.GetBIOSSettings();
1450
1451 /* ACPI */
1452 QString acpi = biosSettings.GetACPIEnabled()
1453 ? tr ("Enabled", "details report (ACPI)")
1454 : tr ("Disabled", "details report (ACPI)");
1455
1456 /* IO APIC */
1457 QString ioapic = biosSettings.GetIOAPICEnabled()
1458 ? tr ("Enabled", "details report (IO APIC)")
1459 : tr ("Disabled", "details report (IO APIC)");
1460
1461 /* VT-x/AMD-V */
1462 CSystemProperties props = vboxGlobal().virtualBox().GetSystemProperties();
1463 QString virt = m.GetHWVirtExEnabled() == KTSBool_True ?
1464 tr ("Enabled", "details report (VT-x/AMD-V)") :
1465 m.GetHWVirtExEnabled() == KTSBool_False ?
1466 tr ("Disabled", "details report (VT-x/AMD-V)") :
1467 props.GetHWVirtExEnabled() ?
1468 tr ("Enabled", "details report (VT-x/AMD-V)") :
1469 tr ("Disabled", "details report (VT-x/AMD-V)");
1470
1471 /* General + Hard Disks */
1472 detailsReport
1473 = generalFullTpl
1474 .arg (m.GetName())
1475 .arg (vmGuestOSTypeDescription (m.GetOSTypeId()))
1476 .arg (m.GetMemorySize())
1477 .arg (m.GetVRAMSize())
1478 .arg (bootOrder)
1479 .arg (acpi)
1480 .arg (ioapic)
1481 .arg (virt)
1482 + hardDisks;
1483
1484 QString item;
1485
1486 /* DVD */
1487 CDVDDrive dvd = m.GetDVDDrive();
1488 item = QString (sSectionItemTpl);
1489 switch (dvd.GetState())
1490 {
1491 case KDriveState_NotMounted:
1492 item = item.arg (tr ("Not mounted", "details report (DVD)"), "");
1493 break;
1494 case KDriveState_ImageMounted:
1495 {
1496 CDVDImage img = dvd.GetImage();
1497 item = item.arg (tr ("Image", "details report (DVD)"),
1498 prepareFileNameForHTML (img.GetFilePath()));
1499 break;
1500 }
1501 case KDriveState_HostDriveCaptured:
1502 {
1503 CHostDVDDrive drv = dvd.GetHostDrive();
1504 QString drvName = drv.GetName();
1505 QString description = drv.GetDescription();
1506 QString fullName = description.isEmpty() ?
1507 drvName :
1508 QString ("%1 (%2)").arg (description, drvName);
1509 item = item.arg (tr ("Host Drive", "details report (DVD)"),
1510 fullName);
1511 break;
1512 }
1513 default:
1514 AssertMsgFailed (("Invalid DVD state: %d", dvd.GetState()));
1515 }
1516 detailsReport += sectionTpl
1517 .arg (2 + 1) /* rows */
1518 .arg (":/cd_16px.png", /* icon */
1519 "#dvd", /* link */
1520 tr ("CD/DVD-ROM", "details report"), /* title */
1521 item); // items
1522
1523 /* Floppy */
1524 CFloppyDrive floppy = m.GetFloppyDrive();
1525 item = QString (sSectionItemTpl);
1526 switch (floppy.GetState())
1527 {
1528 case KDriveState_NotMounted:
1529 item = item.arg (tr ("Not mounted", "details report (floppy)"), "");
1530 break;
1531 case KDriveState_ImageMounted:
1532 {
1533 CFloppyImage img = floppy.GetImage();
1534 item = item.arg (tr ("Image", "details report (floppy)"),
1535 prepareFileNameForHTML (img.GetFilePath()));
1536 break;
1537 }
1538 case KDriveState_HostDriveCaptured:
1539 {
1540 CHostFloppyDrive drv = floppy.GetHostDrive();
1541 QString drvName = drv.GetName();
1542 QString description = drv.GetDescription();
1543 QString fullName = description.isEmpty() ?
1544 drvName :
1545 QString ("%1 (%2)").arg (description, drvName);
1546 item = item.arg (tr ("Host Drive", "details report (floppy)"),
1547 fullName);
1548 break;
1549 }
1550 default:
1551 AssertMsgFailed (("Invalid floppy state: %d", floppy.GetState()));
1552 }
1553 detailsReport += sectionTpl
1554 .arg (2 + 1) /* rows */
1555 .arg (":/fd_16px.png", /* icon */
1556 "#floppy", /* link */
1557 tr ("Floppy", "details report"), /* title */
1558 item); /* items */
1559
1560 /* audio */
1561 {
1562 CAudioAdapter audio = m.GetAudioAdapter();
1563 int rows = audio.GetEnabled() ? 3 : 2;
1564 if (audio.GetEnabled())
1565 item = QString (sSectionItemTpl)
1566 .arg (tr ("Host Driver", "details report (audio)"),
1567 toString (audio.GetAudioDriver())) +
1568 QString (sSectionItemTpl)
1569 .arg (tr ("Controller", "details report (audio)"),
1570 toString (audio.GetAudioController()));
1571 else
1572 item = QString (sSectionItemTpl)
1573 .arg (tr ("Disabled", "details report (audio)"), "");
1574
1575 detailsReport += sectionTpl
1576 .arg (rows + 1) /* rows */
1577 .arg (":/sound_16px.png", /* icon */
1578 "#audio", /* link */
1579 tr ("Audio", "details report"), /* title */
1580 item); /* items */
1581 }
1582 /* network */
1583 {
1584 item = QString::null;
1585 ulong count = mVBox.GetSystemProperties().GetNetworkAdapterCount();
1586 int rows = 2; /* including section header and footer */
1587 for (ulong slot = 0; slot < count; slot ++)
1588 {
1589 CNetworkAdapter adapter = m.GetNetworkAdapter (slot);
1590 if (adapter.GetEnabled())
1591 {
1592 KNetworkAttachmentType type = adapter.GetAttachmentType();
1593 QString attType = toString (adapter.GetAdapterType())
1594 .replace (QRegExp ("\\s\\(.+\\)"), " (%1)");
1595 /* don't use the adapter type string for types that have
1596 * an additional symbolic network/interface name field, use
1597 * this name instead */
1598 if (type == KNetworkAttachmentType_HostInterface)
1599 attType = attType.arg (tr ("host interface, %1",
1600 "details report (network)").arg (adapter.GetHostInterface()));
1601 else if (type == KNetworkAttachmentType_Internal)
1602 attType = attType.arg (tr ("internal network, '%1'",
1603 "details report (network)").arg (adapter.GetInternalNetwork()));
1604 else
1605 attType = attType.arg (vboxGlobal().toString (type));
1606
1607 item += QString (sSectionItemTpl)
1608 .arg (tr ("Adapter %1", "details report (network)")
1609 .arg (adapter.GetSlot()))
1610 .arg (attType);
1611 ++ rows;
1612 }
1613 }
1614 if (item.isNull())
1615 {
1616 item = QString (sSectionItemTpl)
1617 .arg (tr ("Disabled", "details report (network)"), "");
1618 ++ rows;
1619 }
1620
1621 detailsReport += sectionTpl
1622 .arg (rows) /* rows */
1623 .arg (":/nw_16px.png", /* icon */
1624 "#network", /* link */
1625 tr ("Network", "details report"), /* title */
1626 item); /* items */
1627 }
1628 /* serial ports */
1629 {
1630 item = QString::null;
1631 ulong count = mVBox.GetSystemProperties().GetSerialPortCount();
1632 int rows = 2; /* including section header and footer */
1633 for (ulong slot = 0; slot < count; slot ++)
1634 {
1635 CSerialPort port = m.GetSerialPort (slot);
1636 if (port.GetEnabled())
1637 {
1638 KPortMode mode = port.GetHostMode();
1639 QString data =
1640 toCOMPortName (port.GetIRQ(), port.GetIOBase()) + ", ";
1641 if (mode == KPortMode_HostPipe ||
1642 mode == KPortMode_HostDevice)
1643 data += QString ("%1 (<nobr>%2</nobr>)")
1644 .arg (vboxGlobal().toString (mode))
1645 .arg (QDir::convertSeparators (port.GetPath()));
1646 else
1647 data += toString (mode);
1648
1649 item += QString (sSectionItemTpl)
1650 .arg (tr ("Port %1", "details report (serial ports)")
1651 .arg (port.GetSlot()))
1652 .arg (data);
1653 ++ rows;
1654 }
1655 }
1656 if (item.isNull())
1657 {
1658 item = QString (sSectionItemTpl)
1659 .arg (tr ("Disabled", "details report (serial ports)"), "");
1660 ++ rows;
1661 }
1662
1663 detailsReport += sectionTpl
1664 .arg (rows) /* rows */
1665 .arg (":/serial_port_16px.png", /* icon */
1666 "#serialPorts", /* link */
1667 tr ("Serial Ports", "details report"), /* title */
1668 item); /* items */
1669 }
1670 /* parallel ports */
1671 {
1672 item = QString::null;
1673 ulong count = mVBox.GetSystemProperties().GetParallelPortCount();
1674 int rows = 2; /* including section header and footer */
1675 for (ulong slot = 0; slot < count; slot ++)
1676 {
1677 CParallelPort port = m.GetParallelPort (slot);
1678 if (port.GetEnabled())
1679 {
1680 QString data =
1681 toLPTPortName (port.GetIRQ(), port.GetIOBase()) +
1682 QString (" (<nobr>%1</nobr>)")
1683 .arg (QDir::convertSeparators (port.GetPath()));
1684
1685 item += QString (sSectionItemTpl)
1686 .arg (tr ("Port %1", "details report (parallel ports)")
1687 .arg (port.GetSlot()))
1688 .arg (data);
1689 ++ rows;
1690 }
1691 }
1692 if (item.isNull())
1693 {
1694 item = QString (sSectionItemTpl)
1695 .arg (tr ("Disabled", "details report (parallel ports)"), "");
1696 ++ rows;
1697 }
1698
1699 /* Temporary disabled */
1700 QString dummy = sectionTpl /* detailsReport += sectionTpl */
1701 .arg (rows) /* rows */
1702 .arg (":/parallel_port_16px.png", /* icon */
1703 "#parallelPorts", /* link */
1704 tr ("Parallel Ports", "details report"), /* title */
1705 item); /* items */
1706 }
1707 /* USB */
1708 {
1709 CUSBController ctl = m.GetUSBController();
1710 if (!ctl.isNull())
1711 {
1712 /* the USB controller may be unavailable (i.e. in VirtualBox OSE) */
1713
1714 if (ctl.GetEnabled())
1715 {
1716 CUSBDeviceFilterCollection coll = ctl.GetDeviceFilters();
1717 CUSBDeviceFilterEnumerator en = coll.Enumerate();
1718 uint active = 0;
1719 while (en.HasMore())
1720 if (en.GetNext().GetActive())
1721 active ++;
1722
1723 item = QString (sSectionItemTpl)
1724 .arg (tr ("Device Filters", "details report (USB)"),
1725 tr ("%1 (%2 active)", "details report (USB)")
1726 .arg (coll.GetCount()).arg (active));
1727 }
1728 else
1729 item = QString (sSectionItemTpl)
1730 .arg (tr ("Disabled", "details report (USB)"), "");
1731
1732 detailsReport += sectionTpl
1733 .arg (2 + 1) /* rows */
1734 .arg (":/usb_16px.png", /* icon */
1735 "#usb", /* link */
1736 tr ("USB", "details report"), /* title */
1737 item); /* items */
1738 }
1739 }
1740 /* Shared folders */
1741 {
1742 ulong count = m.GetSharedFolders().GetCount();
1743 if (count > 0)
1744 {
1745 item = QString (sSectionItemTpl)
1746 .arg (tr ("Shared Folders", "details report (shared folders)"),
1747 tr ("%1", "details report (shadef folders)")
1748 .arg (count));
1749 }
1750 else
1751 item = QString (sSectionItemTpl)
1752 .arg (tr ("None", "details report (shared folders)"), "");
1753
1754 detailsReport += sectionTpl
1755 .arg (2 + 1) /* rows */
1756 .arg (":/shared_folder_16px.png", /* icon */
1757 "#sfolders", /* link */
1758 tr ("Shared Folders", "details report"), /* title */
1759 item); /* items */
1760 }
1761 /* VRDP */
1762 {
1763 CVRDPServer srv = m.GetVRDPServer();
1764 if (!srv.isNull())
1765 {
1766 /* the VRDP server may be unavailable (i.e. in VirtualBox OSE) */
1767
1768 if (srv.GetEnabled())
1769 item = QString (sSectionItemTpl)
1770 .arg (tr ("VRDP Server Port", "details report (VRDP)"),
1771 tr ("%1", "details report (VRDP)")
1772 .arg (srv.GetPort()));
1773 else
1774 item = QString (sSectionItemTpl)
1775 .arg (tr ("Disabled", "details report (VRDP)"), "");
1776
1777 detailsReport += sectionTpl
1778 .arg (2 + 1) /* rows */
1779 .arg (":/vrdp_16px.png", /* icon */
1780 "#vrdp", /* link */
1781 tr ("Remote Display", "details report"), /* title */
1782 item); /* items */
1783 }
1784 }
1785 }
1786
1787 return QString (sTableTpl). arg (detailsReport);
1788}
1789
1790#ifdef Q_WS_X11
1791bool VBoxGlobal::showVirtualBoxLicense()
1792{
1793 /* get the apps doc path */
1794 int size = 256;
1795 char *buffer = (char*) RTMemTmpAlloc (size);
1796 RTPathAppDocs (buffer, size);
1797 QString path (buffer);
1798 RTMemTmpFree (buffer);
1799 QDir docDir (path);
1800 docDir.setFilter (QDir::Files);
1801 docDir.setNameFilter ("License-*.html");
1802
1803 /* get the license files list and search for the latest license */
1804 QStringList filesList = docDir.entryList();
1805 double maxVersionNumber = 0;
1806 for (uint index = 0; index < filesList.count(); ++ index)
1807 {
1808 QRegExp regExp ("License-([\\d\\.]+).html");
1809 regExp.search (filesList [index]);
1810 QString version = regExp.cap (1);
1811 if (maxVersionNumber < version.toDouble())
1812 maxVersionNumber = version.toDouble();
1813 }
1814 if (!maxVersionNumber)
1815 {
1816 vboxProblem().cannotFindLicenseFiles (path);
1817 return false;
1818 }
1819
1820 /* compose the latest license file full path */
1821 QString latestVersion = QString::number (maxVersionNumber);
1822 QString latestFilePath = docDir.absFilePath (
1823 QString ("License-%1.html").arg (latestVersion));
1824
1825 /* check for the agreed license version */
1826 QString licenseAgreed = virtualBox().GetExtraData (VBoxDefs::GUI_LicenseKey);
1827 if (licenseAgreed == latestVersion)
1828 return true;
1829
1830 VBoxLicenseViewer licenseDialog (latestFilePath);
1831 bool result = licenseDialog.exec() == QDialog::Accepted;
1832 if (result)
1833 virtualBox().SetExtraData (VBoxDefs::GUI_LicenseKey, latestVersion);
1834 return result;
1835}
1836#endif
1837
1838/**
1839 * Opens a direct session for a machine with the given ID.
1840 * This method does user-friendly error handling (display error messages, etc.).
1841 * and returns a null CSession object in case of any error.
1842 * If this method succeeds, don't forget to close the returned session when
1843 * it is no more necessary.
1844 *
1845 * @param aId Machine ID.
1846 * @param aExisting @c true to open an existing session with the machine
1847 * which is already running, @c false to open a new direct
1848 * session.
1849 */
1850CSession VBoxGlobal::openSession (const QUuid &aId, bool aExisting /* = false */)
1851{
1852 CSession session;
1853 session.createInstance (CLSID_Session);
1854 if (session.isNull())
1855 {
1856 vboxProblem().cannotOpenSession (session);
1857 return session;
1858 }
1859
1860 aExisting ? mVBox.OpenExistingSession (session, aId) :
1861 mVBox.OpenSession (session, aId);
1862
1863 if (!mVBox.isOk())
1864 {
1865 CMachine machine = CVirtualBox (mVBox).GetMachine (aId);
1866 vboxProblem().cannotOpenSession (mVBox, machine);
1867 session.detach();
1868 }
1869
1870 return session;
1871}
1872
1873/**
1874 * Starts a machine with the given ID.
1875 */
1876bool VBoxGlobal::startMachine (const QUuid &id)
1877{
1878 AssertReturn (mValid, false);
1879
1880 CSession session = vboxGlobal().openSession (id);
1881 if (session.isNull())
1882 return false;
1883
1884 return consoleWnd().openView (session);
1885}
1886
1887/**
1888 * Appends the disk object and all its children to the media list.
1889 */
1890static
1891void addMediaToList (VBoxMediaList &aList,
1892 const CUnknown &aDisk,
1893 VBoxDefs::DiskType aType)
1894{
1895 VBoxMedia media (aDisk, aType, VBoxMedia::Unknown);
1896 aList += media;
1897 /* append all vdi children */
1898 if (aType == VBoxDefs::HD)
1899 {
1900 CHardDisk hd = aDisk;
1901 CHardDiskEnumerator enumerator = hd.GetChildren().Enumerate();
1902 while (enumerator.HasMore())
1903 {
1904 CHardDisk subHd = enumerator.GetNext();
1905 addMediaToList (aList, CUnknown (subHd), VBoxDefs::HD);
1906 }
1907 }
1908}
1909
1910/**
1911 * Starts a thread that asynchronously enumerates all currently registered
1912 * media, checks for its accessibility and posts VBoxEnumerateMediaEvent
1913 * events to the VBoxGlobal object until all media is enumerated.
1914 *
1915 * If the enumeration is already in progress, no new thread is started.
1916 *
1917 * @sa #currentMediaList()
1918 * @sa #isMediaEnumerationStarted()
1919 */
1920void VBoxGlobal::startEnumeratingMedia()
1921{
1922 Assert (mValid);
1923
1924 /* check if already started but not yet finished */
1925 if (media_enum_thread)
1926 return;
1927
1928 /* ignore the request during application termination */
1929 if (sVBoxGlobalInCleanup)
1930 return;
1931
1932 /* composes a list of all currently known media & their children */
1933 media_list.clear();
1934 {
1935 CHardDiskEnumerator enHD = mVBox.GetHardDisks().Enumerate();
1936 while (enHD.HasMore())
1937 addMediaToList (media_list, CUnknown (enHD.GetNext()), VBoxDefs::HD);
1938
1939 CDVDImageEnumerator enCD = mVBox.GetDVDImages().Enumerate();
1940 while (enCD.HasMore())
1941 addMediaToList (media_list, CUnknown (enCD.GetNext()), VBoxDefs::CD);
1942
1943 CFloppyImageEnumerator enFD = mVBox.GetFloppyImages().Enumerate();
1944 while (enFD.HasMore())
1945 addMediaToList (media_list, CUnknown (enFD.GetNext()), VBoxDefs::FD);
1946 }
1947
1948 /* enumeration thread class */
1949 class Thread : public QThread
1950 {
1951 public:
1952
1953 Thread (const VBoxMediaList &aList) : mList (aList) {}
1954
1955 virtual void run()
1956 {
1957 LogFlow (("MediaEnumThread started.\n"));
1958 COMBase::InitializeCOM();
1959
1960 CVirtualBox mVBox = vboxGlobal().virtualBox();
1961 QObject *target = &vboxGlobal();
1962
1963 /* enumerating list */
1964 int index = 0;
1965 VBoxMediaList::const_iterator it;
1966 for (it = mList.begin();
1967 it != mList.end() && !sVBoxGlobalInCleanup;
1968 ++ it, ++ index)
1969 {
1970 VBoxMedia media = *it;
1971 switch (media.type)
1972 {
1973 case VBoxDefs::HD:
1974 {
1975 CHardDisk hd = media.disk;
1976 media.status =
1977 hd.GetAccessible() == TRUE ? VBoxMedia::Ok :
1978 hd.isOk() ? VBoxMedia::Inaccessible :
1979 VBoxMedia::Error;
1980 /* assign back to store error info if any */
1981 media.disk = hd;
1982 if (media.status == VBoxMedia::Inaccessible)
1983 {
1984 QUuid machineId = hd.GetMachineId();
1985 if (!machineId.isNull())
1986 {
1987 CMachine machine = mVBox.GetMachine (machineId);
1988 if (!machine.isNull() && (machine.GetState() >= KMachineState_Running))
1989 media.status = VBoxMedia::Ok;
1990 }
1991 }
1992 QApplication::postEvent (target,
1993 new VBoxEnumerateMediaEvent (media, index));
1994 break;
1995 }
1996 case VBoxDefs::CD:
1997 {
1998 CDVDImage cd = media.disk;
1999 media.status =
2000 cd.GetAccessible() == TRUE ? VBoxMedia::Ok :
2001 cd.isOk() ? VBoxMedia::Inaccessible :
2002 VBoxMedia::Error;
2003 /* assign back to store error info if any */
2004 media.disk = cd;
2005 QApplication::postEvent (target,
2006 new VBoxEnumerateMediaEvent (media, index));
2007 break;
2008 }
2009 case VBoxDefs::FD:
2010 {
2011 CFloppyImage fd = media.disk;
2012 media.status =
2013 fd.GetAccessible() == TRUE ? VBoxMedia::Ok :
2014 fd.isOk() ? VBoxMedia::Inaccessible :
2015 VBoxMedia::Error;
2016 /* assign back to store error info if any */
2017 media.disk = fd;
2018 QApplication::postEvent (target,
2019 new VBoxEnumerateMediaEvent (media, index));
2020 break;
2021 }
2022 default:
2023 {
2024 AssertMsgFailed (("Invalid aMedia type\n"));
2025 break;
2026 }
2027 }
2028 }
2029
2030 /* post the last message to indicate the end of enumeration */
2031 if (!sVBoxGlobalInCleanup)
2032 QApplication::postEvent (target, new VBoxEnumerateMediaEvent());
2033
2034 COMBase::CleanupCOM();
2035 LogFlow (("MediaEnumThread finished.\n"));
2036 }
2037
2038 private:
2039
2040 const VBoxMediaList &mList;
2041 };
2042
2043 media_enum_thread = new Thread (media_list);
2044 AssertReturnVoid (media_enum_thread);
2045
2046 /* emit mediaEnumStarted() after we set media_enum_thread to != NULL
2047 * to cause isMediaEnumerationStarted() to return TRUE from slots */
2048 emit mediaEnumStarted();
2049
2050 media_enum_thread->start();
2051}
2052
2053/**
2054 * Adds a new media to the current media list.
2055 * @note Currently, this method does nothing but emits the mediaAdded() signal.
2056 * Later, it will be used to synchronize the current media list with
2057 * the actial media list on the server after a single media opetartion
2058 * performed from within one of our UIs.
2059 * @sa #currentMediaList()
2060 */
2061void VBoxGlobal::addMedia (const VBoxMedia &aMedia)
2062{
2063 emit mediaAdded (aMedia);
2064}
2065
2066/**
2067 * Updates the media in the current media list.
2068 * @note Currently, this method does nothing but emits the mediaUpdated() signal.
2069 * Later, it will be used to synchronize the current media list with
2070 * the actial media list on the server after a single media opetartion
2071 * performed from within one of our UIs.
2072 * @sa #currentMediaList()
2073 */
2074void VBoxGlobal::updateMedia (const VBoxMedia &aMedia)
2075{
2076 emit mediaUpdated (aMedia);
2077}
2078
2079/**
2080 * Removes the media from the current media list.
2081 * @note Currently, this method does nothing but emits the mediaRemoved() signal.
2082 * Later, it will be used to synchronize the current media list with
2083 * the actial media list on the server after a single media opetartion
2084 * performed from within one of our UIs.
2085 * @sa #currentMediaList()
2086 */
2087void VBoxGlobal::removeMedia (VBoxDefs::DiskType aType, const QUuid &aId)
2088{
2089 emit mediaRemoved (aType, aId);
2090}
2091
2092/**
2093 * Searches for a VBoxMedia object representing the given COM media object.
2094 *
2095 * @return true if found and false otherwise.
2096 */
2097bool VBoxGlobal::findMedia (const CUnknown &aObj, VBoxMedia &aMedia) const
2098{
2099 for (VBoxMediaList::ConstIterator it = media_list.begin();
2100 it != media_list.end(); ++ it)
2101 {
2102 if ((*it).disk == aObj)
2103 {
2104 aMedia = (*it);
2105 return true;
2106 }
2107 }
2108
2109 return false;
2110}
2111
2112/**
2113 * Native language name of the currently installed translation.
2114 * Returns "English" if no translation is installed
2115 * or if the translation file is invalid.
2116 */
2117QString VBoxGlobal::languageName() const
2118{
2119
2120 return qApp->translate ("@@@", "English",
2121 "Native language name");
2122}
2123
2124/**
2125 * Native language country name of the currently installed translation.
2126 * Returns "--" if no translation is installed or if the translation file is
2127 * invalid, or if the language is independent on the country.
2128 */
2129QString VBoxGlobal::languageCountry() const
2130{
2131 return qApp->translate ("@@@", "--",
2132 "Native language country name "
2133 "(empty if this language is for all countries)");
2134}
2135
2136/**
2137 * Language name of the currently installed translation, in English.
2138 * Returns "English" if no translation is installed
2139 * or if the translation file is invalid.
2140 */
2141QString VBoxGlobal::languageNameEnglish() const
2142{
2143
2144 return qApp->translate ("@@@", "English",
2145 "Language name, in English");
2146}
2147
2148/**
2149 * Language country name of the currently installed translation, in English.
2150 * Returns "--" if no translation is installed or if the translation file is
2151 * invalid, or if the language is independent on the country.
2152 */
2153QString VBoxGlobal::languageCountryEnglish() const
2154{
2155 return qApp->translate ("@@@", "--",
2156 "Language country name, in English "
2157 "(empty if native country name is empty)");
2158}
2159
2160/**
2161 * Comma-separated list of authors of the currently installed translation.
2162 * Returns "innotek" if no translation is installed or if the translation
2163 * file is invalid, or if the translation is supplied by innotek.
2164 */
2165QString VBoxGlobal::languageTranslators() const
2166{
2167 return qApp->translate ("@@@", "innotek",
2168 "Comma-separated list of translators");
2169}
2170
2171/**
2172 * Changes the language of all global string constants according to the
2173 * currently installed translations tables.
2174 */
2175void VBoxGlobal::languageChange()
2176{
2177 machineStates [KMachineState_PoweredOff] = tr ("Powered Off", "MachineState");
2178 machineStates [KMachineState_Saved] = tr ("Saved", "MachineState");
2179 machineStates [KMachineState_Aborted] = tr ("Aborted", "MachineState");
2180 machineStates [KMachineState_Running] = tr ("Running", "MachineState");
2181 machineStates [KMachineState_Paused] = tr ("Paused", "MachineState");
2182 machineStates [KMachineState_Stuck] = tr ("Stuck", "MachineState");
2183 machineStates [KMachineState_Starting] = tr ("Starting", "MachineState");
2184 machineStates [KMachineState_Stopping] = tr ("Stopping", "MachineState");
2185 machineStates [KMachineState_Saving] = tr ("Saving", "MachineState");
2186 machineStates [KMachineState_Restoring] = tr ("Restoring", "MachineState");
2187 machineStates [KMachineState_Discarding] = tr ("Discarding", "MachineState");
2188
2189 sessionStates [KSessionState_Closed] = tr ("Closed", "SessionState");
2190 sessionStates [KSessionState_Open] = tr ("Open", "SessionState");
2191 sessionStates [KSessionState_Spawning] = tr ("Spawning", "SessionState");
2192 sessionStates [KSessionState_Closing] = tr ("Closing", "SessionState");
2193
2194 deviceTypes [KDeviceType_Null] = tr ("None", "DeviceType");
2195 deviceTypes [KDeviceType_Floppy] = tr ("Floppy", "DeviceType");
2196 deviceTypes [KDeviceType_DVD] = tr ("CD/DVD-ROM", "DeviceType");
2197 deviceTypes [KDeviceType_HardDisk] = tr ("Hard Disk", "DeviceType");
2198 deviceTypes [KDeviceType_Network] = tr ("Network", "DeviceType");
2199
2200 diskControllerTypes [KDiskControllerType_IDE0] =
2201 tr ("Primary", "DiskControllerType");
2202 diskControllerTypes [KDiskControllerType_IDE1] =
2203 tr ("Secondary", "DiskControllerType");
2204
2205 diskTypes [KHardDiskType_Normal] =
2206 tr ("Normal", "DiskType");
2207 diskTypes [KHardDiskType_Immutable] =
2208 tr ("Immutable", "DiskType");
2209 diskTypes [KHardDiskType_Writethrough] =
2210 tr ("Writethrough", "DiskType");
2211
2212 diskStorageTypes [KHardDiskStorageType_VirtualDiskImage] =
2213 tr ("Virtual Disk Image", "DiskStorageType");
2214 diskStorageTypes [KHardDiskStorageType_ISCSIHardDisk] =
2215 tr ("iSCSI", "DiskStorageType");
2216 diskStorageTypes [KHardDiskStorageType_VMDKImage] =
2217 tr ("VMDK Image", "DiskStorageType");
2218 diskStorageTypes [KHardDiskStorageType_CustomHardDisk] =
2219 tr ("Custom Hard Disk", "DiskStorageType");
2220 diskStorageTypes [KHardDiskStorageType_VHDImage] =
2221 tr ("VHD Image", "DiskStorageType");
2222
2223 vrdpAuthTypes [KVRDPAuthType_Null] =
2224 tr ("Null", "VRDPAuthType");
2225 vrdpAuthTypes [KVRDPAuthType_External] =
2226 tr ("External", "VRDPAuthType");
2227 vrdpAuthTypes [KVRDPAuthType_Guest] =
2228 tr ("Guest", "VRDPAuthType");
2229
2230 portModeTypes [KPortMode_Disconnected] =
2231 tr ("Disconnected", "PortMode");
2232 portModeTypes [KPortMode_HostPipe] =
2233 tr ("Host Pipe", "PortMode");
2234 portModeTypes [KPortMode_HostDevice] =
2235 tr ("Host Device", "PortMode");
2236
2237 usbFilterActionTypes [KUSBDeviceFilterAction_Ignore] =
2238 tr ("Ignore", "USBFilterActionType");
2239 usbFilterActionTypes [KUSBDeviceFilterAction_Hold] =
2240 tr ("Hold", "USBFilterActionType");
2241
2242 Assert (diskControllerDevices.count() == 3);
2243 diskControllerDevices [0] = tr ("Master", "DiskControllerDevice");
2244 diskControllerDevices [1] = tr ("Slave", "DiskControllerDevice");
2245 diskControllerDevices [2] = tr ("Device&nbsp;%1", "DiskControllerDevice");
2246
2247 audioDriverTypes [KAudioDriverType_Null] =
2248 tr ("Null Audio Driver", "AudioDriverType");
2249 audioDriverTypes [KAudioDriverType_WINMM] =
2250 tr ("Windows Multimedia", "AudioDriverType");
2251 audioDriverTypes [KAudioDriverType_OSS] =
2252 tr ("OSS Audio Driver", "AudioDriverType");
2253 audioDriverTypes [KAudioDriverType_ALSA] =
2254 tr ("ALSA Audio Driver", "AudioDriverType");
2255 audioDriverTypes [KAudioDriverType_DSOUND] =
2256 tr ("Windows DirectSound", "AudioDriverType");
2257 audioDriverTypes [KAudioDriverType_Core] =
2258 tr ("CoreAudio", "AudioDriverType");
2259 audioDriverTypes [KAudioDriverType_Pulse] =
2260 tr ("PulseAudio", "AudioDriverType");
2261
2262 audioControllerTypes [KAudioControllerType_AC97] =
2263 tr ("ICH AC97", "AudioControllerType");
2264 audioControllerTypes [KAudioControllerType_SB16] =
2265 tr ("SoundBlaster 16", "AudioControllerType");
2266
2267 networkAdapterTypes [KNetworkAdapterType_Am79C970A] =
2268 tr ("PCnet-PCI II (Am79C970A)", "NetworkAdapterType");
2269 networkAdapterTypes [KNetworkAdapterType_Am79C973] =
2270 tr ("PCnet-FAST III (Am79C973)", "NetworkAdapterType");
2271 networkAdapterTypes [KNetworkAdapterType_I82540EM] =
2272 tr ("Intel PRO/1000 MT Desktop (82540EM)", "NetworkAdapterType");
2273
2274 networkAttachmentTypes [KNetworkAttachmentType_Null] =
2275 tr ("Not attached", "NetworkAttachmentType");
2276 networkAttachmentTypes [KNetworkAttachmentType_NAT] =
2277 tr ("NAT", "NetworkAttachmentType");
2278 networkAttachmentTypes [KNetworkAttachmentType_HostInterface] =
2279 tr ("Host Interface", "NetworkAttachmentType");
2280 networkAttachmentTypes [KNetworkAttachmentType_Internal] =
2281 tr ("Internal Network", "NetworkAttachmentType");
2282
2283 clipboardTypes [KClipboardMode_Disabled] =
2284 tr ("Disabled", "ClipboardType");
2285 clipboardTypes [KClipboardMode_HostToGuest] =
2286 tr ("Host To Guest", "ClipboardType");
2287 clipboardTypes [KClipboardMode_GuestToHost] =
2288 tr ("Guest To Host", "ClipboardType");
2289 clipboardTypes [KClipboardMode_Bidirectional] =
2290 tr ("Bidirectional", "ClipboardType");
2291
2292 ideControllerTypes [KIDEControllerType_PIIX3] =
2293 tr ("PIIX3", "IDEControllerType");
2294 ideControllerTypes [KIDEControllerType_PIIX4] =
2295 tr ("PIIX4", "IDEControllerType");
2296
2297 USBDeviceStates [KUSBDeviceState_NotSupported] =
2298 tr ("Not supported", "USBDeviceState");
2299 USBDeviceStates [KUSBDeviceState_Unavailable] =
2300 tr ("Unavailable", "USBDeviceState");
2301 USBDeviceStates [KUSBDeviceState_Busy] =
2302 tr ("Busy", "USBDeviceState");
2303 USBDeviceStates [KUSBDeviceState_Available] =
2304 tr ("Available", "USBDeviceState");
2305 USBDeviceStates [KUSBDeviceState_Held] =
2306 tr ("Held", "USBDeviceState");
2307 USBDeviceStates [KUSBDeviceState_Captured] =
2308 tr ("Captured", "USBDeviceState");
2309
2310 mUserDefinedPortName = tr ("User-defined", "serial port");
2311
2312 detailReportTemplatesReady = false;
2313
2314#if defined (Q_WS_PM) || defined (Q_WS_X11)
2315 /* As PM and X11 do not (to my knowledge) have functionality for providing
2316 * human readable key names, we keep a table of them, which must be
2317 * updated when the language is changed. */
2318#warning port me
2319 QIHotKeyEdit::languageChange_qt3();
2320#endif
2321}
2322
2323// public static stuff
2324////////////////////////////////////////////////////////////////////////////////
2325
2326/* static */
2327bool VBoxGlobal::isDOSType (const QString &aOSTypeId)
2328{
2329 if (aOSTypeId.left (3) == "dos" ||
2330 aOSTypeId.left (3) == "win" ||
2331 aOSTypeId.left (3) == "os2")
2332 return true;
2333
2334 return false;
2335}
2336
2337/**
2338 * Sets the QLabel background and frame colors according tho the pixmap
2339 * contents. The bottom right pixel of the label pixmap defines the
2340 * background color of the label, the top right pixel defines the color of
2341 * the one-pixel frame around it. This function also sets the alignment of
2342 * the pixmap to AlignVTop (to correspond to the color choosing logic).
2343 *
2344 * This method is useful to provide nice scaling of pixmal labels without
2345 * scaling pixmaps themselves. To see th eeffect, the size policy of the
2346 * label in the corresponding direction (vertical, for now) should be set to
2347 * something like MinimumExpanding.
2348 *
2349 * @todo Parametrize corners to select pixels from and set the alignment
2350 * accordingly.
2351 */
2352/* static */
2353void VBoxGlobal::adoptLabelPixmap (QLabel *aLabel)
2354{
2355 AssertReturnVoid (aLabel);
2356
2357 const QPixmap *pix = aLabel->pixmap();
2358 QImage img = pix->convertToImage();
2359 QRgb rgbBack = img.pixel (img.width() - 1, img.height() - 1);
2360 QRgb rgbFrame = img.pixel (img.width() - 1, 0);
2361
2362 aLabel->setAlignment (Qt::AlignTop);
2363
2364 aLabel->setPaletteBackgroundColor (QColor (rgbBack));
2365 aLabel->setFrameShadow (Q3Frame::Plain);
2366 aLabel->setFrameShape (Q3Frame::Box);
2367 aLabel->setPaletteForegroundColor (QColor (rgbFrame));
2368}
2369
2370extern const char *gVBoxLangSubDir = "/nls";
2371extern const char *gVBoxLangFileBase = "VirtualBox_";
2372extern const char *gVBoxLangFileExt = ".qm";
2373extern const char *gVBoxLangIDRegExp = "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
2374extern const char *gVBoxBuiltInLangName = "C";
2375
2376class VBoxTranslator : public QTranslator
2377{
2378public:
2379
2380 VBoxTranslator (QObject *aParent = 0)
2381 : QTranslator (aParent, "VBoxTranslatorObject") {}
2382
2383 bool loadFile (const QString &aFileName)
2384 {
2385 QFile file (aFileName);
2386 if (!file.open (QIODevice::ReadOnly))
2387 return false;
2388 mData = file.readAll();
2389 return load ((uchar*) mData.data(), mData.size());
2390 }
2391
2392private:
2393
2394 QByteArray mData;
2395};
2396
2397static VBoxTranslator *sTranslator = 0;
2398static QString sLoadedLangId = gVBoxBuiltInLangName;
2399
2400/**
2401 * Returns the loaded (active) language ID.
2402 * Note that it may not match with VBoxGlobalSettings::languageId() if the
2403 * specified language cannot be loaded.
2404 * If the built-in language is active, this method returns "C".
2405 *
2406 * @note "C" is treated as the built-in language for simplicity -- the C
2407 * locale is used in unix environments as a fallback when the requested
2408 * locale is invalid. This way we don't need to process both the "built_in"
2409 * language and the "C" language (which is a valid environment setting)
2410 * separately.
2411 */
2412/* static */
2413QString VBoxGlobal::languageId()
2414{
2415 return sLoadedLangId;
2416}
2417
2418/**
2419 * Loads the language by language ID.
2420 *
2421 * @param aLangId Language ID in in form of xx_YY. QString::null means the
2422 * system default language.
2423 */
2424/* static */
2425void VBoxGlobal::loadLanguage (const QString &aLangId)
2426{
2427 QString langId = aLangId.isNull() ?
2428 VBoxGlobal::systemLanguageId() : aLangId;
2429 QString languageFileName;
2430 QString selectedLangId = gVBoxBuiltInLangName;
2431
2432 char szNlsPath[RTPATH_MAX];
2433 int rc;
2434
2435 rc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
2436 Assert(RT_SUCCESS(rc));
2437
2438 QString nlsPath = QString(szNlsPath) + gVBoxLangSubDir;
2439 QDir nlsDir (nlsPath);
2440
2441 Assert (!langId.isEmpty());
2442 if (!langId.isEmpty() && langId != gVBoxBuiltInLangName)
2443 {
2444 QRegExp regExp (gVBoxLangIDRegExp);
2445 int pos = regExp.search (langId);
2446 /* the language ID should match the regexp completely */
2447 AssertReturnVoid (pos == 0);
2448
2449 QString lang = regExp.cap (2);
2450
2451 if (nlsDir.exists (gVBoxLangFileBase + langId + gVBoxLangFileExt))
2452 {
2453 languageFileName = nlsDir.absFilePath (gVBoxLangFileBase + langId +
2454 gVBoxLangFileExt);
2455 selectedLangId = langId;
2456 }
2457 else if (nlsDir.exists (gVBoxLangFileBase + lang + gVBoxLangFileExt))
2458 {
2459 languageFileName = nlsDir.absFilePath (gVBoxLangFileBase + lang +
2460 gVBoxLangFileExt);
2461 selectedLangId = lang;
2462 }
2463 else
2464 {
2465 /* Never complain when the default language is requested. In any
2466 * case, if no explicit language file exists, we will simply
2467 * fall-back to English (built-in). */
2468 if (!aLangId.isNull())
2469 vboxProblem().cannotFindLanguage (langId, nlsPath);
2470 /* selectedLangId remains built-in here */
2471 AssertReturnVoid (selectedLangId == gVBoxBuiltInLangName);
2472 }
2473 }
2474
2475 /* delete the old translator if there is one */
2476 if (sTranslator)
2477 {
2478 /* QTranslator destructor will call qApp->removeTranslator() for
2479 * us. It will also delete all its child translations we attach to it
2480 * below, so we don't have to care about them specially. */
2481 delete sTranslator;
2482 }
2483
2484 /* load new language files */
2485 sTranslator = new VBoxTranslator (qApp);
2486 Assert (sTranslator);
2487 bool loadOk = true;
2488 if (sTranslator)
2489 {
2490 if (selectedLangId != gVBoxBuiltInLangName)
2491 {
2492 Assert (!languageFileName.isNull());
2493 loadOk = sTranslator->loadFile (languageFileName);
2494 }
2495 /* we install the translator in any case: on failure, this will
2496 * activate an empty translator that will give us English
2497 * (built-in) */
2498 qApp->installTranslator (sTranslator);
2499 }
2500 else
2501 loadOk = false;
2502
2503 if (loadOk)
2504 sLoadedLangId = selectedLangId;
2505 else
2506 {
2507 vboxProblem().cannotLoadLanguage (languageFileName);
2508 sLoadedLangId = gVBoxBuiltInLangName;
2509 }
2510
2511 /* Try to load the corresponding Qt translation */
2512 if (sLoadedLangId != gVBoxBuiltInLangName)
2513 {
2514#ifdef Q_OS_UNIX
2515 /* We use system installations of Qt on Linux systems, so first, try
2516 * to load the Qt translation from the system location. */
2517 languageFileName = QString (qInstallPathTranslations()) + "/qt_" +
2518 sLoadedLangId + gVBoxLangFileExt;
2519 QTranslator *qtSysTr = new QTranslator (sTranslator);
2520 Assert (qtSysTr);
2521 if (qtSysTr && qtSysTr->load (languageFileName))
2522 qApp->installTranslator (qtSysTr);
2523 /* Note that the Qt translation supplied by innotek is always loaded
2524 * afterwards to make sure it will take precedence over the system
2525 * translation (it may contain more decent variants of translation
2526 * that better correspond to VirtualBox UI). We need to load both
2527 * because a newer version of Qt may be installed on the user computer
2528 * and the innotek version may not fully support it. We don't do it on
2529 * Win32 because we supply a Qt library there and therefore the
2530 * innotek translation is always the best one. */
2531#endif
2532 languageFileName = nlsDir.absFilePath (QString ("qt_") +
2533 sLoadedLangId +
2534 gVBoxLangFileExt);
2535 QTranslator *qtTr = new QTranslator (sTranslator);
2536 Assert (qtTr);
2537 if (qtTr && (loadOk = qtTr->load (languageFileName)))
2538 qApp->installTranslator (qtTr);
2539 /* The below message doesn't fit 100% (because it's an additonal
2540 * language and the main one won't be reset to built-in on failure)
2541 * but the load failure is so rare here that it's not worth a separate
2542 * message (but still, having something is better than having none) */
2543 if (!loadOk && !aLangId.isNull())
2544 vboxProblem().cannotLoadLanguage (languageFileName);
2545 }
2546}
2547
2548/* static */
2549QIcon VBoxGlobal::iconSet (const char *aNormal,
2550 const char *aDisabled /* = NULL */,
2551 const char *aActive /* = NULL */)
2552{
2553 QIcon iconSet;
2554
2555 iconSet.setPixmap (QPixmap (aNormal),
2556 QIcon::Automatic, QIcon::Normal);
2557 if (aDisabled != NULL)
2558 iconSet.setPixmap (QPixmap (aDisabled),
2559 QIcon::Automatic, QIcon::Disabled);
2560 if (aActive != NULL)
2561 iconSet.setPixmap (QPixmap (aActive),
2562 QIcon::Automatic, QIcon::Active);
2563 return iconSet;
2564}
2565
2566/* static */
2567QIcon VBoxGlobal::
2568iconSetEx (const char *aNormal, const char *aSmallNormal,
2569 const char *aDisabled /* = NULL */,
2570 const char *aSmallDisabled /* = NULL */,
2571 const char *aActive /* = NULL */,
2572 const char *aSmallActive /* = NULL */)
2573{
2574 QIcon iconSet;
2575
2576 iconSet.setPixmap (QPixmap (aNormal),
2577 QIcon::Large, QIcon::Normal);
2578 iconSet.setPixmap (QPixmap (aSmallNormal),
2579 QIcon::Small, QIcon::Normal);
2580 if (aSmallDisabled != NULL)
2581 {
2582 iconSet.setPixmap (QPixmap (aDisabled),
2583 QIcon::Large, QIcon::Disabled);
2584 iconSet.setPixmap (QPixmap (aSmallDisabled),
2585 QIcon::Small, QIcon::Disabled);
2586 }
2587 if (aSmallActive != NULL)
2588 {
2589 iconSet.setPixmap (QPixmap (aActive),
2590 QIcon::Large, QIcon::Active);
2591 iconSet.setPixmap (QPixmap (aSmallActive),
2592 QIcon::Small, QIcon::Active);
2593 }
2594
2595 return iconSet;
2596}
2597
2598/**
2599 * Replacement for QToolButton::setTextLabel() that handles the shortcut
2600 * letter (if it is present in the argument string) as if it were a setText()
2601 * call: the shortcut letter is used to automatically assign an "Alt+<letter>"
2602 * accelerator key sequence to the given tool button.
2603 *
2604 * @note This method preserves the icon set if it was assigned before. Only
2605 * the text label and the accelerator are changed.
2606 *
2607 * @param aToolButton Tool button to set the text label on.
2608 * @param aTextLabel Text label to set.
2609 */
2610/* static */
2611void VBoxGlobal::setTextLabel (QToolButton *aToolButton,
2612 const QString &aTextLabel)
2613{
2614 AssertReturnVoid (aToolButton != NULL);
2615
2616 /* remember the icon set as setText() will kill it */
2617 QIcon iset = aToolButton->iconSet();
2618 /* re-use the setText() method to detect and set the accelerator */
2619 aToolButton->setText (aTextLabel);
2620 QKeySequence accel = aToolButton->accel();
2621 aToolButton->setTextLabel (aTextLabel);
2622 aToolButton->setIconSet (iset);
2623 /* set the accel last as setIconSet() would kill it */
2624 aToolButton->setAccel (accel);
2625}
2626
2627/**
2628 * Ensures that the given rectangle \a aRect is fully contained within the
2629 * rectangle \a aBoundRect by moving \a aRect if necessary. If \a aRect is
2630 * larger than \a aBoundRect, its top left corner is simply aligned with the
2631 * top left corner of \a aRect and, if \a aCanResize is true, \a aRect is
2632 * shrinked to become fully visible.
2633 */
2634/* static */
2635QRect VBoxGlobal::normalizeGeometry (const QRect &aRect, const QRect &aBoundRect,
2636 bool aCanResize /* = true */)
2637{
2638 QRect fr = aRect;
2639
2640 /* make the bottom right corner visible */
2641 int rd = aBoundRect.right() - fr.right();
2642 int bd = aBoundRect.bottom() - fr.bottom();
2643 fr.moveBy (rd < 0 ? rd : 0, bd < 0 ? bd : 0);
2644
2645 /* ensure the top left corner is visible */
2646 int ld = fr.left() - aBoundRect.left();
2647 int td = fr.top() - aBoundRect.top();
2648 fr.moveBy (ld < 0 ? -ld : 0, td < 0 ? -td : 0);
2649
2650 if (aCanResize)
2651 {
2652 /* adjust the size to make the rectangle fully contained */
2653 rd = aBoundRect.right() - fr.right();
2654 bd = aBoundRect.bottom() - fr.bottom();
2655 if (rd < 0)
2656 fr.rRight() += rd;
2657 if (bd < 0)
2658 fr.rBottom() += bd;
2659 }
2660
2661 return fr;
2662}
2663
2664/**
2665 * Aligns the center of \a aWidget with the center of \a aRelative.
2666 *
2667 * If necessary, \a aWidget's position is adjusted to make it fully visible
2668 * within the available desktop area. If \a aWidget is bigger then this area,
2669 * it will also be resized unless \a aCanResize is false or there is an
2670 * inappropriate minimum size limit (in which case the top left corner will be
2671 * simply aligned with the top left corner of the available desktop area).
2672 *
2673 * \a aWidget must be a top-level widget. \a aRelative may be any widget, but
2674 * if it's not top-level itself, its top-level widget will be used for
2675 * calculations. \a aRelative can also be NULL, in which case \a aWidget will
2676 * be centered relative to the available desktop area.
2677 */
2678/* static */
2679void VBoxGlobal::centerWidget (QWidget *aWidget, QWidget *aRelative,
2680 bool aCanResize /* = true */)
2681{
2682 AssertReturnVoid (aWidget);
2683 AssertReturnVoid (aWidget->isTopLevel());
2684
2685 QRect deskGeo, parentGeo;
2686 QWidget *w = aRelative;
2687 if (w)
2688 {
2689 w = w->topLevelWidget();
2690 deskGeo = QApplication::desktop()->availableGeometry (w);
2691 parentGeo = w->frameGeometry();
2692 /* On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level
2693 * widgets with parents, what a shame. Use mapToGlobal() to workaround. */
2694 QPoint d = w->mapToGlobal (QPoint (0, 0));
2695 d.rx() -= w->geometry().x() - w->x();
2696 d.ry() -= w->geometry().y() - w->y();
2697 parentGeo.moveTopLeft (d);
2698 }
2699 else
2700 {
2701 deskGeo = QApplication::desktop()->availableGeometry();
2702 parentGeo = deskGeo;
2703 }
2704
2705 /* On X11, there is no way to determine frame geometry (including WM
2706 * decorations) before the widget is shown for the first time. Stupidly
2707 * enumerate other top level widgets to find the thickest frame. The code
2708 * is based on the idea taken from QDialog::adjustPositionInternal(). */
2709
2710 int extraw = 0, extrah = 0;
2711
2712 QWidgetList list = QApplication::topLevelWidgets();
2713 QListIterator<QWidget*> it (list);
2714 while ((extraw == 0 || extrah == 0) && it.hasNext())
2715 {
2716 int framew, frameh;
2717 QWidget *current = it.next();
2718 if (!current->isVisible())
2719 continue;
2720
2721 framew = current->frameGeometry().width() - current->width();
2722 frameh = current->frameGeometry().height() - current->height();
2723
2724 extraw = QMAX (extraw, framew);
2725 extrah = QMAX (extrah, frameh);
2726 }
2727
2728 /// @todo (r=dmik) not sure if we really need this
2729#if 0
2730 /* sanity check for decoration frames. With embedding, we
2731 * might get extraordinary values */
2732 if (extraw == 0 || extrah == 0 || extraw > 20 || extrah > 50)
2733 {
2734 extrah = 50;
2735 extraw = 20;
2736 }
2737#endif
2738
2739 /* On non-X11 platforms, the following would be enough instead of the
2740 * above workaround: */
2741 // QRect geo = frameGeometry();
2742 QRect geo = QRect (0, 0, aWidget->width() + extraw,
2743 aWidget->height() + extrah);
2744
2745 geo.moveCenter (QPoint (parentGeo.x() + (parentGeo.width() - 1) / 2,
2746 parentGeo.y() + (parentGeo.height() - 1) / 2));
2747
2748 /* ensure the widget is within the available desktop area */
2749 QRect newGeo = normalizeGeometry (geo, deskGeo, aCanResize);
2750
2751 aWidget->move (newGeo.topLeft());
2752
2753 if (aCanResize &&
2754 (geo.width() != newGeo.width() || geo.height() != newGeo.height()))
2755 aWidget->resize (newGeo.width() - extraw, newGeo.height() - extrah);
2756}
2757
2758/**
2759 * Returns the decimal separator for the current locale.
2760 */
2761/* static */
2762QChar VBoxGlobal::decimalSep()
2763{
2764 QString n = QLocale::system().toString (0.0, 'f', 1).stripWhiteSpace();
2765 return n [1];
2766}
2767
2768/**
2769 * Returns the regexp string that defines the format of the human-readable
2770 * size representation, <tt>####[.##] B|KB|MB|GB|TB|PB</tt>.
2771 *
2772 * This regexp will capture 5 groups of text:
2773 * - cap(1): integer number in case when no decimal point is present
2774 * (if empty, it means that decimal point is present)
2775 * - cap(2): size suffix in case when no decimal point is present (may be empty)
2776 * - cap(3): integer number in case when decimal point is present (may be empty)
2777 * - cap(4): fraction number (hundredth) in case when decimal point is present
2778 * - cap(5): size suffix in case when decimal point is present (note that
2779 * B cannot appear there)
2780 */
2781/* static */
2782QString VBoxGlobal::sizeRegexp()
2783{
2784 QString regexp =
2785 QString ("^(?:(?:(\\d+)(?:\\s?([KMGTP]?B))?)|(?:(\\d*)%1(\\d{1,2})(?:\\s?([KMGTP]B))))$")
2786 .arg (decimalSep());
2787 return regexp;
2788}
2789
2790/**
2791 * Parses the given size string that should be in form of
2792 * <tt>####[.##] B|KB|MB|GB|TB|PB</tt> and returns the size value
2793 * in bytes. Zero is returned on error.
2794 */
2795/* static */
2796Q_UINT64 VBoxGlobal::parseSize (const QString &aText)
2797{
2798 QRegExp regexp (sizeRegexp());
2799 int pos = regexp.search (aText);
2800 if (pos != -1)
2801 {
2802 QString intgS = regexp.cap (1);
2803 QString hundS;
2804 QString suff = regexp.cap (2);
2805 if (intgS.isEmpty())
2806 {
2807 intgS = regexp.cap (3);
2808 hundS = regexp.cap (4);
2809 suff = regexp.cap (5);
2810 }
2811
2812 Q_UINT64 denom = 0;
2813 if (suff.isEmpty() || suff == "B")
2814 denom = 1;
2815 else if (suff == "KB")
2816 denom = _1K;
2817 else if (suff == "MB")
2818 denom = _1M;
2819 else if (suff == "GB")
2820 denom = _1G;
2821 else if (suff == "TB")
2822 denom = _1T;
2823 else if (suff == "PB")
2824 denom = _1P;
2825
2826 Q_UINT64 intg = intgS.toULongLong();
2827 if (denom == 1)
2828 return intg;
2829
2830 Q_UINT64 hund = hundS.rightJustify (2, '0').toULongLong();
2831 hund = hund * denom / 100;
2832 intg = intg * denom + hund;
2833 return intg;
2834 }
2835 else
2836 return 0;
2837}
2838
2839/**
2840 * Formats the given \a size value in bytes to a human readable string
2841 * in form of <tt>####[.##] B|KB|MB|GB|TB|PB</tt>.
2842 *
2843 * The \a mode parameter is used for resulting numbers that get a fractional
2844 * part after converting the \a size to KB, MB etc:
2845 * <ul>
2846 * <li>When \a mode is 0, the result is rounded to the closest number
2847 * containing two decimal digits.
2848 * </li>
2849 * <li>When \a mode is -1, the result is rounded to the largest two decimal
2850 * digit number that is not greater than the result. This guarantees that
2851 * converting the resulting string back to the integer value in bytes
2852 * will not produce a value greater that the initial \a size parameter.
2853 * </li>
2854 * <li>When \a mode is 1, the result is rounded to the smallest two decimal
2855 * digit number that is not less than the result. This guarantees that
2856 * converting the resulting string back to the integer value in bytes
2857 * will not produce a value less that the initial \a size parameter.
2858 * </li>
2859 * </ul>
2860 *
2861 * @param aSize size value in bytes
2862 * @param aMode convertion mode (-1, 0 or 1)
2863 * @return human-readable size string
2864 */
2865/* static */
2866QString VBoxGlobal::formatSize (Q_UINT64 aSize, int aMode /* = 0 */)
2867{
2868 static const char *Suffixes [] = { "B", "KB", "MB", "GB", "TB", "PB", NULL };
2869
2870 Q_UINT64 denom = 0;
2871 int suffix = 0;
2872
2873 if (aSize < _1K)
2874 {
2875 denom = 1;
2876 suffix = 0;
2877 }
2878 else if (aSize < _1M)
2879 {
2880 denom = _1K;
2881 suffix = 1;
2882 }
2883 else if (aSize < _1G)
2884 {
2885 denom = _1M;
2886 suffix = 2;
2887 }
2888 else if (aSize < _1T)
2889 {
2890 denom = _1G;
2891 suffix = 3;
2892 }
2893 else if (aSize < _1P)
2894 {
2895 denom = _1T;
2896 suffix = 4;
2897 }
2898 else
2899 {
2900 denom = _1P;
2901 suffix = 5;
2902 }
2903
2904 Q_UINT64 intg = aSize / denom;
2905 Q_UINT64 hund = aSize % denom;
2906
2907 QString number;
2908 if (denom > 1)
2909 {
2910 if (hund)
2911 {
2912 hund *= 100;
2913 /* not greater */
2914 if (aMode < 0) hund = hund / denom;
2915 /* not less */
2916 else if (aMode > 0) hund = (hund + denom - 1) / denom;
2917 /* nearest */
2918 else hund = (hund + denom / 2) / denom;
2919 }
2920 /* check for the fractional part overflow due to rounding */
2921 if (hund == 100)
2922 {
2923 hund = 0;
2924 ++ intg;
2925 /* check if we've got 1024 XB after rounding and scale down if so */
2926 if (intg == 1024 && Suffixes [suffix + 1] != NULL)
2927 {
2928 intg /= 1024;
2929 ++ suffix;
2930 }
2931 }
2932 number = QString ("%1%2%3").arg (intg).arg (decimalSep())
2933 .arg (QString::number (hund).rightJustify (2, '0'));
2934 }
2935 else
2936 {
2937 number = QString::number (intg);
2938 }
2939
2940 return QString ("%1 %2").arg (number).arg (Suffixes [suffix]);
2941}
2942
2943/**
2944 * Reformats the input string @a aStr so that:
2945 * - strings in single quotes will be put inside <nobr> and marked
2946 * with blue color;
2947 * - UUIDs be put inside <nobr> and marked
2948 * with green color;
2949 * - replaces new line chars with </p><p> constructs to form paragraphs
2950 * (note that <p> and </p> are not appended to the beginnign and to the
2951 * end of the string respectively, to allow the result be appended
2952 * or prepended to the existing paragraph).
2953 *
2954 * If @a aToolTip is true, colouring is not applied, only the <nobr> tag
2955 * is added. Also, new line chars are replaced with <br> instead of <p>.
2956 */
2957/* static */
2958QString VBoxGlobal::highlight (const QString &aStr, bool aToolTip /* = false */)
2959{
2960 QString strFont;
2961 QString uuidFont;
2962 QString endFont;
2963 if (!aToolTip)
2964 {
2965 strFont = "<font color=#0000CC>";
2966 uuidFont = "<font color=#008000>";
2967 endFont = "</font>";
2968 }
2969
2970 QString text = aStr;
2971
2972 /* replace special entities, '&' -- first! */
2973 text.replace ('&', "&amp;");
2974 text.replace ('<', "&lt;");
2975 text.replace ('>', "&gt;");
2976 text.replace ('\"', "&quot;");
2977
2978 /* mark strings in single quotes with color */
2979 QRegExp rx = QRegExp ("((?:^|\\s)[(]?)'([^']*)'(?=[:.-!);]?(?:\\s|$))");
2980 rx.setMinimal (true);
2981 text.replace (rx,
2982 QString ("\\1%1<nobr>'\\2'</nobr>%2")
2983 .arg (strFont). arg (endFont));
2984
2985 /* mark UUIDs with color */
2986 text.replace (QRegExp (
2987 "((?:^|\\s)[(]?)"
2988 "(\\{[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}\\})"
2989 "(?=[:.-!);]?(?:\\s|$))"),
2990 QString ("\\1%1<nobr>\\2</nobr>%2")
2991 .arg (uuidFont). arg (endFont));
2992
2993 /* split to paragraphs at \n chars */
2994 if (!aToolTip)
2995 text.replace ('\n', "</p><p>");
2996 else
2997 text.replace ('\n', "<br>");
2998
2999 return text;
3000}
3001
3002/**
3003 * This does exactly the same as QLocale::system().name() but corrects its
3004 * wrong behavior on Linux systems (LC_NUMERIC for some strange reason takes
3005 * precedence over any other locale setting in the QLocale::system()
3006 * implementation). This implementation first looks at LC_ALL (as defined by
3007 * SUS), then looks at LC_MESSAGES which is designed to define a language for
3008 * program messages in case if it differs from the language for other locale
3009 * categories. Then it looks for LANG and finally falls back to
3010 * QLocale::system().name().
3011 *
3012 * The order of precedence is well defined here:
3013 * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
3014 *
3015 * @note This method will return "C" when the requested locale is invalid or
3016 * when the "C" locale is set explicitly.
3017 */
3018/* static */
3019QString VBoxGlobal::systemLanguageId()
3020{
3021#ifdef Q_OS_UNIX
3022 const char *s = RTEnvGet ("LC_ALL");
3023 if (s == 0)
3024 s = RTEnvGet ("LC_MESSAGES");
3025 if (s == 0)
3026 s = RTEnvGet ("LANG");
3027 if (s != 0)
3028 return QLocale (s).name();
3029#endif
3030 return QLocale::system().name();
3031}
3032
3033/**
3034 * Reimplementation of QFileDialog::getExistingDirectory() that removes some
3035 * oddities and limitations.
3036 *
3037 * On Win32, this function makes sure a native dialog is launched in
3038 * another thread to avoid dialog visualization errors occuring due to
3039 * multi-threaded COM apartment initialization on the main UI thread while
3040 * the appropriate native dialog function expects a single-threaded one.
3041 *
3042 * On all other platforms, this function is equivalent to
3043 * QFileDialog::getExistingDirectory().
3044 */
3045QString VBoxGlobal::getExistingDirectory (const QString &aDir,
3046 QWidget *aParent, const char *aName,
3047 const QString &aCaption,
3048 bool aDirOnly,
3049 bool aResolveSymlinks)
3050{
3051#if defined Q_WS_WIN
3052
3053 /**
3054 * QEvent class reimplementation to carry Win32 API native dialog's
3055 * result folder information
3056 */
3057 class GetExistDirectoryEvent : public OpenNativeDialogEvent
3058 {
3059 public:
3060
3061 enum { TypeId = QEvent::User + 300 };
3062
3063 GetExistDirectoryEvent (const QString &aResult)
3064 : OpenNativeDialogEvent (aResult, (QEvent::Type) TypeId) {}
3065 };
3066
3067 /**
3068 * QThread class reimplementation to open Win32 API native folder's dialog
3069 */
3070 class Thread : public QThread
3071 {
3072 public:
3073
3074 Thread (QWidget *aParent, QObject *aTarget,
3075 const QString &aDir, const QString &aCaption)
3076 : mParent (aParent), mTarget (aTarget), mDir (aDir), mCaption (aCaption) {}
3077
3078 virtual void run()
3079 {
3080 QString result;
3081
3082 QWidget *topParent = mParent ? mParent->topLevelWidget() : qApp->mainWidget();
3083 QString title = mCaption.isNull() ? tr ("Select a directory") : mCaption;
3084
3085 TCHAR path[MAX_PATH];
3086 path [0] = 0;
3087 TCHAR initPath [MAX_PATH];
3088 initPath [0] = 0;
3089
3090 BROWSEINFO bi;
3091 bi.hwndOwner = topParent ? topParent->winId() : 0;
3092 bi.pidlRoot = NULL;
3093 bi.lpszTitle = (TCHAR*)title.ucs2();
3094 bi.pszDisplayName = initPath;
3095 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
3096 bi.lpfn = winGetExistDirCallbackProc;
3097 bi.lParam = Q_ULONG (&mDir);
3098
3099 /* Qt is uncapable to properly handle modal state if the modal
3100 * window is not a QWidget. For example, if we have the W1->W2->N
3101 * ownership where Wx are QWidgets (W2 is modal), and N is a
3102 * native modal window, cliking on the title bar of W1 will still
3103 * activate W2 and redirect keyboard/mouse to it. The dirty hack
3104 * to prevent it is to disable the entire widget... */
3105 if (mParent)
3106 mParent->setEnabled (false);
3107
3108 LPITEMIDLIST itemIdList = SHBrowseForFolder (&bi);
3109 if (itemIdList)
3110 {
3111 SHGetPathFromIDList (itemIdList, path);
3112 IMalloc *pMalloc;
3113 if (SHGetMalloc (&pMalloc) != NOERROR)
3114 result = QString::null;
3115 else
3116 {
3117 pMalloc->Free (itemIdList);
3118 pMalloc->Release();
3119 result = QString::fromUcs2 ((ushort*)path);
3120 }
3121 }
3122 else
3123 result = QString::null;
3124 QApplication::postEvent (mTarget, new GetExistDirectoryEvent (result));
3125
3126 /* Enable the parent widget again. */
3127 if (mParent)
3128 mParent->setEnabled (true);
3129 }
3130
3131 private:
3132
3133 QWidget *mParent;
3134 QObject *mTarget;
3135 QString mDir;
3136 QString mCaption;
3137 };
3138
3139 QString dir = QDir::convertSeparators (aDir);
3140 LoopObject loopObject ((QEvent::Type) GetExistDirectoryEvent::TypeId);
3141 Thread openDirThread (aParent, &loopObject, dir, aCaption);
3142 openDirThread.start();
3143 qApp->eventLoop()->enterLoop();
3144 openDirThread.wait();
3145 return loopObject.result();
3146
3147#else
3148
3149 return Q3FileDialog::getExistingDirectory (aDir, aParent, aName, aCaption,
3150 aDirOnly, aResolveSymlinks);
3151
3152#endif
3153}
3154
3155/**
3156 * Reimplementation of QFileDialog::getOpenFileName() that removes some
3157 * oddities and limitations.
3158 *
3159 * On Win32, this funciton makes sure a file filter is applied automatically
3160 * right after it is selected from the drop-down list, to conform to common
3161 * experience in other applications. Note that currently, @a selectedFilter
3162 * is always set to null on return.
3163 *
3164 * On all other platforms, this function is equivalent to
3165 * QFileDialog::getOpenFileName().
3166 */
3167/* static */
3168QString VBoxGlobal::getOpenFileName (const QString &aStartWith,
3169 const QString &aFilters,
3170 QWidget *aParent,
3171 const char *aName,
3172 const QString &aCaption,
3173 QString *aSelectedFilter,
3174 bool aResolveSymlinks)
3175{
3176#if defined Q_WS_WIN
3177
3178 /**
3179 * QEvent class reimplementation to carry Win32 API native dialog's
3180 * result folder information
3181 */
3182 class GetOpenFileNameEvent : public OpenNativeDialogEvent
3183 {
3184 public:
3185
3186 enum { TypeId = QEvent::User + 301 };
3187
3188 GetOpenFileNameEvent (const QString &aResult)
3189 : OpenNativeDialogEvent (aResult, (QEvent::Type) TypeId) {}
3190 };
3191
3192 /**
3193 * QThread class reimplementation to open Win32 API native file dialog
3194 */
3195 class Thread : public QThread
3196 {
3197 public:
3198
3199 Thread (QWidget *aParent, QObject *aTarget,
3200 const QString &aStartWith, const QString &aFilters,
3201 const QString &aCaption) :
3202 mParent (aParent), mTarget (aTarget),
3203 mStartWith (aStartWith), mFilters (aFilters),
3204 mCaption (aCaption) {}
3205
3206 virtual void run()
3207 {
3208 QString result;
3209
3210 QString workDir;
3211 QString initSel;
3212 QFileInfo fi (mStartWith);
3213
3214 if (fi.isDir())
3215 workDir = mStartWith;
3216 else
3217 {
3218 workDir = fi.dirPath (true);
3219 initSel = fi.fileName();
3220 }
3221
3222 workDir = QDir::convertSeparators (workDir);
3223 if (!workDir.endsWith ("\\"))
3224 workDir += "\\";
3225
3226 QString title = mCaption.isNull() ? tr ("Select a file") : mCaption;
3227
3228 QWidget *topParent = mParent ? mParent->topLevelWidget() : qApp->mainWidget();
3229 QString winFilters = winFilter (mFilters);
3230 AssertCompile (sizeof (TCHAR) == sizeof (QChar));
3231 TCHAR buf [1024];
3232 if (initSel.length() > 0 && initSel.length() < sizeof (buf))
3233 memcpy (buf, initSel.ucs2(), (initSel.length() + 1) * sizeof (TCHAR));
3234 else
3235 buf [0] = 0;
3236
3237 OPENFILENAME ofn;
3238 memset (&ofn, 0, sizeof (OPENFILENAME));
3239
3240 ofn.lStructSize = sizeof (OPENFILENAME);
3241 ofn.hwndOwner = topParent ? topParent->winId() : 0;
3242 ofn.lpstrFilter = (TCHAR *) winFilters.ucs2();
3243 ofn.lpstrFile = buf;
3244 ofn.nMaxFile = sizeof (buf) - 1;
3245 ofn.lpstrInitialDir = (TCHAR *) workDir.ucs2();
3246 ofn.lpstrTitle = (TCHAR *) title.ucs2();
3247 ofn.Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY |
3248 OFN_EXPLORER | OFN_ENABLEHOOK |
3249 OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
3250 ofn.lpfnHook = OFNHookProc;
3251
3252 if (GetOpenFileName (&ofn))
3253 {
3254 result = QString::fromUcs2 ((ushort *) ofn.lpstrFile);
3255 }
3256
3257 // qt_win_eatMouseMove();
3258 MSG msg = {0, 0, 0, 0, 0, 0, 0};
3259 while (PeekMessage (&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE));
3260 if (msg.message == WM_MOUSEMOVE)
3261 PostMessage (msg.hwnd, msg.message, 0, msg.lParam);
3262
3263 result = result.isEmpty() ? result : QFileInfo (result).absFilePath();
3264
3265 QApplication::postEvent (mTarget, new GetOpenFileNameEvent (result));
3266 }
3267
3268 private:
3269
3270 QWidget *mParent;
3271 QObject *mTarget;
3272 QString mStartWith;
3273 QString mFilters;
3274 QString mCaption;
3275 };
3276
3277 if (aSelectedFilter)
3278 *aSelectedFilter = QString::null;
3279 QString startWith = QDir::convertSeparators (aStartWith);
3280 LoopObject loopObject ((QEvent::Type) GetOpenFileNameEvent::TypeId);
3281 if (aParent) qt_enter_modal (aParent);
3282 Thread openDirThread (aParent, &loopObject, startWith, aFilters, aCaption);
3283 openDirThread.start();
3284 qApp->eventLoop()->enterLoop();
3285 openDirThread.wait();
3286 if (aParent) qt_leave_modal (aParent);
3287 return loopObject.result();
3288
3289#else
3290
3291 return Q3FileDialog::getOpenFileName (aStartWith, aFilters, aParent, aName,
3292 aCaption, aSelectedFilter, aResolveSymlinks);
3293
3294#endif
3295}
3296
3297/**
3298 * Search for the first directory that exists starting from the passed one
3299 * and going up through its parents. In case if none of the directories
3300 * exist (except the root one), the function returns QString::null.
3301 */
3302/* static */
3303QString VBoxGlobal::getFirstExistingDir (const QString &aStartDir)
3304{
3305 QString result = QString::null;
3306 QDir dir (aStartDir);
3307 while (!dir.exists() && !dir.isRoot())
3308 {
3309 QFileInfo dirInfo (dir.absPath());
3310 dir = dirInfo.dirPath (true);
3311 }
3312 if (dir.exists() && !dir.isRoot())
3313 result = dir.absPath();
3314 return result;
3315}
3316
3317#if defined (Q_WS_X11)
3318
3319static char *XXGetProperty (Display *aDpy, Window aWnd,
3320 Atom aPropType, const char *aPropName)
3321{
3322 Atom propNameAtom = XInternAtom (aDpy, aPropName,
3323 True /* only_if_exists */);
3324 if (propNameAtom == None)
3325 return NULL;
3326
3327 Atom actTypeAtom = None;
3328 int actFmt = 0;
3329 unsigned long nItems = 0;
3330 unsigned long nBytesAfter = 0;
3331 unsigned char *propVal = NULL;
3332 int rc = XGetWindowProperty (aDpy, aWnd, propNameAtom,
3333 0, LONG_MAX, False /* delete */,
3334 aPropType, &actTypeAtom, &actFmt,
3335 &nItems, &nBytesAfter, &propVal);
3336 if (rc != Success)
3337 return NULL;
3338
3339 return reinterpret_cast <char *> (propVal);
3340}
3341
3342static Bool XXSendClientMessage (Display *aDpy, Window aWnd, const char *aMsg,
3343 unsigned long aData0 = 0, unsigned long aData1 = 0,
3344 unsigned long aData2 = 0, unsigned long aData3 = 0,
3345 unsigned long aData4 = 0)
3346{
3347 Atom msgAtom = XInternAtom (aDpy, aMsg, True /* only_if_exists */);
3348 if (msgAtom == None)
3349 return False;
3350
3351 XEvent ev;
3352
3353 ev.xclient.type = ClientMessage;
3354 ev.xclient.serial = 0;
3355 ev.xclient.send_event = True;
3356 ev.xclient.display = aDpy;
3357 ev.xclient.window = aWnd;
3358 ev.xclient.message_type = msgAtom;
3359
3360 /* always send as 32 bit for now */
3361 ev.xclient.format = 32;
3362 ev.xclient.data.l [0] = aData0;
3363 ev.xclient.data.l [1] = aData1;
3364 ev.xclient.data.l [2] = aData2;
3365 ev.xclient.data.l [3] = aData3;
3366 ev.xclient.data.l [4] = aData4;
3367
3368 return XSendEvent (aDpy, DefaultRootWindow (aDpy), False,
3369 SubstructureRedirectMask, &ev) != 0;
3370}
3371
3372#endif
3373
3374/**
3375 * Activates the specified window. If necessary, the window will be
3376 * de-iconified activation.
3377 *
3378 * @note On X11, it is implied that @a aWid represents a window of the same
3379 * display the application was started on.
3380 *
3381 * @param aWId Window ID to activate.
3382 * @param aSwitchDesktop @c true to switch to the window's desktop before
3383 * activation.
3384 *
3385 * @return @c true on success and @c false otherwise.
3386 */
3387/* static */
3388bool VBoxGlobal::activateWindow (WId aWId, bool aSwitchDesktop /* = true */)
3389{
3390 bool result = true;
3391
3392#if defined (Q_WS_WIN32)
3393
3394 if (IsIconic (aWId))
3395 result &= !!ShowWindow (aWId, SW_RESTORE);
3396 else if (!IsWindowVisible (aWId))
3397 result &= !!ShowWindow (aWId, SW_SHOW);
3398
3399 result &= !!SetForegroundWindow (aWId);
3400
3401#elif defined (Q_WS_X11)
3402
3403 Display *dpy = QPaintDevice::x11AppDisplay();
3404
3405 if (aSwitchDesktop)
3406 {
3407 /* try to find the desktop ID using the NetWM property */
3408 CARD32 *desktop = (CARD32 *) XXGetProperty (dpy, aWId, XA_CARDINAL,
3409 "_NET_WM_DESKTOP");
3410 if (desktop == NULL)
3411 /* if the NetWM propery is not supported try to find the desktop
3412 * ID using the GNOME WM property */
3413 desktop = (CARD32 *) XXGetProperty (dpy, aWId, XA_CARDINAL,
3414 "_WIN_WORKSPACE");
3415
3416 if (desktop != NULL)
3417 {
3418 Bool ok = XXSendClientMessage (dpy, DefaultRootWindow (dpy),
3419 "_NET_CURRENT_DESKTOP",
3420 *desktop);
3421 if (!ok)
3422 {
3423 LogWarningFunc (("Couldn't switch to desktop=%08X\n",
3424 desktop));
3425 result = false;
3426 }
3427 XFree (desktop);
3428 }
3429 else
3430 {
3431 LogWarningFunc (("Couldn't find a desktop ID for aWId=%08X\n",
3432 aWId));
3433 result = false;
3434 }
3435 }
3436
3437 Bool ok = XXSendClientMessage (dpy, aWId, "_NET_ACTIVE_WINDOW");
3438 result &= !!ok;
3439
3440 XRaiseWindow (dpy, aWId);
3441
3442#else
3443
3444 AssertFailed();
3445 result = false;
3446
3447#endif
3448
3449 if (!result)
3450 LogWarningFunc (("Couldn't activate aWId=%08X\n", aWId));
3451
3452 return result;
3453}
3454
3455/**
3456 * Removes the acceletartor mark (the ampersand symbol) from the given string
3457 * and returns the result. The string is supposed to be a menu item's text
3458 * that may (or may not) contain the accelerator mark.
3459 *
3460 * In order to support accelerators used in non-alphabet languages
3461 * (e.g. Japanese) that has a form of "(&<L>)" (where <L> is a latin letter),
3462 * this method first searches for this pattern and, if found, removes it as a
3463 * whole. If such a pattern is not found, then the '&' character is simply
3464 * removed from the string.
3465 *
3466 * @note This function removes only the first occurense of the accelerator
3467 * mark.
3468 *
3469 * @param aText Menu item's text to remove the acceletaror mark from.
3470 *
3471 * @return The resulting string.
3472 */
3473/* static */
3474QString VBoxGlobal::removeAccelMark (const QString &aText)
3475{
3476 QString result = aText;
3477
3478 QRegExp accel ("\\(&[a-zA-Z]\\)");
3479 int pos = accel.search (result);
3480 if (pos >= 0)
3481 result.remove (pos, accel.cap().length());
3482 else
3483 {
3484 pos = result.find ('&');
3485 if (pos >= 0)
3486 result.remove (pos, 1);
3487 }
3488
3489 return result;
3490}
3491
3492/**
3493 * Searches for a widget that with @a aName (if it is not NULL) which inherits
3494 * @a aClassName (if it is not NULL) and among children of @a aParent. If @a
3495 * aParent is NULL, all top-level widgets are searched. If @a aRecursive is
3496 * true, child widgets are recursively searched as well.
3497 */
3498/* static */
3499QWidget *VBoxGlobal::findWidget (QWidget *aParent, const char *aName,
3500 const char *aClassName /* = NULL */,
3501 bool aRecursive /* = false */)
3502{
3503 if (aParent == NULL)
3504 {
3505 QWidgetList list = QApplication::topLevelWidgets();
3506 QWidget* w = NULL;
3507 foreach(w, list)
3508 {
3509 if ((!aName || strcmp (w->name(), aName) == 0) &&
3510 (!aClassName || strcmp (w->className(), aClassName) == 0))
3511 break;
3512 if (aRecursive)
3513 {
3514 w = findWidget (w, aName, aClassName, aRecursive);
3515 if (w)
3516 break;
3517 }
3518 }
3519 return w;
3520 }
3521
3522 QObjectList list = aParent->queryList (aName, aClassName, false, true);
3523 QObject *obj = NULL;
3524 foreach(obj, list)
3525 {
3526 if (obj->isWidgetType())
3527 break;
3528 }
3529 return (QWidget *) obj;
3530}
3531
3532// Public slots
3533////////////////////////////////////////////////////////////////////////////////
3534
3535/**
3536 * Opens the specified URL using OS/Desktop capabilities.
3537 *
3538 * @param aURL URL to open
3539 *
3540 * @return true on success and false otherwise
3541 */
3542bool VBoxGlobal::openURL (const QString &aURL)
3543{
3544#if defined (Q_WS_WIN)
3545 /* We cannot use ShellExecute() on the main UI thread because we've
3546 * initialized COM with CoInitializeEx(COINIT_MULTITHREADED). See
3547 * http://support.microsoft.com/default.aspx?scid=kb;en-us;287087
3548 * for more details. */
3549 class Thread : public QThread
3550 {
3551 public:
3552
3553 Thread (const QString &aURL, QObject *aObject)
3554 : mObject (aObject), mURL (aURL) {}
3555
3556 void run()
3557 {
3558 int rc = (int) ShellExecute (NULL, NULL, mURL.ucs2(), NULL, NULL, SW_SHOW);
3559 bool ok = rc > 32;
3560 QApplication::postEvent
3561 (mObject,
3562 new VBoxShellExecuteEvent (this, mURL, ok));
3563 }
3564
3565 QString mURL;
3566 QObject *mObject;
3567 };
3568
3569 Thread *thread = new Thread (aURL, this);
3570 thread->start();
3571 /* thread will be deleted in the VBoxShellExecuteEvent handler */
3572
3573 return true;
3574
3575#elif defined (Q_WS_X11)
3576
3577 static const char * const commands[] =
3578 { "kfmclient:exec", "gnome-open", "x-www-browser", "firefox", "konqueror" };
3579
3580 for (size_t i = 0; i < ELEMENTS (commands); ++ i)
3581 {
3582 QStringList args = QStringList::split (':', commands [i]);
3583 args += aURL;
3584 Q3Process cmd (args);
3585 if (cmd.start())
3586 return true;
3587 }
3588
3589#elif defined (Q_WS_MAC)
3590
3591 /* The code below is taken from Psi 0.10 sources
3592 * (http://www.psi-im.org) */
3593
3594 /* Use Internet Config to hand the URL to the appropriate application, as
3595 * set by the user in the Internet Preferences pane.
3596 * NOTE: ICStart could be called once at Psi startup, saving the
3597 * ICInstance in a global variable, as a minor optimization.
3598 * ICStop should then be called at Psi shutdown if ICStart
3599 * succeeded. */
3600 ICInstance icInstance;
3601 OSType psiSignature = 'psi ';
3602 OSStatus error = ::ICStart (&icInstance, psiSignature);
3603 if (error == noErr)
3604 {
3605 ConstStr255Param hint (0x0);
3606 Q3CString cs = aURL.local8Bit();
3607 const char* data = cs.data();
3608 long length = cs.length();
3609 long start (0);
3610 long end (length);
3611 /* Don't bother testing return value (error); launched application
3612 * will report problems. */
3613 ::ICLaunchURL (icInstance, hint, data, length, &start, &end);
3614 ICStop (icInstance);
3615 return true;
3616 }
3617
3618#else
3619 vboxProblem().message
3620 (NULL, VBoxProblemReporter::Error,
3621 tr ("Opening URLs is not implemented yet."));
3622 return false;
3623#endif
3624
3625 /* if we go here it means we couldn't open the URL */
3626 vboxProblem().cannotOpenURL (aURL);
3627
3628 return false;
3629}
3630
3631void VBoxGlobal::showRegistrationDialog (bool aForce)
3632{
3633#ifdef VBOX_WITH_REGISTRATION
3634 if (!aForce && !VBoxRegistrationDlg::hasToBeShown())
3635 return;
3636
3637 if (mRegDlg)
3638 {
3639 /* Show the already opened registration dialog */
3640 mRegDlg->setWindowState (mRegDlg->windowState() & ~Qt::WindowMinimized);
3641 mRegDlg->raise();
3642 mRegDlg->setActiveWindow();
3643 }
3644 else
3645 {
3646 /* Store the ID of the main window to ensure that only one
3647 * registration dialog is shown at a time. Due to manipulations with
3648 * OnExtraDataCanChange() and OnExtraDataChange() signals, this extra
3649 * data item acts like an inter-process mutex, so the first process
3650 * that attempts to set it will win, the rest will get a failure from
3651 * the SetExtraData() call. */
3652 mVBox.SetExtraData (VBoxDefs::GUI_RegistrationDlgWinID,
3653 QString ("%1").arg ((long) qApp->mainWidget()->winId()));
3654
3655 if (mVBox.isOk())
3656 {
3657 /* We've got the "mutex", create a new registration dialog */
3658#warning port me
3659// VBoxRegistrationDlg *dlg =
3660// new VBoxRegistrationDlg (0, 0, false, Qt::WDestructiveClose);
3661// dlg->setup (&mRegDlg);
3662// Assert (dlg == mRegDlg);
3663// mRegDlg->show();
3664 }
3665 }
3666#endif
3667}
3668
3669// Protected members
3670////////////////////////////////////////////////////////////////////////////////
3671
3672bool VBoxGlobal::event (QEvent *e)
3673{
3674 switch (e->type())
3675 {
3676#if defined (Q_WS_WIN)
3677 case VBoxDefs::ShellExecuteEventType:
3678 {
3679 VBoxShellExecuteEvent *ev = (VBoxShellExecuteEvent *) e;
3680 if (!ev->mOk)
3681 vboxProblem().cannotOpenURL (ev->mURL);
3682 /* wait for the thread and free resources */
3683 ev->mThread->wait();
3684 delete ev->mThread;
3685 return true;
3686 }
3687#endif
3688
3689 case VBoxDefs::AsyncEventType:
3690 {
3691 VBoxAsyncEvent *ev = (VBoxAsyncEvent *) e;
3692 ev->handle();
3693 return true;
3694 }
3695
3696 case VBoxDefs::EnumerateMediaEventType:
3697 {
3698 VBoxEnumerateMediaEvent *ev = (VBoxEnumerateMediaEvent *) e;
3699
3700 if (!ev->mLast)
3701 {
3702 if (ev->mMedia.status == VBoxMedia::Error)
3703 vboxProblem().cannotGetMediaAccessibility (ev->mMedia.disk);
3704 media_list [ev->mIndex] = ev->mMedia;
3705 emit mediaEnumerated (media_list [ev->mIndex], ev->mIndex);
3706 }
3707 else
3708 {
3709 /* the thread has posted the last message, wait for termination */
3710 media_enum_thread->wait();
3711 delete media_enum_thread;
3712 media_enum_thread = 0;
3713
3714 emit mediaEnumFinished (media_list);
3715 }
3716
3717 return true;
3718 }
3719
3720 /* VirtualBox callback events */
3721
3722 case VBoxDefs::MachineStateChangeEventType:
3723 {
3724 emit machineStateChanged (*(VBoxMachineStateChangeEvent *) e);
3725 return true;
3726 }
3727 case VBoxDefs::MachineDataChangeEventType:
3728 {
3729 emit machineDataChanged (*(VBoxMachineDataChangeEvent *) e);
3730 return true;
3731 }
3732 case VBoxDefs::MachineRegisteredEventType:
3733 {
3734 emit machineRegistered (*(VBoxMachineRegisteredEvent *) e);
3735 return true;
3736 }
3737 case VBoxDefs::SessionStateChangeEventType:
3738 {
3739 emit sessionStateChanged (*(VBoxSessionStateChangeEvent *) e);
3740 return true;
3741 }
3742 case VBoxDefs::SnapshotEventType:
3743 {
3744 emit snapshotChanged (*(VBoxSnapshotEvent *) e);
3745 return true;
3746 }
3747 case VBoxDefs::CanShowRegDlgEventType:
3748 {
3749 emit canShowRegDlg (((VBoxCanShowRegDlgEvent *) e)->mCanShow);
3750 return true;
3751 }
3752
3753 default:
3754 break;
3755 }
3756
3757 return QObject::event (e);
3758}
3759
3760bool VBoxGlobal::eventFilter (QObject *aObject, QEvent *aEvent)
3761{
3762 if (aEvent->type() == QEvent::LanguageChange &&
3763 aObject->isWidgetType() &&
3764 static_cast <QWidget *> (aObject)->isTopLevel())
3765 {
3766 /* Catch the language change event before any other widget gets it in
3767 * order to invalidate cached string resources (like the details view
3768 * templates) that may be used by other widgets. */
3769 QWidgetList list = QApplication::topLevelWidgets();
3770 if (list.first() == aObject)
3771 {
3772 /* call this only once per every language change (see
3773 * QApplication::installTranslator() for details) */
3774 languageChange();
3775 }
3776 }
3777
3778 return QObject::eventFilter (aObject, aEvent);
3779}
3780
3781// Private members
3782////////////////////////////////////////////////////////////////////////////////
3783
3784void VBoxGlobal::init()
3785{
3786#ifdef DEBUG
3787 verString += " [DEBUG]";
3788#endif
3789
3790#ifdef Q_WS_WIN
3791 /* COM for the main thread is initialized in main() */
3792#else
3793 HRESULT rc = COMBase::InitializeCOM();
3794 if (FAILED (rc))
3795 {
3796 vboxProblem().cannotInitCOM (rc);
3797 return;
3798 }
3799#endif
3800
3801 mVBox.createInstance (CLSID_VirtualBox);
3802 if (!mVBox.isOk())
3803 {
3804 vboxProblem().cannotCreateVirtualBox (mVBox);
3805 return;
3806 }
3807
3808 /* initialize guest OS type vector */
3809 CGuestOSTypeCollection coll = mVBox.GetGuestOSTypes();
3810 int osTypeCount = coll.GetCount();
3811 AssertMsg (osTypeCount > 0, ("Number of OS types must not be zero"));
3812 if (osTypeCount > 0)
3813 {
3814 vm_os_types.resize (osTypeCount);
3815 int i = 0;
3816 CGuestOSTypeEnumerator en = coll.Enumerate();
3817 while (en.HasMore())
3818 vm_os_types [i++] = en.GetNext();
3819 }
3820
3821 /* fill in OS type icon dictionary */
3822 static const char *osTypeIcons[][2] =
3823 {
3824 {"unknown", ":/os_other.png"},
3825 {"dos", ":/os_dos.png"},
3826 {"win31", ":/os_win31.png"},
3827 {"win95", ":/os_win95.png"},
3828 {"win98", ":/os_win98.png"},
3829 {"winme", ":/os_winme.png"},
3830 {"winnt4", ":/os_winnt.png"},
3831 {"win2k", ":/os_win2000.png"},
3832 {"winxp", ":/os_winxp.png"},
3833 {"win2k3", ":/os_win2003.png"},
3834 {"winvista", ":/os_winvista.png"},
3835 {"os2warp3", ":/os_os2.png"},
3836 {"os2warp4", ":/os_os2.png"},
3837 {"os2warp45", ":/os_os2.png"},
3838 {"linux22", ":/os_linux.png"},
3839 {"linux24", ":/os_linux.png"},
3840 {"linux26", ":/os_linux.png"},
3841 {"freebsd", ":/os_freebsd.png"},
3842 {"openbsd", ":/os_openbsd.png"},
3843 {"netbsd", ":/os_netbsd.png"},
3844 {"netware", ":/os_netware.png"},
3845 {"solaris", ":/os_solaris.png"},
3846 {"l4", ":/os_l4.png"},
3847 };
3848 vm_os_type_icons.setAutoDelete (true); /* takes ownership of elements */
3849 for (uint n = 0; n < SIZEOF_ARRAY (osTypeIcons); n ++)
3850 {
3851 vm_os_type_icons.insert (osTypeIcons [n][0],
3852 new QPixmap (osTypeIcons [n][1]));
3853 }
3854
3855 /* fill in VM state icon dictionary */
3856 static struct
3857 {
3858 KMachineState state;
3859 const char *name;
3860 }
3861 vmStateIcons[] =
3862 {
3863 {KMachineState_Null, NULL},
3864 {KMachineState_PoweredOff, ":/state_powered_off_16px.png"},
3865 {KMachineState_Saved, ":/state_saved_16px.png"},
3866 {KMachineState_Aborted, ":/state_aborted_16px.png"},
3867 {KMachineState_Running, ":/state_running_16px.png"},
3868 {KMachineState_Paused, ":/state_paused_16px.png"},
3869 {KMachineState_Stuck, ":/state_stuck_16px.png"},
3870 {KMachineState_Starting, ":/state_running_16px.png"}, /// @todo (dmik) separate icon?
3871 {KMachineState_Stopping, ":/state_running_16px.png"}, /// @todo (dmik) separate icon?
3872 {KMachineState_Saving, ":/state_saving_16px.png"},
3873 {KMachineState_Restoring, ":/state_restoring_16px.png"},
3874 {KMachineState_Discarding, ":/state_discarding_16px.png"},
3875 };
3876 mStateIcons.setAutoDelete (true); // takes ownership of elements
3877 for (uint n = 0; n < SIZEOF_ARRAY (vmStateIcons); n ++)
3878 {
3879 mStateIcons.insert (vmStateIcons [n].state,
3880 new QPixmap (vmStateIcons [n].name));
3881 }
3882
3883 /* online/offline snapshot icons */
3884 mOfflineSnapshotIcon = QPixmap (":/offline_snapshot_16px.png");
3885 mOnlineSnapshotIcon = QPixmap (":/online_snapshot_16px.png");
3886
3887 /* initialize state colors vector */
3888 vm_state_color.setAutoDelete (true); /* takes ownership of elements */
3889 vm_state_color.insert (KMachineState_Null, new QColor(Qt::red));
3890 vm_state_color.insert (KMachineState_PoweredOff, new QColor(Qt::gray));
3891 vm_state_color.insert (KMachineState_Saved, new QColor(Qt::yellow));
3892 vm_state_color.insert (KMachineState_Aborted, new QColor(Qt::darkRed));
3893 vm_state_color.insert (KMachineState_Running, new QColor(Qt::green));
3894 vm_state_color.insert (KMachineState_Paused, new QColor(Qt::darkGreen));
3895 vm_state_color.insert (KMachineState_Stuck, new QColor(Qt::darkMagenta));
3896 vm_state_color.insert (KMachineState_Starting, new QColor(Qt::green));
3897 vm_state_color.insert (KMachineState_Stopping, new QColor(Qt::green));
3898 vm_state_color.insert (KMachineState_Saving, new QColor(Qt::green));
3899 vm_state_color.insert (KMachineState_Restoring, new QColor(Qt::green));
3900 vm_state_color.insert (KMachineState_Discarding, new QColor(Qt::green));
3901
3902 qApp->installEventFilter (this);
3903
3904 /* create default non-null global settings */
3905 gset = VBoxGlobalSettings (false);
3906
3907 /* try to load global settings */
3908 gset.load (mVBox);
3909 if (!mVBox.isOk() || !gset)
3910 {
3911 vboxProblem().cannotLoadGlobalConfig (mVBox, gset.lastError());
3912 return;
3913 }
3914
3915 /* Load customized language if any */
3916 QString languageId = gset.languageId();
3917 if (!languageId.isNull())
3918 loadLanguage (languageId);
3919
3920 languageChange();
3921
3922 /* process command line */
3923
3924 vm_render_mode_str = 0;
3925#ifdef VBOX_WITH_DEBUGGER_GUI
3926#ifdef VBOX_WITH_DEBUGGER_GUI_MENU
3927 dbg_enabled = true;
3928#else
3929 dbg_enabled = false;
3930#endif
3931 dbg_visible_at_startup = false;
3932#endif
3933
3934 int argc = qApp->argc();
3935 int i = 1;
3936 while ( i < argc ) {
3937 const char *arg = qApp->argv()[i];
3938 if ( !::strcmp( arg, "-startvm" ) ) {
3939 if ( ++i < argc ) {
3940 QString param = QString (qApp->argv()[i]);
3941 QUuid uuid = QUuid (param);
3942 if (!uuid.isNull()) {
3943 vmUuid = uuid;
3944 } else {
3945 CMachine m = mVBox.FindMachine (param);
3946 if (m.isNull()) {
3947 vboxProblem().cannotFindMachineByName (mVBox, param);
3948 return;
3949 }
3950 vmUuid = m.GetId();
3951 }
3952 }
3953 } else if ( !::strcmp( arg, "-comment" ) ) {
3954 ++i;
3955 } else if ( !::strcmp( arg, "-rmode" ) ) {
3956 if ( ++i < argc )
3957 vm_render_mode_str = qApp->argv()[i];
3958 }
3959#ifdef VBOX_WITH_DEBUGGER_GUI
3960 else if ( !::strcmp( arg, "-dbg" ) ) {
3961 dbg_enabled = true;
3962 }
3963#ifdef DEBUG
3964 else if ( !::strcmp( arg, "-nodebug" ) ) {
3965 dbg_enabled = false;
3966 dbg_visible_at_startup = false;
3967 }
3968#else
3969 else if ( !::strcmp( arg, "-debug" ) ) {
3970 dbg_enabled = true;
3971 dbg_visible_at_startup = true;
3972 }
3973#endif
3974#endif
3975 i++;
3976 }
3977
3978 vm_render_mode = vboxGetRenderMode( vm_render_mode_str );
3979
3980 /* setup the callback */
3981 callback = CVirtualBoxCallback (new VBoxCallback (*this));
3982 mVBox.RegisterCallback (callback);
3983 AssertWrapperOk (mVBox);
3984 if (!mVBox.isOk())
3985 return;
3986
3987 /* Redefine default large and small icon sizes. In particular, it is
3988 * necessary to consider both 32px and 22px icon sizes as Large when we
3989 * explicitly define them as Large (seems to be a bug in
3990 * QToolButton::sizeHint()). */
3991#warning port me
3992// QIcon::setIconSize (QIcon::Small, QSize (16, 16));
3993// QIcon::setIconSize (QIcon::Large, QSize (22, 22));
3994
3995 mValid = true;
3996}
3997
3998/** @internal
3999 *
4000 * This method should be never called directly. It is called automatically
4001 * when the application terminates.
4002 */
4003void VBoxGlobal::cleanup()
4004{
4005 /* sanity check */
4006 if (!sVBoxGlobalInCleanup)
4007 {
4008 AssertMsgFailed (("Should never be called directly\n"));
4009 return;
4010 }
4011
4012 if (!callback.isNull())
4013 {
4014 mVBox.UnregisterCallback (callback);
4015 AssertWrapperOk (mVBox);
4016 callback.detach();
4017 }
4018
4019 if (media_enum_thread)
4020 {
4021 /* sVBoxGlobalInCleanup is true here, so just wait for the thread */
4022 media_enum_thread->wait();
4023 delete media_enum_thread;
4024 media_enum_thread = 0;
4025 }
4026
4027#ifdef VBOX_WITH_REGISTRATION
4028 if (mRegDlg)
4029 mRegDlg->close();
4030#endif
4031
4032 if (mConsoleWnd)
4033 delete mConsoleWnd;
4034 if (mSelectorWnd)
4035 delete mSelectorWnd;
4036
4037 /* ensure CGuestOSType objects are no longer used */
4038 vm_os_types.clear();
4039 /* media list contains a lot of CUUnknown, release them */
4040 media_list.clear();
4041 /* the last step to ensure we don't use COM any more */
4042 mVBox.detach();
4043
4044 /* There may be VBoxEnumerateMediaEvent instances still in the message
4045 * queue which reference COM objects. Remove them to release those objects
4046 * before uninitializing the COM subsystem. */
4047 QApplication::removePostedEvents (this);
4048
4049#ifdef Q_WS_WIN
4050 /* COM for the main thread is shutdown in main() */
4051#else
4052 COMBase::CleanupCOM();
4053#endif
4054
4055 mValid = false;
4056}
4057
4058/** @fn vboxGlobal
4059 *
4060 * Shortcut to the static VBoxGlobal::instance() method, for convenience.
4061 */
4062
4063
4064/**
4065 * USB Popup Menu class methods
4066 * This class provides the list of USB devices attached to the host.
4067 */
4068VBoxUSBMenu::VBoxUSBMenu (QWidget *aParent) : Q3PopupMenu (aParent)
4069{
4070 connect (this, SIGNAL (aboutToShow()),
4071 this, SLOT (processAboutToShow()));
4072 connect (this, SIGNAL (highlighted (int)),
4073 this, SLOT (processHighlighted (int)));
4074}
4075
4076const CUSBDevice& VBoxUSBMenu::getUSB (int aIndex)
4077{
4078 return mUSBDevicesMap [aIndex];
4079}
4080
4081void VBoxUSBMenu::setConsole (const CConsole &aConsole)
4082{
4083 mConsole = aConsole;
4084}
4085
4086void VBoxUSBMenu::processAboutToShow()
4087{
4088 clear();
4089 mUSBDevicesMap.clear();
4090
4091 CHost host = vboxGlobal().virtualBox().GetHost();
4092
4093 bool isUSBEmpty = host.GetUSBDevices().GetCount() == 0;
4094 if (isUSBEmpty)
4095 {
4096 insertItem (
4097 tr ("<no available devices>", "USB devices"),
4098 USBDevicesMenuNoDevicesId);
4099 setItemEnabled (USBDevicesMenuNoDevicesId, false);
4100 }
4101 else
4102 {
4103 CHostUSBDeviceEnumerator en = host.GetUSBDevices().Enumerate();
4104 while (en.HasMore())
4105 {
4106 CHostUSBDevice iterator = en.GetNext();
4107 CUSBDevice usb = CUnknown (iterator);
4108 int id = insertItem (vboxGlobal().details (usb));
4109 mUSBDevicesMap [id] = usb;
4110 /* check if created item was alread attached to this session */
4111 if (!mConsole.isNull())
4112 {
4113 CUSBDevice attachedUSB =
4114 mConsole.GetUSBDevices().FindById (usb.GetId());
4115 setItemChecked (id, !attachedUSB.isNull());
4116 setItemEnabled (id, iterator.GetState() !=
4117 KUSBDeviceState_Unavailable);
4118 }
4119 }
4120 }
4121}
4122
4123void VBoxUSBMenu::processHighlighted (int aIndex)
4124{
4125 /* the <no available devices> item is highlighted */
4126 if (aIndex == USBDevicesMenuNoDevicesId)
4127 {
4128 QToolTip::add (this,
4129 tr ("No supported devices connected to the host PC",
4130 "USB device tooltip"));
4131 return;
4132 }
4133
4134 CUSBDevice usb = mUSBDevicesMap [aIndex];
4135 /* if null then some other item but a USB device is highlighted */
4136 if (usb.isNull())
4137 {
4138 QToolTip::remove (this);
4139 return;
4140 }
4141
4142 QToolTip::remove (this);
4143 QToolTip::add (this, vboxGlobal().toolTip (usb));
4144}
4145
4146
4147/**
4148 * Enable/Disable Menu class.
4149 * This class provides enable/disable menu items.
4150 */
4151VBoxSwitchMenu::VBoxSwitchMenu (QWidget *aParent, QAction *aAction,
4152 bool aInverted)
4153 : Q3PopupMenu (aParent), mAction (aAction), mInverted (aInverted)
4154{
4155 /* this menu works only with toggle action */
4156 Assert (aAction->isToggleAction());
4157 connect (this, SIGNAL (aboutToShow()),
4158 this, SLOT (processAboutToShow()));
4159 connect (this, SIGNAL (activated (int)),
4160 this, SLOT (processActivated (int)));
4161}
4162
4163void VBoxSwitchMenu::setToolTip (const QString &aTip)
4164{
4165 mTip = aTip;
4166}
4167
4168void VBoxSwitchMenu::processAboutToShow()
4169{
4170 clear();
4171 QString text = mAction->isOn() ^ mInverted ? tr ("Disable") : tr ("Enable");
4172 int id = insertItem (text);
4173 setItemEnabled (id, mAction->isEnabled());
4174 QToolTip::add (this, tr ("%1 %2").arg (text).arg (mTip));
4175}
4176
4177void VBoxSwitchMenu::processActivated (int /*aIndex*/)
4178{
4179 mAction->setOn (!mAction->isOn());
4180}
4181
4182#ifdef Q_WS_X11
4183#include "VBoxGlobal.moc"
4184#endif
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette