VirtualBox

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

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

Main/Settings: Applied all current XML settings format todos and increased version from 1.3.pre to 1.3.

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

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