Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooser.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooser.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooser.cpp	(revision 42529)
@@ -0,0 +1,125 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooser class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QVBoxLayout>
+#include <QStatusBar>
+
+/* GUI includes: */
+#include "UIGChooser.h"
+#include "UIGChooserModel.h"
+#include "UIGChooserView.h"
+#include "UIVirtualBoxEventHandler.h"
+#include "VBoxGlobal.h"
+
+UIGChooser::UIGChooser(QWidget *pParent)
+    : QWidget(pParent)
+    , m_pMainLayout(0)
+    , m_pChooserModel(0)
+    , m_pChooserView(0)
+    , m_pStatusBar(0)
+{
+    /* Create main-layout: */
+    m_pMainLayout = new QVBoxLayout(this);
+    m_pMainLayout->setContentsMargins(0, 0, 0, 0);
+    m_pMainLayout->setSpacing(0);
+
+    /* Create chooser-model: */
+    m_pChooserModel = new UIGChooserModel(this);
+
+    /* Create chooser-view: */
+    m_pChooserView = new UIGChooserView(this);
+    m_pChooserView->setFrameShape(QFrame::NoFrame);
+    m_pChooserView->setFrameShadow(QFrame::Plain);
+    m_pChooserView->setScene(m_pChooserModel->scene());
+    m_pChooserView->show();
+    setFocusProxy(m_pChooserView);
+
+    /* Add tool-bar into layout: */
+    m_pMainLayout->addWidget(m_pChooserView);
+
+    /* Prepare connections: */
+    prepareConnections();
+
+    /* Load model: */
+    m_pChooserModel->load();
+
+    /* Load last selected item: */
+    m_pChooserModel->setCurrentItemDefinition(vboxGlobal().virtualBox().GetExtraData(GUI_LastItemSelected));
+}
+
+UIGChooser::~UIGChooser()
+{
+    /* Save last selected item: */
+    vboxGlobal().virtualBox().SetExtraData(GUI_LastItemSelected, m_pChooserModel->currentItemDefinition());
+
+    /* Save model: */
+    m_pChooserModel->save();
+}
+
+void UIGChooser::setCurrentItem(int iCurrentItemIndex)
+{
+    m_pChooserModel->setCurrentItem(iCurrentItemIndex);
+}
+
+UIVMItem* UIGChooser::currentItem() const
+{
+    return m_pChooserModel->currentItem();
+}
+
+QList<UIVMItem*> UIGChooser::currentItems() const
+{
+    return m_pChooserModel->currentItems();
+}
+
+bool UIGChooser::singleGroupSelected() const
+{
+    return m_pChooserModel->singleGroupSelected();
+}
+
+void UIGChooser::setStatusBar(QStatusBar *pStatusBar)
+{
+    /* Old status-bar set? */
+    if (m_pStatusBar)
+       m_pChooserModel->disconnect(m_pStatusBar);
+
+    /* Connect new status-bar: */
+    m_pStatusBar = pStatusBar;
+    connect(m_pChooserModel, SIGNAL(sigClearStatusMessage()), m_pStatusBar, SLOT(clearMessage()));
+    connect(m_pChooserModel, SIGNAL(sigShowStatusMessage(const QString&)), m_pStatusBar, SLOT(showMessage(const QString&)));
+}
+
+void UIGChooser::prepareConnections()
+{
+    /* Chooser-model connections: */
+    connect(m_pChooserModel, SIGNAL(sigRootItemResized(const QSizeF&, int)),
+            m_pChooserView, SLOT(sltHandleRootItemResized(const QSizeF&, int)));
+    connect(m_pChooserModel, SIGNAL(sigSelectionChanged()), this, SIGNAL(sigSelectionChanged()));
+
+    /* Chooser-view connections: */
+    connect(m_pChooserView, SIGNAL(sigResized()), m_pChooserModel, SLOT(sltHandleViewResized()));
+
+    /* Global connections: */
+    connect(gVBoxEvents, SIGNAL(sigMachineStateChange(QString, KMachineState)), m_pChooserModel, SLOT(sltMachineStateChanged(QString, KMachineState)));
+    connect(gVBoxEvents, SIGNAL(sigMachineDataChange(QString)), m_pChooserModel, SLOT(sltMachineDataChanged(QString)));
+    connect(gVBoxEvents, SIGNAL(sigMachineRegistered(QString, bool)), m_pChooserModel, SLOT(sltMachineRegistered(QString, bool)));
+    connect(gVBoxEvents, SIGNAL(sigSessionStateChange(QString, KSessionState)), m_pChooserModel, SLOT(sltSessionStateChanged(QString, KSessionState)));
+    connect(gVBoxEvents, SIGNAL(sigSnapshotChange(QString, QString)), m_pChooserModel, SLOT(sltSnapshotChanged(QString, QString)));
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooser.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooser.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooser.h	(revision 42529)
@@ -0,0 +1,73 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooser class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooser_h__
+#define __UIGChooser_h__
+
+/* Qt includes: */
+#include <QWidget>
+
+/* GUI includes: */
+#include "UIGChooserItem.h"
+
+/* Forward declartions: */
+class UIVMItem;
+class QVBoxLayout;
+class UIGChooserModel;
+class UIGChooserView;
+class QStatusBar;
+
+/* Graphics selector widget: */
+class UIGChooser : public QWidget
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifiers: Selection change: */
+    void sigSelectionChanged();
+
+public:
+
+    /* Constructor/destructor: */
+    UIGChooser(QWidget *pParent);
+    ~UIGChooser();
+
+    /* API: Current item stuff: */
+    void setCurrentItem(int iCurrentItemIndex);
+    UIVMItem* currentItem() const;
+    QList<UIVMItem*> currentItems() const;
+    bool singleGroupSelected() const;
+
+    /* API: Status bar stuff: */
+    void setStatusBar(QStatusBar *pStatusBar);
+
+private:
+
+    /* Helpers: */
+    void prepareConnections();
+
+    /* Variables: */
+    QVBoxLayout *m_pMainLayout;
+    UIGChooserModel *m_pChooserModel;
+    UIGChooserView *m_pChooserView;
+    QStatusBar *m_pStatusBar;
+};
+
+#endif /* __UIGChooser_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerKeyboard.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerKeyboard.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerKeyboard.cpp	(revision 42529)
@@ -0,0 +1,239 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserHandlerKeyboard class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QKeyEvent>
+
+/* GUI incluedes: */
+#include "UIGChooserHandlerKeyboard.h"
+#include "UIGChooserModel.h"
+
+UIGChooserHandlerKeyboard::UIGChooserHandlerKeyboard(UIGChooserModel *pParent)
+    : QObject(pParent)
+    , m_pModel(pParent)
+{
+}
+
+bool UIGChooserHandlerKeyboard::handle(QKeyEvent *pEvent, UIKeyboardEventType type) const
+{
+    /* Process passed event: */
+    switch (type)
+    {
+        case UIKeyboardEventType_Press: return handleKeyPress(pEvent);
+        case UIKeyboardEventType_Release: return handleKeyRelease(pEvent);
+    }
+    /* Pass event if unknown: */
+    return false;
+}
+
+UIGChooserModel* UIGChooserHandlerKeyboard::model() const
+{
+    return m_pModel;
+}
+
+bool UIGChooserHandlerKeyboard::handleKeyPress(QKeyEvent *pEvent) const
+{
+    /* Which key it was? */
+    switch (pEvent->key())
+    {
+        /* Key UP? */
+        case Qt::Key_Up:
+        {
+            /* Determine focus item position: */
+            int iPosition = model()->navigationList().indexOf(model()->focusItem());
+            /* Determine 'previous' item: */
+            UIGChooserItem *pPreviousItem = iPosition > 0 ?
+                                             model()->navigationList().at(iPosition - 1) : 0;
+            if (pPreviousItem)
+            {
+                /* Make sure 'previous' item is visible: */
+                pPreviousItem->makeSureItsVisible();
+                /* Move focus to 'previous' item: */
+                model()->setFocusItem(pPreviousItem);
+                /* Was 'shift' modifier pressed? */
+#ifdef Q_WS_MAC
+                if (pEvent->modifiers() & Qt::ShiftModifier &&
+                    pEvent->modifiers() & Qt::KeypadModifier)
+#else /* Q_WS_MAC */
+                if (pEvent->modifiers() == Qt::ShiftModifier)
+#endif /* !Q_WS_MAC */
+                {
+                    /* Calculate positions: */
+                    UIGChooserItem *pFirstItem = model()->selectionList().first();
+                    int iFirstPosition = model()->navigationList().indexOf(pFirstItem);
+                    int iPreviousPosition = model()->navigationList().indexOf(pPreviousItem);
+                    /* Clear selection: */
+                    model()->clearSelectionList();
+                    /* Select all the items from 'first' to 'previous': */
+                    if (iFirstPosition <= iPreviousPosition)
+                        for (int i = iFirstPosition; i <= iPreviousPosition; ++i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                    else
+                        for (int i = iFirstPosition; i >= iPreviousPosition; --i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                }
+                /* There is no modifiers pressed? */
+#ifdef Q_WS_MAC
+                else if (pEvent->modifiers() == Qt::KeypadModifier)
+#else /* Q_WS_MAC */
+                else if (pEvent->modifiers() == Qt::NoModifier)
+#endif /* !Q_WS_MAC */
+                {
+                    /* Move selection to 'previous' item: */
+                    model()->clearSelectionList();
+                    model()->addToSelectionList(pPreviousItem);
+                }
+                /* Notify selection changed: */
+                model()->notifySelectionChanged();
+                /* Filter-out this event: */
+                return true;
+            }
+            /* Pass this event: */
+            return false;
+        }
+        /* Key DOWN? */
+        case Qt::Key_Down:
+        {
+            /* Determine focus item position: */
+            int iPosition = model()->navigationList().indexOf(model()->focusItem());
+            /* Determine 'next' item: */
+            UIGChooserItem *pNextItem = iPosition < model()->navigationList().size() - 1 ?
+                                          model()->navigationList().at(iPosition + 1) : 0;
+            if (pNextItem)
+            {
+                /* Make sure 'next' item is visible: */
+                pNextItem->makeSureItsVisible();
+                /* Move focus to 'next' item: */
+                model()->setFocusItem(pNextItem);
+                /* Was shift modifier pressed? */
+#ifdef Q_WS_MAC
+                if (pEvent->modifiers() & Qt::ShiftModifier &&
+                    pEvent->modifiers() & Qt::KeypadModifier)
+#else /* Q_WS_MAC */
+                if (pEvent->modifiers() == Qt::ShiftModifier)
+#endif /* !Q_WS_MAC */
+                {
+                    /* Calculate positions: */
+                    UIGChooserItem *pFirstItem = model()->selectionList().first();
+                    int iFirstPosition = model()->navigationList().indexOf(pFirstItem);
+                    int iNextPosition = model()->navigationList().indexOf(pNextItem);
+                    /* Clear selection: */
+                    model()->clearSelectionList();
+                    /* Select all the items from 'first' to 'next': */
+                    if (iFirstPosition <= iNextPosition)
+                        for (int i = iFirstPosition; i <= iNextPosition; ++i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                    else
+                        for (int i = iFirstPosition; i >= iNextPosition; --i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                }
+                /* There is no modifiers pressed? */
+#ifdef Q_WS_MAC
+                else if (pEvent->modifiers() == Qt::KeypadModifier)
+#else /* Q_WS_MAC */
+                else if (pEvent->modifiers() == Qt::NoModifier)
+#endif /* !Q_WS_MAC */
+                {
+                    /* Move selection to 'next' item: */
+                    model()->clearSelectionList();
+                    model()->addToSelectionList(pNextItem);
+                }
+                /* Notify selection changed: */
+                model()->notifySelectionChanged();
+                /* Filter-out this event: */
+                return true;
+            }
+            /* Pass this event: */
+            return false;
+        }
+        /* Key LEFT? */
+        case Qt::Key_Left:
+        {
+            /* If there is a focus item: */
+            if (UIGChooserItem *pFocusItem = model()->focusItem())
+            {
+                /* Of the known type: */
+                switch (pFocusItem->type())
+                {
+                    case UIGChooserItemType_Group:
+                    case UIGChooserItemType_Machine:
+                    {
+                        /* Unindent root if its NOT main: */
+                        if (model()->root() != model()->mainRoot())
+                            model()->unindentRoot();
+                        break;
+                    }
+                    default:
+                        break;
+                }
+            }
+            /* Pass that event: */
+            return false;
+        }
+        /* Key RIGHT? */
+        case Qt::Key_Right:
+        {
+            /* If there is focus item: */
+            if (UIGChooserItem *pFocusItem = model()->focusItem())
+            {
+                /* Of the group type: */
+                if (pFocusItem->type() == UIGChooserItemType_Group)
+                {
+                    /* Indent root with this item: */
+                    model()->indentRoot(pFocusItem);
+                }
+            }
+            /* Pass that event: */
+            return false;
+        }
+        /* Key F2? */
+        case Qt::Key_F2:
+        {
+            /* If this item is of group type: */
+            if (model()->focusItem()->type() == UIGChooserItemType_Group)
+            {
+                /* Start embedded editing focus item: */
+                model()->focusItem()->startEditing();
+                /* Filter that event out: */
+                return true;
+            }
+            /* Pass event to other items: */
+            return false;
+        }
+        case Qt::Key_Return:
+        case Qt::Key_Enter:
+        {
+            /* Activate item: */
+            model()->activate();
+            /* And filter out that event: */
+            return true;
+        }
+        default:
+            break;
+    }
+    /* Pass all other events: */
+    return false;
+}
+
+bool UIGChooserHandlerKeyboard::handleKeyRelease(QKeyEvent*) const
+{
+    /* Pass all events: */
+    return false;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerKeyboard.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerKeyboard.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerKeyboard.h	(revision 42529)
@@ -0,0 +1,63 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserHandlerKeyboard class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserHandlerKeyboard_h__
+#define __UIGChooserHandlerKeyboard_h__
+
+/* Qt includes: */
+#include <QObject>
+
+/* Forward declarations: */
+class UIGChooserModel;
+class QKeyEvent;
+
+/* Keyboard event type: */
+enum UIKeyboardEventType
+{
+    UIKeyboardEventType_Press,
+    UIKeyboardEventType_Release
+};
+
+/* Keyboard handler for graphics selector: */
+class UIGChooserHandlerKeyboard : public QObject
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGChooserHandlerKeyboard(UIGChooserModel *pParent);
+
+    /* API: Model keyboard-event handler delegate: */
+    bool handle(QKeyEvent *pEvent, UIKeyboardEventType type) const;
+
+private:
+
+    /* API: Model wrapper: */
+    UIGChooserModel* model() const;
+
+    /* Helpers: Model keyboard-event handler delegates: */
+    bool handleKeyPress(QKeyEvent *pEvent) const;
+    bool handleKeyRelease(QKeyEvent *pEvent) const;
+
+    /* Variables: */
+    UIGChooserModel *m_pModel;
+};
+
+#endif /* __UIGChooserHandlerKeyboard_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerMouse.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerMouse.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerMouse.cpp	(revision 42529)
@@ -0,0 +1,242 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserHandlerMouse class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsSceneMouseEvent>
+
+/* GUI incluedes: */
+#include "UIGChooserHandlerMouse.h"
+#include "UIGChooserModel.h"
+#include "UIGChooserItemGroup.h"
+#include "UIGChooserItemMachine.h"
+
+UIGChooserHandlerMouse::UIGChooserHandlerMouse(UIGChooserModel *pParent)
+    : QObject(pParent)
+    , m_pModel(pParent)
+{
+}
+
+bool UIGChooserHandlerMouse::handle(QGraphicsSceneMouseEvent *pEvent, UIMouseEventType type) const
+{
+    /* Process passed event: */
+    switch (type)
+    {
+        case UIMouseEventType_Press: return handleMousePress(pEvent);
+        case UIMouseEventType_Release: return handleMouseRelease(pEvent);
+        case UIMouseEventType_DoubleClick: return handleMouseDoubleClick(pEvent);
+    }
+    /* Pass event if unknown: */
+    return false;
+}
+
+UIGChooserModel* UIGChooserHandlerMouse::model() const
+{
+    return m_pModel;
+}
+
+bool UIGChooserHandlerMouse::handleMousePress(QGraphicsSceneMouseEvent *pEvent) const
+{
+    /* Get item under mouse cursor: */
+    QPointF scenePos = pEvent->scenePos();
+    if (QGraphicsItem *pItemUnderMouse = model()->itemAt(scenePos))
+    {
+        /* Which button it was? */
+        switch (pEvent->button())
+        {
+            /* Left one? */
+            case Qt::LeftButton:
+            {
+                /* Which item we just clicked? */
+                UIGChooserItem *pClickedItem = 0;
+                /* Was that a group item? */
+                if (UIGChooserItemGroup *pGroupItem = qgraphicsitem_cast<UIGChooserItemGroup*>(pItemUnderMouse))
+                    pClickedItem = pGroupItem;
+                /* Or a machine one? */
+                else if (UIGChooserItemMachine *pMachineItem = qgraphicsitem_cast<UIGChooserItemMachine*>(pItemUnderMouse))
+                    pClickedItem = pMachineItem;
+                /* If we had clicked one of the required item types: */
+                if (pClickedItem && pClickedItem->parentItem())
+                {
+                    /* Old selection list: */
+                    QList<UIGChooserItem*> oldSelectionList = model()->selectionList();
+                    /* Move focus to clicked item: */
+                    model()->setFocusItem(pClickedItem);
+                    /* Was 'shift' modifier pressed? */
+                    if (pEvent->modifiers() == Qt::ShiftModifier)
+                    {
+                        /* Calculate positions: */
+                        UIGChooserItem *pFirstItem = model()->selectionList().first();
+                        int iFirstPosition = model()->navigationList().indexOf(pFirstItem);
+                        int iClickedPosition = model()->navigationList().indexOf(pClickedItem);
+                        /* Clear selection: */
+                        model()->clearSelectionList();
+                        /* Select all the items from 'first' to 'clicked': */
+                        if (iFirstPosition <= iClickedPosition)
+                            for (int i = iFirstPosition; i <= iClickedPosition; ++i)
+                                model()->addToSelectionList(model()->navigationList().at(i));
+                        else
+                            for (int i = iFirstPosition; i >= iClickedPosition; --i)
+                                model()->addToSelectionList(model()->navigationList().at(i));
+                    }
+                    /* Was 'control' modifier pressed? */
+                    else if (pEvent->modifiers() == Qt::ControlModifier)
+                    {
+                        /* Select clicked item, inverting if necessary: */
+                        if (model()->selectionList().contains(pClickedItem))
+                            model()->removeFromSelectionList(pClickedItem);
+                        else
+                            model()->addToSelectionList(pClickedItem);
+                    }
+                    /* Was no modifiers pressed? */
+                    else if (pEvent->modifiers() == Qt::NoModifier)
+                    {
+                        /* Move selection to clicked item: */
+                        model()->clearSelectionList();
+                        model()->addToSelectionList(pClickedItem);
+                    }
+                    /* Selection list changed?: */
+                    if (oldSelectionList != model()->selectionList())
+                        model()->notifySelectionChanged();
+                }
+                break;
+            }
+            /* Right one? */
+            case Qt::RightButton:
+            {
+                /* Which item we just clicked? */
+                UIGChooserItem *pClickedItem = 0;
+                /* Was that a group item? */
+                if (UIGChooserItemGroup *pGroupItem = qgraphicsitem_cast<UIGChooserItemGroup*>(pItemUnderMouse))
+                    pClickedItem = pGroupItem;
+                /* Or a machine one? */
+                else if (UIGChooserItemMachine *pMachineItem = qgraphicsitem_cast<UIGChooserItemMachine*>(pItemUnderMouse))
+                    pClickedItem = pMachineItem;
+                /* If we had clicked one of the required item types: */
+                if (pClickedItem)
+                {
+                    /* For non-root items: */
+                    if (pClickedItem->parentItem())
+                    {
+                        /* Is clicked item in selection list: */
+                        bool fIsClickedItemInSelectionList = contains(model()->selectionList(), pClickedItem);
+                        /* Move focus to clicked item (with selection if not selected yet): */
+                        model()->setFocusItem(pClickedItem, !fIsClickedItemInSelectionList);
+                    }
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    /* Pass all other events: */
+    return false;
+}
+
+bool UIGChooserHandlerMouse::handleMouseRelease(QGraphicsSceneMouseEvent*) const
+{
+    /* Pass all events: */
+    return false;
+}
+
+bool UIGChooserHandlerMouse::handleMouseDoubleClick(QGraphicsSceneMouseEvent *pEvent) const
+{
+    /* Get item under mouse cursor: */
+    QPointF scenePos = pEvent->scenePos();
+    if (QGraphicsItem *pItemUnderMouse = model()->itemAt(scenePos))
+    {
+        /* Which button it was? */
+        switch (pEvent->button())
+        {
+            /* Left one? */
+            case Qt::LeftButton:
+            {
+                /* Was that a group item? */
+                if (UIGChooserItemGroup *pGroupItem = qgraphicsitem_cast<UIGChooserItemGroup*>(pItemUnderMouse))
+                {
+                    /* Prepare variables: */
+                    int iGroupItemWidth = pGroupItem->geometry().toRect().width();
+                    int iMouseDoubleClickX = pEvent->scenePos().toPoint().x();
+                    /* If click was at left part: */
+                    if (iMouseDoubleClickX < iGroupItemWidth / 2)
+                    {
+                        /* Unindent root if possible: */
+                        if (model()->root() != model()->mainRoot())
+                            model()->unindentRoot();
+                    }
+                    else
+                    {
+                        /* Indent root with group item: */
+                        model()->indentRoot(pGroupItem);
+                    }
+                    /* Filter that event out: */
+                    return true;
+                }
+                /* Or a machine one? */
+                else if (UIGChooserItemMachine *pMachineItem = qgraphicsitem_cast<UIGChooserItemMachine*>(pItemUnderMouse))
+                {
+                    /* Prepare variables: */
+                    int iMachineItemWidth = pMachineItem->geometry().toRect().width();
+                    int iMouseDoubleClickX = pEvent->scenePos().toPoint().x();
+                    /* If click was at left part: */
+                    if (iMouseDoubleClickX < iMachineItemWidth / 2)
+                    {
+                        /* Unindent root if possible: */
+                        if (model()->root() != model()->mainRoot())
+                            model()->unindentRoot();
+                    }
+                    else
+                    {
+                        /* Activate machine item: */
+                        model()->activate();
+                    }
+                    /* Filter that event out: */
+                    return true;
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    /* Pass all other events: */
+    return false;
+}
+
+bool UIGChooserHandlerMouse::contains(QList<UIGChooserItem*> list,
+                                      UIGChooserItem *pRequiredItem,
+                                      bool fRecursively /* = false */) const
+{
+    /* Search throught the all passed list items: */
+    foreach (UIGChooserItem *pItem, list)
+    {
+        /* Check item first: */
+        if (pItem == pRequiredItem)
+            return true;
+        /* Check if this item supports children: */
+        if (fRecursively && pItem->type() == UIGChooserItemType_Group)
+        {
+            /* Check items recursively: */
+            if (contains(pItem->items(), pRequiredItem))
+                return true;
+        }
+    }
+    return false;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerMouse.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerMouse.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserHandlerMouse.h	(revision 42529)
@@ -0,0 +1,69 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserHandlerMouse class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserHandlerMouse_h__
+#define __UIGChooserHandlerMouse_h__
+
+/* Qt includes: */
+#include <QObject>
+
+/* Forward declarations: */
+class UIGChooserModel;
+class QGraphicsSceneMouseEvent;
+class UIGChooserItem;
+
+/* Mouse event type: */
+enum UIMouseEventType
+{
+    UIMouseEventType_Press,
+    UIMouseEventType_Release,
+    UIMouseEventType_DoubleClick
+};
+
+/* Mouse handler for graphics selector: */
+class UIGChooserHandlerMouse : public QObject
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGChooserHandlerMouse(UIGChooserModel *pParent);
+
+    /* API: Model mouse-event handler delegate: */
+    bool handle(QGraphicsSceneMouseEvent *pEvent, UIMouseEventType type) const;
+
+private:
+
+    /* API: Model wrapper: */
+    UIGChooserModel* model() const;
+
+    /* Helpers: Model mouse-event handler delegates: */
+    bool handleMousePress(QGraphicsSceneMouseEvent *pEvent) const;
+    bool handleMouseRelease(QGraphicsSceneMouseEvent *pEvent) const;
+    bool handleMouseDoubleClick(QGraphicsSceneMouseEvent *pEvent) const;
+
+    /* Helper: Check if some list contains some item: */
+    bool contains(QList<UIGChooserItem*> list, UIGChooserItem *pRequiredItem, bool fRecursively = false) const;
+
+    /* Variables: */
+    UIGChooserModel *m_pModel;
+};
+
+#endif /* __UIGChooserHandlerMouse_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItem.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItem.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItem.cpp	(revision 42529)
@@ -0,0 +1,334 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserItem class definition
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QApplication>
+#include <QStyle>
+#include <QPainter>
+#include <QGraphicsScene>
+#include <QStyleOptionFocusRect>
+#include <QGraphicsSceneMouseEvent>
+#include <QStateMachine>
+#include <QPropertyAnimation>
+#include <QSignalTransition>
+
+/* GUI includes: */
+#include "UIGChooserItem.h"
+#include "UIGChooserModel.h"
+#include "UIGChooserItemGroup.h"
+#include "UIGChooserItemMachine.h"
+
+UIGChooserItem::UIGChooserItem(UIGChooserItem *pParent)
+    : m_fRoot(!pParent)
+    , m_pParent(pParent)
+    , m_dragTokenPlace(DragToken_Off)
+    , m_fHovered(false)
+    , m_pHighlightMachine(0)
+    , m_pForwardAnimation(0)
+    , m_pBackwardAnimation(0)
+    , m_iAnimationDuration(300)
+    , m_iDefaultDarkness(115)
+    , m_iHighlightDarkness(90)
+    , m_iGradient(m_iDefaultDarkness)
+{
+    /* Basic item setup: */
+    setOwnedByLayout(false);
+    setAcceptDrops(true);
+    setFocusPolicy(Qt::NoFocus);
+    setFlag(QGraphicsItem::ItemIsSelectable, false);
+
+    /* Non-root item? */
+    if (!isRoot())
+    {
+        /* Non-root item setup: */
+        setAcceptHoverEvents(true);
+
+        /* Create state machine: */
+        m_pHighlightMachine = new QStateMachine(this);
+        /* Create 'default' state: */
+        QState *pStateDefault = new QState(m_pHighlightMachine);
+        /* Create 'highlighted' state: */
+        QState *pStateHighlighted = new QState(m_pHighlightMachine);
+
+        /* Forward animation: */
+        m_pForwardAnimation = new QPropertyAnimation(this, "gradient", this);
+        m_pForwardAnimation->setDuration(m_iAnimationDuration);
+        m_pForwardAnimation->setStartValue(m_iDefaultDarkness);
+        m_pForwardAnimation->setEndValue(m_iHighlightDarkness);
+
+        /* Backward animation: */
+        m_pBackwardAnimation = new QPropertyAnimation(this, "gradient", this);
+        m_pBackwardAnimation->setDuration(m_iAnimationDuration);
+        m_pBackwardAnimation->setStartValue(m_iHighlightDarkness);
+        m_pBackwardAnimation->setEndValue(m_iDefaultDarkness);
+
+        /* Add state transitions: */
+        QSignalTransition *pDefaultToHighlighted = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHighlighted);
+        pDefaultToHighlighted->addAnimation(m_pForwardAnimation);
+        QSignalTransition *pHighlightedToDefault = pStateHighlighted->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault);
+        pHighlightedToDefault->addAnimation(m_pBackwardAnimation);
+
+        /* Initial state is 'default': */
+        m_pHighlightMachine->setInitialState(pStateDefault);
+        /* Start state-machine: */
+        m_pHighlightMachine->start();
+    }
+}
+
+UIGChooserItemGroup* UIGChooserItem::toGroupItem()
+{
+    UIGChooserItemGroup *pItem = qgraphicsitem_cast<UIGChooserItemGroup*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGChooserItemGroup!"));
+    return pItem;
+}
+
+UIGChooserItemMachine* UIGChooserItem::toMachineItem()
+{
+    UIGChooserItemMachine *pItem = qgraphicsitem_cast<UIGChooserItemMachine*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGChooserItemMachine!"));
+    return pItem;
+}
+
+UIGChooserModel* UIGChooserItem::model() const
+{
+    UIGChooserModel *pModel = qobject_cast<UIGChooserModel*>(QIGraphicsWidget::scene()->parent());
+    AssertMsg(pModel, ("Incorrect graphics scene parent set!"));
+    return pModel;
+}
+
+UIGChooserItem* UIGChooserItem::parentItem() const
+{
+    return m_pParent;
+}
+
+void UIGChooserItem::show()
+{
+    /* Call to base-class: */
+    QIGraphicsWidget::show();
+}
+
+void UIGChooserItem::hide()
+{
+    /* Call to base-class: */
+    QIGraphicsWidget::hide();
+}
+
+void UIGChooserItem::setRoot(bool fRoot)
+{
+    m_fRoot = fRoot;
+    setAcceptHoverEvents(!m_fRoot);
+}
+
+bool UIGChooserItem::isRoot() const
+{
+    return m_fRoot;
+}
+
+void UIGChooserItem::makeSureItsVisible()
+{
+    /* If item is not visible: */
+    if (!isVisible())
+    {
+        /* Get parrent item, assert if can't: */
+        if (UIGChooserItemGroup *pParentItem = parentItem()->toGroupItem())
+        {
+            /* We should make parent visible: */
+            pParentItem->makeSureItsVisible();
+            /* And make sure its opened: */
+            if (pParentItem->closed())
+                pParentItem->open();
+        }
+    }
+}
+
+void UIGChooserItem::setDragTokenPlace(DragToken where)
+{
+    /* Something changed? */
+    if (m_dragTokenPlace != where)
+    {
+        m_dragTokenPlace = where;
+        update();
+    }
+}
+
+DragToken UIGChooserItem::dragTokenPlace() const
+{
+    return m_dragTokenPlace;
+}
+
+void UIGChooserItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
+{
+    if (m_fHovered != true)
+    {
+        m_fHovered = true;
+        emit sigHoverEnter();
+    }
+}
+
+void UIGChooserItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
+{
+    if (m_fHovered != false)
+    {
+        m_fHovered = false;
+        emit sigHoverLeave();
+    }
+}
+
+void UIGChooserItem::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
+{
+    /* By default, non-moveable and non-selectable items
+     * can't grab mouse-press events which is required
+     * to grab further mouse-move events which we wants... */
+    if (isRoot())
+        pEvent->ignore();
+    else
+        pEvent->accept();
+}
+
+void UIGChooserItem::mouseMoveEvent(QGraphicsSceneMouseEvent *pEvent)
+{
+    /* Make sure item is really dragged: */
+    if (QLineF(pEvent->screenPos(),
+               pEvent->buttonDownScreenPos(Qt::LeftButton)).length() <
+        QApplication::startDragDistance())
+        return;
+
+    /* Initialize dragging: */
+    QDrag *pDrag = new QDrag(pEvent->widget());
+    model()->setCurrentDragObject(pDrag);
+    pDrag->setPixmap(toPixmap());
+    pDrag->setMimeData(createMimeData());
+    pDrag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
+}
+
+void UIGChooserItem::dragMoveEvent(QGraphicsSceneDragDropEvent *pEvent)
+{
+    /* Make sure we are non-root: */
+    if (!isRoot())
+    {
+        /* Allow drag tokens only for the same item type as current: */
+        bool fAllowDragToken = false;
+        if ((type() == UIGChooserItemType_Group &&
+             pEvent->mimeData()->hasFormat(UIGChooserItemGroup::className())) ||
+            (type() == UIGChooserItemType_Machine &&
+             pEvent->mimeData()->hasFormat(UIGChooserItemMachine::className())))
+            fAllowDragToken = true;
+        /* Do we need a drag-token? */
+        if (fAllowDragToken)
+        {
+            QPoint p = pEvent->pos().toPoint();
+            if (p.y() < 10)
+                setDragTokenPlace(DragToken_Up);
+            else if (p.y() > minimumSizeHint().toSize().height() - 10)
+                setDragTokenPlace(DragToken_Down);
+            else
+                setDragTokenPlace(DragToken_Off);
+        }
+    }
+    /* Check if drop is allowed: */
+    pEvent->setAccepted(isDropAllowed(pEvent, dragTokenPlace()));
+}
+
+void UIGChooserItem::dragLeaveEvent(QGraphicsSceneDragDropEvent*)
+{
+    resetDragToken();
+}
+
+void UIGChooserItem::dropEvent(QGraphicsSceneDragDropEvent *pEvent)
+{
+    /* Do we have token active? */
+    switch (dragTokenPlace())
+    {
+        case DragToken_Off:
+        {
+            /* Its our drop, processing: */
+            processDrop(pEvent);
+            break;
+        }
+        default:
+        {
+            /* Its parent drop, passing: */
+            parentItem()->processDrop(pEvent, this, dragTokenPlace());
+            break;
+        }
+    }
+}
+
+/* static */
+void UIGChooserItem::configurePainterShape(QPainter *pPainter,
+                                           const QStyleOptionGraphicsItem *pOption,
+                                           int iRadius)
+{
+    /* Rounded corners? */
+    if (iRadius)
+    {
+        /* Setup clipping: */
+        QPainterPath roundedPath;
+        roundedPath.addRoundedRect(pOption->rect, iRadius, iRadius);
+        pPainter->setRenderHint(QPainter::Antialiasing);
+        pPainter->setClipPath(roundedPath);
+    }
+}
+
+/* static */
+void UIGChooserItem::paintFrameRect(QPainter *pPainter, const QRect &rect, bool fIsSelected, int iRadius)
+{
+    pPainter->save();
+    QPalette pal = QApplication::palette();
+    QColor base = pal.color(QPalette::Active, fIsSelected ? QPalette::Highlight : QPalette::Window);
+    pPainter->setPen(base.darker(160));
+    if (iRadius)
+        pPainter->drawRoundedRect(rect, iRadius, iRadius);
+    else
+        pPainter->drawRect(rect);
+    pPainter->restore();
+}
+
+/* static */
+void UIGChooserItem::paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap)
+{
+    pPainter->drawPixmap(rect, pixmap);
+}
+
+/* static */
+void UIGChooserItem::paintText(QPainter *pPainter, const QRect &rect, const QFont &font, const QString &strText)
+{
+    pPainter->save();
+    pPainter->setFont(font);
+    pPainter->drawText(rect, strText);
+    pPainter->restore();
+}
+
+UIGChooserItemMimeData::UIGChooserItemMimeData(UIGChooserItem *pItem)
+    : m_pItem(pItem)
+{
+}
+
+bool UIGChooserItemMimeData::hasFormat(const QString &strMimeType) const
+{
+    if (strMimeType == QString(m_pItem->metaObject()->className()))
+        return true;
+    return false;
+}
+
+UIGChooserItem* UIGChooserItemMimeData::item() const
+{
+    return m_pItem;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItem.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItem.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItem.h	(revision 42529)
@@ -0,0 +1,181 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserItem class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserItem_h__
+#define __UIGChooserItem_h__
+
+/* Qt includes: */
+#include <QMimeData>
+
+/* GUI includes: */
+#include "QIGraphicsWidget.h"
+
+/* Forward declaration: */
+class UIGChooserModel;
+class UIGChooserItemGroup;
+class UIGChooserItemMachine;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneDragDropEvent;
+class QStateMachine;
+class QPropertyAnimation;
+
+/* UIGChooserItem types: */
+enum UIGChooserItemType
+{
+    UIGChooserItemType_Any     = QGraphicsItem::UserType,
+    UIGChooserItemType_Group   = QGraphicsItem::UserType + 1,
+    UIGChooserItemType_Machine = QGraphicsItem::UserType + 2
+};
+
+/* Drag token placement: */
+enum DragToken { DragToken_Off, DragToken_Up, DragToken_Down };
+
+/* Graphics item interface
+ * for graphics selector model/view architecture: */
+class UIGChooserItem : public QIGraphicsWidget
+{
+    Q_OBJECT;
+    Q_PROPERTY(int gradient READ gradient WRITE setGradient);
+
+signals:
+
+    /* Notifiers: Hover stuff: */
+    void sigHoverEnter();
+    void sigHoverLeave();
+
+public:
+
+    /* Constructor: */
+    UIGChooserItem(UIGChooserItem *pParent);
+
+    /* API: Cast stuff: */
+    UIGChooserItemGroup* toGroupItem();
+    UIGChooserItemMachine* toMachineItem();
+
+    /* API: Model stuff: */
+    UIGChooserModel* model() const;
+
+    /* API: Parent stuff: */
+    UIGChooserItem* parentItem() const;
+
+    /* API: Basic stuff: */
+    virtual void show();
+    virtual void hide();
+    virtual void startEditing() = 0;
+    virtual QString name() const = 0;
+    void setRoot(bool fRoot);
+    bool isRoot() const;
+
+    /* API: Children stuff: */
+    virtual void addItem(UIGChooserItem *pItem, int iPosition) = 0;
+    virtual void removeItem(UIGChooserItem *pItem) = 0;
+    virtual QList<UIGChooserItem*> items(UIGChooserItemType type = UIGChooserItemType_Any) const = 0;
+    virtual bool hasItems(UIGChooserItemType type = UIGChooserItemType_Any) const = 0;
+    virtual void clearItems(UIGChooserItemType type = UIGChooserItemType_Any) = 0;
+
+    /* API: Layout stuff: */
+    virtual void updateSizeHint() = 0;
+    virtual void updateLayout() = 0;
+    virtual int minimumWidthHint() const = 0;
+    virtual int minimumHeightHint() const = 0;
+
+    /* API: Navigation stuff: */
+    virtual void makeSureItsVisible();
+
+    /* API: Drag and drop stuff: */
+    virtual QPixmap toPixmap() = 0;
+    virtual bool isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where = DragToken_Off) const = 0;
+    virtual void processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGChooserItem *pFromWho = 0, DragToken where = DragToken_Off) = 0;
+    virtual void resetDragToken() = 0;
+    void setDragTokenPlace(DragToken where);
+    DragToken dragTokenPlace() const;
+
+protected:
+
+    /* Hover-enter event: */
+    void hoverEnterEvent(QGraphicsSceneHoverEvent *pEvent);
+    /* Hover-leave event: */
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent);
+    /* Mouse-press event: */
+    void mousePressEvent(QGraphicsSceneMouseEvent *pEvent);
+    /* Mouse-move event: */
+    void mouseMoveEvent(QGraphicsSceneMouseEvent *pEvent);
+    /* Drag-move event: */
+    void dragMoveEvent(QGraphicsSceneDragDropEvent *pEvent);
+    /* Drag-leave event: */
+    void dragLeaveEvent(QGraphicsSceneDragDropEvent *pEvent);
+    /* Drop event: */
+    void dropEvent(QGraphicsSceneDragDropEvent *pEvent);
+
+    /* Static paint stuff: */
+    static void configurePainterShape(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, int iRadius);
+    static void paintFrameRect(QPainter *pPainter, const QRect &rect, bool fIsSelected, int iRadius);
+    static void paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap);
+    static void paintText(QPainter *pPainter, const QRect &rect, const QFont &font, const QString &strText);
+
+    /* Helpers: Drag and drop stuff: */
+    virtual QMimeData* createMimeData() = 0;
+
+    /* Hover stuff: */
+    bool isHovered() const { return m_fHovered; }
+    int gradient() const { return m_iGradient; }
+    void setGradient(int iGradient) { m_iGradient = iGradient; update(); }
+
+private:
+
+    /* Variables: */
+    bool m_fRoot;
+    UIGChooserItem *m_pParent;
+    DragToken m_dragTokenPlace;
+
+    /* Highlight animation stuff: */
+    bool m_fHovered;
+    QStateMachine *m_pHighlightMachine;
+    QPropertyAnimation *m_pForwardAnimation;
+    QPropertyAnimation *m_pBackwardAnimation;
+    int m_iAnimationDuration;
+    int m_iDefaultDarkness;
+    int m_iHighlightDarkness;
+    int m_iGradient;
+};
+
+/* Mime-data for graphics item interface: */
+class UIGChooserItemMimeData : public QMimeData
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGChooserItemMimeData(UIGChooserItem *pItem);
+
+    /* API: Format checker: */
+    bool hasFormat(const QString &strMimeType) const;
+
+    /* API: Item getter: */
+    UIGChooserItem* item() const;
+
+private:
+
+    /* Variables: */
+    UIGChooserItem *m_pItem;
+};
+
+#endif /* __UIGChooserItem_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemGroup.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemGroup.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemGroup.cpp	(revision 42529)
@@ -0,0 +1,1182 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserItemGroup class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QGraphicsSceneDragDropEvent>
+#include <QLineEdit>
+#include <QGraphicsProxyWidget>
+#include <QGraphicsScene>
+
+/* GUI includes: */
+#include "UIGChooserItemGroup.h"
+#include "UIGChooserItemMachine.h"
+#include "UIGChooserModel.h"
+#include "UIIconPool.h"
+#include "UIGraphicsRotatorButton.h"
+
+/* static */
+QString UIGChooserItemGroup::className() { return "UIGChooserItemGroup"; }
+
+UIGChooserItemGroup::UIGChooserItemGroup(QGraphicsScene *pScene)
+    : UIGChooserItem(0)
+    , m_fClosed(false)
+    , m_pButton(0)
+    , m_pNameEditorWidget(0)
+    , m_pNameEditor(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+{
+    /* Add item to the scene: */
+    if (pScene)
+        pScene->addItem(this);
+}
+
+UIGChooserItemGroup::UIGChooserItemGroup(QGraphicsScene *pScene,
+                                         UIGChooserItemGroup *pCopyFrom)
+    : UIGChooserItem(0)
+    , m_strName(pCopyFrom->name())
+    , m_fClosed(pCopyFrom->closed())
+    , m_pButton(0)
+    , m_pNameEditorWidget(0)
+    , m_pNameEditor(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+{
+    /* Add item to the scene: */
+    if (pScene)
+        pScene->addItem(this);
+
+    /* Copy content to 'this': */
+    copyContent(pCopyFrom, this);
+}
+
+UIGChooserItemGroup::UIGChooserItemGroup(UIGChooserItem *pParent,
+                                         const QString &strName,
+                                         bool fOpened /* = false */,
+                                         int iPosition /* = -1 */)
+    : UIGChooserItem(pParent)
+    , m_strName(strName)
+    , m_fClosed(!fOpened)
+    , m_pButton(0)
+    , m_pNameEditorWidget(0)
+    , m_pNameEditor(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+{
+    /* Prepare: */
+    prepare();
+
+    /* Add item to the parent: */
+    AssertMsg(parentItem(), ("Incorrect parent passed!"));
+    parentItem()->addItem(this, iPosition);
+    setZValue(parentItem()->zValue() + 1);
+}
+
+UIGChooserItemGroup::UIGChooserItemGroup(UIGChooserItem *pParent,
+                                         UIGChooserItemGroup *pCopyFrom,
+                                         int iPosition /* = -1 */)
+    : UIGChooserItem(pParent)
+    , m_strName(pCopyFrom->name())
+    , m_fClosed(pCopyFrom->closed())
+    , m_pButton(0)
+    , m_pNameEditorWidget(0)
+    , m_pNameEditor(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+{
+    /* Prepare: */
+    prepare();
+
+    /* Add item to the parent: */
+    AssertMsg(parentItem(), ("Incorrect parent passed!"));
+    parentItem()->addItem(this, iPosition);
+    setZValue(parentItem()->zValue() + 1);
+
+    /* Copy content to 'this': */
+    copyContent(pCopyFrom, this);
+}
+
+UIGChooserItemGroup::~UIGChooserItemGroup()
+{
+    /* Delete all the items: */
+    clearItems();
+
+    /* If that item is focused: */
+    if (model()->focusItem() == this)
+    {
+        /* Unset the focus/selection: */
+        model()->setFocusItem(0, true);
+    }
+    /* If that item is NOT focused, but selected: */
+    else if (model()->selectionList().contains(this))
+    {
+        /* Remove item from the selection list: */
+        model()->removeFromSelectionList(this);
+    }
+    /* Remove item from the navigation list: */
+    model()->removeFromNavigationList(this);
+
+    /* Remove item from the parent: */
+    if (parentItem())
+        parentItem()->removeItem(this);
+}
+
+QString UIGChooserItemGroup::name() const
+{
+    return m_strName;
+}
+
+bool UIGChooserItemGroup::closed() const
+{
+    return m_fClosed && !isRoot();
+}
+
+bool UIGChooserItemGroup::opened() const
+{
+    return !m_fClosed || isRoot();
+}
+
+void UIGChooserItemGroup::close()
+{
+    AssertMsg(parentItem(), ("Can't close root-item!"));
+    m_pButton->setToggled(false);
+}
+
+void UIGChooserItemGroup::open()
+{
+    AssertMsg(parentItem(), ("Can't open root-item!"));
+    m_pButton->setToggled(true);
+}
+
+bool UIGChooserItemGroup::contains(const QString &strId, bool fRecursively /* = false */) const
+{
+    /* Check machine items: */
+    foreach (UIGChooserItem *pItem, m_machineItems)
+        if (pItem->toMachineItem()->id() == strId)
+            return true;
+    /* If recursively => check group items: */
+    if (fRecursively)
+        foreach (UIGChooserItem *pItem, m_groupItems)
+            if (pItem->toGroupItem()->contains(strId, fRecursively))
+                return true;
+    return false;
+}
+
+void UIGChooserItemGroup::sltNameEditingFinished()
+{
+    /* Not for root-item: */
+    if (isRoot())
+        return;
+
+    /* Lock name-editor: */
+    m_pNameEditor->hide();
+
+    /* Enumerate all the group names: */
+    QStringList groupNames;
+    foreach (UIGChooserItem *pItem, parentItem()->items(UIGChooserItemType_Group))
+        groupNames << pItem->name();
+
+    /* If proposed name is empty or not unique, reject it: */
+    QString strNewName = m_pNameEditorWidget->text().trimmed();
+    if (strNewName.isEmpty() || groupNames.contains(strNewName))
+        return;
+
+    m_strName = strNewName;
+}
+
+void UIGChooserItemGroup::sltGroupToggleStart()
+{
+    /* Not for root-item: */
+    if (isRoot())
+        return;
+
+    /* Setup animation: */
+    updateAnimationParameters();
+
+    /* Group closed, we are opening it: */
+    if (m_fClosed)
+    {
+        /* Toggle-state and navigation will be
+         * updated on toggle finish signal! */
+    }
+    /* Group opened, we are closing it: */
+    else
+    {
+        /* Update toggle-state: */
+        m_fClosed = true;
+        /* Update navigation: */
+        model()->updateNavigation();
+        /* Relayout model: */
+        model()->updateLayout();
+    }
+}
+
+void UIGChooserItemGroup::sltGroupToggleFinish(bool fToggled)
+{
+    /* Not for root-item: */
+    if (isRoot())
+        return;
+
+    /* Update toggle-state: */
+    m_fClosed = !fToggled;
+    /* Update navigation: */
+    model()->updateNavigation();
+    /* Relayout model: */
+    model()->updateLayout();
+}
+
+QVariant UIGChooserItemGroup::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case GroupItemData_HorizonalMargin: return isRoot() ? 1 : 8;
+        case GroupItemData_VerticalMargin: return isRoot() ? 1 : 5;
+        case GroupItemData_MajorSpacing: return isRoot() ? 0 : 10;
+        case GroupItemData_MinorSpacing: return 0;
+        /* Pixmaps: */
+        case GroupItemData_ButtonPixmap: return UIIconPool::iconSet(":/arrow_right_10px.png");
+        case GroupItemData_GroupPixmap: return UIIconPool::iconSet(":/nw_16px.png");
+        case GroupItemData_MachinePixmap: return UIIconPool::iconSet(":/machine_16px.png");
+        /* Fonts: */
+        case GroupItemData_NameFont:
+        {
+            QFont nameFont = font();
+            nameFont.setWeight(QFont::Bold);
+            return nameFont;
+        }
+        case GroupItemData_InfoFont:
+        {
+            QFont infoFont = font();
+            return infoFont;
+        }
+        /* Texts: */
+        case GroupItemData_Name: return m_strName;
+        case GroupItemData_GroupCountText: return QString::number(m_groupItems.size());
+        case GroupItemData_MachineCountText: return QString::number(m_machineItems.size());
+        /* Sizes: */
+        case GroupItemData_ButtonSize: return m_pButton ? m_pButton->minimumSizeHint() : QSizeF(0, 0);
+        case GroupItemData_NameSize:
+        {
+            if (isRoot())
+                return QSizeF(0, 0);
+            QFontMetrics fm(data(GroupItemData_NameFont).value<QFont>());
+            return QSize(fm.width(data(GroupItemData_Name).toString()), fm.height());
+        }
+        case GroupItemData_NameEditorSize:
+        {
+            if (isRoot())
+                return QSizeF(0, 0);
+            return m_pNameEditorWidget->minimumSizeHint();
+        }
+        case GroupItemData_GroupPixmapSize:
+            return isRoot() ? QSizeF(0, 0) : data(GroupItemData_GroupPixmap).value<QIcon>().availableSizes().at(0);
+        case GroupItemData_MachinePixmapSize:
+            return isRoot() ? QSizeF(0, 0) : data(GroupItemData_MachinePixmap).value<QIcon>().availableSizes().at(0);
+        case GroupItemData_GroupCountTextSize:
+        {
+            if (isRoot())
+                return QSizeF(0, 0);
+            QFontMetrics fm(data(GroupItemData_InfoFont).value<QFont>());
+            return QSize(fm.width(data(GroupItemData_GroupCountText).toString()), fm.height());
+        }
+        case GroupItemData_MachineCountTextSize:
+        {
+            if (isRoot())
+                return QSizeF(0, 0);
+            QFontMetrics fm(data(GroupItemData_InfoFont).value<QFont>());
+            return QSize(fm.width(data(GroupItemData_MachineCountText).toString()), fm.height());
+        }
+        case GroupItemData_FullHeaderSize:
+        {
+            /* Prepare variables: */
+            int iMajorSpacing = data(GroupItemData_MajorSpacing).toInt();
+            int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+            QSize buttonSize = data(GroupItemData_ButtonSize).toSize();
+            QSize nameSize = data(GroupItemData_NameSize).toSize();
+            QSize groupPixmapSize = data(GroupItemData_GroupPixmapSize).toSize();
+            QSize machinePixmapSize = data(GroupItemData_MachinePixmapSize).toSize();
+            QSize groupCountTextSize = data(GroupItemData_GroupCountTextSize).toSize();
+            QSize machineCountTextSize = data(GroupItemData_MachineCountTextSize).toSize();
+
+            /* Calculate minimum width: */
+            int iGroupItemHeaderWidth = /* Button width: */
+                                        buttonSize.width() +
+                                        /* Spacing between button and name: */
+                                        iMajorSpacing +
+                                        /* Some hardcoded magic: */
+                                        1 /* frame width from Qt sources */ +
+                                        2 /* internal QLineEdit margin from Qt sources */ +
+                                        1 /* internal QLineEdit align shifting from Qt sources */ +
+                                        /* Name width: */
+                                        nameSize.width() +
+                                        /* Spacing between name and info: */
+                                        iMajorSpacing +
+                                        /* Group stuff width: */
+                                        groupPixmapSize.width() + iMinorSpacing +
+                                        groupCountTextSize.width() + iMinorSpacing +
+                                        /* Machine stuff width: */
+                                        machinePixmapSize.width() + iMinorSpacing +
+                                        machineCountTextSize.width();
+
+            /* Search for maximum height: */
+            QList<int> heights;
+            heights << buttonSize.height()
+                    << nameSize.height()
+                    << groupPixmapSize.height() << machinePixmapSize.height()
+                    << groupCountTextSize.height() << machineCountTextSize.height();
+            int iGroupItemHeaderHeight = 0;
+            foreach (int iHeight, heights)
+                iGroupItemHeaderHeight = qMax(iGroupItemHeaderHeight, iHeight);
+
+            /* Return result: */
+            return QSize(iGroupItemHeaderWidth, iGroupItemHeaderHeight);
+        }
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGChooserItemGroup::show()
+{
+    /* Call to base-class: */
+    UIGChooserItem::show();
+    /* Show children: */
+    if (!closed())
+        foreach (UIGChooserItem *pItem, items())
+            pItem->show();
+}
+
+void UIGChooserItemGroup::hide()
+{
+    /* Call to base-class: */
+    UIGChooserItem::hide();
+    /* Hide children: */
+    foreach (UIGChooserItem *pItem, items())
+        pItem->hide();
+}
+
+void UIGChooserItemGroup::startEditing()
+{
+    /* Not for root-item: */
+    if (isRoot())
+        return;
+
+    /* Unlock name-editor: */
+    m_pNameEditor->show();
+    m_pNameEditorWidget->setText(m_strName);
+    m_pNameEditorWidget->setFocus();
+}
+
+void UIGChooserItemGroup::addItem(UIGChooserItem *pItem, int iPosition)
+{
+    /* Check item type: */
+    switch (pItem->type())
+    {
+        case UIGChooserItemType_Group:
+        {
+            if (iPosition < 0 || iPosition >= m_groupItems.size())
+                m_groupItems.append(pItem);
+            else
+                m_groupItems.insert(iPosition, pItem);
+            scene()->addItem(pItem);
+            break;
+        }
+        case UIGChooserItemType_Machine:
+        {
+            if (iPosition < 0 || iPosition >= m_machineItems.size())
+                m_machineItems.append(pItem);
+            else
+                m_machineItems.insert(iPosition, pItem);
+            scene()->addItem(pItem);
+            break;
+        }
+        default:
+        {
+            AssertMsgFailed(("Invalid item type!"));
+            break;
+        }
+    }
+}
+
+void UIGChooserItemGroup::removeItem(UIGChooserItem *pItem)
+{
+    /* Check item type: */
+    switch (pItem->type())
+    {
+        case UIGChooserItemType_Group:
+        {
+            scene()->removeItem(pItem);
+            m_groupItems.removeAt(m_groupItems.indexOf(pItem));
+            break;
+        }
+        case UIGChooserItemType_Machine:
+        {
+            scene()->removeItem(pItem);
+            m_machineItems.removeAt(m_machineItems.indexOf(pItem));
+            break;
+        }
+        default:
+        {
+            AssertMsgFailed(("Invalid item type!"));
+            break;
+        }
+    }
+}
+
+QList<UIGChooserItem*> UIGChooserItemGroup::items(UIGChooserItemType type /* = UIGChooserItemType_Any */) const
+{
+    switch (type)
+    {
+        case UIGChooserItemType_Any: return items(UIGChooserItemType_Group) + items(UIGChooserItemType_Machine);
+        case UIGChooserItemType_Group: return m_groupItems;
+        case UIGChooserItemType_Machine: return m_machineItems;
+        default: break;
+    }
+    return QList<UIGChooserItem*>();
+}
+
+bool UIGChooserItemGroup::hasItems(UIGChooserItemType type /* = UIGChooserItemType_Any */) const
+{
+    switch (type)
+    {
+        case UIGChooserItemType_Any:
+            return hasItems(UIGChooserItemType_Group) || hasItems(UIGChooserItemType_Machine);
+        case UIGChooserItemType_Group:
+            return !m_groupItems.isEmpty();
+        case UIGChooserItemType_Machine:
+            return !m_machineItems.isEmpty();
+    }
+    return false;
+}
+
+void UIGChooserItemGroup::clearItems(UIGChooserItemType type /* = UIGChooserItemType_Any */)
+{
+    switch (type)
+    {
+        case UIGChooserItemType_Any:
+        {
+            clearItems(UIGChooserItemType_Group);
+            clearItems(UIGChooserItemType_Machine);
+            break;
+        }
+        case UIGChooserItemType_Group:
+        {
+            while (!m_groupItems.isEmpty()) { delete m_groupItems.last(); }
+            break;
+        }
+        case UIGChooserItemType_Machine:
+        {
+            while (!m_machineItems.isEmpty()) { delete m_machineItems.last(); }
+            break;
+        }
+    }
+}
+
+void UIGChooserItemGroup::updateSizeHint()
+{
+    /* Update size-hints for all the items: */
+    foreach (UIGChooserItem *pItem, items())
+        pItem->updateSizeHint();
+    /* Update size-hint for this item: */
+    updateGeometry();
+}
+
+void UIGChooserItemGroup::updateLayout()
+{
+    /* Prepare variables: */
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    int iVerticalMargin = data(GroupItemData_VerticalMargin).toInt();
+    int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+    int iButtonHeight = data(GroupItemData_ButtonSize).toSize().height();
+    int iButtonWidth = data(GroupItemData_ButtonSize).toSize().width();
+    int iFullHeaderHeight = data(GroupItemData_FullHeaderSize).toSize().height();
+    int iPreviousVerticalIndent = 0;
+
+    /* Header (root item): */
+    if (isRoot())
+    {
+        /* Hide button: */
+        if (m_pButton && m_pButton->isVisible())
+            m_pButton->hide();
+
+        /* Hide name-editor: */
+        if (m_pNameEditor && m_pNameEditor->isVisible())
+            m_pNameEditor->hide();
+
+        /* Prepare body indent: */
+        iPreviousVerticalIndent = iVerticalMargin;
+    }
+    /* Header (non-root item): */
+    else
+    {
+        /* Show button: */
+        if (!m_pButton->isVisible())
+            m_pButton->show();
+        /* Layout button: */
+        int iButtonX = iHorizontalMargin;
+        int iButtonY = iButtonHeight == iFullHeaderHeight ? iVerticalMargin :
+                       iVerticalMargin + (iFullHeaderHeight - iButtonHeight) / 2;
+        m_pButton->setPos(iButtonX, iButtonY);
+
+        /* Layout name-editor: */
+        int iNameEditorX = iHorizontalMargin + iButtonWidth + iMinorSpacing;
+        int iNameEditorY = 1;
+        m_pNameEditor->setPos(iNameEditorX, iNameEditorY);
+        m_pNameEditorWidget->resize(geometry().width() - iNameEditorX - iHorizontalMargin, m_pNameEditorWidget->height());
+
+        /* Prepare body indent: */
+        iPreviousVerticalIndent = 2 * iVerticalMargin + iFullHeaderHeight;
+    }
+
+    /* No body for closed group: */
+    if (closed())
+    {
+        /* Hide all the items: */
+        foreach (UIGChooserItem *pItem, items())
+            if (pItem->isVisible())
+                pItem->hide();
+    }
+    /* Body for opened group: */
+    else
+    {
+        /* Prepare variables: */
+        int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+        QRect geo = geometry().toRect();
+        int iX = geo.x();
+        int iY = geo.y();
+        int iWidth = geo.width();
+        /* Layout all the items: */
+        foreach (UIGChooserItem *pItem, items())
+        {
+            /* Show if hidden: */
+            if (!pItem->isVisible())
+                pItem->show();
+            /* Get item's height-hint: */
+            int iMinimumHeight = pItem->minimumHeightHint();
+            /* Set item's position: */
+            pItem->setPos(iX + iHorizontalMargin, iY + iPreviousVerticalIndent);
+            /* Set item's size: */
+            pItem->resize(iWidth - 2 * iHorizontalMargin, iMinimumHeight);
+            /* Relayout group: */
+            pItem->updateLayout();
+            /* Update indent for next items: */
+            iPreviousVerticalIndent += (iMinimumHeight + iMinorSpacing);
+        }
+    }
+}
+
+int UIGChooserItemGroup::minimumWidthHint(bool fClosedGroup) const
+{
+    /* Prepare variables: */
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    QSize fullHeaderSize = data(GroupItemData_FullHeaderSize).toSize();
+
+    /* Calculating proposed width: */
+    int iProposedWidth = 0;
+
+    /* Simple group item have 2 margins - left and right: */
+    iProposedWidth += 2 * iHorizontalMargin;
+    /* And full header width to take into account: */
+    iProposedWidth += fullHeaderSize.width();
+    /* But if group is opened: */
+    if (!fClosedGroup)
+    {
+        /* We have to make sure that we had taken into account: */
+        foreach (UIGChooserItem *pItem, items())
+        {
+            int iItemWidth = 2 * iHorizontalMargin + pItem->minimumWidthHint();
+            iProposedWidth = qMax(iProposedWidth, iItemWidth);
+        }
+    }
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGChooserItemGroup::minimumHeightHint(bool fClosedGroup) const
+{
+    /* Prepare variables: */
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    int iVerticalMargin = data(GroupItemData_VerticalMargin).toInt();
+    int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+    QSize fullHeaderSize = data(GroupItemData_FullHeaderSize).toSize();
+
+    /* Calculating proposed height: */
+    int iProposedHeight = 0;
+
+    /* Simple group item have 2 margins - top and bottom: */
+    iProposedHeight += 2 * iVerticalMargin;
+    /* And full header height to take into account: */
+    iProposedHeight += fullHeaderSize.height();
+    /* But if group is opened: */
+    if (!fClosedGroup)
+    {
+        /* We should take into account: */
+        for (int i = 0; i < m_groupItems.size(); ++i)
+        {
+            /* Every group item height: */
+            UIGChooserItem *pItem = m_groupItems[i];
+            iProposedHeight += pItem->minimumHeightHint();
+            /* And every spacing between sub-groups: */
+            if (i < m_groupItems.size() - 1)
+                iProposedHeight += iMinorSpacing;
+        }
+        /* Minor spacing between group and machine item: */
+        if (hasItems(UIGChooserItemType_Group) && hasItems(UIGChooserItemType_Machine))
+            iProposedHeight += iMinorSpacing;
+        for (int i = 0; i < m_machineItems.size(); ++i)
+        {
+            /* Every machine item height: */
+            UIGChooserItem *pItem = m_machineItems[i];
+            iProposedHeight += pItem->minimumHeightHint();
+            /* And every spacing between sub-machines: */
+            if (i < m_machineItems.size() - 1)
+                iProposedHeight += iMinorSpacing;
+        }
+        /* Bottom margin: */
+        iProposedHeight += iHorizontalMargin;
+    }
+    /* Finally, additional height during animation: */
+    if (fClosedGroup && m_pButton && m_pButton->isAnimationRunning())
+        iProposedHeight += m_iAdditionalHeight;
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+int UIGChooserItemGroup::minimumWidthHint() const
+{
+    return minimumWidthHint(closed());
+}
+
+int UIGChooserItemGroup::minimumHeightHint() const
+{
+    return minimumHeightHint(closed());
+}
+
+QSizeF UIGChooserItemGroup::minimumSizeHint(bool fClosedGroup) const
+{
+    return QSizeF(minimumWidthHint(fClosedGroup), minimumHeightHint(fClosedGroup));
+}
+
+QSizeF UIGChooserItemGroup::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    /* If Qt::MinimumSize requested: */
+    if (which == Qt::MinimumSize)
+        return minimumSizeHint(closed());
+    /* Else call to base-class: */
+    return UIGChooserItem::sizeHint(which, constraint);
+}
+
+QPixmap UIGChooserItemGroup::toPixmap()
+{
+    QSize minimumSize = minimumSizeHint(true).toSize();
+    QPixmap pixmap(minimumSize);
+    QPainter painter(&pixmap);
+    QStyleOptionGraphicsItem options;
+    options.rect = QRect(QPoint(0, 0), minimumSize);
+    paint(&painter, &options, true);
+    return pixmap;
+}
+
+bool UIGChooserItemGroup::isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const
+{
+    /* Get mime: */
+    const QMimeData *pMimeData = pEvent->mimeData();
+    /* If drag token is shown, its up to parent to decide: */
+    if (where != DragToken_Off)
+        return parentItem()->isDropAllowed(pEvent);
+    /* Else we should check mime format: */
+    if (pMimeData->hasFormat(UIGChooserItemGroup::className()))
+    {
+        /* Get passed group item: */
+        const UIGChooserItemMimeData *pCastedMimeData = qobject_cast<const UIGChooserItemMimeData*>(pMimeData);
+        AssertMsg(pCastedMimeData, ("Can't cast passed mime-data to UIGChooserItemMimeData!"));
+        UIGChooserItem *pItem = pCastedMimeData->item();
+        /* Make sure passed group is not 'this': */
+        if (pItem == this)
+            return false;
+        /* Make sure passed group is not among our parents: */
+        const UIGChooserItem *pTestedWidget = this;
+        while (UIGChooserItem *pParentOfTestedWidget = pTestedWidget->parentItem())
+        {
+            if (pItem == pParentOfTestedWidget)
+                return false;
+            pTestedWidget = pParentOfTestedWidget;
+        }
+        return true;
+    }
+    else if (pMimeData->hasFormat(UIGChooserItemMachine::className()))
+    {
+        /* Get passed machine item: */
+        const UIGChooserItemMimeData *pCastedMimeData = qobject_cast<const UIGChooserItemMimeData*>(pMimeData);
+        AssertMsg(pCastedMimeData, ("Can't cast passed mime-data to UIGChooserItemMimeData!"));
+        UIGChooserItem *pItem = pCastedMimeData->item();
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            {
+                /* Make sure passed item is ours or there is no other item with such id: */
+                return m_machineItems.contains(pItem) || !contains(pItem->toMachineItem()->id());
+            }
+            case Qt::CopyAction:
+            {
+                /* Make sure there is no other item with such id: */
+                return !contains(pItem->toMachineItem()->id());
+            }
+        }
+    }
+    /* That was invalid mime: */
+    return false;
+}
+
+void UIGChooserItemGroup::processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGChooserItem *pFromWho, DragToken where)
+{
+    /* Get mime: */
+    const QMimeData *pMime = pEvent->mimeData();
+    /* Check mime format: */
+    if (pMime->hasFormat(UIGChooserItemGroup::className()))
+    {
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            case Qt::CopyAction:
+            {
+                /* Remember scene: */
+                UIGChooserModel *pModel = model();
+
+                /* Get passed group item: */
+                const UIGChooserItemMimeData *pCastedMime = qobject_cast<const UIGChooserItemMimeData*>(pMime);
+                AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIGChooserItemMimeData!"));
+                UIGChooserItem *pItem = pCastedMime->item();
+
+                /* Check if we have position information: */
+                int iPosition = m_groupItems.size();
+                if (pFromWho && where != DragToken_Off)
+                {
+                    /* Make sure sender item if our child: */
+                    AssertMsg(m_groupItems.contains(pFromWho), ("Sender item is NOT our child!"));
+                    if (m_groupItems.contains(pFromWho))
+                    {
+                        iPosition = m_groupItems.indexOf(pFromWho);
+                        if (where == DragToken_Down)
+                            ++iPosition;
+                    }
+                }
+
+                /* Copy passed item into this group: */
+                UIGChooserItem *pNewGroupItem = new UIGChooserItemGroup(this, pItem->toGroupItem(), iPosition);
+
+                /* If proposed action is 'move': */
+                if (pEvent->proposedAction() == Qt::MoveAction)
+                {
+                    /* Delete passed item: */
+                    delete pItem;
+                }
+
+                /* Update scene: */
+                pModel->updateGroupTree();
+                pModel->updateNavigation();
+                pModel->updateLayout();
+                pModel->setCurrentItem(pNewGroupItem->parentItem()->toGroupItem()->opened() ?
+                                       pNewGroupItem : pNewGroupItem->parentItem());
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    else if (pMime->hasFormat(UIGChooserItemMachine::className()))
+    {
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            case Qt::CopyAction:
+            {
+                /* Remember scene: */
+                UIGChooserModel *pModel = model();
+
+                /* Get passed item: */
+                const UIGChooserItemMimeData *pCastedMime = qobject_cast<const UIGChooserItemMimeData*>(pMime);
+                AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIGChooserItemMimeData!"));
+                UIGChooserItem *pItem = pCastedMime->item();
+
+                /* Check if we have position information: */
+                int iPosition = m_machineItems.size();
+                if (pFromWho && where != DragToken_Off)
+                {
+                    /* Make sure sender item if our child: */
+                    AssertMsg(m_machineItems.contains(pFromWho), ("Sender item is NOT our child!"));
+                    if (m_machineItems.contains(pFromWho))
+                    {
+                        iPosition = m_machineItems.indexOf(pFromWho);
+                        if (where == DragToken_Down)
+                            ++iPosition;
+                    }
+                }
+
+                /* Copy passed machine item into this group: */
+                UIGChooserItem *pNewMachineItem = new UIGChooserItemMachine(this, pItem->toMachineItem(), iPosition);
+
+                /* If proposed action is 'move': */
+                if (pEvent->proposedAction() == Qt::MoveAction)
+                {
+                    /* Delete passed item: */
+                    delete pItem;
+                }
+
+                /* Update scene: */
+                pModel->updateGroupTree();
+                pModel->updateNavigation();
+                pModel->updateLayout();
+                pModel->setCurrentItem(pNewMachineItem->parentItem()->toGroupItem()->opened() ?
+                                       pNewMachineItem : pNewMachineItem->parentItem());
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+void UIGChooserItemGroup::resetDragToken()
+{
+    /* Reset drag token for this item: */
+    if (dragTokenPlace() != DragToken_Off)
+    {
+        setDragTokenPlace(DragToken_Off);
+        update();
+    }
+    /* Reset drag tokens for all the items: */
+    foreach (UIGChooserItem *pItem, items())
+        pItem->resetDragToken();
+}
+
+QMimeData* UIGChooserItemGroup::createMimeData()
+{
+    return new UIGChooserItemMimeData(this);
+}
+
+void UIGChooserItemGroup::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget* /* pWidget = 0 */)
+{
+    paint(pPainter, pOption, closed());
+}
+
+void UIGChooserItemGroup::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool fClosedGroup)
+{
+    /* Non-root item: */
+    if (!isRoot())
+    {
+        /* Configure painter shape: */
+        configurePainterShape(pPainter, pOption, m_iCornerRadius);
+    }
+
+    /* Any item: */
+    {
+        /* Paint decorations: */
+        paintDecorations(pPainter, pOption);
+    }
+
+    /* Non-root item: */
+    if (!isRoot())
+    {
+        /* Paint group info: */
+        paintGroupInfo(pPainter, pOption, fClosedGroup);
+    }
+}
+
+void UIGChooserItemGroup::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Prepare variables: */
+    QRect fullRect = pOption->rect;
+
+    /* Any item: */
+    {
+        /* Paint background: */
+        paintBackground(/* Painter: */
+                        pPainter,
+                        /* Rectangle to paint in: */
+                        fullRect);
+    }
+
+    /* Non-root item: */
+    if (!isRoot())
+    {
+        /* Paint frame: */
+        paintFrameRect(/* Painter: */
+                       pPainter,
+                       /* Rectangle to paint in: */
+                       fullRect,
+                       /* Is item selected? */
+                       model()->selectionList().contains(this),
+                       /* Rounded corner radius: */
+                       m_iCornerRadius);
+    }
+}
+
+void UIGChooserItemGroup::paintBackground(QPainter *pPainter, const QRect &rect)
+{
+    /* Save painter: */
+    pPainter->save();
+
+    /* Prepare color: */
+    QPalette pal = palette();
+    QColor base = pal.color(QPalette::Active, model()->selectionList().contains(this) ?
+                            QPalette::Highlight : QPalette::Window);
+
+    /* Root item: */
+    if (isRoot())
+    {
+        /* Simple and clear: */
+        pPainter->fillRect(rect, base.darker(100));
+    }
+    /* Non-root item: */
+    else
+    {
+        /* Prepare variables: */
+        int iMargin = data(GroupItemData_VerticalMargin).toInt();
+        int iHeaderHeight = data(GroupItemData_FullHeaderSize).toSize().height();
+        int iFullHeaderHeight = 2 * iMargin + iHeaderHeight;
+
+        /* Fill rectangle with brush/color: */
+        pPainter->fillRect(rect, Qt::white);
+
+        /* Make even less rectangle: */
+        QRect backGroundRect = rect;
+        backGroundRect.setTopLeft(backGroundRect.topLeft() + QPoint(2, 2));
+        backGroundRect.setBottomRight(backGroundRect.bottomRight() - QPoint(2, 2));
+        /* Add even more clipping: */
+        QPainterPath roundedPath;
+        roundedPath.addRoundedRect(backGroundRect, m_iCornerRadius, m_iCornerRadius);
+        pPainter->setClipPath(roundedPath);
+
+        /* Calculate bottom rectangle: */
+        QRect bRect = backGroundRect;
+        bRect.setTop(bRect.bottom() - iFullHeaderHeight);
+        /* Prepare bottom gradient: */
+        QLinearGradient bGradient(bRect.topLeft(), bRect.bottomLeft());
+        bGradient.setColorAt(0, base.darker(gradient()));
+        bGradient.setColorAt(1, base.darker(104));
+        /* Fill bottom rectangle: */
+        pPainter->fillRect(bRect, bGradient);
+
+        /* Calculate top rectangle: */
+        QRect tRect = backGroundRect;
+        tRect.setBottom(tRect.top() + iFullHeaderHeight);
+        /* Prepare top gradient: */
+        QLinearGradient tGradient(tRect.bottomLeft(), tRect.topLeft());
+        tGradient.setColorAt(0, base.darker(gradient()));
+        tGradient.setColorAt(1, base.darker(104));
+        /* Fill top rectangle: */
+        pPainter->fillRect(tRect, tGradient);
+
+        if (bRect.top() > tRect.bottom())
+        {
+            /* Calculate middle rectangle: */
+            QRect midRect = QRect(tRect.bottomLeft(), bRect.topRight());
+            /* Paint all the stuff: */
+            pPainter->fillRect(midRect, base.darker(gradient()));
+        }
+
+        /* Paint drag token UP? */
+        if (dragTokenPlace() != DragToken_Off)
+        {
+            QLinearGradient dragTokenGradient;
+            QRect dragTokenRect = backGroundRect;
+            if (dragTokenPlace() == DragToken_Up)
+            {
+                dragTokenRect.setHeight(5);
+                dragTokenGradient.setStart(dragTokenRect.bottomLeft());
+                dragTokenGradient.setFinalStop(dragTokenRect.topLeft());
+            }
+            else if (dragTokenPlace() == DragToken_Down)
+            {
+                dragTokenRect.setTopLeft(dragTokenRect.bottomLeft() - QPoint(0, 5));
+                dragTokenGradient.setStart(dragTokenRect.topLeft());
+                dragTokenGradient.setFinalStop(dragTokenRect.bottomLeft());
+            }
+            dragTokenGradient.setColorAt(0, base.darker(110));
+            dragTokenGradient.setColorAt(1, base.darker(150));
+            pPainter->fillRect(dragTokenRect, dragTokenGradient);
+        }
+    }
+
+    /* Restore painter: */
+    pPainter->restore();
+}
+
+void UIGChooserItemGroup::paintGroupInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool)
+{
+    /* Prepare variables: */
+    int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    int iVerticalMargin = data(GroupItemData_VerticalMargin).toInt();
+    QSize buttonSize = data(GroupItemData_ButtonSize).toSize();
+    QSize nameSize = data(GroupItemData_NameSize).toSize();
+    int iFullHeaderHeight = data(GroupItemData_FullHeaderSize).toSize().height();
+
+    /* Paint name: */
+    int iNameX = iHorizontalMargin + buttonSize.width() + iMinorSpacing +
+                 1 /* frame width from Qt sources */ +
+                 2 /* internal QLineEdit margin from Qt sources */ +
+                 1 /* internal QLineEdit align shifting from Qt sources */;
+    int iNameY = nameSize.height() == iFullHeaderHeight ? iVerticalMargin :
+                 iVerticalMargin + (iFullHeaderHeight - nameSize.height()) / 2;
+    paintText(/* Painter: */
+              pPainter,
+              /* Rectangle to paint in: */
+              QRect(QPoint(iNameX, iNameY), nameSize),
+              /* Font to paint text: */
+              data(GroupItemData_NameFont).value<QFont>(),
+              /* Text to paint: */
+              data(GroupItemData_Name).toString());
+
+    /* Should we add more info? */
+    if (isHovered())
+    {
+        /* Prepare variables: */
+        QRect fullRect = pOption->rect;
+        int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+        QSize groupPixmapSize = data(GroupItemData_GroupPixmapSize).toSize();
+        QSize machinePixmapSize = data(GroupItemData_MachinePixmapSize).toSize();
+        QSize groupCountTextSize = data(GroupItemData_GroupCountTextSize).toSize();
+        QSize machineCountTextSize = data(GroupItemData_MachineCountTextSize).toSize();
+        QFont infoFont = data(GroupItemData_InfoFont).value<QFont>();
+        QString strGroupCountText = data(GroupItemData_GroupCountText).toString();
+        QString strMachineCountText = data(GroupItemData_MachineCountText).toString();
+        QPixmap groupPixmap = data(GroupItemData_GroupPixmap).value<QIcon>().pixmap(groupPixmapSize);
+        QPixmap machinePixmap = data(GroupItemData_MachinePixmap).value<QIcon>().pixmap(machinePixmapSize);
+
+        /* We should add machine count: */
+        int iMachineCountTextX = fullRect.right() -
+                                 iHorizontalMargin -
+                                 machineCountTextSize.width();
+        int iMachineCountTextY = machineCountTextSize.height() == iFullHeaderHeight ?
+                                 iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - machineCountTextSize.height()) / 2;
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(QPoint(iMachineCountTextX, iMachineCountTextY), machineCountTextSize),
+                  /* Font to paint text: */
+                  infoFont,
+                  /* Text to paint: */
+                  strMachineCountText);
+
+        /* We should draw machine pixmap: */
+        int iMachinePixmapX = iMachineCountTextX -
+                              iMinorSpacing -
+                              machinePixmapSize.width();
+        int iMachinePixmapY = machinePixmapSize.height() == iFullHeaderHeight ?
+                              iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - machinePixmapSize.height()) / 2;
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(QPoint(iMachinePixmapX, iMachinePixmapY), machinePixmapSize),
+                    /* Pixmap to paint: */
+                    machinePixmap);
+
+        /* We should add group count: */
+        int iGroupCountTextX = iMachinePixmapX -
+                               iMinorSpacing -
+                               groupCountTextSize.width();
+        int iGroupCountTextY = groupCountTextSize.height() == iFullHeaderHeight ?
+                               iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - groupCountTextSize.height()) / 2;
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(QPoint(iGroupCountTextX, iGroupCountTextY), groupCountTextSize),
+                  /* Font to paint text: */
+                  infoFont,
+                  /* Text to paint: */
+                  strGroupCountText);
+
+        /* We should draw group pixmap: */
+        int iGroupPixmapX = iGroupCountTextX -
+                            iMinorSpacing -
+                            groupPixmapSize.width();
+        int iGroupPixmapY = groupPixmapSize.height() == iFullHeaderHeight ?
+                            iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - groupPixmapSize.height()) / 2;
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(QPoint(iGroupPixmapX, iGroupPixmapY), groupPixmapSize),
+                    /* Pixmap to paint: */
+                    groupPixmap);
+    }
+}
+
+void UIGChooserItemGroup::updateAnimationParameters()
+{
+    /* Only for item with button: */
+    if (!m_pButton)
+        return;
+
+    /* Recalculate animation parameters: */
+    QSizeF openedSize = minimumSizeHint(false);
+    QSizeF closedSize = minimumSizeHint(true);
+    int iAdditionalHeight = openedSize.height() - closedSize.height();
+    m_pButton->setAnimationRange(0, iAdditionalHeight);
+}
+
+void UIGChooserItemGroup::setAdditionalHeight(int iAdditionalHeight)
+{
+    m_iAdditionalHeight = iAdditionalHeight;
+    model()->updateLayout();
+}
+
+int UIGChooserItemGroup::additionalHeight() const
+{
+    return m_iAdditionalHeight;
+}
+
+void UIGChooserItemGroup::prepare()
+{
+    /* Setup toggle-button: */
+    m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", opened());
+    m_pButton->setIcon(data(GroupItemData_ButtonPixmap).value<QIcon>());
+    connect(m_pButton, SIGNAL(sigRotationStart()), this, SLOT(sltGroupToggleStart()));
+    connect(m_pButton, SIGNAL(sigRotationFinish(bool)), this, SLOT(sltGroupToggleFinish(bool)));
+    m_pButton->hide();
+
+    /* Setup name-editor: */
+    m_pNameEditorWidget = new QLineEdit(m_strName);
+    m_pNameEditorWidget->setTextMargins(0, 0, 0, 0);
+    m_pNameEditorWidget->setFont(data(GroupItemData_NameFont).value<QFont>());
+    connect(m_pNameEditorWidget, SIGNAL(editingFinished()), this, SLOT(sltNameEditingFinished()));
+    m_pNameEditor = new QGraphicsProxyWidget(this);
+    m_pNameEditor->setWidget(m_pNameEditorWidget);
+    m_pNameEditor->hide();
+}
+
+/* static */
+void UIGChooserItemGroup::copyContent(UIGChooserItemGroup *pFrom, UIGChooserItemGroup *pTo)
+{
+    /* Copy group items: */
+    foreach (UIGChooserItem *pGroupItem, pFrom->items(UIGChooserItemType_Group))
+        new UIGChooserItemGroup(pTo, pGroupItem->toGroupItem());
+    /* Copy machine items: */
+    foreach (UIGChooserItem *pMachineItem, pFrom->items(UIGChooserItemType_Machine))
+        new UIGChooserItemMachine(pTo, pMachineItem->toMachineItem());
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemGroup.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemGroup.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemGroup.h	(revision 42529)
@@ -0,0 +1,168 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserItemGroup class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserItemGroup_h__
+#define __UIGChooserItemGroup_h__
+
+/* GUI includes: */
+#include "UIGChooserItem.h"
+
+/* Forward declarations: */
+class QGraphicsScene;
+class UIGraphicsRotatorButton;
+class QLineEdit;
+class QGraphicsProxyWidget;
+
+/* Graphics group item
+ * for graphics selector model/view architecture: */
+class UIGChooserItemGroup : public UIGChooserItem
+{
+    Q_OBJECT;
+    Q_PROPERTY(int additionalHeight READ additionalHeight WRITE setAdditionalHeight);
+
+public:
+
+    /* Class-name used for drag&drop mime-data format: */
+    static QString className();
+
+    /* Graphics-item type: */
+    enum { Type = UIGChooserItemType_Group };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGChooserItemGroup(QGraphicsScene *pScene);
+    UIGChooserItemGroup(QGraphicsScene *pScene, UIGChooserItemGroup *pCopyFrom);
+    UIGChooserItemGroup(UIGChooserItem *pParent, const QString &strName,
+                        bool fOpened  = false , int iPosition  = -1 );
+    UIGChooserItemGroup(UIGChooserItem *pParent, UIGChooserItemGroup *pCopyFrom,
+                        int iPosition  = -1 );
+    ~UIGChooserItemGroup();
+
+    /* API: Basic stuff: */
+    QString name() const;
+    bool closed() const;
+    bool opened() const;
+    void close();
+    void open();
+
+    /* API: Children stuff: */
+    bool contains(const QString &strId, bool fRecursively = false) const;
+
+private slots:
+
+    /* Handler: Group name editing: */
+    void sltNameEditingFinished();
+
+    /* Handler: Collapse/expand stuff: */
+    void sltGroupToggleStart();
+    void sltGroupToggleFinish(bool fToggled);
+
+private:
+
+    /* Data enumerator: */
+    enum GroupItemData
+    {
+        /* Layout hints: */
+        GroupItemData_HorizonalMargin,
+        GroupItemData_VerticalMargin,
+        GroupItemData_MajorSpacing,
+        GroupItemData_MinorSpacing,
+        /* Pixmaps: */
+        GroupItemData_ButtonPixmap,
+        GroupItemData_GroupPixmap,
+        GroupItemData_MachinePixmap,
+        /* Fonts: */
+        GroupItemData_NameFont,
+        GroupItemData_InfoFont,
+        /* Text: */
+        GroupItemData_Name,
+        GroupItemData_GroupCountText,
+        GroupItemData_MachineCountText,
+        /* Sizes: */
+        GroupItemData_ButtonSize,
+        GroupItemData_NameSize,
+        GroupItemData_NameEditorSize,
+        GroupItemData_GroupPixmapSize,
+        GroupItemData_MachinePixmapSize,
+        GroupItemData_GroupCountTextSize,
+        GroupItemData_MachineCountTextSize,
+        GroupItemData_FullHeaderSize
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Helpers: Basic stuff: */
+    void show();
+    void hide();
+    void startEditing();
+
+    /* Helpers: Children stuff: */
+    void addItem(UIGChooserItem *pItem, int iPosition);
+    void removeItem(UIGChooserItem *pItem);
+    QList<UIGChooserItem*> items(UIGChooserItemType type = UIGChooserItemType_Any) const;
+    bool hasItems(UIGChooserItemType type = UIGChooserItemType_Any) const;
+    void clearItems(UIGChooserItemType type = UIGChooserItemType_Any);
+
+    /* Helpers: Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+    int minimumWidthHint(bool fClosedGroup) const;
+    int minimumHeightHint(bool fClosedGroup) const;
+    int minimumWidthHint() const;
+    int minimumHeightHint() const;
+    QSizeF minimumSizeHint(bool fClosedGroup) const;
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* Helpers: Drag and drop stuff: */
+    QPixmap toPixmap();
+    bool isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const;
+    void processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGChooserItem *pFromWho, DragToken where);
+    void resetDragToken();
+    QMimeData* createMimeData();
+
+    /* Helpers: Paint stuff: */
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool fClosedGroup);
+    void paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+    void paintBackground(QPainter *pPainter, const QRect &rect);
+    void paintGroupInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool fClosedGroup);
+
+    /* Helpers: Animation stuff: */
+    void updateAnimationParameters();
+    void setAdditionalHeight(int iAdditionalHeight);
+    int additionalHeight() const;
+
+    /* Helpers: Prepare stuff: */
+    void prepare();
+    static void copyContent(UIGChooserItemGroup *pFrom, UIGChooserItemGroup *pTo);
+
+    /* Variables: */
+    QString m_strName;
+    bool m_fClosed;
+    UIGraphicsRotatorButton *m_pButton;
+    QLineEdit *m_pNameEditorWidget;
+    QGraphicsProxyWidget *m_pNameEditor;
+    QList<UIGChooserItem*> m_groupItems;
+    QList<UIGChooserItem*> m_machineItems;
+    int m_iAdditionalHeight;
+    int m_iCornerRadius;
+};
+
+#endif /* __UIGChooserItemGroup_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp	(revision 42529)
@@ -0,0 +1,674 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserItemMachine class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QGraphicsSceneMouseEvent>
+
+/* GUI includes: */
+#include "UIGChooserItemMachine.h"
+#include "UIGChooserItemGroup.h"
+#include "UIGChooserModel.h"
+#include "UIGraphicsToolBar.h"
+#include "UIGraphicsZoomButton.h"
+#include "VBoxGlobal.h"
+#include "UIConverter.h"
+#include "UIIconPool.h"
+#include "UIActionPoolSelector.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+#include "CMachine.h"
+
+/* static */
+QString UIGChooserItemMachine::className() { return "UIGChooserItemMachine"; }
+
+UIGChooserItemMachine::UIGChooserItemMachine(UIGChooserItem *pParent,
+                                             const CMachine &machine,
+                                             int iPosition /* = -1 */)
+    : UIGChooserItem(pParent)
+    , UIVMItem(machine)
+    , m_pToolBar(0)
+    , m_pSettingsButton(0)
+    , m_pStartButton(0)
+    , m_pPauseButton(0)
+    , m_pCloseButton(0)
+    , m_iCornerRadius(6)
+{
+    /* Prepare: */
+    prepare();
+
+    /* Add item to the parent: */
+    AssertMsg(parentItem(), ("No parent set for machine item!"));
+    parentItem()->addItem(this, iPosition);
+    setZValue(parentItem()->zValue() + 1);
+}
+
+UIGChooserItemMachine::UIGChooserItemMachine(UIGChooserItem *pParent,
+                                             UIGChooserItemMachine *pCopyFrom,
+                                             int iPosition /* = -1 */)
+    : UIGChooserItem(pParent)
+    , UIVMItem(pCopyFrom->machine())
+    , m_pToolBar(0)
+    , m_pSettingsButton(0)
+    , m_pStartButton(0)
+    , m_pPauseButton(0)
+    , m_pCloseButton(0)
+    , m_iCornerRadius(6)
+{
+    /* Prepare: */
+    prepare();
+
+    /* Add item to the parent: */
+    AssertMsg(parentItem(), ("No parent set for machine item!"));
+    parentItem()->addItem(this, iPosition);
+    setZValue(parentItem()->zValue() + 1);
+}
+
+UIGChooserItemMachine::~UIGChooserItemMachine()
+{
+    /* If that item is focused: */
+    if (model()->focusItem() == this)
+    {
+        /* Unset the focus/selection: */
+        model()->setFocusItem(0, true);
+    }
+    /* If that item is NOT focused, but selected: */
+    else if (model()->selectionList().contains(this))
+    {
+        /* Remove item from the selection list: */
+        model()->removeFromSelectionList(this);
+    }
+    /* Remove item from the navigation list: */
+    model()->removeFromNavigationList(this);
+
+    /* Remove item from the parent: */
+    AssertMsg(parentItem(), ("No parent set for machine item!"));
+    parentItem()->removeItem(this);
+}
+
+QString UIGChooserItemMachine::name() const
+{
+    return UIVMItem::name();
+}
+
+QVariant UIGChooserItemMachine::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case MachineItemData_Margin: return 5;
+        case MachineItemData_MajorSpacing: return 10;
+        case MachineItemData_MinorSpacing: return 4;
+        case MachineItemData_TextSpacing: return 2;
+        /* Pixmaps: */
+        case MachineItemData_Pixmap: return osIcon();
+        case MachineItemData_StatePixmap: return machineStateIcon();
+        case MachineItemData_SettingsButtonPixmap: return UIIconPool::iconSet(":/settings_16px.png");
+        case MachineItemData_StartButtonPixmap: return UIIconPool::iconSet(":/start_16px.png");
+        case MachineItemData_PauseButtonPixmap: return UIIconPool::iconSet(":/pause_16px.png");
+        case MachineItemData_CloseButtonPixmap: return UIIconPool::iconSet(":/exit_16px.png");
+        /* Fonts: */
+        case MachineItemData_NameFont:
+        {
+            QFont machineNameFont = qApp->font();
+            machineNameFont.setPointSize(machineNameFont.pointSize() + 1);
+            machineNameFont.setWeight(QFont::Bold);
+            return machineNameFont;
+        }
+        case MachineItemData_SnapshotNameFont:
+        {
+            QFont snapshotStateFont = qApp->font();
+            snapshotStateFont.setPointSize(snapshotStateFont.pointSize() + 1);
+            return snapshotStateFont;
+        }
+        case MachineItemData_StateTextFont:
+        {
+            QFont machineStateFont = qApp->font();
+            machineStateFont.setPointSize(machineStateFont.pointSize() + 1);
+            return machineStateFont;
+        }
+        /* Texts: */
+        case MachineItemData_Name: return name();
+        case MachineItemData_SnapshotName: return snapshotName();
+        case MachineItemData_StateText: return gpConverter->toString(machineState());
+        /* Sizes: */
+        case MachineItemData_PixmapSize: return osIcon().availableSizes().at(0);
+        case MachineItemData_StatePixmapSize: return machineStateIcon().availableSizes().at(0);
+        case MachineItemData_NameSize:
+        {
+            QFontMetrics fm(data(MachineItemData_NameFont).value<QFont>());
+            return QSize(fm.width(data(MachineItemData_Name).toString()), fm.height());
+        }
+        case MachineItemData_SnapshotNameSize:
+        {
+            QFontMetrics fm(data(MachineItemData_SnapshotNameFont).value<QFont>());
+            return QSize(fm.width(QString("(%1)").arg(data(MachineItemData_SnapshotName).toString())), fm.height());
+        }
+        case MachineItemData_StateTextSize:
+        {
+            QFontMetrics fm(data(MachineItemData_StateTextFont).value<QFont>());
+            return QSize(fm.width(data(MachineItemData_StateText).toString()), fm.height());
+        }
+        case MachineItemData_ToolBarSize: return m_pToolBar->minimumSizeHint().toSize();
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGChooserItemMachine::startEditing()
+{
+    AssertMsgFailed(("Machine graphics item do NOT support editing yet!"));
+}
+
+void UIGChooserItemMachine::addItem(UIGChooserItem*, int)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+void UIGChooserItemMachine::removeItem(UIGChooserItem*)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+QList<UIGChooserItem*> UIGChooserItemMachine::items(UIGChooserItemType) const
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+    return QList<UIGChooserItem*>();
+}
+
+bool UIGChooserItemMachine::hasItems(UIGChooserItemType) const
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+    return false;
+}
+
+void UIGChooserItemMachine::clearItems(UIGChooserItemType)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+void UIGChooserItemMachine::updateSizeHint()
+{
+    updateGeometry();
+}
+
+void UIGChooserItemMachine::updateLayout()
+{
+    /* Prepare variables: */
+    QSize size = geometry().size().toSize();
+
+    /* Prepare variables: */
+    int iMachineItemWidth = size.width();
+    int iMachineItemHeight = size.height();
+    int iToolBarHeight = data(MachineItemData_ToolBarSize).toSize().height();
+
+    /* Configure tool-bar: */
+    QSize toolBarSize = m_pToolBar->minimumSizeHint().toSize();
+    int iToolBarX = iMachineItemWidth - 1 - toolBarSize.width();
+    int iToolBarY = (iMachineItemHeight - iToolBarHeight) / 2;
+    m_pToolBar->setPos(iToolBarX, iToolBarY);
+    m_pToolBar->resize(toolBarSize);
+    m_pToolBar->updateLayout();
+
+    /* Configure buttons: */
+    m_pStartButton->updateAnimation();
+    m_pSettingsButton->updateAnimation();
+    m_pCloseButton->updateAnimation();
+    m_pPauseButton->updateAnimation();
+}
+
+int UIGChooserItemMachine::minimumWidthHint() const
+{
+    /* First of all, we have to prepare few variables: */
+    int iMachineItemMargin = data(MachineItemData_Margin).toInt();
+    int iMachineItemMajorSpacing = data(MachineItemData_MajorSpacing).toInt();
+    int iMachineItemMinorSpacing = data(MachineItemData_MinorSpacing).toInt();
+    QSize machinePixmapSize = data(MachineItemData_PixmapSize).toSize();
+    QSize machineNameSize = data(MachineItemData_NameSize).toSize();
+    QSize snapshotNameSize = data(MachineItemData_SnapshotNameSize).toSize();
+    QSize machineStatePixmapSize = data(MachineItemData_StatePixmapSize).toSize();
+    QSize machineStateTextSize = data(MachineItemData_StateTextSize).toSize();
+    QSize toolBarSize = data(MachineItemData_ToolBarSize).toSize();
+
+    /* Calculating proposed width: */
+    int iProposedWidth = 0;
+
+    /* We are taking into account only left margin,
+     * tool-bar contains right one: */
+    iProposedWidth += iMachineItemMargin;
+    /* And machine item content to take into account: */
+    int iFirstLineWidth = machineNameSize.width() +
+                          iMachineItemMinorSpacing +
+                          snapshotNameSize.width();
+    int iSecondLineWidth = machineStatePixmapSize.width() +
+                           iMachineItemMinorSpacing +
+                           machineStateTextSize.width();
+    int iSecondColumnWidth = qMax(iFirstLineWidth, iSecondLineWidth);
+    int iMachineItemWidth = machinePixmapSize.width() +
+                            iMachineItemMajorSpacing +
+                            iSecondColumnWidth +
+                            iMachineItemMajorSpacing +
+                            toolBarSize.width() + 1;
+    iProposedWidth += iMachineItemWidth;
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGChooserItemMachine::minimumHeightHint() const
+{
+    /* First of all, we have to prepare few variables: */
+    int iMachineItemMargin = data(MachineItemData_Margin).toInt();
+    int iMachineItemTextSpacing = data(MachineItemData_TextSpacing).toInt();
+    QSize machinePixmapSize = data(MachineItemData_PixmapSize).toSize();
+    QSize machineNameSize = data(MachineItemData_NameSize).toSize();
+    QSize snapshotNameSize = data(MachineItemData_SnapshotNameSize).toSize();
+    QSize machineStatePixmapSize = data(MachineItemData_StatePixmapSize).toSize();
+    QSize machineStateTextSize = data(MachineItemData_StateTextSize).toSize();
+    QSize toolBarSize = data(MachineItemData_ToolBarSize).toSize();
+
+    /* Calculating proposed height: */
+    int iProposedHeight = 0;
+
+    /* Simple machine item have 2 margins - top and bottom: */
+    iProposedHeight += 2 * iMachineItemMargin;
+    /* And machine item content to take into account: */
+    int iFirstLineHeight = qMax(machineNameSize.height(), snapshotNameSize.height());
+    int iSecondLineHeight = qMax(machineStatePixmapSize.height(), machineStateTextSize.height());
+    int iSecondColumnHeight = iFirstLineHeight +
+                              iMachineItemTextSpacing +
+                              iSecondLineHeight;
+    QList<int> heights;
+    heights << machinePixmapSize.height() << iSecondColumnHeight
+            << (toolBarSize.height() - 2 * iMachineItemMargin + 2);
+    int iMaxHeight = 0;
+    foreach (int iHeight, heights)
+        iMaxHeight = qMax(iMaxHeight, iHeight);
+    iProposedHeight += iMaxHeight;
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+QSizeF UIGChooserItemMachine::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    /* If Qt::MinimumSize requested: */
+    if (which == Qt::MinimumSize)
+    {
+        /* Return wrappers: */
+        return QSizeF(minimumWidthHint(), minimumHeightHint());
+    }
+
+    /* Call to base-class: */
+    return UIGChooserItem::sizeHint(which, constraint);
+}
+
+QPixmap UIGChooserItemMachine::toPixmap()
+{
+    /* Ask item to paint itself into pixmap: */
+    QSize minimumSize = minimumSizeHint().toSize();
+    QPixmap pixmap(minimumSize);
+    QPainter painter(&pixmap);
+    QStyleOptionGraphicsItem options;
+    options.rect = QRect(QPoint(0, 0), minimumSize);
+    paint(&painter, &options);
+    return pixmap;
+}
+
+bool UIGChooserItemMachine::isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const
+{
+    /* Get mime: */
+    const QMimeData *pMimeData = pEvent->mimeData();
+    /* If drag token is shown, its up to parent to decide: */
+    if (where != DragToken_Off)
+        return parentItem()->isDropAllowed(pEvent);
+    /* Else we should try to cast mime to known classes: */
+    if (pMimeData->hasFormat(UIGChooserItemMachine::className()))
+    {
+        /* Make sure passed item id is not ours: */
+        const UIGChooserItemMimeData *pCastedMimeData = qobject_cast<const UIGChooserItemMimeData*>(pMimeData);
+        AssertMsg(pCastedMimeData, ("Can't cast passed mime-data to UIGChooserItemMimeData!"));
+        UIGChooserItem *pItem = pCastedMimeData->item();
+        return pItem->toMachineItem()->id() != id();
+    }
+    /* That was invalid mime: */
+    return false;
+}
+
+void UIGChooserItemMachine::processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGChooserItem *pFromWho, DragToken where)
+{
+    /* Get mime: */
+    const QMimeData *pMime = pEvent->mimeData();
+    /* Make sure this handler called by this item (not by children): */
+    AssertMsg(!pFromWho && where == DragToken_Off, ("Machine graphics item do NOT support children!"));
+    Q_UNUSED(pFromWho);
+    Q_UNUSED(where);
+    if (pMime->hasFormat(UIGChooserItemMachine::className()))
+    {
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            case Qt::CopyAction:
+            {
+                /* Remember scene: */
+                UIGChooserModel *pModel = model();
+
+                /* Get passed item: */
+                const UIGChooserItemMimeData *pCastedMime = qobject_cast<const UIGChooserItemMimeData*>(pMime);
+                AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIGChooserItemMimeData!"));
+                UIGChooserItem *pItem = pCastedMime->item();
+
+                /* Group passed item with current item into the new group: */
+                UIGChooserItemGroup *pNewGroupItem = new UIGChooserItemGroup(parentItem(),
+                                                                             model()->uniqueGroupName(parentItem()));
+                new UIGChooserItemMachine(pNewGroupItem, this);
+                new UIGChooserItemMachine(pNewGroupItem, pItem->toMachineItem());
+
+                /* If proposed action is 'move': */
+                if (pEvent->proposedAction() == Qt::MoveAction)
+                {
+                    /* Delete passed item: */
+                    delete pItem;
+                }
+                /* Delete this item: */
+                delete this;
+
+                /* Update scene: */
+                pModel->updateGroupTree();
+                pModel->updateNavigation();
+                pModel->updateLayout();
+                pModel->setCurrentItem(pNewGroupItem);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+void UIGChooserItemMachine::resetDragToken()
+{
+    /* Reset drag token for this item: */
+    if (dragTokenPlace() != DragToken_Off)
+    {
+        setDragTokenPlace(DragToken_Off);
+        update();
+    }
+}
+
+QMimeData* UIGChooserItemMachine::createMimeData()
+{
+    return new UIGChooserItemMimeData(this);
+}
+
+void UIGChooserItemMachine::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget * /* pWidget = 0 */)
+{
+    /* Configure painter shape: */
+    configurePainterShape(pPainter, pOption, m_iCornerRadius);
+
+    /* Paint decorations: */
+    paintDecorations(pPainter, pOption);
+
+    /* Paint machine info: */
+    paintMachineInfo(pPainter, pOption);
+}
+
+void UIGChooserItemMachine::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Prepare variables: */
+    QRect fullRect = pOption->rect;
+
+    /* Paint background: */
+    paintBackground(pPainter, fullRect);
+
+    /* Paint frame: */
+    paintFrameRect(pPainter, fullRect, model()->selectionList().contains(this), m_iCornerRadius);
+}
+
+void UIGChooserItemMachine::paintBackground(QPainter *pPainter, const QRect &rect)
+{
+    /* Save painter: */
+    pPainter->save();
+
+    /* Fill rectangle with white color: */
+    pPainter->fillRect(rect, Qt::white);
+
+    /* Prepare color: */
+    QPalette pal = palette();
+    QColor base = pal.color(QPalette::Active, model()->selectionList().contains(this) ?
+                            QPalette::Highlight : QPalette::Window);
+
+    /* Make even less rectangle: */
+    QRect backGroundRect = rect;
+    backGroundRect.setTopLeft(backGroundRect.topLeft() + QPoint(2, 2));
+    backGroundRect.setBottomRight(backGroundRect.bottomRight() - QPoint(2, 2));
+    /* Add even more clipping: */
+    QPainterPath roundedPath;
+    roundedPath.addRoundedRect(backGroundRect, m_iCornerRadius, m_iCornerRadius);
+    pPainter->setClipPath(roundedPath);
+
+    /* Calculate top rectangle: */
+    QRect tRect = backGroundRect;
+    tRect.setBottom(tRect.top() + tRect.height() / 3);
+    /* Calculate bottom rectangle: */
+    QRect bRect = backGroundRect;
+    bRect.setTop(bRect.bottom() - bRect.height() / 3);
+    /* Calculate middle rectangle: */
+    QRect midRect = QRect(tRect.bottomLeft(), bRect.topRight());
+
+    /* Prepare top gradient: */
+    QLinearGradient tGradient(tRect.bottomLeft(), tRect.topLeft());
+    tGradient.setColorAt(0, base.darker(gradient()));
+    tGradient.setColorAt(1, base.darker(104));
+    /* Prepare bottom gradient: */
+    QLinearGradient bGradient(bRect.topLeft(), bRect.bottomLeft());
+    bGradient.setColorAt(0, base.darker(gradient()));
+    bGradient.setColorAt(1, base.darker(104));
+
+    /* Paint all the stuff: */
+    pPainter->fillRect(midRect, base.darker(gradient()));
+    pPainter->fillRect(tRect, tGradient);
+    pPainter->fillRect(bRect, bGradient);
+
+    /* Paint drag token UP? */
+    if (dragTokenPlace() != DragToken_Off)
+    {
+        QLinearGradient dragTokenGradient;
+        QRect dragTokenRect = backGroundRect;
+        if (dragTokenPlace() == DragToken_Up)
+        {
+            dragTokenRect.setHeight(5);
+            dragTokenGradient.setStart(dragTokenRect.bottomLeft());
+            dragTokenGradient.setFinalStop(dragTokenRect.topLeft());
+        }
+        else if (dragTokenPlace() == DragToken_Down)
+        {
+            dragTokenRect.setTopLeft(dragTokenRect.bottomLeft() - QPoint(0, 5));
+            dragTokenGradient.setStart(dragTokenRect.topLeft());
+            dragTokenGradient.setFinalStop(dragTokenRect.bottomLeft());
+        }
+        dragTokenGradient.setColorAt(0, base.darker(110));
+        dragTokenGradient.setColorAt(1, base.darker(150));
+        pPainter->fillRect(dragTokenRect, dragTokenGradient);
+    }
+
+    /* Restore painter: */
+    pPainter->restore();
+}
+
+void UIGChooserItemMachine::paintMachineInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Initialize some necessary variables: */
+    QRect fullRect = pOption->rect;
+    int iMachineItemMargin = data(MachineItemData_Margin).toInt();
+    int iMachineItemMajorSpacing = data(MachineItemData_MajorSpacing).toInt();
+    int iMachineItemMinorSpacing = data(MachineItemData_MinorSpacing).toInt();
+    int iMachineItemTextSpacing = data(MachineItemData_TextSpacing).toInt();
+    QSize machinePixmapSize = data(MachineItemData_PixmapSize).toSize();
+    QSize machineNameSize = data(MachineItemData_NameSize).toSize();
+    QString strSnapshotName = data(MachineItemData_SnapshotName).toString();
+    QSize snapshotNameSize = data(MachineItemData_SnapshotNameSize).toSize();
+    QSize machineStatePixmapSize = data(MachineItemData_StatePixmapSize).toSize();
+    QSize machineStateTextSize = data(MachineItemData_StateTextSize).toSize();
+
+    /* Paint pixmap: */
+    {
+        /* Calculate attributes: */
+        int iMachinePixmapHeight = machinePixmapSize.height();
+        int iFirstLineHeight = qMax(machineNameSize.height(), snapshotNameSize.height());
+        int iSecondLineHeight = qMax(machineStatePixmapSize.height(), machineStateTextSize.height());
+        int iRightSizeHeight = iFirstLineHeight + iMachineItemTextSpacing + iSecondLineHeight;
+        int iMinimumHeight = qMin(iMachinePixmapHeight, iRightSizeHeight);
+        int iMaximumHeight = qMax(iMachinePixmapHeight, iRightSizeHeight);
+        int iDelta = iMaximumHeight - iMinimumHeight;
+        int iHalfDelta = iDelta / 2;
+        int iMachinePixmapX = iMachineItemMargin;
+        int iMachinePixmapY = iMachinePixmapHeight >= iRightSizeHeight ?
+                              iMachineItemMargin : iMachineItemMargin + iHalfDelta;
+
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(fullRect.topLeft() +
+                          QPoint(iMachinePixmapX, iMachinePixmapY),
+                          machinePixmapSize),
+                    /* Pixmap to paint: */
+                    data(MachineItemData_Pixmap).value<QIcon>().pixmap(machinePixmapSize));
+    }
+
+    /* Paint name: */
+    {
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(fullRect.topLeft() +
+                        QPoint(iMachineItemMargin, iMachineItemMargin) +
+                        QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0),
+                        machineNameSize),
+                  /* Font to paint text: */
+                  data(MachineItemData_NameFont).value<QFont>(),
+                  /* Text to paint: */
+                  data(MachineItemData_Name).toString());
+    }
+
+    /* Paint snapshot name (if necessary): */
+    if (!strSnapshotName.isEmpty())
+    {
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(fullRect.topLeft() +
+                        QPoint(iMachineItemMargin, iMachineItemMargin) +
+                        QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0) +
+                        QPoint(machineNameSize.width() + iMachineItemMinorSpacing, 0),
+                        snapshotNameSize),
+                  /* Font to paint text: */
+                  data(MachineItemData_SnapshotNameFont).value<QFont>(),
+                  /* Text to paint: */
+                  QString("(%1)").arg(strSnapshotName));
+    }
+
+    /* Paint state pixmap: */
+    {
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(fullRect.topLeft() +
+                          QPoint(iMachineItemMargin, iMachineItemMargin) +
+                          QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0) +
+                          QPoint(0, machineNameSize.height() + iMachineItemTextSpacing),
+                          machineStatePixmapSize),
+                    /* Pixmap to paint: */
+                    data(MachineItemData_StatePixmap).value<QIcon>().pixmap(machineStatePixmapSize));
+    }
+
+    /* Paint state text: */
+    {
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(fullRect.topLeft() +
+                        QPoint(iMachineItemMargin, iMachineItemMargin) +
+                        QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0) +
+                        QPoint(0, machineNameSize.height() + iMachineItemTextSpacing) +
+                        QPoint(machineStatePixmapSize.width() + iMachineItemMinorSpacing, 0),
+                        machineStateTextSize),
+                  /* Font to paint text: */
+                  data(MachineItemData_StateTextFont).value<QFont>(),
+                  /* Text to paint: */
+                  data(MachineItemData_StateText).toString());
+    }
+
+    /* Show/hide start-button: */
+    if (isHovered())
+    {
+        if (!m_pToolBar->isVisible())
+            m_pToolBar->show();
+    }
+    else
+    {
+        if (m_pToolBar->isVisible())
+            m_pToolBar->hide();
+    }
+}
+
+void UIGChooserItemMachine::prepare()
+{
+    /* Create tool-bar: */
+    m_pToolBar = new UIGraphicsToolBar(this, 2, 2);
+
+    /* Create buttons: */
+    m_pSettingsButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Top | UIGraphicsZoomDirection_Left);
+    m_pSettingsButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pSettingsButton->setIcon(data(MachineItemData_SettingsButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pSettingsButton, 0, 0);
+
+    m_pStartButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Top | UIGraphicsZoomDirection_Right);
+    m_pStartButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pStartButton->setIcon(data(MachineItemData_StartButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pStartButton, 0, 1);
+
+    m_pPauseButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Bottom | UIGraphicsZoomDirection_Left);
+    m_pPauseButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pPauseButton->setIcon(data(MachineItemData_PauseButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pPauseButton, 1, 0);
+
+    m_pCloseButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Bottom | UIGraphicsZoomDirection_Right);
+    m_pCloseButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pCloseButton->setIcon(data(MachineItemData_CloseButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pCloseButton, 1, 1);
+
+    connect(m_pSettingsButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_Simple_Machine_SettingsDialog), SLOT(trigger()),
+            Qt::QueuedConnection);
+    connect(m_pStartButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow), SLOT(trigger()),
+            Qt::QueuedConnection);
+    connect(m_pPauseButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_Toggle_Machine_PauseAndResume), SLOT(trigger()),
+            Qt::QueuedConnection);
+    connect(m_pCloseButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_Simple_Machine_Close_PowerOff), SLOT(trigger()),
+            Qt::QueuedConnection);
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.h	(revision 42529)
@@ -0,0 +1,134 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserItemMachine class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserItemMachine_h__
+#define __UIGChooserItemMachine_h__
+
+/* GUI includes: */
+#include "UIVMItem.h"
+#include "UIGChooserItem.h"
+
+/* Forward declarations: */
+class CMachine;
+class UIGraphicsToolBar;
+class UIGraphicsZoomButton;
+
+/* Graphics machine item
+ * for graphics selector model/view architecture: */
+class UIGChooserItemMachine : public UIGChooserItem, public UIVMItem
+{
+    Q_OBJECT;
+
+public:
+
+    /* Class-name used for drag&drop mime-data format: */
+    static QString className();
+
+    /* Graphics-item type: */
+    enum { Type = UIGChooserItemType_Machine };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGChooserItemMachine(UIGChooserItem *pParent, const CMachine &machine, int iPosition = -1);
+    UIGChooserItemMachine(UIGChooserItem *pParent, UIGChooserItemMachine *pCopyFrom, int iPosition = -1);
+    ~UIGChooserItemMachine();
+
+    /* API: Basic stuff: */
+    QString name() const;
+
+private:
+
+    /* Data enumerator: */
+    enum MachineItemData
+    {
+        /* Layout hints: */
+        MachineItemData_Margin,
+        MachineItemData_MajorSpacing,
+        MachineItemData_MinorSpacing,
+        MachineItemData_TextSpacing,
+        /* Pixmaps: */
+        MachineItemData_Pixmap,
+        MachineItemData_StatePixmap,
+        MachineItemData_SettingsButtonPixmap,
+        MachineItemData_StartButtonPixmap,
+        MachineItemData_PauseButtonPixmap,
+        MachineItemData_CloseButtonPixmap,
+        /* Fonts: */
+        MachineItemData_NameFont,
+        MachineItemData_SnapshotNameFont,
+        MachineItemData_StateTextFont,
+        /* Text: */
+        MachineItemData_Name,
+        MachineItemData_SnapshotName,
+        MachineItemData_StateText,
+        /* Sizes: */
+        MachineItemData_PixmapSize,
+        MachineItemData_StatePixmapSize,
+        MachineItemData_NameSize,
+        MachineItemData_SnapshotNameSize,
+        MachineItemData_StateTextSize,
+        MachineItemData_ToolBarSize
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Helpers: Basic stuff: */
+    void startEditing();
+
+    /* Helpers: Children stuff: */
+    void addItem(UIGChooserItem *pItem, int iPosition);
+    void removeItem(UIGChooserItem *pItem);
+    QList<UIGChooserItem*> items(UIGChooserItemType type) const;
+    bool hasItems(UIGChooserItemType type) const;
+    void clearItems(UIGChooserItemType type);
+
+    /* Helpers: Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+    int minimumWidthHint() const;
+    int minimumHeightHint() const;
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* Helpers: Drag and drop stuff: */
+    QPixmap toPixmap();
+    bool isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const;
+    void processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGChooserItem *pFromWho, DragToken where);
+    void resetDragToken();
+    QMimeData* createMimeData();
+
+    /* Helpers: Paint stuff: */
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
+    void paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+    void paintBackground(QPainter *pPainter, const QRect &rect);
+    void paintMachineInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+
+    /* Helpers: Prepare stuff: */
+    void prepare();
+
+    /* Variables: */
+    UIGraphicsToolBar *m_pToolBar;
+    UIGraphicsZoomButton *m_pSettingsButton;
+    UIGraphicsZoomButton *m_pStartButton;
+    UIGraphicsZoomButton *m_pPauseButton;
+    UIGraphicsZoomButton *m_pCloseButton;
+    int m_iCornerRadius;
+};
+
+#endif /* __UIGChooserItemMachine_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserModel.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserModel.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserModel.cpp	(revision 42529)
@@ -0,0 +1,1557 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserModel class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QRegExp>
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsSceneContextMenuEvent>
+#include <QPropertyAnimation>
+#include <QParallelAnimationGroup>
+
+/* GUI includes: */
+#include "UIGChooserModel.h"
+#include "UIGChooserItemGroup.h"
+#include "UIGChooserItemMachine.h"
+#include "UIDefs.h"
+#include "VBoxGlobal.h"
+#include "UIMessageCenter.h"
+#include "UIActionPoolSelector.h"
+#include "UIGChooserHandlerMouse.h"
+#include "UIGChooserHandlerKeyboard.h"
+
+/* COM includes: */
+#include "CMachine.h"
+#include "CVirtualBox.h"
+
+UIGChooserModel::UIGChooserModel(QObject *pParent)
+    : QObject(pParent)
+    , m_pScene(0)
+    , m_fSliding(false)
+    , m_pLeftRoot(0)
+    , m_pRightRoot(0)
+    , m_pAfterSlidingFocus(0)
+    , m_pMouseHandler(0)
+    , m_pKeyboardHandler(0)
+    , m_pContextMenuRoot(0)
+    , m_pContextMenuGroup(0)
+    , m_pContextMenuMachine(0)
+{
+    /* Prepare scene: */
+    prepareScene();
+
+    /* Prepare root: */
+    prepareRoot();
+
+    /* Prepare context-menu: */
+    prepareContextMenu();
+
+    /* Prepare handlers: */
+    prepareHandlers();
+}
+
+UIGChooserModel::~UIGChooserModel()
+{
+    /* Cleanup handlers: */
+    cleanupHandlers();
+
+    /* Prepare context-menu: */
+    cleanupContextMenu();
+
+    /* Cleanup root: */
+    cleanupRoot();
+
+    /* Cleanup scene: */
+    cleanupScene();
+ }
+
+void UIGChooserModel::load()
+{
+    /* Prepare group-tree: */
+    prepareGroupTree();
+}
+
+void UIGChooserModel::save()
+{
+    /* Cleanup group-tree: */
+    cleanupGroupTree();
+}
+
+QGraphicsScene* UIGChooserModel::scene() const
+{
+    return m_pScene;
+}
+
+UIGChooserItem* UIGChooserModel::mainRoot() const
+{
+    return m_rootStack.first();
+}
+
+UIGChooserItem* UIGChooserModel::root() const
+{
+    return m_rootStack.last();
+}
+
+void UIGChooserModel::indentRoot(UIGChooserItem *pNewRootItem)
+{
+    /* Do nothing is sliding already: */
+    if (m_fSliding)
+        return;
+
+    /* We are sliding: */
+    m_fSliding = true;
+
+    /* Hiding root: */
+    root()->hide();
+
+    /* Create left root: */
+    m_pLeftRoot = new UIGChooserItemGroup(scene(), root()->toGroupItem());
+    m_pLeftRoot->setPos(0, 0);
+    m_pLeftRoot->resize(root()->geometry().size());
+
+    /* Create right root: */
+    m_pRightRoot = new UIGChooserItemGroup(scene(), pNewRootItem->toGroupItem());
+    m_pRightRoot->setPos(root()->geometry().width(), 0);
+    m_pRightRoot->resize(root()->geometry().size());
+
+    /* Indent root: */
+    m_rootStack << pNewRootItem;
+    root()->setRoot(true);
+    m_pAfterSlidingFocus = root()->items().first();
+
+    /* Slide root: */
+    slideRoot(true);
+}
+
+void UIGChooserModel::unindentRoot()
+{
+    /* Do nothing is sliding already: */
+    if (m_fSliding)
+        return;
+
+    /* We are sliding: */
+    m_fSliding = true;
+
+    /* Hiding root: */
+    root()->hide();
+    root()->setRoot(false);
+
+    /* Create left root: */
+    m_pLeftRoot = new UIGChooserItemGroup(scene(), m_rootStack.at(m_rootStack.size() - 2)->toGroupItem());
+    m_pLeftRoot->setPos(- root()->geometry().width(), 0);
+    m_pLeftRoot->resize(root()->geometry().size());
+
+    /* Create right root: */
+    m_pRightRoot = new UIGChooserItemGroup(scene(), root()->toGroupItem());
+    m_pRightRoot->setPos(0, 0);
+    m_pRightRoot->resize(root()->geometry().size());
+
+    /* Unindent root: */
+    m_pAfterSlidingFocus = root();
+    m_rootStack.removeLast();
+
+    /* Slide root: */
+    slideRoot(false);
+}
+
+void UIGChooserModel::setCurrentItem(int iItemIndex)
+{
+    /* Make sure passed index feats the bounds: */
+    if (iItemIndex >= 0 && iItemIndex < navigationList().size())
+    {
+        /* And call for other wrapper: */
+        setCurrentItem(navigationList().at(iItemIndex));
+    }
+    else
+        AssertMsgFailed(("Passed index out of bounds!"));
+}
+
+void UIGChooserModel::setCurrentItem(UIGChooserItem *pItem)
+{
+    /* If navigation list contains passed item: */
+    if (navigationList().contains(pItem))
+    {
+        /* Pass focus/selection to that item: */
+        setFocusItem(pItem, true);
+    }
+    else
+        AssertMsgFailed(("Passed item not in navigation list!"));
+}
+
+void UIGChooserModel::unsetCurrentItem()
+{
+    /* Clear focus/selection: */
+    setFocusItem(0, true);
+}
+
+UIVMItem* UIGChooserModel::currentItem() const
+{
+    /* Search for the first selected machine: */
+    return searchCurrentItem(selectionList());
+}
+
+QList<UIVMItem*> UIGChooserModel::currentItems() const
+{
+    /* Populate list of selected machines: */
+    QList<UIVMItem*> currentItemList;
+    enumerateCurrentItems(selectionList(), currentItemList);
+    return currentItemList;
+}
+
+void UIGChooserModel::setCurrentItemDefinition(const QString &strDefinition)
+{
+    /* Make sure something was passed: */
+    if (strDefinition.isEmpty())
+    {
+        if (mainRoot()->hasItems())
+            setCurrentItem(0);
+        else
+            unsetCurrentItem();
+        return;
+    }
+
+    /* Parse definitions: */
+    QString strItemType = strDefinition.section('=', 0, 0);
+    QString strItemName = strDefinition.section('=', 1, -1);
+    UIGChooserItem *pItem = 0;
+
+    /* Its group item? */
+    if (strItemType == "g")
+    {
+        /* Make sure group item with passed id exists: */
+        pItem = findGroupItem(strItemName, mainRoot());
+    }
+    /* Its machine item? */
+    else if (strItemType == "m")
+    {
+        /* Make sure machine with passed name registered: */
+        CMachine machine = vboxGlobal().virtualBox().FindMachine(strItemName);
+        if (!machine.isNull())
+        {
+            /* Make sure machine item with passed id exists: */
+            pItem = findMachineItem(machine.GetName(), mainRoot());
+        }
+    }
+
+    /* Found nothing? */
+    if (!pItem)
+    {
+        setCurrentItem(0);
+        return;
+    }
+
+    /* Select desired item: */
+    if (navigationList().contains(pItem))
+        setCurrentItem(pItem);
+    else
+        setCurrentItem(0);
+}
+
+QString UIGChooserModel::currentItemDefinition() const
+{
+    /* Determine item type: */
+    QString strItemType;
+    QString strItemName;
+
+    /* Get first selected item: */
+    UIGChooserItem *pSelectedItem = selectionList().isEmpty() ? 0 : selectionList().first();
+    /* Item exists? */
+    if (pSelectedItem)
+    {
+        /* Update item type: */
+        if (pSelectedItem->type() == UIGChooserItemType_Group)
+            strItemType = "g";
+        else if (pSelectedItem->type() == UIGChooserItemType_Machine)
+            strItemType = "m";
+
+        /* Update item name: */
+        strItemName = pSelectedItem->name();
+    }
+
+    /* Return result: */
+    return pSelectedItem ? strItemType + "=" + strItemName : QString();
+}
+
+bool UIGChooserModel::singleGroupSelected() const
+{
+    return selectionList().size() == 1 &&
+           selectionList().first()->type() == UIGChooserItemType_Group;
+}
+
+void UIGChooserModel::setFocusItem(UIGChooserItem *pItem, bool fWithSelection /* = false */)
+{
+    /* Make sure real focus unset: */
+    clearRealFocus();
+
+    /* Something changed? */
+    if (m_pFocusItem != pItem || !pItem)
+    {
+        /* Remember previous focus item: */
+        QPointer<UIGChooserItem> pPreviousFocusItem = m_pFocusItem;
+        /* Set new focus item: */
+        m_pFocusItem = pItem;
+
+        /* Should we move selection too? */
+        if (fWithSelection)
+        {
+            /* Clear selection: */
+            clearSelectionList();
+            /* Add focus item into selection (if any): */
+            if (m_pFocusItem)
+                addToSelectionList(m_pFocusItem);
+            /* Notify selection changed: */
+            notifySelectionChanged();
+        }
+
+        /* Update previous focus item (if any): */
+        if (pPreviousFocusItem)
+        {
+            pPreviousFocusItem->disconnect(this);
+            pPreviousFocusItem->update();
+        }
+        /* Update new focus item (if any): */
+        if (m_pFocusItem)
+        {
+            connect(m_pFocusItem, SIGNAL(destroyed(QObject*)), this, SLOT(sltFocusItemDestroyed()));
+            m_pFocusItem->update();
+        }
+    }
+}
+
+UIGChooserItem* UIGChooserModel::focusItem() const
+{
+    return m_pFocusItem;
+}
+
+QGraphicsItem* UIGChooserModel::itemAt(const QPointF &position, const QTransform &deviceTransform /* = QTransform() */) const
+{
+    return scene()->itemAt(position, deviceTransform);
+}
+
+void UIGChooserModel::updateGroupTree()
+{
+    updateGroupTree(mainRoot());
+}
+
+const QList<UIGChooserItem*>& UIGChooserModel::navigationList() const
+{
+    return m_navigationList;
+}
+
+void UIGChooserModel::removeFromNavigationList(UIGChooserItem *pItem)
+{
+    AssertMsg(pItem, ("Passed item is invalid!"));
+    m_navigationList.removeAll(pItem);
+}
+
+void UIGChooserModel::clearNavigationList()
+{
+    m_navigationList.clear();
+}
+
+void UIGChooserModel::updateNavigation()
+{
+    /* Recreate navigation list: */
+    clearNavigationList();
+    m_navigationList = createNavigationList(root());
+}
+
+const QList<UIGChooserItem*>& UIGChooserModel::selectionList() const
+{
+    return m_selectionList;
+}
+
+void UIGChooserModel::addToSelectionList(UIGChooserItem *pItem)
+{
+    AssertMsg(pItem, ("Passed item is invalid!"));
+    m_selectionList << pItem;
+    pItem->update();
+}
+
+void UIGChooserModel::removeFromSelectionList(UIGChooserItem *pItem)
+{
+    AssertMsg(pItem, ("Passed item is invalid!"));
+    m_selectionList.removeAll(pItem);
+    pItem->update();
+}
+
+void UIGChooserModel::clearSelectionList()
+{
+    QList<UIGChooserItem*> oldSelectedList = m_selectionList;
+    m_selectionList.clear();
+    foreach (UIGChooserItem *pItem, oldSelectedList)
+        pItem->update();
+}
+
+void UIGChooserModel::notifySelectionChanged()
+{
+    /* Make sure selection item list is never empty
+     * if at least one item (for example 'focus') present: */
+    if (selectionList().isEmpty() && focusItem())
+        addToSelectionList(focusItem());
+    /* Notify listeners about selection change: */
+    emit sigSelectionChanged();
+}
+
+void UIGChooserModel::updateLayout()
+{
+    /* No layout updates while sliding: */
+    if (m_fSliding)
+        return;
+
+    /* Initialize variables: */
+    int iSceneMargin = data(SelectorModelData_Margin).toInt();
+    QSize viewportSize = scene()->views()[0]->viewport()->size();
+    int iViewportWidth = viewportSize.width() - 2 * iSceneMargin;
+    int iViewportHeight = viewportSize.height() - 2 * iSceneMargin;
+    /* Update all the size-hints recursively: */
+    root()->updateSizeHint();
+    /* Set root item position: */
+    root()->setPos(iSceneMargin, iSceneMargin);
+    /* Set root item size: */
+    root()->resize(iViewportWidth, iViewportHeight);
+    /* Relayout root item: */
+    root()->updateLayout();
+    /* Notify listener about root-item relayouted: */
+    emit sigRootItemResized(root()->geometry().size(), root()->minimumWidthHint());
+}
+
+void UIGChooserModel::setCurrentDragObject(QDrag *pDragObject)
+{
+    /* Make sure real focus unset: */
+    clearRealFocus();
+
+    /* Remember new drag-object: */
+    m_pCurrentDragObject = pDragObject;
+    connect(m_pCurrentDragObject, SIGNAL(destroyed(QObject*)), this, SLOT(sltCurrentDragObjectDestroyed()));
+}
+
+void UIGChooserModel::activate()
+{
+    gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow)->activate(QAction::Trigger);
+}
+
+QString UIGChooserModel::uniqueGroupName(UIGChooserItem *pRoot)
+{
+    /* Enumerate all the group names: */
+    QStringList groupNames;
+    foreach (UIGChooserItem *pItem, pRoot->items(UIGChooserItemType_Group))
+        groupNames << pItem->name();
+
+    /* Prepare reg-exp: */
+    QString strMinimumName = tr("New group");
+    QString strShortTemplate = strMinimumName;
+    QString strFullTemplate = strShortTemplate + QString(" (\\d+)");
+    QRegExp shortRegExp(strShortTemplate);
+    QRegExp fullRegExp(strFullTemplate);
+
+    /* Search for the maximum index: */
+    int iMinimumPossibleNumber = 0;
+    foreach (const QString &strName, groupNames)
+    {
+        if (shortRegExp.exactMatch(strName))
+            iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, 2);
+        else if (fullRegExp.exactMatch(strName))
+            iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, fullRegExp.cap(1).toInt() + 1);
+    }
+
+    /* Prepare result: */
+    QString strResult = strMinimumName;
+    if (iMinimumPossibleNumber)
+        strResult += " " + QString::number(iMinimumPossibleNumber);
+    return strResult;
+}
+
+void UIGChooserModel::sltMachineStateChanged(QString strId, KMachineState)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, mainRoot());
+}
+
+void UIGChooserModel::sltMachineDataChanged(QString strId)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, mainRoot());
+}
+
+void UIGChooserModel::sltMachineRegistered(QString strId, bool fRegistered)
+{
+    /* New VM registered? */
+    if (fRegistered)
+    {
+        /* Search for corresponding machine: */
+        CMachine machine = vboxGlobal().virtualBox().FindMachine(strId);
+        /* Machine was found? */
+        if (!machine.isNull())
+        {
+            /* Add new machine item: */
+            addMachineIntoTheTree(machine, true);
+            /* And update model: */
+            updateNavigation();
+            updateLayout();
+            setCurrentItem(findMachineItem(machine.GetName(), mainRoot()));
+        }
+    }
+    /* Existing VM unregistered? */
+    else
+    {
+        /* Remove machine items with passed id: */
+        removeMachineItems(strId, mainRoot());
+        /* And update model: */
+        updateGroupTree();
+        updateNavigation();
+        updateLayout();
+        if (mainRoot()->hasItems())
+            setCurrentItem(0);
+        else
+            unsetCurrentItem();
+    }
+}
+
+void UIGChooserModel::sltSessionStateChanged(QString strId, KSessionState)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, mainRoot());
+}
+
+void UIGChooserModel::sltSnapshotChanged(QString strId, QString)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, mainRoot());
+}
+
+void UIGChooserModel::sltHandleViewResized()
+{
+    /* Relayout: */
+    updateLayout();
+}
+
+void UIGChooserModel::sltCurrentDragObjectDestroyed()
+{
+    /* Reset drag tokens starting from the root item: */
+    root()->resetDragToken();
+}
+
+void UIGChooserModel::sltRemoveCurrentlySelectedGroup()
+{
+    /* Make sure focus item is of group type! */
+    AssertMsg(focusItem()->type() == UIGChooserItemType_Group, ("This is not group item!"));
+
+    /* Compose focus group name: */
+    QString strFocusGroupName = fullName(focusItem());
+    /* Enumerate all the unique sub-machine-items recursively: */
+    QList<UIVMItem*> items;
+    enumerateCurrentItems(focusItem()->items(), items);
+    /* Enumerate all the machine groups recursively: */
+    QMap<QString, QStringList> groupMap;
+    gatherGroupTree(groupMap, mainRoot());
+
+    /* For each the sub-machine-item: */
+    foreach (UIVMItem *pItem, items)
+    {
+        /* Get machine groups: */
+        QStringList groups = groupMap.value(pItem->id());
+        /* For each the machine group: */
+        bool fUniqueMachine = true;
+        foreach (const QString &strGroupName, groups)
+        {
+            /* Check if this item is unique: */
+            if (strGroupName != strFocusGroupName &&
+                !strGroupName.startsWith(strFocusGroupName + "/"))
+            {
+                fUniqueMachine = false;
+                break;
+            }
+        }
+        /* Add unique item into root: */
+        if (fUniqueMachine)
+            createMachineItem(pItem->machine(), mainRoot());
+    }
+
+    /* Delete focus group: */
+    delete focusItem();
+
+    /* And update model: */
+    updateGroupTree();
+    updateNavigation();
+    updateLayout();
+    if (mainRoot()->hasItems())
+        setCurrentItem(0);
+    else
+        unsetCurrentItem();
+}
+
+void UIGChooserModel::sltRemoveCurrentlySelectedMachine()
+{
+    /* Enumerate all the selected machine items: */
+    QList<UIGChooserItem*> selectedMachineItemList = gatherMachineItems(selectionList());
+    /* Enumerate all the existing machine items: */
+    QList<UIGChooserItem*> existingMachineItemList = gatherMachineItems(mainRoot()->items());
+
+    /* Prepare removing map: */
+    QMap<QString, bool> removingMap;
+
+    /* For each selected machine item: */
+    foreach (UIGChooserItem *pItem, selectedMachineItemList)
+    {
+        /* Get item name: */
+        QString strName = pItem->name();
+
+        /* Check if we already decided for that machine: */
+        if (removingMap.contains(strName))
+            continue;
+
+        /* Selected copy count: */
+        int iSelectedCopyCount = 0;
+        foreach (UIGChooserItem *pSelectedItem, selectedMachineItemList)
+            if (pSelectedItem->name() == strName)
+                ++iSelectedCopyCount;
+
+        /* Existing copy count: */
+        int iExistingCopyCount = 0;
+        foreach (UIGChooserItem *pExistingItem, existingMachineItemList)
+            if (pExistingItem->name() == strName)
+                ++iExistingCopyCount;
+
+        /* If selected copy count equal to existing copy count,
+         * we will propose ro unregister machine fully else
+         * we will just propose to remove selected items: */
+        removingMap.insert(strName, iSelectedCopyCount == iExistingCopyCount);
+    }
+
+    /* If we have something to remove: */
+    if (removingMap.values().contains(false))
+    {
+        /* Gather names: */
+        QStringList names;
+        foreach (const QString &strName, removingMap.keys())
+            if (!removingMap[strName])
+                names << strName;
+        removeMachineItems(names, selectedMachineItemList);
+    }
+    /* If we have something to unregister: */
+    if (removingMap.values().contains(true))
+    {
+        /* Gather names: */
+        QStringList names;
+        foreach (const QString &strName, removingMap.keys())
+            if (removingMap[strName])
+                names << strName;
+        unregisterMachines(names);
+    }
+}
+
+void UIGChooserModel::sltStartEditingSelectedGroup()
+{
+    /* Only for single selected group: */
+    if (!singleGroupSelected())
+        return;
+
+    /* Start editing group name: */
+    selectionList().first()->startEditing();
+}
+
+void UIGChooserModel::sltActionHovered(QAction *pAction)
+{
+    emit sigShowStatusMessage(pAction->statusTip());
+}
+
+void UIGChooserModel::sltFocusItemDestroyed()
+{
+    AssertMsgFailed(("Focus item destroyed!"));
+}
+
+void UIGChooserModel::sltLeftRootSlidingProgress()
+{
+    /* Update left root: */
+    m_pLeftRoot->updateSizeHint();
+    m_pLeftRoot->updateLayout();
+}
+
+void UIGChooserModel::sltRightRootSlidingProgress()
+{
+    /* Update right root: */
+    m_pRightRoot->updateSizeHint();
+    m_pRightRoot->updateLayout();
+}
+
+void UIGChooserModel::sltSlidingComplete()
+{
+    /* Delete temporary roots: */
+    delete m_pLeftRoot;
+    m_pLeftRoot = 0;
+    delete m_pRightRoot;
+    m_pRightRoot = 0;
+
+    /* We are no more sliding: */
+    m_fSliding = false;
+
+    /* Update model: */
+    updateGroupTree();
+    updateNavigation();
+    updateLayout();
+    if (m_pAfterSlidingFocus)
+    {
+        setCurrentItem(m_pAfterSlidingFocus);
+        m_pAfterSlidingFocus = 0;
+    }
+    else
+    {
+        if (root()->hasItems())
+            setCurrentItem(root()->items().first());
+        else
+            unsetCurrentItem();
+    }
+}
+
+QVariant UIGChooserModel::data(int iKey) const
+{
+    switch (iKey)
+    {
+        case SelectorModelData_Margin: return 0;
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGChooserModel::prepareScene()
+{
+    m_pScene = new QGraphicsScene(this);
+    m_pScene->installEventFilter(this);
+}
+
+void UIGChooserModel::prepareRoot()
+{
+    m_rootStack << new UIGChooserItemGroup(scene());
+}
+
+void UIGChooserModel::prepareContextMenu()
+{
+    /* Context menu for empty group: */
+    m_pContextMenuRoot = new QMenu;
+    m_pContextMenuRoot->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_NewWizard));
+    m_pContextMenuRoot->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_AddDialog));
+
+    /* Context menu for group: */
+    m_pContextMenuGroup = new QMenu;
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_NewWizard));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_AddDialog));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_RenameDialog));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_RemoveDialog));
+    m_pContextMenuGroup->addSeparator();
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_State_Group_StartOrShow));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Toggle_Group_PauseAndResume));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_Reset));
+    m_pContextMenuGroup->addMenu(gActionPool->action(UIActionIndexSelector_Menu_Machine_Close)->menu());
+    m_pContextMenuGroup->addSeparator();
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndex_Simple_LogDialog));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_Refresh));
+    m_pContextMenuGroup->addSeparator();
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_ShowInFileManager));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_CreateShortcut));
+//    m_pContextMenuGroup->addSeparator();
+//    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Group_Sort));
+
+    /* Context menu for machine(s): */
+    m_pContextMenuMachine = new QMenu;
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_SettingsDialog));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_CloneWizard));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_RemoveDialog));
+    m_pContextMenuMachine->addSeparator();
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Toggle_Machine_PauseAndResume));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Reset));
+    m_pContextMenuMachine->addMenu(gActionPool->action(UIActionIndexSelector_Menu_Machine_Close)->menu());
+    m_pContextMenuMachine->addSeparator();
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Discard));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndex_Simple_LogDialog));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Refresh));
+    m_pContextMenuMachine->addSeparator();
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_ShowInFileManager));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_CreateShortcut));
+//    m_pContextMenuMachine->addSeparator();
+//    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Sort));
+
+    connect(m_pContextMenuRoot, SIGNAL(hovered(QAction*)), this, SLOT(sltActionHovered(QAction*)));
+    connect(m_pContextMenuGroup, SIGNAL(hovered(QAction*)), this, SLOT(sltActionHovered(QAction*)));
+    connect(m_pContextMenuMachine, SIGNAL(hovered(QAction*)), this, SLOT(sltActionHovered(QAction*)));
+
+    connect(gActionPool->action(UIActionIndexSelector_Simple_Group_RenameDialog), SIGNAL(triggered()),
+            this, SLOT(sltStartEditingSelectedGroup()));
+    connect(gActionPool->action(UIActionIndexSelector_Simple_Group_RemoveDialog), SIGNAL(triggered()),
+            this, SLOT(sltRemoveCurrentlySelectedGroup()));
+    connect(gActionPool->action(UIActionIndexSelector_Simple_Machine_RemoveDialog), SIGNAL(triggered()),
+            this, SLOT(sltRemoveCurrentlySelectedMachine()));
+}
+
+void UIGChooserModel::prepareHandlers()
+{
+    m_pMouseHandler = new UIGChooserHandlerMouse(this);
+    m_pKeyboardHandler = new UIGChooserHandlerKeyboard(this);
+}
+
+void UIGChooserModel::prepareGroupTree()
+{
+    /* Load group tree: */
+    loadGroupTree();
+
+    /* Update model: */
+    updateNavigation();
+    updateLayout();
+    if (mainRoot()->hasItems())
+        setCurrentItem(0);
+    else
+        unsetCurrentItem();
+}
+
+void UIGChooserModel::cleanupGroupTree()
+{
+    /* Save group tree: */
+    saveGroupTree();
+    /* Save order: */
+    saveGroupsOrder();
+}
+
+void UIGChooserModel::cleanupHandlers()
+{
+    delete m_pKeyboardHandler;
+    m_pKeyboardHandler = 0;
+    delete m_pMouseHandler;
+    m_pMouseHandler = 0;
+}
+
+void UIGChooserModel::cleanupContextMenu()
+{
+    delete m_pContextMenuRoot;
+    m_pContextMenuRoot = 0;
+    delete m_pContextMenuGroup;
+    m_pContextMenuGroup = 0;
+    delete m_pContextMenuMachine;
+    m_pContextMenuMachine = 0;
+}
+
+void UIGChooserModel::cleanupRoot()
+{
+    delete mainRoot();
+    m_rootStack.clear();
+}
+
+void UIGChooserModel::cleanupScene()
+{
+    delete m_pScene;
+    m_pScene = 0;
+}
+
+bool UIGChooserModel::eventFilter(QObject *pWatched, QEvent *pEvent)
+{
+    /* Process only scene events: */
+    if (pWatched != m_pScene)
+        return QObject::eventFilter(pWatched, pEvent);
+
+    /* Process only item is focused by model, not by scene: */
+    if (scene()->focusItem())
+        return QObject::eventFilter(pWatched, pEvent);
+
+    /* Checking event-type: */
+    switch (pEvent->type())
+    {
+        /* Keyboard handler: */
+        case QEvent::KeyPress:
+            return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Press);
+        case QEvent::KeyRelease:
+            return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Release);
+        /* Mouse handler: */
+        case QEvent::GraphicsSceneMousePress:
+            return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Press);
+        case QEvent::GraphicsSceneMouseRelease:
+            return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Release);
+        case QEvent::GraphicsSceneMouseDoubleClick:
+            return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_DoubleClick);
+        /* Context menu: */
+        case QEvent::GraphicsSceneContextMenu:
+            return processContextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(pEvent));
+    }
+
+    /* Call to base-class: */
+    return QObject::eventFilter(pWatched, pEvent);
+}
+
+void UIGChooserModel::clearRealFocus()
+{
+    /* Set real focus to null: */
+    scene()->setFocusItem(0);
+}
+
+UIVMItem* UIGChooserModel::searchCurrentItem(const QList<UIGChooserItem*> &list) const
+{
+    /* Iterate over all the passed items: */
+    foreach (UIGChooserItem *pItem, list)
+    {
+        /* If item is machine, just return it: */
+        if (pItem->type() == UIGChooserItemType_Machine)
+        {
+            if (UIGChooserItemMachine *pMachineItem = pItem->toMachineItem())
+                return pMachineItem;
+        }
+        /* If item is group: */
+        else if (pItem->type() == UIGChooserItemType_Group)
+        {
+            /* If it have at least one machine item: */
+            if (pItem->hasItems(UIGChooserItemType_Machine))
+                /* Iterate over all the machine items recursively: */
+                return searchCurrentItem(pItem->items(UIGChooserItemType_Machine));
+            /* If it have at least one group item: */
+            else if (pItem->hasItems(UIGChooserItemType_Group))
+                /* Iterate over all the group items recursively: */
+                return searchCurrentItem(pItem->items(UIGChooserItemType_Group));
+        }
+    }
+    return 0;
+}
+
+void UIGChooserModel::enumerateCurrentItems(const QList<UIGChooserItem*> &il, QList<UIVMItem*> &ol) const
+{
+    /* Enumerate all the passed items: */
+    foreach (UIGChooserItem *pItem, il)
+    {
+        /* If item is machine, add if missed: */
+        if (pItem->type() == UIGChooserItemType_Machine)
+        {
+            if (UIGChooserItemMachine *pMachineItem = pItem->toMachineItem())
+                if (!contains(ol, pMachineItem))
+                    ol << pMachineItem;
+        }
+        /* If item is group: */
+        else if (pItem->type() == UIGChooserItemType_Group)
+        {
+            /* Enumerate all the machine items recursively: */
+            enumerateCurrentItems(pItem->items(UIGChooserItemType_Machine), ol);
+            /* Enumerate all the group items recursively: */
+            enumerateCurrentItems(pItem->items(UIGChooserItemType_Group), ol);
+        }
+    }
+}
+
+bool UIGChooserModel::contains(const QList<UIVMItem*> &list, UIVMItem *pItem) const
+{
+    /* Check if passed list contains passed item: */
+    foreach (UIVMItem *pIteratedItem, list)
+        if (pIteratedItem->id() == pItem->id())
+            return true;
+    return false;
+}
+
+void UIGChooserModel::loadGroupTree()
+{
+    /* Add all the machines we have into the group-tree: */
+    foreach (const CMachine &machine, vboxGlobal().virtualBox().GetMachines())
+        addMachineIntoTheTree(machine);
+}
+
+void UIGChooserModel::addMachineIntoTheTree(const CMachine &machine, bool fMakeItVisible /* = false */)
+{
+    /* Which groups passed machine attached to? */
+    QVector<QString> groups = machine.GetGroups();
+    foreach (QString strGroup, groups)
+    {
+        /* Remove last '/' if any: */
+        if (strGroup.right(1) == "/")
+            strGroup.truncate(strGroup.size() - 1);
+        /* Create machine item with found group item as parent: */
+        createMachineItem(machine, getGroupItem(strGroup, mainRoot(), fMakeItVisible));
+    }
+    /* Update group definitions: */
+    m_groups[machine.GetId()] = UIStringSet::fromList(groups.toList());
+}
+
+UIGChooserItem* UIGChooserModel::getGroupItem(const QString &strName, UIGChooserItem *pParentItem, bool fAllGroupsOpened)
+{
+    /* Check passed stuff: */
+    if (pParentItem->name() == strName)
+        return pParentItem;
+
+    /* Prepare variables: */
+    QString strFirstSubName = strName.section('/', 0, 0);
+    QString strFirstSuffix = strName.section('/', 1, -1);
+    QString strSecondSubName = strFirstSuffix.section('/', 0, 0);
+    QString strSecondSuffix = strFirstSuffix.section('/', 1, -1);
+
+    /* Passed group name equal to first sub-name: */
+    if (pParentItem->name() == strFirstSubName)
+    {
+        /* Make sure first-suffix is NOT empty: */
+        AssertMsg(!strFirstSuffix.isEmpty(), ("Invalid group name!"));
+        /* Trying to get group item among our children: */
+        foreach (UIGChooserItem *pGroupItem, pParentItem->items(UIGChooserItemType_Group))
+            if (pGroupItem->name() == strSecondSubName)
+                return getGroupItem(strFirstSuffix, pGroupItem, fAllGroupsOpened);
+    }
+
+    /* Found nothing? Creating: */
+    UIGChooserItemGroup *pNewGroupItem =
+            new UIGChooserItemGroup(/* Parent item and desired group name: */
+                                    pParentItem, strSecondSubName,
+                                    /* Should be new group opened when created? */
+                                    fAllGroupsOpened || shouldBeGroupOpened(pParentItem, strSecondSubName),
+                                    /* Which position new group item should be placed in? */
+                                    getDesiredPosition(pParentItem, UIGChooserItemType_Group, strSecondSubName));
+    return strSecondSuffix.isEmpty() ? pNewGroupItem : getGroupItem(strFirstSuffix, pNewGroupItem, fAllGroupsOpened);
+}
+
+bool UIGChooserModel::shouldBeGroupOpened(UIGChooserItem *pParentItem, const QString &strName)
+{
+    /* Prepare extra-data key for the parent-item: */
+    QString strExtraDataKey = UIDefs::GUI_GroupDefinitions + fullName(pParentItem);
+    /* Read group definitions: */
+    QStringList definitions = vboxGlobal().virtualBox().GetExtraDataStringList(strExtraDataKey);
+    /* Return 'false' if no definitions found: */
+    if (definitions.isEmpty())
+        return false;
+
+    /* Prepare required group definition reg-exp: */
+    QString strDefinitionTemplate = QString("g(\\S)*=%1").arg(strName);
+    QRegExp definitionRegExp(strDefinitionTemplate);
+    /* For each the group definition: */
+    for (int i = 0; i < definitions.size(); ++i)
+    {
+        /* Get current definition: */
+        const QString &strDefinition = definitions[i];
+        /* Check if this is required definition: */
+        if (definitionRegExp.indexIn(strDefinition) == 0)
+        {
+            /* Get group descriptor: */
+            QString strDescriptor(definitionRegExp.cap(1));
+            if (strDescriptor.contains('o'))
+                return true;
+        }
+    }
+
+    /* Return 'false' by default: */
+    return false;
+}
+
+int UIGChooserModel::getDesiredPosition(UIGChooserItem *pParentItem, UIGChooserItemType type, const QString &strName)
+{
+    /* End of list (by default)? */
+    int iNewItemDesiredPosition = -1;
+    /* Which position should be new item placed by definitions: */
+    int iNewItemDefinitionPosition = positionFromDefinitions(pParentItem, type, strName);
+    /* If some position wanted: */
+    if (iNewItemDefinitionPosition != -1)
+    {
+        /* Start of list if some definition present: */
+        iNewItemDesiredPosition = 0;
+        /* We have to check all the existing item positions: */
+        QList<UIGChooserItem*> items = pParentItem->items(type);
+        for (int i = items.size() - 1; i >= 0; --i)
+        {
+            /* Get current item: */
+            UIGChooserItem *pItem = items[i];
+            /* Which position should be current item placed by definitions? */
+            int iItemDefinitionPosition = positionFromDefinitions(pParentItem, type, pItem->name());
+            /* If some position wanted: */
+            if (iItemDefinitionPosition != -1)
+            {
+                AssertMsg(iItemDefinitionPosition != iNewItemDefinitionPosition, ("Incorrect definitions!"));
+                if (iItemDefinitionPosition < iNewItemDefinitionPosition)
+                {
+                    iNewItemDesiredPosition = i + 1;
+                    break;
+                }
+            }
+        }
+    }
+    /* Return desired item position: */
+    return iNewItemDesiredPosition;
+}
+
+int UIGChooserModel::positionFromDefinitions(UIGChooserItem *pParentItem, UIGChooserItemType type, const QString &strName)
+{
+    /* Prepare extra-data key for the parent-item: */
+    QString strExtraDataKey = UIDefs::GUI_GroupDefinitions + fullName(pParentItem);
+    /* Read group definitions: */
+    QStringList definitions = vboxGlobal().virtualBox().GetExtraDataStringList(strExtraDataKey);
+    /* Return 'false' if no definitions found: */
+    if (definitions.isEmpty())
+        return -1;
+
+    /* Prepare definition reg-exp: */
+    QString strDefinitionTemplateShort;
+    QString strDefinitionTemplateFull;
+    switch (type)
+    {
+        case UIGChooserItemType_Group:
+            strDefinitionTemplateShort = QString("g(\\S)*=");
+            strDefinitionTemplateFull = QString("g(\\S)*=%1").arg(strName);
+            break;
+        case UIGChooserItemType_Machine:
+            strDefinitionTemplateShort = QString("m=");
+            strDefinitionTemplateFull = QString("m=%1").arg(strName);
+            break;
+        default: return -1;
+    }
+    QRegExp definitionRegExpShort(strDefinitionTemplateShort);
+    QRegExp definitionRegExpFull(strDefinitionTemplateFull);
+
+    /* For each the definition: */
+    int iDefinitionIndex = -1;
+    for (int i = 0; i < definitions.size(); ++i)
+    {
+        /* Get current definition: */
+        QString strDefinition = definitions[i];
+        /* Check if this definition is of required type: */
+        if (definitionRegExpShort.indexIn(strDefinition) == 0)
+        {
+            ++iDefinitionIndex;
+            /* Check if this definition is exactly what we need: */
+            if (definitionRegExpFull.indexIn(strDefinition) == 0)
+                return iDefinitionIndex;
+        }
+    }
+
+    /* Return result: */
+    return -1;
+}
+
+void UIGChooserModel::createMachineItem(const CMachine &machine, UIGChooserItem *pParentItem)
+{
+    /* Create corresponding item: */
+    new UIGChooserItemMachine(/* Parent item and corresponding machine: */
+                              pParentItem, machine,
+                              /* Which position new group item should be placed in? */
+                              getDesiredPosition(pParentItem, UIGChooserItemType_Machine, machine.GetName()));
+}
+
+void UIGChooserModel::saveGroupTree()
+{
+    /* Prepare machine map: */
+    QMap<QString, QStringList> groups;
+    /* Iterate over all the items: */
+    gatherGroupTree(groups, mainRoot());
+    /* Saving groups: */
+    foreach (const QString &strId, groups.keys())
+    {
+        /* Get new group list: */
+        const QStringList &newGroupList = groups.value(strId);
+        /* Get old group set: */
+        AssertMsg(m_groups.contains(strId), ("Invalid group set!"));
+        const UIStringSet &oldGroupSet = m_groups.value(strId);
+        /* Get new group set: */
+        const UIStringSet &newGroupSet = UIStringSet::fromList(newGroupList);
+        /* Is group set changed? */
+        if (oldGroupSet != newGroupSet)
+        {
+            /* Open session to save machine settings: */
+            CSession session = vboxGlobal().openSession(strId);
+            if (session.isNull())
+                return;
+            /* Get machine: */
+            CMachine machine = session.GetMachine();
+            /* Save groups: */
+//            printf(" Saving groups for machine {%s}: {%s}\n",
+//                   machine.GetName().toAscii().constData(),
+//                   newGroupList.join(",").toAscii().constData());
+            machine.SetGroups(newGroupList.toVector());
+            machine.SaveSettings();
+            if (!machine.isOk())
+                msgCenter().cannotSaveMachineSettings(machine);
+            /* Close the session: */
+            session.UnlockMachine();
+        }
+    }
+}
+
+void UIGChooserModel::saveGroupsOrder()
+{
+    /* Clear all the extra-data records related to group-definitions: */
+    const QVector<QString> extraDataKeys = vboxGlobal().virtualBox().GetExtraDataKeys();
+    foreach (const QString &strKey, extraDataKeys)
+        if (strKey.startsWith(UIDefs::GUI_GroupDefinitions))
+            vboxGlobal().virtualBox().SetExtraData(strKey, QString());
+    /* Save order starting from the root-item: */
+    saveGroupsOrder(mainRoot());
+}
+
+void UIGChooserModel::saveGroupsOrder(UIGChooserItem *pParentItem)
+{
+    /* Prepare extra-data key for current group: */
+    QString strExtraDataKey = UIDefs::GUI_GroupDefinitions + fullName(pParentItem);
+    /* Gather item order: */
+    QStringList order;
+    foreach (UIGChooserItem *pItem, pParentItem->items(UIGChooserItemType_Group))
+    {
+        saveGroupsOrder(pItem);
+        QString strGroupDescriptor(pItem->toGroupItem()->opened() ? "go" : "gc");
+        order << QString("%1=%2").arg(strGroupDescriptor, pItem->name());
+    }
+    foreach (UIGChooserItem *pItem, pParentItem->items(UIGChooserItemType_Machine))
+        order << QString("m=%1").arg(pItem->name());
+    vboxGlobal().virtualBox().SetExtraDataStringList(strExtraDataKey, order);
+}
+
+void UIGChooserModel::gatherGroupTree(QMap<QString, QStringList> &groups,
+                                              UIGChooserItem *pParentGroup)
+{
+    /* Iterate over all the machine items: */
+    foreach (UIGChooserItem *pItem, pParentGroup->items(UIGChooserItemType_Machine))
+        if (UIGChooserItemMachine *pMachineItem = pItem->toMachineItem())
+            groups[pMachineItem->id()] << fullName(pParentGroup);
+    /* Iterate over all the group items: */
+    foreach (UIGChooserItem *pItem, pParentGroup->items(UIGChooserItemType_Group))
+        gatherGroupTree(groups, pItem);
+}
+
+QString UIGChooserModel::fullName(UIGChooserItem *pItem)
+{
+    /* Return '/' for root-group: */
+    if (!pItem->parentItem())
+        return QString("/");
+    /* Get full parent name, append with '/' if not yet appended: */
+    QString strParentFullName = fullName(pItem->parentItem());
+    if (!strParentFullName.endsWith("/"))
+        strParentFullName += QString("/");
+    /* Return full item name based on parent prefix: */
+    return strParentFullName + pItem->name();
+}
+
+void UIGChooserModel::updateGroupTree(UIGChooserItem *pGroupItem)
+{
+    /* Cleanup all the group items first: */
+    foreach (UIGChooserItem *pSubGroupItem, pGroupItem->items(UIGChooserItemType_Group))
+        updateGroupTree(pSubGroupItem);
+    if (!pGroupItem->hasItems())
+    {
+        /* Cleanup only non-root items: */
+        if (!pGroupItem->isRoot())
+            delete pGroupItem;
+        /* Unindent root items: */
+        else if (root() != mainRoot())
+            unindentRoot();
+    }
+}
+
+QList<UIGChooserItem*> UIGChooserModel::createNavigationList(UIGChooserItem *pItem)
+{
+    /* Prepare navigation list: */
+    QList<UIGChooserItem*> navigationItems;
+
+    /* Iterate over all the group items: */
+    foreach (UIGChooserItem *pGroupItem, pItem->items(UIGChooserItemType_Group))
+    {
+        navigationItems << pGroupItem;
+        if (pGroupItem->toGroupItem()->opened())
+            navigationItems << createNavigationList(pGroupItem);
+    }
+    /* Iterate over all the machine items: */
+    foreach (UIGChooserItem *pMachineItem, pItem->items(UIGChooserItemType_Machine))
+        navigationItems << pMachineItem;
+
+    /* Return navigation list: */
+    return navigationItems;
+}
+
+void UIGChooserModel::updateMachineItems(const QString &strId, UIGChooserItem *pParent)
+{
+    /* For each group item in passed parent: */
+    foreach (UIGChooserItem *pItem, pParent->items(UIGChooserItemType_Group))
+        updateMachineItems(strId, pItem->toGroupItem());
+    /* For each machine item in passed parent: */
+    foreach (UIGChooserItem *pItem, pParent->items(UIGChooserItemType_Machine))
+        if (UIGChooserItemMachine *pMachineItem = pItem->toMachineItem())
+            if (pMachineItem->id() == strId)
+            {
+                pMachineItem->recache();
+                pMachineItem->update();
+            }
+}
+
+void UIGChooserModel::removeMachineItems(const QString &strId, UIGChooserItem *pParent)
+{
+    /* For each group item in passed parent: */
+    foreach (UIGChooserItem *pItem, pParent->items(UIGChooserItemType_Group))
+        removeMachineItems(strId, pItem->toGroupItem());
+    /* For each machine item in passed parent: */
+    foreach (UIGChooserItem *pItem, pParent->items(UIGChooserItemType_Machine))
+        if (pItem->toMachineItem()->id() == strId)
+            delete pItem;
+}
+
+UIGChooserItem* UIGChooserModel::findGroupItem(const QString &strName, UIGChooserItem *pParent)
+{
+    /* Search among all the group items of passed parent: */
+    foreach (UIGChooserItem *pGroupItem, pParent->items(UIGChooserItemType_Group))
+        if (pGroupItem->name() == strName)
+            return pGroupItem;
+    /* Recursively iterate into each the group item of the passed parent: */
+    foreach (UIGChooserItem *pGroupItem, pParent->items(UIGChooserItemType_Group))
+        if (UIGChooserItem *pSubGroupItem = findGroupItem(strName, pGroupItem))
+            return pSubGroupItem;
+    /* Nothing found? */
+    return 0;
+}
+
+UIGChooserItem* UIGChooserModel::findMachineItem(const QString &strName, UIGChooserItem *pParent)
+{
+    /* Search among all the machine items of passed parent: */
+    foreach (UIGChooserItem *pMachineItem, pParent->items(UIGChooserItemType_Machine))
+        if (pMachineItem->name() == strName)
+            return pMachineItem;
+    /* Recursively iterate into each the group item of the passed parent: */
+    foreach (UIGChooserItem *pGroupItem, pParent->items(UIGChooserItemType_Group))
+        if (UIGChooserItem *pSubMachineItem = findMachineItem(strName, pGroupItem))
+            return pSubMachineItem;
+    /* Nothing found? */
+    return 0;
+}
+
+bool UIGChooserModel::processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent)
+{
+    /* Whats the reason? */
+    switch (pEvent->reason())
+    {
+        case QGraphicsSceneContextMenuEvent::Mouse:
+        {
+            /* First of all we should look for an item under cursor: */
+            if (QGraphicsItem *pItem = itemAt(pEvent->scenePos()))
+            {
+                /* If this item of known type? */
+                switch (pItem->type())
+                {
+                    case UIGChooserItemType_Group:
+                    {
+                        /* Get group item: */
+                        UIGChooserItem *pGroupItem = qgraphicsitem_cast<UIGChooserItemGroup*>(pItem);
+                        /* Is this group item only the one selected? */
+                        if (selectionList().contains(pGroupItem) && selectionList().size() == 1)
+                        {
+                            /* Group context menu in that case: */
+                            popupContextMenu(UIGraphicsSelectorContextMenuType_Group, pEvent->screenPos());
+                            return true;
+                        }
+                        /* Is this root-group item? */
+                        else if (!pGroupItem->parentItem())
+                        {
+                            /* Root context menu in that cases: */
+                            popupContextMenu(UIGraphicsSelectorContextMenuType_Root, pEvent->screenPos());
+                            return true;
+                        }
+                    }
+                    case UIGChooserItemType_Machine:
+                    {
+                        /* Machine context menu for other Group/Machine cases: */
+                        popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
+                        return true;
+                    }
+                    default:
+                        break;
+                }
+            }
+            /* Root context menu for all the other cases: */
+            popupContextMenu(UIGraphicsSelectorContextMenuType_Root, pEvent->screenPos());
+            return true;
+        }
+        case QGraphicsSceneContextMenuEvent::Keyboard:
+        {
+            /* Get first selected item: */
+            if (UIGChooserItem *pItem = selectionList().first())
+            {
+                /* If this item of known type? */
+                switch (pItem->type())
+                {
+                    case UIGChooserItemType_Group:
+                    {
+                        /* Is this group item only the one selected? */
+                        if (selectionList().size() == 1)
+                        {
+                            /* Group context menu in that case: */
+                            popupContextMenu(UIGraphicsSelectorContextMenuType_Group, pEvent->screenPos());
+                            return true;
+                        }
+                    }
+                    case UIGChooserItemType_Machine:
+                    {
+                        /* Machine context menu for other Group/Machine cases: */
+                        popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
+                        return true;
+                    }
+                    default:
+                        break;
+                }
+            }
+            /* Root context menu for all the other cases: */
+            popupContextMenu(UIGraphicsSelectorContextMenuType_Root, pEvent->screenPos());
+            return true;
+        }
+        default:
+            break;
+    }
+    /* Pass others context menu events: */
+    return false;
+}
+
+void UIGChooserModel::popupContextMenu(UIGraphicsSelectorContextMenuType type, QPoint point)
+{
+    /* Which type of context-menu requested? */
+    switch (type)
+    {
+        /* For empty group? */
+        case UIGraphicsSelectorContextMenuType_Root:
+        {
+            m_pContextMenuRoot->exec(point);
+            break;
+        }
+        /* For group? */
+        case UIGraphicsSelectorContextMenuType_Group:
+        {
+            m_pContextMenuGroup->exec(point);
+            break;
+        }
+        /* For machine(s)? */
+        case UIGraphicsSelectorContextMenuType_Machine:
+        {
+            m_pContextMenuMachine->exec(point);
+            break;
+        }
+    }
+    /* Clear status-bar: */
+    emit sigClearStatusMessage();
+}
+
+void UIGChooserModel::slideRoot(bool fForward)
+{
+    /* Animation group: */
+    QParallelAnimationGroup *pAnimation = new QParallelAnimationGroup(this);
+    connect(pAnimation, SIGNAL(finished()), this, SLOT(sltSlidingComplete()), Qt::QueuedConnection);
+
+    /* Left root animation: */
+    {
+        QPropertyAnimation *pLeftAnimation = new QPropertyAnimation(m_pLeftRoot, "geometry", this);
+        connect(pLeftAnimation, SIGNAL(valueChanged(const QVariant&)), this, SLOT(sltLeftRootSlidingProgress()));
+        QRectF startGeo = m_pLeftRoot->geometry();
+        QRectF endGeo = fForward ? startGeo.translated(- startGeo.width(), 0) :
+                                   startGeo.translated(startGeo.width(), 0);
+        pLeftAnimation->setEasingCurve(QEasingCurve::InCubic);
+        pLeftAnimation->setDuration(500);
+        pLeftAnimation->setStartValue(startGeo);
+        pLeftAnimation->setEndValue(endGeo);
+        pAnimation->addAnimation(pLeftAnimation);
+    }
+
+    /* Right root animation: */
+    {
+        QPropertyAnimation *pRightAnimation = new QPropertyAnimation(m_pRightRoot, "geometry", this);
+        connect(pRightAnimation, SIGNAL(valueChanged(const QVariant&)), this, SLOT(sltRightRootSlidingProgress()));
+        QRectF startGeo = m_pRightRoot->geometry();
+        QRectF endGeo = fForward ? startGeo.translated(- startGeo.width(), 0) :
+                                   startGeo.translated(startGeo.width(), 0);
+        pRightAnimation->setEasingCurve(QEasingCurve::InCubic);
+        pRightAnimation->setDuration(500);
+        pRightAnimation->setStartValue(startGeo);
+        pRightAnimation->setEndValue(endGeo);
+        pAnimation->addAnimation(pRightAnimation);
+    }
+
+    /* Start animation: */
+    pAnimation->start();
+}
+
+QList<UIGChooserItem*> UIGChooserModel::gatherMachineItems(const QList<UIGChooserItem*> &selectedItems) const
+{
+    QList<UIGChooserItem*> machineItems;
+    foreach (UIGChooserItem *pItem, selectedItems)
+    {
+        if (pItem->type() == UIGChooserItemType_Machine)
+            machineItems << pItem;
+        if (pItem->type() == UIGChooserItemType_Group)
+            machineItems << gatherMachineItems(pItem->items());
+    }
+    return machineItems;
+}
+
+void UIGChooserModel::removeMachineItems(const QStringList &names, QList<UIGChooserItem*> &selectedItems)
+{
+    /* Show machine items remove dialog: */
+    int rc = msgCenter().confirmMachineItemRemoval(names);
+    if (rc == QIMessageBox::Cancel)
+        return;
+
+    /* Remove all the required items: */
+    foreach (UIGChooserItem *pItem, selectedItems)
+        if (names.contains(pItem->name()))
+            delete pItem;
+
+    /* And update model: */
+    updateGroupTree();
+    updateNavigation();
+    updateLayout();
+    if (mainRoot()->hasItems())
+        setCurrentItem(0);
+    else
+        unsetCurrentItem();
+}
+
+void UIGChooserModel::unregisterMachines(const QStringList &names)
+{
+    /* Populate machine list: */
+    QList<CMachine> machines;
+    CVirtualBox vbox = vboxGlobal().virtualBox();
+    foreach (const QString &strName, names)
+    {
+        CMachine machine = vbox.FindMachine(strName);
+        if (!machine.isNull())
+            machines << machine;
+    }
+
+    /* Show machine remove dialog: */
+    int rc = msgCenter().confirmMachineDeletion(machines);
+    if (rc != QIMessageBox::Cancel)
+    {
+        /* For every selected item: */
+        foreach (CMachine machine, machines)
+        {
+            if (rc == QIMessageBox::Yes)
+            {
+                /* Unregister and cleanup machine's data & hard-disks: */
+                CMediumVector mediums = machine.Unregister(KCleanupMode_DetachAllReturnHardDisksOnly);
+                if (machine.isOk())
+                {
+                    /* Delete machine hard-disks: */
+                    CProgress progress = machine.Delete(mediums);
+                    if (machine.isOk())
+                    {
+                        msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_delete_90px.png", 0, true);
+                        if (progress.GetResultCode() != 0)
+                            msgCenter().cannotDeleteMachine(machine, progress);
+                    }
+                }
+                if (!machine.isOk())
+                    msgCenter().cannotDeleteMachine(machine);
+            }
+            else
+            {
+                /* Just unregister machine: */
+                machine.Unregister(KCleanupMode_DetachAllReturnNone);
+                if (!machine.isOk())
+                    msgCenter().cannotDeleteMachine(machine);
+            }
+        }
+    }
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserModel.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserModel.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserModel.h	(revision 42529)
@@ -0,0 +1,275 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserModel class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserModel_h__
+#define __UIGChooserModel_h__
+
+/* Qt includes: */
+#include <QObject>
+#include <QPointer>
+#include <QTransform>
+#include <QMap>
+#include <QSet>
+
+/* GUI includes: */
+#include "UIGChooserItem.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+
+/* Forward declaration: */
+class QGraphicsScene;
+class QGraphicsItem;
+class QDrag;
+class QMenu;
+class QAction;
+class QGraphicsSceneContextMenuEvent;
+class CMachine;
+class UIVMItem;
+class UIGChooserHandlerMouse;
+class UIGChooserHandlerKeyboard;
+
+/* Type defs: */
+typedef QSet<QString> UIStringSet;
+
+/* Context-menu type: */
+enum UIGraphicsSelectorContextMenuType
+{
+    UIGraphicsSelectorContextMenuType_Root,
+    UIGraphicsSelectorContextMenuType_Group,
+    UIGraphicsSelectorContextMenuType_Machine
+};
+
+/* Graphics selector model: */
+class UIGChooserModel : public QObject
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifier: Root-item resize stuff: */
+    void sigRootItemResized(const QSizeF &size, int iMinimumWidth);
+
+    /* Notifier: Selection change: */
+    void sigSelectionChanged();
+
+    /* Notifiers Status-bar stuff: */
+    void sigClearStatusMessage();
+    void sigShowStatusMessage(const QString &strStatusMessage);
+
+public:
+
+    /* Constructor/destructor: */
+    UIGChooserModel(QObject *pParent);
+    ~UIGChooserModel();
+
+    /* API: Load/save stuff: */
+    void load();
+    void save();
+
+    /* API: Scene getter: */
+    QGraphicsScene* scene() const;
+
+    /* API: Root stuff: */
+    UIGChooserItem* mainRoot() const;
+    UIGChooserItem* root() const;
+    void indentRoot(UIGChooserItem *pNewRootItem);
+    void unindentRoot();
+
+    /* API: Current item stuff: */
+    void setCurrentItem(int iItemIndex);
+    void setCurrentItem(UIGChooserItem *pItem);
+    void unsetCurrentItem();
+    UIVMItem* currentItem() const;
+    QList<UIVMItem*> currentItems() const;
+    void setCurrentItemDefinition(const QString &strDefinition);
+    QString currentItemDefinition() const;
+    bool singleGroupSelected() const;
+
+    /* API: Focus item stuff: */
+    void setFocusItem(UIGChooserItem *pItem, bool fWithSelection = false);
+    UIGChooserItem* focusItem() const;
+
+    /* API: Positioning item stuff: */
+    QGraphicsItem* itemAt(const QPointF &position, const QTransform &deviceTransform = QTransform()) const;
+
+    /* API: Update stuff: */
+    void updateGroupTree();
+
+    /* API: Navigation stuff: */
+    const QList<UIGChooserItem*>& navigationList() const;
+    void removeFromNavigationList(UIGChooserItem *pItem);
+    void clearNavigationList();
+    void updateNavigation();
+
+    /* API: Selection stuff: */
+    const QList<UIGChooserItem*>& selectionList() const;
+    void addToSelectionList(UIGChooserItem *pItem);
+    void removeFromSelectionList(UIGChooserItem *pItem);
+    void clearSelectionList();
+    void notifySelectionChanged();
+
+    /* API: Layout stuff: */
+    void updateLayout();
+
+    /* API: Drag and drop stuff: */
+    void setCurrentDragObject(QDrag *pDragObject);
+
+    /* API: Activate stuff: */
+    void activate();
+
+    /* API: Group name stuff: */
+    QString uniqueGroupName(UIGChooserItem *pRoot);
+
+private slots:
+
+    /* Handlers: Global events: */
+    void sltMachineStateChanged(QString strId, KMachineState state);
+    void sltMachineDataChanged(QString strId);
+    void sltMachineRegistered(QString strId, bool fRegistered);
+    void sltSessionStateChanged(QString strId, KSessionState state);
+    void sltSnapshotChanged(QString strId, QString strSnapshotId);
+
+    /* Handler: View-resize: */
+    void sltHandleViewResized();
+
+    /* Handler: Drag object destruction: */
+    void sltCurrentDragObjectDestroyed();
+
+    /* Handlers: Remove currently selected items: */
+    void sltRemoveCurrentlySelectedGroup();
+    void sltRemoveCurrentlySelectedMachine();
+
+    /* Handler: Group name editing stuff: */
+    void sltStartEditingSelectedGroup();
+
+    /* Handler: Context menu hovering: */
+    void sltActionHovered(QAction *pAction);
+
+    /* Handler: Focus item destruction: */
+    void sltFocusItemDestroyed();
+
+    /* Handlers: Root-sliding stuff: */
+    void sltLeftRootSlidingProgress();
+    void sltRightRootSlidingProgress();
+    void sltSlidingComplete();
+
+private:
+
+    /* Data enumerator: */
+    enum SelectorModelData
+    {
+        /* Layout hints: */
+        SelectorModelData_Margin
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Helpers: Prepare stuff: */
+    void prepareScene();
+    void prepareRoot();
+    void prepareContextMenu();
+    void prepareHandlers();
+    void prepareGroupTree();
+
+    /* Helpers: Cleanup stuff: */
+    void cleanupGroupTree();
+    void cleanupHandlers();
+    void cleanupContextMenu();
+    void cleanupRoot();
+    void cleanupScene();
+
+    /* Event handler: */
+    bool eventFilter(QObject *pWatched, QEvent *pEvent);
+
+    /* Helpers: Focus item stuff: */
+    void clearRealFocus();
+
+    /* Helpers: Current item stuff: */
+    UIVMItem* searchCurrentItem(const QList<UIGChooserItem*> &list) const;
+    void enumerateCurrentItems(const QList<UIGChooserItem*> &il, QList<UIVMItem*> &ol) const;
+    bool contains(const QList<UIVMItem*> &list, UIVMItem *pItem) const;
+
+    /* Helpers: Loading: */
+    void loadGroupTree();
+    void addMachineIntoTheTree(const CMachine &machine, bool fMakeItVisible = false);
+    UIGChooserItem* getGroupItem(const QString &strName, UIGChooserItem *pParentItem, bool fAllGroupsOpened);
+    bool shouldBeGroupOpened(UIGChooserItem *pParentItem, const QString &strName);
+    int getDesiredPosition(UIGChooserItem *pParentItem, UIGChooserItemType type, const QString &strName);
+    int positionFromDefinitions(UIGChooserItem *pParentItem, UIGChooserItemType type, const QString &strName);
+    void createMachineItem(const CMachine &machine, UIGChooserItem *pParentItem);
+
+    /* Helpers: Saving: */
+    void saveGroupTree();
+    void saveGroupsOrder();
+    void saveGroupsOrder(UIGChooserItem *pParentItem);
+    void gatherGroupTree(QMap<QString, QStringList> &groups, UIGChooserItem *pParentGroup);
+    QString fullName(UIGChooserItem *pItem);
+
+    /* Helpers: Update stuff: */
+    void updateGroupTree(UIGChooserItem *pGroupItem);
+
+    /* Helpers: Navigation stuff: */
+    QList<UIGChooserItem*> createNavigationList(UIGChooserItem *pItem);
+
+    /* Helpers: Search stuff: */
+    UIGChooserItem* findGroupItem(const QString &strName, UIGChooserItem *pParent);
+    UIGChooserItem* findMachineItem(const QString &strName, UIGChooserItem *pParent);
+
+    /* Helpers: Global event stuff: */
+    void updateMachineItems(const QString &strId, UIGChooserItem *pParent);
+    void removeMachineItems(const QString &strId, UIGChooserItem *pParent);
+
+    /* Helpers: Context menu stuff: */
+    bool processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent);
+    void popupContextMenu(UIGraphicsSelectorContextMenuType type, QPoint point);
+
+    /* Helper: Root item stuff: */
+    void slideRoot(bool fForward);
+
+    /* Helper: Search stuff: */
+    QList<UIGChooserItem*> gatherMachineItems(const QList<UIGChooserItem*> &selectedItems) const;
+
+    /* Helpers: Remove stuff: */
+    void removeMachineItems(const QStringList &names, QList<UIGChooserItem*> &selectedItems);
+    void unregisterMachines(const QStringList &names);
+
+    /* Variables: */
+    QGraphicsScene *m_pScene;
+
+    QList<UIGChooserItem*> m_rootStack;
+    bool m_fSliding;
+    UIGChooserItem *m_pLeftRoot;
+    UIGChooserItem *m_pRightRoot;
+    QPointer<UIGChooserItem> m_pAfterSlidingFocus;
+
+    QMap<QString, UIStringSet> m_groups;
+    QList<UIGChooserItem*> m_navigationList;
+    QList<UIGChooserItem*> m_selectionList;
+    UIGChooserHandlerMouse *m_pMouseHandler;
+    UIGChooserHandlerKeyboard *m_pKeyboardHandler;
+    QPointer<QDrag> m_pCurrentDragObject;
+    QPointer<UIGChooserItem> m_pFocusItem;
+    QMenu *m_pContextMenuRoot;
+    QMenu *m_pContextMenuGroup;
+    QMenu *m_pContextMenuMachine;
+};
+
+#endif /* __UIGChooserModel_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserView.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserView.cpp	(revision 42529)
@@ -0,0 +1,67 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserView class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QScrollBar>
+
+/* GUI includes: */
+#include "UIGChooserView.h"
+
+UIGChooserView::UIGChooserView(QWidget *pParent)
+    : QGraphicsView(pParent)
+{
+    /* Fix palette: */
+    QPalette pal = palette();
+    pal.setColor(QPalette::Base, pal.color(QPalette::Window));
+    setPalette(pal);
+
+    /* Scrollbars policy: */
+    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+    /* Update scene-rect: */
+    updateSceneRect();
+}
+
+void UIGChooserView::sltHandleRootItemResized(const QSizeF &size, int iMinimumWidth)
+{
+    /* Update scene-rect: */
+    updateSceneRect(size);
+
+    /* Set minimum width: */
+    setMinimumWidth(2 * frameWidth() + iMinimumWidth +
+                    verticalScrollBar()->sizeHint().width());
+}
+
+void UIGChooserView::resizeEvent(QResizeEvent*)
+{
+    /* Update scene-rect: */
+    updateSceneRect();
+    /* Notify listeners: */
+    emit sigResized();
+}
+
+void UIGChooserView::updateSceneRect(const QSizeF &sizeHint /* = QSizeF() */)
+{
+    QPointF topLeft = QPointF(0, 0);
+    QSizeF rectSize = viewport()->size();
+    if (!sizeHint.isNull())
+        rectSize = rectSize.expandedTo(sizeHint);
+    setSceneRect(QRectF(topLeft, rectSize));
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserView.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserView.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserView.h	(revision 42529)
@@ -0,0 +1,55 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGChooserView class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGChooserView_h__
+#define __UIGChooserView_h__
+
+/* Qt includes: */
+#include <QGraphicsView>
+
+/* Graphics selector view: */
+class UIGChooserView : public QGraphicsView
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifiers: Resize stuff: */
+    void sigResized();
+
+public:
+
+    /* Constructor: */
+    UIGChooserView(QWidget *pParent);
+
+private slots:
+
+    /* Handler: Root-item resize stuff: */
+    void sltHandleRootItemResized(const QSizeF &size, int iMinimumWidth);
+
+private:
+
+    /* Event handler: Resize-event: */
+    void resizeEvent(QResizeEvent *pEvent);
+
+    /* Helpers: */
+    void updateSceneRect(const QSizeF &sizeHint = QSizeF());
+};
+
+#endif /* __UIGChooserView_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItem.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItem.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItem.cpp	(revision 42529)
@@ -0,0 +1,426 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGSelectorItem class definition
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QApplication>
+#include <QStyle>
+#include <QPainter>
+#include <QGraphicsScene>
+#include <QStyleOptionFocusRect>
+#include <QGraphicsSceneMouseEvent>
+#include <QStateMachine>
+#include <QPropertyAnimation>
+#include <QSignalTransition>
+
+/* GUI includes: */
+#include "UIGSelectorItem.h"
+#include "UIGraphicsSelectorModel.h"
+#include "UIGSelectorItemGroup.h"
+#include "UIGSelectorItemMachine.h"
+
+UIGSelectorItem::UIGSelectorItem(UIGSelectorItem *pParent)
+    : QIGraphicsWidget(pParent)
+    , m_pParent(pParent)
+    , m_dragTokenPlace(DragToken_Off)
+    , m_pHighlightMachine(0)
+    , m_pForwardAnimation(0)
+    , m_pBackwardAnimation(0)
+    , m_iAnimationDuration(300)
+    , m_iDefaultDarkness(115)
+    , m_iHighlightDarkness(90)
+    , m_iGradient(m_iDefaultDarkness)
+{
+    /* Basic item setup: */
+    setOwnedByLayout(false);
+    setAcceptDrops(true);
+    setFocusPolicy(Qt::NoFocus);
+    setFlag(QGraphicsItem::ItemIsSelectable, false);
+
+    /* Non-root item? */
+    if (parentItem())
+    {
+        /* Non-root item setup: */
+        setAcceptHoverEvents(true);
+
+        /* Create state machine: */
+        m_pHighlightMachine = new QStateMachine(this);
+        /* Create 'default' state: */
+        QState *pStateDefault = new QState(m_pHighlightMachine);
+        /* Create 'highlighted' state: */
+        QState *pStateHighlighted = new QState(m_pHighlightMachine);
+
+        /* Forward animation: */
+        m_pForwardAnimation = new QPropertyAnimation(this, "gradient", this);
+        m_pForwardAnimation->setDuration(m_iAnimationDuration);
+        m_pForwardAnimation->setStartValue(m_iDefaultDarkness);
+        m_pForwardAnimation->setEndValue(m_iHighlightDarkness);
+
+        /* Backward animation: */
+        m_pBackwardAnimation = new QPropertyAnimation(this, "gradient", this);
+        m_pBackwardAnimation->setDuration(m_iAnimationDuration);
+        m_pBackwardAnimation->setStartValue(m_iHighlightDarkness);
+        m_pBackwardAnimation->setEndValue(m_iDefaultDarkness);
+
+        /* Add state transitions: */
+        QSignalTransition *pDefaultToHighlighted = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHighlighted);
+        pDefaultToHighlighted->addAnimation(m_pForwardAnimation);
+        QSignalTransition *pHighlightedToDefault = pStateHighlighted->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault);
+        pHighlightedToDefault->addAnimation(m_pBackwardAnimation);
+
+        /* Setup connections: */
+        connect(this, SIGNAL(sigHoverEnter()), this, SLOT(sltUnhoverParent()));
+
+        /* Initial state is 'default': */
+        m_pHighlightMachine->setInitialState(pStateDefault);
+        /* Start state-machine: */
+        m_pHighlightMachine->start();
+    }
+}
+
+UIGSelectorItem::~UIGSelectorItem()
+{
+    /* If that item is focused: */
+    if (model()->focusItem() == this)
+    {
+        /* Unset the focus/selection: */
+        model()->setFocusItem(0, true);
+    }
+    /* If that item is NOT focused, but selected: */
+    else if (model()->selectionList().contains(this))
+    {
+        /* Remove item from the selection list: */
+        model()->removeFromSelectionList(this);
+    }
+    /* Remove item from the navigation list: */
+    model()->removeFromNavigationList(this);
+}
+
+UIGSelectorItemGroup* UIGSelectorItem::toGroupItem()
+{
+    UIGSelectorItemGroup *pItem = qgraphicsitem_cast<UIGSelectorItemGroup*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGSelectorItemGroup!"));
+    return pItem;
+}
+
+UIGSelectorItemMachine* UIGSelectorItem::toMachineItem()
+{
+    UIGSelectorItemMachine *pItem = qgraphicsitem_cast<UIGSelectorItemMachine*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGSelectorItemMachine!"));
+    return pItem;
+}
+
+UIGraphicsSelectorModel* UIGSelectorItem::model() const
+{
+    UIGraphicsSelectorModel *pModel = qobject_cast<UIGraphicsSelectorModel*>(QIGraphicsWidget::scene()->parent());
+    AssertMsg(pModel, ("Incorrect graphics scene parent set!"));
+    return pModel;
+}
+
+UIGSelectorItem* UIGSelectorItem::parentItem() const
+{
+    return m_pParent;
+}
+
+void UIGSelectorItem::makeSureItsVisible()
+{
+    /* If item is not visible: */
+    if (!isVisible())
+    {
+        /* Get parrent item, assert if can't: */
+        if (UIGSelectorItemGroup *pParentItem = parentItem()->toGroupItem())
+        {
+            /* We should make parent visible: */
+            pParentItem->makeSureItsVisible();
+            /* And make sure its opened: */
+            if (pParentItem->closed())
+                pParentItem->open();
+        }
+    }
+}
+
+void UIGSelectorItem::releaseHover()
+{
+    emit sigHoverLeave();
+}
+
+void UIGSelectorItem::setDragTokenPlace(DragToken where)
+{
+    /* Something changed? */
+    if (m_dragTokenPlace != where)
+    {
+        m_dragTokenPlace = where;
+        update();
+    }
+}
+
+DragToken UIGSelectorItem::dragTokenPlace() const
+{
+    return m_dragTokenPlace;
+}
+
+void UIGSelectorItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
+{
+    emit sigHoverEnter();
+}
+
+void UIGSelectorItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
+{
+    emit sigHoverLeave();
+}
+
+void UIGSelectorItem::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
+{
+    /* By default, non-moveable and non-selectable items
+     * can't grab mouse-press events which is required
+     * to grab further mouse-move events which we wants... */
+    if (parentItem())
+        pEvent->accept();
+    else
+        pEvent->ignore();
+}
+
+void UIGSelectorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *pEvent)
+{
+    /* Make sure item is really dragged: */
+    if (QLineF(pEvent->screenPos(),
+               pEvent->buttonDownScreenPos(Qt::LeftButton)).length() <
+        QApplication::startDragDistance())
+        return;
+
+    /* Initialize dragging: */
+    QDrag *pDrag = new QDrag(pEvent->widget());
+    model()->setCurrentDragObject(pDrag);
+    pDrag->setPixmap(toPixmap());
+    pDrag->setMimeData(createMimeData());
+    pDrag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
+}
+
+void UIGSelectorItem::dragMoveEvent(QGraphicsSceneDragDropEvent *pEvent)
+{
+    /* Make sure we are non-root: */
+    if (parentItem())
+    {
+        /* Allow drag tokens only for the same item type as current: */
+        bool fAllowDragToken = false;
+        if ((type() == UIGSelectorItemType_Group &&
+             pEvent->mimeData()->hasFormat(UIGSelectorItemGroup::className())) ||
+            (type() == UIGSelectorItemType_Machine &&
+             pEvent->mimeData()->hasFormat(UIGSelectorItemMachine::className())))
+            fAllowDragToken = true;
+        /* Do we need a drag-token? */
+        if (fAllowDragToken)
+        {
+            QPoint p = pEvent->pos().toPoint();
+            if (p.y() < 10)
+                setDragTokenPlace(DragToken_Up);
+            else if (p.y() > minimumSizeHint().toSize().height() - 10)
+                setDragTokenPlace(DragToken_Down);
+            else
+                setDragTokenPlace(DragToken_Off);
+        }
+    }
+    /* Check if drop is allowed: */
+    pEvent->setAccepted(isDropAllowed(pEvent, dragTokenPlace()));
+}
+
+void UIGSelectorItem::dragLeaveEvent(QGraphicsSceneDragDropEvent*)
+{
+    resetDragToken();
+}
+
+void UIGSelectorItem::dropEvent(QGraphicsSceneDragDropEvent *pEvent)
+{
+    /* Do we have token active? */
+    switch (dragTokenPlace())
+    {
+        case DragToken_Off:
+        {
+            /* Its our drop, processing: */
+            processDrop(pEvent);
+            break;
+        }
+        default:
+        {
+            /* Its parent drop, passing: */
+            parentItem()->processDrop(pEvent, this, dragTokenPlace());
+            break;
+        }
+    }
+}
+
+/* static */
+void UIGSelectorItem::configurePainterShape(QPainter *pPainter,
+                                            const QStyleOptionGraphicsItem *pOption,
+                                            int iRadius)
+{
+    /* Rounded corners? */
+    if (iRadius)
+    {
+        /* Setup clipping: */
+        QPainterPath roundedPath;
+        roundedPath.addRoundedRect(pOption->rect, iRadius, iRadius);
+        pPainter->setRenderHint(QPainter::Antialiasing);
+        pPainter->setClipPath(roundedPath);
+    }
+}
+
+/* static */
+void UIGSelectorItem::paintBackground(QPainter *pPainter, const QRect &rect,
+                                      bool fHasParent, bool fIsSelected,
+                                      int iGradientDarkness, DragToken dragTokenWhere,
+                                      int iRadius)
+{
+    /* Save painter: */
+    pPainter->save();
+
+    /* Fill rectangle with brush/color: */
+    QPalette pal = QApplication::palette();
+    QBrush brush = pal.brush(QPalette::Active, QPalette::Base);
+    pPainter->fillRect(rect, brush);
+    pPainter->fillRect(rect, Qt::white);
+
+    /* Prepare color: */
+    QColor base = pal.color(QPalette::Active, fIsSelected ? QPalette::Highlight : QPalette::Window);
+
+    /* Non-root item: */
+    if (fHasParent)
+    {
+        /* Make even less rectangle: */
+        QRect backGroundRect = rect;
+        backGroundRect.setTopLeft(backGroundRect.topLeft() + QPoint(2, 2));
+        backGroundRect.setBottomRight(backGroundRect.bottomRight() - QPoint(2, 2));
+        /* Add even more clipping: */
+        QPainterPath roundedPath;
+        roundedPath.addRoundedRect(backGroundRect, iRadius, iRadius);
+        pPainter->setClipPath(roundedPath);
+
+        /* Calculate top rectangle: */
+        QRect tRect = backGroundRect;
+        tRect.setBottom(tRect.top() + tRect.height() / 3);
+        /* Calculate bottom rectangle: */
+        QRect bRect = backGroundRect;
+        bRect.setTop(bRect.bottom() - bRect.height() / 3);
+        /* Calculate middle rectangle: */
+        QRect midRect = QRect(tRect.bottomLeft(), bRect.topRight());
+
+        /* Prepare top gradient: */
+        QLinearGradient tGradient(tRect.bottomLeft(), tRect.topLeft());
+        tGradient.setColorAt(0, base.darker(104));
+        tGradient.setColorAt(1, base.darker(iGradientDarkness));
+        /* Prepare bottom gradient: */
+        QLinearGradient bGradient(bRect.topLeft(), bRect.bottomLeft());
+        bGradient.setColorAt(0, base.darker(104));
+        bGradient.setColorAt(1, base.darker(iGradientDarkness));
+
+        /* Paint all the stuff: */
+        pPainter->fillRect(midRect, base.darker(104));
+        pPainter->fillRect(tRect, tGradient);
+        pPainter->fillRect(bRect, bGradient);
+
+        /* Paint drag token UP? */
+        if (dragTokenWhere != DragToken_Off)
+        {
+            QLinearGradient dragTokenGradient;
+            QRect dragTokenRect = backGroundRect;
+            if (dragTokenWhere == DragToken_Up)
+            {
+                dragTokenRect.setHeight(5);
+                dragTokenGradient.setStart(dragTokenRect.bottomLeft());
+                dragTokenGradient.setFinalStop(dragTokenRect.topLeft());
+            }
+            else if (dragTokenWhere == DragToken_Down)
+            {
+                dragTokenRect.setTopLeft(dragTokenRect.bottomLeft() - QPoint(0, 5));
+                dragTokenGradient.setStart(dragTokenRect.topLeft());
+                dragTokenGradient.setFinalStop(dragTokenRect.bottomLeft());
+            }
+            dragTokenGradient.setColorAt(0, base.darker(110));
+            dragTokenGradient.setColorAt(1, base.darker(150));
+            pPainter->fillRect(dragTokenRect, dragTokenGradient);
+        }
+    }
+    /* Root item: */
+    else
+    {
+        /* Simple and clear: */
+        pPainter->fillRect(rect, base.darker(100));
+    }
+
+    /* Restore painter: */
+    pPainter->restore();
+}
+
+/* static */
+void UIGSelectorItem::paintFrameRect(QPainter *pPainter, const QRect &rect, bool fIsSelected, int iRadius)
+{
+    pPainter->save();
+    QPalette pal = QApplication::palette();
+    QColor base = pal.color(QPalette::Active, fIsSelected ? QPalette::Highlight : QPalette::Window);
+    pPainter->setPen(base.darker(160));
+    if (iRadius)
+        pPainter->drawRoundedRect(rect, iRadius, iRadius);
+    else
+        pPainter->drawRect(rect);
+    pPainter->restore();
+}
+
+/* static */
+void UIGSelectorItem::paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap)
+{
+    pPainter->drawPixmap(rect, pixmap);
+}
+
+/* static */
+void UIGSelectorItem::paintText(QPainter *pPainter, const QRect &rect, const QFont &font, const QString &strText)
+{
+    pPainter->setFont(font);
+    pPainter->drawText(rect, strText);
+}
+
+/* static */
+void UIGSelectorItem::paintFocus(QPainter *pPainter, const QRect &rect)
+{
+    QStyleOptionFocusRect option;
+    option.rect = rect;
+    QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, pPainter);
+}
+
+void UIGSelectorItem::sltUnhoverParent()
+{
+    AssertMsg(parentItem(), ("There should be a parent!"));
+    parentItem()->releaseHover();
+}
+
+UIGSelectorItemMimeData::UIGSelectorItemMimeData(UIGSelectorItem *pItem)
+    : m_pItem(pItem)
+{
+}
+
+bool UIGSelectorItemMimeData::hasFormat(const QString &strMimeType) const
+{
+    if (strMimeType == QString(m_pItem->metaObject()->className()))
+        return true;
+    return false;
+}
+
+UIGSelectorItem* UIGSelectorItemMimeData::item() const
+{
+    return m_pItem;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItem.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItem.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItem.h	(revision 42529)
@@ -0,0 +1,189 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGSelectorItem class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGSelectorItem_h__
+#define __UIGSelectorItem_h__
+
+/* Qt includes: */
+#include <QMimeData>
+
+/* GUI includes: */
+#include "QIGraphicsWidget.h"
+
+/* Forward declaration: */
+class UIGraphicsSelectorModel;
+class UIGSelectorItemGroup;
+class UIGSelectorItemMachine;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneDragDropEvent;
+class QStateMachine;
+class QPropertyAnimation;
+
+/* UIGSelectorItem types: */
+enum UIGSelectorItemType
+{
+    UIGSelectorItemType_Any     = QGraphicsItem::UserType,
+    UIGSelectorItemType_Group   = QGraphicsItem::UserType + 1,
+    UIGSelectorItemType_Machine = QGraphicsItem::UserType + 2
+};
+
+/* Drag token placement: */
+enum DragToken { DragToken_Off, DragToken_Up, DragToken_Down };
+
+/* Graphics item interface
+ * for graphics selector model/view architecture: */
+class UIGSelectorItem : public QIGraphicsWidget
+{
+    Q_OBJECT;
+    Q_PROPERTY(int gradient READ gradient WRITE setGradient);
+
+signals:
+
+    /* Hover signals: */
+    void sigHoverEnter();
+    void sigHoverLeave();
+
+public:
+
+    /* Constructor/destructor: */
+    UIGSelectorItem(UIGSelectorItem *pParent);
+    ~UIGSelectorItem();
+
+    /* API: Cast stuff: */
+    UIGSelectorItemGroup* toGroupItem();
+    UIGSelectorItemMachine* toMachineItem();
+
+    /* API: Model stuff: */
+    UIGraphicsSelectorModel* model() const;
+
+    /* API: Parent stuff: */
+    UIGSelectorItem* parentItem() const;
+
+    /* API: Basic stuff: */
+    virtual void startEditing() = 0;
+    virtual QString name() const = 0;
+
+    /* API: Children stuff: */
+    virtual void addItem(UIGSelectorItem *pItem, int iPosition) = 0;
+    virtual void removeItem(UIGSelectorItem *pItem) = 0;
+    virtual void moveItemTo(UIGSelectorItem *pItem, int iPosition) = 0;
+    virtual QList<UIGSelectorItem*> items(UIGSelectorItemType type = UIGSelectorItemType_Any) const = 0;
+    virtual bool hasItems(UIGSelectorItemType type = UIGSelectorItemType_Any) const = 0;
+    virtual void clearItems(UIGSelectorItemType type = UIGSelectorItemType_Any) = 0;
+
+    /* API: Layout stuff: */
+    virtual void updateSizeHint() = 0;
+    virtual void updateLayout() = 0;
+    virtual int minimumWidthHint() const = 0;
+    virtual int minimumHeightHint() const = 0;
+
+    /* API: Navigation stuff: */
+    virtual void makeSureItsVisible();
+
+    /* API: Hover stuff: */
+    void releaseHover();
+
+    /* API: Drag and drop stuff: */
+    virtual QPixmap toPixmap() = 0;
+    virtual bool isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where = DragToken_Off) const = 0;
+    virtual void processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGSelectorItem *pFromWho = 0, DragToken where = DragToken_Off) = 0;
+    virtual void resetDragToken() = 0;
+    void setDragTokenPlace(DragToken where);
+    DragToken dragTokenPlace() const;
+
+protected:
+
+    /* Hover-enter event: */
+    void hoverEnterEvent(QGraphicsSceneHoverEvent *pEvent);
+    /* Hover-leave event: */
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent);
+    /* Mouse-press event: */
+    void mousePressEvent(QGraphicsSceneMouseEvent *pEvent);
+    /* Mouse-move event: */
+    void mouseMoveEvent(QGraphicsSceneMouseEvent *pEvent);
+    /* Drag-move event: */
+    void dragMoveEvent(QGraphicsSceneDragDropEvent *pEvent);
+    /* Drag-leave event: */
+    void dragLeaveEvent(QGraphicsSceneDragDropEvent *pEvent);
+    /* Drop event: */
+    void dropEvent(QGraphicsSceneDragDropEvent *pEvent);
+
+    /* Static paint stuff: */
+    static void configurePainterShape(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, int iRadius);
+    static void paintBackground(QPainter *pPainter, const QRect &rect,
+                                bool fHasParent, bool fIsSelected,
+                                int iGradientDarkness, DragToken dragTokenWhere,
+                                int iRadius);
+    static void paintFrameRect(QPainter *pPainter, const QRect &rect, bool fIsSelected, int iRadius);
+    static void paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap);
+    static void paintText(QPainter *pPainter, const QRect &rect, const QFont &font, const QString &strText);
+    static void paintFocus(QPainter *pPainter, const QRect &rect);
+
+    /* Helpers: Drag and drop stuff: */
+    virtual QMimeData* createMimeData() = 0;
+
+    /* Gradient animation (property) stuff: */
+    int gradient() const { return m_iGradient; }
+    void setGradient(int iGradient) { m_iGradient = iGradient; update(); }
+
+private slots:
+
+    /* Private handlers: Hover stuff: */
+    void sltUnhoverParent();
+
+private:
+
+    /* Variables: */
+    UIGSelectorItem *m_pParent;
+    DragToken m_dragTokenPlace;
+
+    /* Highlight animation stuff: */
+    QStateMachine *m_pHighlightMachine;
+    QPropertyAnimation *m_pForwardAnimation;
+    QPropertyAnimation *m_pBackwardAnimation;
+    int m_iAnimationDuration;
+    int m_iDefaultDarkness;
+    int m_iHighlightDarkness;
+    int m_iGradient;
+};
+
+/* Mime-data for graphics item interface: */
+class UIGSelectorItemMimeData : public QMimeData
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGSelectorItemMimeData(UIGSelectorItem *pItem);
+
+    /* API: Format checker: */
+    bool hasFormat(const QString &strMimeType) const;
+
+    /* API: Item getter: */
+    UIGSelectorItem* item() const;
+
+private:
+
+    /* Variables: */
+    UIGSelectorItem *m_pItem;
+};
+
+#endif /* __UIGSelectorItem_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemGroup.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemGroup.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemGroup.cpp	(revision 42529)
@@ -0,0 +1,1042 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGSelectorItemGroup class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QGraphicsSceneDragDropEvent>
+#include <QPropertyAnimation>
+#include <QLineEdit>
+#include <QGraphicsProxyWidget>
+
+/* GUI includes: */
+#include "UIGSelectorItemGroup.h"
+#include "UIGSelectorItemMachine.h"
+#include "UIGraphicsSelectorModel.h"
+#include "UIIconPool.h"
+#include "UIGraphicsRotatorButton.h"
+
+/* static */
+QString UIGSelectorItemGroup::className() { return "UIGSelectorItemGroup"; }
+
+UIGSelectorItemGroup::UIGSelectorItemGroup(UIGSelectorItem *pParent /* = 0 */,
+                                           const QString &strName /* = QString() */,
+                                           int iPosition /* = -1 */)
+    : UIGSelectorItem(pParent)
+    , m_strName(strName)
+    , m_fClosed(parentItem() ? true : false)
+    , m_pButton(0)
+    , m_pNameEditorWidget(0)
+    , m_pNameEditor(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+{
+    /* Prepare: */
+    prepare();
+
+    /* Add item to the parent: */
+    if (parentItem())
+        parentItem()->addItem(this, iPosition);
+}
+
+UIGSelectorItemGroup::UIGSelectorItemGroup(UIGSelectorItem *pParent,
+                                           UIGSelectorItemGroup *pCopyFrom,
+                                           int iPosition /* = -1 */)
+    : UIGSelectorItem(pParent)
+    , m_strName(pCopyFrom->name())
+    , m_fClosed(pCopyFrom->closed())
+    , m_pButton(0)
+    , m_pNameEditorWidget(0)
+    , m_pNameEditor(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+{
+    /* Prepare: */
+    prepare();
+
+    /* Copy content to 'this': */
+    copyContent(pCopyFrom, this);
+
+    /* Add item to the parent: */
+    if (parentItem())
+        parentItem()->addItem(this, iPosition);
+}
+
+UIGSelectorItemGroup::~UIGSelectorItemGroup()
+{
+    /* Delete all the items: */
+    clearItems();
+
+    /* Remove item from the parent: */
+    if (parentItem())
+        parentItem()->removeItem(this);
+}
+
+QString UIGSelectorItemGroup::name() const
+{
+    return m_strName;
+}
+
+bool UIGSelectorItemGroup::closed() const
+{
+    return m_fClosed;
+}
+
+bool UIGSelectorItemGroup::opened() const
+{
+    return !m_fClosed;
+}
+
+void UIGSelectorItemGroup::close()
+{
+    AssertMsg(parentItem(), ("Can't close root-item!"));
+    m_pButton->setToggled(false);
+}
+
+void UIGSelectorItemGroup::open()
+{
+    AssertMsg(parentItem(), ("Can't open root-item!"));
+    m_pButton->setToggled(true);
+}
+
+void UIGSelectorItemGroup::sltOpen()
+{
+    AssertMsg(parentItem(), ("Can't open root-item!"));
+    m_pButton->setToggled(true, false);
+}
+
+bool UIGSelectorItemGroup::contains(const QString &strId, bool fRecursively /* = false */) const
+{
+    /* Check machine items: */
+    foreach (UIGSelectorItem *pItem, m_machineItems)
+        if (pItem->toMachineItem()->id() == strId)
+            return true;
+    /* If recursively => check group items: */
+    if (fRecursively)
+        foreach (UIGSelectorItem *pItem, m_groupItems)
+            if (pItem->toGroupItem()->contains(strId, fRecursively))
+                return true;
+    return false;
+}
+
+void UIGSelectorItemGroup::sltNameEditingFinished()
+{
+    /* Lock name-editor: */
+    m_pNameEditor->hide();
+
+    /* Update group name: */
+    QString strNewName = m_pNameEditorWidget->text();
+    if (!strNewName.isEmpty())
+        m_strName = strNewName;
+}
+
+void UIGSelectorItemGroup::sltGroupToggleStart()
+{
+    /* Not for root-item: */
+    AssertMsg(parentItem(), ("Can't toggle root-item!"));
+
+    /* Setup animation: */
+    updateAnimationParameters();
+
+    /* Group closed, we are opening it: */
+    if (m_fClosed)
+    {
+        /* Toggle-state and navigation will be
+         * updated on toggle finish signal! */
+    }
+    /* Group opened, we are closing it: */
+    else
+    {
+        /* Update toggle-state: */
+        m_fClosed = true;
+        /* Update navigation: */
+        model()->updateNavigation();
+        /* Relayout model: */
+        model()->updateLayout();
+    }
+}
+
+void UIGSelectorItemGroup::sltGroupToggleFinish(bool fToggled)
+{
+    /* Not for root-item: */
+    AssertMsg(parentItem(), ("Can't toggle root-item!"));
+
+    /* Update toggle-state: */
+    m_fClosed = !fToggled;
+    /* Update navigation: */
+    model()->updateNavigation();
+    /* Relayout model: */
+    model()->updateLayout();
+}
+
+QVariant UIGSelectorItemGroup::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case GroupItemData_HorizonalMargin: return parentItem() ? 8 : 1;
+        case GroupItemData_VerticalMargin: return parentItem() ? 2 : 1;
+        case GroupItemData_MajorSpacing: return parentItem() ? 10 : 0;
+        case GroupItemData_MinorSpacing: return 1;
+        /* Pixmaps: */
+        case GroupItemData_ButtonPixmap: return UIIconPool::iconSet(":/arrow_right_10px.png");
+        case GroupItemData_GroupPixmap: return UIIconPool::iconSet(":/nw_16px.png");
+        case GroupItemData_MachinePixmap: return UIIconPool::iconSet(":/machine_16px.png");
+        /* Fonts: */
+        case GroupItemData_NameFont:
+        {
+            QFont nameFont = font();
+            nameFont.setWeight(QFont::Bold);
+            return nameFont;
+        }
+        case GroupItemData_InfoFont:
+        {
+            QFont infoFont = font();
+            return infoFont;
+        }
+        /* Texts: */
+        case GroupItemData_Name: return m_strName;
+        case GroupItemData_GroupCountText: return QString::number(m_groupItems.size());
+        case GroupItemData_MachineCountText: return QString::number(m_machineItems.size());
+        /* Sizes: */
+        case GroupItemData_ButtonSize: return m_pButton ? m_pButton->minimumSizeHint() : QSizeF(0, 0);
+        case GroupItemData_NameSize:
+        {
+            if (!parentItem())
+                return QSizeF(0, 0);
+            QFontMetrics fm(data(GroupItemData_NameFont).value<QFont>());
+            return QSize(fm.width(data(GroupItemData_Name).toString()), fm.height());
+        }
+        case GroupItemData_NameEditorSize:
+        {
+            if (!parentItem())
+                return QSizeF(0, 0);
+            return m_pNameEditorWidget->minimumSizeHint();
+        }
+        case GroupItemData_GroupPixmapSize:
+            return parentItem() ? data(GroupItemData_GroupPixmap).value<QIcon>().availableSizes().at(0) : QSizeF(0, 0);
+        case GroupItemData_MachinePixmapSize:
+            return parentItem() ? data(GroupItemData_MachinePixmap).value<QIcon>().availableSizes().at(0) : QSizeF(0, 0);
+        case GroupItemData_GroupCountTextSize:
+        {
+            if (!parentItem())
+                return QSizeF(0, 0);
+            QFontMetrics fm(data(GroupItemData_InfoFont).value<QFont>());
+            return QSize(fm.width(data(GroupItemData_GroupCountText).toString()), fm.height());
+        }
+        case GroupItemData_MachineCountTextSize:
+        {
+            if (!parentItem())
+                return QSizeF(0, 0);
+            QFontMetrics fm(data(GroupItemData_InfoFont).value<QFont>());
+            return QSize(fm.width(data(GroupItemData_MachineCountText).toString()), fm.height());
+        }
+        case GroupItemData_FullHeaderSize:
+        {
+            /* Prepare variables: */
+            int iMajorSpacing = data(GroupItemData_MajorSpacing).toInt();
+            int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+            QSize buttonSize = data(GroupItemData_ButtonSize).toSize();
+            QSize nameSize = data(GroupItemData_NameSize).toSize();
+            QSize nameEditorSize = data(GroupItemData_NameEditorSize).toSize();
+            QSize groupPixmapSize = data(GroupItemData_GroupPixmapSize).toSize();
+            QSize machinePixmapSize = data(GroupItemData_MachinePixmapSize).toSize();
+            QSize groupCountTextSize = data(GroupItemData_GroupCountTextSize).toSize();
+            QSize machineCountTextSize = data(GroupItemData_MachineCountTextSize).toSize();
+
+            /* Calculate minimum width: */
+            int iGroupItemHeaderWidth = /* Button width: */
+                                        buttonSize.width() +
+                                        /* Spacing between button and name: */
+                                        iMajorSpacing +
+                                        /* Some hardcoded magic: */
+                                        1 /* frame width from Qt sources */ +
+                                        2 /* internal QLineEdit margin from Qt sources */ +
+                                        1 /* internal QLineEdit align shifting from Qt sources */ +
+                                        /* Name width: */
+                                        nameSize.width() +
+                                        /* Spacing between name and info: */
+                                        iMajorSpacing +
+                                        /* Group stuff width: */
+                                        groupPixmapSize.width() + iMinorSpacing +
+                                        groupCountTextSize.width() + iMinorSpacing +
+                                        /* Machine stuff width: */
+                                        machinePixmapSize.width() + iMinorSpacing +
+                                        machineCountTextSize.width();
+
+            /* Search for maximum height: */
+            QList<int> heights;
+            heights << buttonSize.height()
+                    << nameSize.height() << nameEditorSize.height()
+                    << groupPixmapSize.height() << machinePixmapSize.height()
+                    << groupCountTextSize.height() << machineCountTextSize.height();
+            int iGroupItemHeaderHeight = 0;
+            foreach (int iHeight, heights)
+                iGroupItemHeaderHeight = qMax(iGroupItemHeaderHeight, iHeight);
+
+            /* Return result: */
+            return QSize(iGroupItemHeaderWidth, iGroupItemHeaderHeight);
+        }
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGSelectorItemGroup::startEditing()
+{
+    /* Not for root-item: */
+    AssertMsg(parentItem(), ("Can't edit root-item!"));
+    /* Unlock name-editor: */
+    m_pNameEditor->show();
+    m_pNameEditorWidget->setFocus();
+}
+
+void UIGSelectorItemGroup::addItem(UIGSelectorItem *pItem, int iPosition)
+{
+    /* Check item type: */
+    switch (pItem->type())
+    {
+        case UIGSelectorItemType_Group:
+        {
+            if (iPosition < 0 || iPosition >= m_groupItems.size())
+                m_groupItems.append(pItem);
+            else
+                m_groupItems.insert(iPosition, pItem);
+            break;
+        }
+        case UIGSelectorItemType_Machine:
+        {
+            if (iPosition < 0 || iPosition >= m_machineItems.size())
+                m_machineItems.append(pItem);
+            else
+                m_machineItems.insert(iPosition, pItem);
+            break;
+        }
+        default:
+        {
+            AssertMsgFailed(("Invalid item type!"));
+            break;
+        }
+    }
+}
+
+void UIGSelectorItemGroup::removeItem(UIGSelectorItem *pItem)
+{
+    /* Check item type: */
+    switch (pItem->type())
+    {
+        case UIGSelectorItemType_Group:
+        {
+            m_groupItems.removeAt(m_groupItems.indexOf(pItem));
+            break;
+        }
+        case UIGSelectorItemType_Machine:
+        {
+            m_machineItems.removeAt(m_machineItems.indexOf(pItem));
+            break;
+        }
+        default:
+        {
+            AssertMsgFailed(("Invalid item type!"));
+            break;
+        }
+    }
+}
+
+void UIGSelectorItemGroup::moveItemTo(UIGSelectorItem *pItem, int iPosition)
+{
+    /* Check item type: */
+    switch (pItem->type())
+    {
+        case UIGSelectorItemType_Group:
+        {
+            AssertMsg(m_groupItems.contains(pItem), ("Passed item is not our child!"));
+            m_groupItems.removeAt(m_groupItems.indexOf(pItem));
+            if (iPosition < 0 || iPosition >= m_groupItems.size())
+                m_groupItems.append(pItem);
+            else
+                m_groupItems.insert(iPosition, pItem);
+            break;
+        }
+        case UIGSelectorItemType_Machine:
+        {
+            AssertMsg(m_machineItems.contains(pItem), ("Passed item is not our child!"));
+            m_machineItems.removeAt(m_machineItems.indexOf(pItem));
+            if (iPosition < 0 || iPosition >= m_machineItems.size())
+                m_machineItems.append(pItem);
+            else
+                m_machineItems.insert(iPosition, pItem);
+            break;
+        }
+        default:
+        {
+            AssertMsgFailed(("Invalid item type!"));
+            break;
+        }
+    }
+}
+
+QList<UIGSelectorItem*> UIGSelectorItemGroup::items(UIGSelectorItemType type) const
+{
+    switch (type)
+    {
+        case UIGSelectorItemType_Any: return items(UIGSelectorItemType_Group) + items(UIGSelectorItemType_Machine);
+        case UIGSelectorItemType_Group: return m_groupItems;
+        case UIGSelectorItemType_Machine: return m_machineItems;
+        default: break;
+    }
+    return QList<UIGSelectorItem*>();
+}
+
+bool UIGSelectorItemGroup::hasItems(UIGSelectorItemType type /* = UIGSelectorItemType_Any */) const
+{
+    switch (type)
+    {
+        case UIGSelectorItemType_Any:
+            return hasItems(UIGSelectorItemType_Group) || hasItems(UIGSelectorItemType_Machine);
+        case UIGSelectorItemType_Group:
+            return !m_groupItems.isEmpty();
+        case UIGSelectorItemType_Machine:
+            return !m_machineItems.isEmpty();
+    }
+    return false;
+}
+
+void UIGSelectorItemGroup::clearItems(UIGSelectorItemType type /* = UIGSelectorItemType_Any */)
+{
+    switch (type)
+    {
+        case UIGSelectorItemType_Any:
+        {
+            clearItems(UIGSelectorItemType_Group);
+            clearItems(UIGSelectorItemType_Machine);
+            break;
+        }
+        case UIGSelectorItemType_Group:
+        {
+            while (!m_groupItems.isEmpty()) { delete m_groupItems.last(); }
+            break;
+        }
+        case UIGSelectorItemType_Machine:
+        {
+            while (!m_machineItems.isEmpty()) { delete m_machineItems.last(); }
+            break;
+        }
+    }
+}
+
+void UIGSelectorItemGroup::updateSizeHint()
+{
+    /* Update size-hints for all the items: */
+    foreach (UIGSelectorItem *pItem, items())
+        pItem->updateSizeHint();
+    /* Update size-hint for this item: */
+    updateGeometry();
+}
+
+void UIGSelectorItemGroup::updateLayout()
+{
+    /* Prepare variables: */
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    int iVerticalMargin = data(GroupItemData_VerticalMargin).toInt();
+    int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+    int iButtonHeight = data(GroupItemData_ButtonSize).toSize().height();
+    int iButtonWidth = data(GroupItemData_ButtonSize).toSize().width();
+    int iNameEditorHeight = data(GroupItemData_NameEditorSize).toSize().height();
+    int iFullHeaderHeight = data(GroupItemData_FullHeaderSize).toSize().height();
+    int iPreviousVerticalIndent = 0;
+
+    /* Header (non-root item): */
+    if (parentItem())
+    {
+        /* Layout button: */
+        int iButtonX = iHorizontalMargin;
+        int iButtonY = iButtonHeight == iFullHeaderHeight ? iVerticalMargin :
+                       iVerticalMargin + (iFullHeaderHeight - iButtonHeight) / 2;
+        m_pButton->setPos(iButtonX, iButtonY);
+
+        /* Layout name-editor: */
+        int iNameEditorX = iHorizontalMargin + iButtonWidth + iMinorSpacing;
+        int iNameEditorY = iNameEditorHeight == iFullHeaderHeight ? iVerticalMargin :
+                           iVerticalMargin + (iFullHeaderHeight - iNameEditorHeight) / 2;
+        m_pNameEditor->setPos(iNameEditorX, iNameEditorY);
+        m_pNameEditorWidget->resize(geometry().width() - iNameEditorX - iHorizontalMargin, m_pNameEditorWidget->height());
+
+        /* Prepare body indent: */
+        iPreviousVerticalIndent = 2 * iVerticalMargin + iFullHeaderHeight;
+    }
+    /* Header (root item): */
+    else
+    {
+        /* Prepare body indent: */
+        iPreviousVerticalIndent = iVerticalMargin;
+    }
+
+    /* No body for closed group: */
+    if (m_fClosed)
+    {
+        /* Hide all the items: */
+        foreach (UIGSelectorItem *pItem, items())
+            if (pItem->isVisible())
+                pItem->hide();
+    }
+    /* Body for opened group: */
+    else
+    {
+        /* Prepare variables: */
+        int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+        QSize size = geometry().size().toSize();
+        /* Layout all the items: */
+        foreach (UIGSelectorItem *pItem, items())
+        {
+            /* Show if hidden: */
+            if (!pItem->isVisible())
+                pItem->show();
+            /* Get item's height-hint: */
+            int iMinimumHeight = pItem->minimumHeightHint();
+            /* Set item's position: */
+            pItem->setPos(iHorizontalMargin, iPreviousVerticalIndent);
+            /* Set item's size: */
+            pItem->resize(size.width() - 2 * iHorizontalMargin, iMinimumHeight);
+            /* Relayout group: */
+            pItem->updateLayout();
+            /* Update indent for next items: */
+            iPreviousVerticalIndent += (iMinimumHeight + iMinorSpacing);
+        }
+    }
+}
+
+int UIGSelectorItemGroup::minimumWidthHint(bool fClosedGroup) const
+{
+    /* Prepare variables: */
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    QSize fullHeaderSize = data(GroupItemData_FullHeaderSize).toSize();
+
+    /* Calculating proposed width: */
+    int iProposedWidth = 0;
+
+    /* Simple group item have 2 margins - left and right: */
+    iProposedWidth += 2 * iHorizontalMargin;
+    /* And full header width to take into account: */
+    iProposedWidth += fullHeaderSize.width();
+    /* But if group is opened: */
+    if (!fClosedGroup)
+    {
+        /* We have to make sure that we had taken into account: */
+        foreach (UIGSelectorItem *pItem, items())
+        {
+            int iItemWidth = 2 * iHorizontalMargin + pItem->minimumWidthHint();
+            iProposedWidth = qMax(iProposedWidth, iItemWidth);
+        }
+    }
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGSelectorItemGroup::minimumHeightHint(bool fClosedGroup) const
+{
+    /* Prepare variables: */
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    int iVerticalMargin = data(GroupItemData_VerticalMargin).toInt();
+    int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+    QSize fullHeaderSize = data(GroupItemData_FullHeaderSize).toSize();
+
+    /* Calculating proposed height: */
+    int iProposedHeight = 0;
+
+    /* Simple group item have 2 margins - top and bottom: */
+    iProposedHeight += 2 * iVerticalMargin;
+    /* And full header height to take into account: */
+    iProposedHeight += fullHeaderSize.height();
+    /* But if group is opened: */
+    if (!fClosedGroup)
+    {
+        /* We should take into account: */
+        for (int i = 0; i < m_groupItems.size(); ++i)
+        {
+            /* Every group item height: */
+            UIGSelectorItem *pItem = m_groupItems[i];
+            iProposedHeight += pItem->minimumHeightHint();
+            /* And every spacing between sub-groups: */
+            if (i < m_groupItems.size() - 1)
+                iProposedHeight += iMinorSpacing;
+        }
+        /* Minor spacing between group and machine item: */
+        if (hasItems(UIGSelectorItemType_Group) && hasItems(UIGSelectorItemType_Machine))
+            iProposedHeight += iMinorSpacing;
+        for (int i = 0; i < m_machineItems.size(); ++i)
+        {
+            /* Every machine item height: */
+            UIGSelectorItem *pItem = m_machineItems[i];
+            iProposedHeight += pItem->minimumHeightHint();
+            /* And every spacing between sub-machines: */
+            if (i < m_machineItems.size() - 1)
+                iProposedHeight += iMinorSpacing;
+        }
+        /* Bottom margin: */
+        iProposedHeight += iHorizontalMargin;
+    }
+    /* Finally, additional height during animation: */
+    if (fClosedGroup && m_pButton && m_pButton->isAnimationRunning())
+        iProposedHeight += m_iAdditionalHeight;
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+int UIGSelectorItemGroup::minimumWidthHint() const
+{
+    return minimumWidthHint(m_fClosed);
+}
+
+int UIGSelectorItemGroup::minimumHeightHint() const
+{
+    return minimumHeightHint(m_fClosed);
+}
+
+QSizeF UIGSelectorItemGroup::minimumSizeHint(bool fClosedGroup) const
+{
+    return QSizeF(minimumWidthHint(fClosedGroup), minimumHeightHint(fClosedGroup));
+}
+
+QSizeF UIGSelectorItemGroup::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    /* If Qt::MinimumSize requested: */
+    if (which == Qt::MinimumSize)
+        return minimumSizeHint(m_fClosed);
+    /* Else call to base-class: */
+    return UIGSelectorItem::sizeHint(which, constraint);
+}
+
+QPixmap UIGSelectorItemGroup::toPixmap()
+{
+    QSize minimumSize = minimumSizeHint(true).toSize();
+    QPixmap pixmap(minimumSize);
+    QPainter painter(&pixmap);
+    QStyleOptionGraphicsItem options;
+    options.rect = QRect(QPoint(0, 0), minimumSize);
+    paint(&painter, &options, true);
+    return pixmap;
+}
+
+bool UIGSelectorItemGroup::isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const
+{
+    /* Get mime: */
+    const QMimeData *pMimeData = pEvent->mimeData();
+    /* If drag token is shown, its up to parent to decide: */
+    if (where != DragToken_Off)
+        return parentItem()->isDropAllowed(pEvent);
+    /* Else we should check mime format: */
+    if (pMimeData->hasFormat(UIGSelectorItemGroup::className()))
+    {
+        /* Get passed group item: */
+        const UIGSelectorItemMimeData *pCastedMimeData = qobject_cast<const UIGSelectorItemMimeData*>(pMimeData);
+        AssertMsg(pCastedMimeData, ("Can't cast passed mime-data to UIGSelectorItemMimeData!"));
+        UIGSelectorItem *pItem = pCastedMimeData->item();
+        /* Make sure passed group is not 'this': */
+        if (pItem == this)
+            return false;
+        /* Make sure passed group is not among our parents: */
+        const UIGSelectorItem *pTestedWidget = this;
+        while (UIGSelectorItem *pParentOfTestedWidget = pTestedWidget->parentItem())
+        {
+            if (pItem == pParentOfTestedWidget)
+                return false;
+            pTestedWidget = pParentOfTestedWidget;
+        }
+        return true;
+    }
+    else if (pMimeData->hasFormat(UIGSelectorItemMachine::className()))
+    {
+        /* Get passed machine item: */
+        const UIGSelectorItemMimeData *pCastedMimeData = qobject_cast<const UIGSelectorItemMimeData*>(pMimeData);
+        AssertMsg(pCastedMimeData, ("Can't cast passed mime-data to UIGSelectorItemMimeData!"));
+        UIGSelectorItem *pItem = pCastedMimeData->item();
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            {
+                /* Make sure passed item is ours or there is no other item with such id: */
+                return m_machineItems.contains(pItem) || !contains(pItem->toMachineItem()->id());
+            }
+            case Qt::CopyAction:
+            {
+                /* Make sure there is no other item with such id: */
+                return !contains(pItem->toMachineItem()->id());
+            }
+        }
+    }
+    /* That was invalid mime: */
+    return false;
+}
+
+void UIGSelectorItemGroup::processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGSelectorItem *pFromWho, DragToken where)
+{
+    /* Get mime: */
+    const QMimeData *pMime = pEvent->mimeData();
+    /* Check mime format: */
+    if (pMime->hasFormat(UIGSelectorItemGroup::className()))
+    {
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            case Qt::CopyAction:
+            {
+                /* Remember scene: */
+                UIGraphicsSelectorModel *pModel = model();
+
+                /* Get passed group item: */
+                const UIGSelectorItemMimeData *pCastedMime = qobject_cast<const UIGSelectorItemMimeData*>(pMime);
+                AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIGSelectorItemMimeData!"));
+                UIGSelectorItem *pItem = pCastedMime->item();
+
+                /* Check if we have position information: */
+                int iPosition = m_groupItems.size();
+                if (pFromWho && where != DragToken_Off)
+                {
+                    /* Make sure sender item if our child: */
+                    AssertMsg(m_groupItems.contains(pFromWho), ("Sender item is NOT our child!"));
+                    if (m_groupItems.contains(pFromWho))
+                    {
+                        iPosition = m_groupItems.indexOf(pFromWho);
+                        if (where == DragToken_Down)
+                            ++iPosition;
+                    }
+                }
+
+                /* Copy passed item into this group: */
+                UIGSelectorItem *pNewGroupItem = new UIGSelectorItemGroup(this, pItem->toGroupItem(), iPosition);
+
+                /* If proposed action is 'move': */
+                if (pEvent->proposedAction() == Qt::MoveAction)
+                {
+                    /* Delete passed item: */
+                    delete pItem;
+                }
+
+                /* Update scene: */
+                pModel->updateGroupTree();
+                pModel->updateNavigation();
+                pModel->updateLayout();
+                pModel->setCurrentItem(pNewGroupItem->parentItem()->toGroupItem()->opened() ?
+                                       pNewGroupItem : pNewGroupItem->parentItem());
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    else if (pMime->hasFormat(UIGSelectorItemMachine::className()))
+    {
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            case Qt::CopyAction:
+            {
+                /* Remember scene: */
+                UIGraphicsSelectorModel *pModel = model();
+
+                /* Get passed item: */
+                const UIGSelectorItemMimeData *pCastedMime = qobject_cast<const UIGSelectorItemMimeData*>(pMime);
+                AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIGSelectorItemMimeData!"));
+                UIGSelectorItem *pItem = pCastedMime->item();
+
+                /* Check if we have position information: */
+                int iPosition = m_machineItems.size();
+                if (pFromWho && where != DragToken_Off)
+                {
+                    /* Make sure sender item if our child: */
+                    AssertMsg(m_machineItems.contains(pFromWho), ("Sender item is NOT our child!"));
+                    if (m_machineItems.contains(pFromWho))
+                    {
+                        iPosition = m_machineItems.indexOf(pFromWho);
+                        if (where == DragToken_Down)
+                            ++iPosition;
+                    }
+                }
+
+                /* Copy passed machine item into this group: */
+                UIGSelectorItem *pNewMachineItem = new UIGSelectorItemMachine(this, pItem->toMachineItem(), iPosition);
+
+                /* If proposed action is 'move': */
+                if (pEvent->proposedAction() == Qt::MoveAction)
+                {
+                    /* Delete passed item: */
+                    delete pItem;
+                }
+
+                /* Update scene: */
+                pModel->updateGroupTree();
+                pModel->updateNavigation();
+                pModel->updateLayout();
+                pModel->setCurrentItem(pNewMachineItem->parentItem()->toGroupItem()->opened() ?
+                                       pNewMachineItem : pNewMachineItem->parentItem());
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+void UIGSelectorItemGroup::resetDragToken()
+{
+    /* Reset drag token for this item: */
+    if (dragTokenPlace() != DragToken_Off)
+    {
+        setDragTokenPlace(DragToken_Off);
+        update();
+    }
+    /* Reset drag tokens for all the items: */
+    foreach (UIGSelectorItem *pItem, items())
+        pItem->resetDragToken();
+}
+
+QMimeData* UIGSelectorItemGroup::createMimeData()
+{
+    return new UIGSelectorItemMimeData(this);
+}
+
+void UIGSelectorItemGroup::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget* /* pWidget = 0 */)
+{
+    paint(pPainter, pOption, m_fClosed);
+}
+
+void UIGSelectorItemGroup::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool fClosedGroup)
+{
+    /* Non-root item: */
+    if (parentItem())
+    {
+        /* Configure painter shape: */
+        configurePainterShape(pPainter, pOption, m_iCornerRadius);
+    }
+
+    /* Any item: */
+    {
+        /* Paint decorations: */
+        paintDecorations(pPainter, pOption);
+    }
+
+    /* Non-root item: */
+    if (parentItem())
+    {
+        /* Paint group info: */
+        paintGroupInfo(pPainter, pOption, fClosedGroup);
+    }
+}
+
+void UIGSelectorItemGroup::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Prepare variables: */
+    QRect fullRect = pOption->rect;
+
+    /* Any item: */
+    {
+        /* Paint background: */
+        paintBackground(/* Painter: */
+                        pPainter,
+                        /* Rectangle to paint in: */
+                        fullRect,
+                        /* Has parent? */
+                        parentItem(),
+                        /* Is item selected? */
+                        model()->selectionList().contains(this),
+                        /* Gradient darkness for animation: */
+                        gradient(),
+                        /* Show drag where? */
+                        dragTokenPlace(),
+                        /* Rounded corners radius: */
+                        m_iCornerRadius);
+    }
+
+    /* Non-root item: */
+    if (parentItem())
+    {
+        /* Paint frame: */
+        paintFrameRect(/* Painter: */
+                       pPainter,
+                       /* Rectangle to paint in: */
+                       fullRect,
+                       /* Is item selected? */
+                       model()->selectionList().contains(this),
+                       /* Rounded corner radius: */
+                       m_iCornerRadius);
+    }
+}
+
+void UIGSelectorItemGroup::paintGroupInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool)
+{
+    /* Prepare variables: */
+    int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+    int iHorizontalMargin = data(GroupItemData_HorizonalMargin).toInt();
+    int iVerticalMargin = data(GroupItemData_VerticalMargin).toInt();
+    QSize buttonSize = data(GroupItemData_ButtonSize).toSize();
+    QSize nameSize = data(GroupItemData_NameSize).toSize();
+    int iFullHeaderHeight = data(GroupItemData_FullHeaderSize).toSize().height();
+
+    /* Paint name: */
+    int iNameX = iHorizontalMargin + buttonSize.width() + iMinorSpacing +
+                 1 /* frame width from Qt sources */ +
+                 2 /* internal QLineEdit margin from Qt sources */ +
+                 1 /* internal QLineEdit align shifting from Qt sources */;
+    int iNameY = nameSize.height() == iFullHeaderHeight ? iVerticalMargin :
+                 iVerticalMargin + (iFullHeaderHeight - nameSize.height()) / 2;
+    paintText(/* Painter: */
+              pPainter,
+              /* Rectangle to paint in: */
+              QRect(QPoint(iNameX, iNameY), nameSize),
+              /* Font to paint text: */
+              data(GroupItemData_NameFont).value<QFont>(),
+              /* Text to paint: */
+              data(GroupItemData_Name).toString());
+
+    /* Should we add more info? */
+    if (model()->selectionList().contains(this))
+    {
+        /* Prepare variables: */
+        QRect fullRect = pOption->rect;
+        int iMinorSpacing = data(GroupItemData_MinorSpacing).toInt();
+        QSize groupPixmapSize = data(GroupItemData_GroupPixmapSize).toSize();
+        QSize machinePixmapSize = data(GroupItemData_MachinePixmapSize).toSize();
+        QSize groupCountTextSize = data(GroupItemData_GroupCountTextSize).toSize();
+        QSize machineCountTextSize = data(GroupItemData_MachineCountTextSize).toSize();
+        QFont infoFont = data(GroupItemData_InfoFont).value<QFont>();
+        QString strGroupCountText = data(GroupItemData_GroupCountText).toString();
+        QString strMachineCountText = data(GroupItemData_MachineCountText).toString();
+        QPixmap groupPixmap = data(GroupItemData_GroupPixmap).value<QIcon>().pixmap(groupPixmapSize);
+        QPixmap machinePixmap = data(GroupItemData_MachinePixmap).value<QIcon>().pixmap(machinePixmapSize);
+
+        /* We should add machine count: */
+        int iMachineCountTextX = fullRect.right() -
+                                 iHorizontalMargin -
+                                 machineCountTextSize.width();
+        int iMachineCountTextY = machineCountTextSize.height() == iFullHeaderHeight ?
+                                 iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - machineCountTextSize.height()) / 2;
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(QPoint(iMachineCountTextX, iMachineCountTextY), machineCountTextSize),
+                  /* Font to paint text: */
+                  infoFont,
+                  /* Text to paint: */
+                  strMachineCountText);
+
+        /* We should draw machine pixmap: */
+        int iMachinePixmapX = iMachineCountTextX -
+                              iMinorSpacing -
+                              machinePixmapSize.width();
+        int iMachinePixmapY = machinePixmapSize.height() == iFullHeaderHeight ?
+                              iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - machinePixmapSize.height()) / 2;
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(QPoint(iMachinePixmapX, iMachinePixmapY), machinePixmapSize),
+                    /* Pixmap to paint: */
+                    machinePixmap);
+
+        /* We should add group count: */
+        int iGroupCountTextX = iMachinePixmapX -
+                               iMinorSpacing -
+                               groupCountTextSize.width();
+        int iGroupCountTextY = groupCountTextSize.height() == iFullHeaderHeight ?
+                               iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - groupCountTextSize.height()) / 2;
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(QPoint(iGroupCountTextX, iGroupCountTextY), groupCountTextSize),
+                  /* Font to paint text: */
+                  infoFont,
+                  /* Text to paint: */
+                  strGroupCountText);
+
+        /* We should draw group pixmap: */
+        int iGroupPixmapX = iGroupCountTextX -
+                            iMinorSpacing -
+                            groupPixmapSize.width();
+        int iGroupPixmapY = groupPixmapSize.height() == iFullHeaderHeight ?
+                            iVerticalMargin : iVerticalMargin + (iFullHeaderHeight - groupPixmapSize.height()) / 2;
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(QPoint(iGroupPixmapX, iGroupPixmapY), groupPixmapSize),
+                    /* Pixmap to paint: */
+                    groupPixmap);
+    }
+}
+
+void UIGSelectorItemGroup::updateAnimationParameters()
+{
+    /* Recalculate animation parameters: */
+    if (m_pButton)
+    {
+        QSizeF openedSize = minimumSizeHint(false);
+        QSizeF closedSize = minimumSizeHint(true);
+        int iAdditionalHeight = openedSize.height() - closedSize.height();
+        m_pButton->setAnimationRange(0, iAdditionalHeight);
+    }
+}
+
+void UIGSelectorItemGroup::setAdditionalHeight(int iAdditionalHeight)
+{
+    m_iAdditionalHeight = iAdditionalHeight;
+    /* Relayout scene: */
+    model()->updateLayout();
+}
+
+int UIGSelectorItemGroup::additionalHeight() const
+{
+    return m_iAdditionalHeight;
+}
+
+void UIGSelectorItemGroup::prepare()
+{
+    /* Nothing for root: */
+    if (!parentItem())
+        return;
+
+    /* Setup toggle-button: */
+    m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed);
+    m_pButton->setIcon(data(GroupItemData_ButtonPixmap).value<QIcon>());
+    connect(m_pButton, SIGNAL(sigRotationStart()), this, SLOT(sltGroupToggleStart()));
+    connect(m_pButton, SIGNAL(sigRotationFinish(bool)), this, SLOT(sltGroupToggleFinish(bool)));
+
+    /* Setup name-editor: */
+    m_pNameEditorWidget = new QLineEdit(m_strName);
+    m_pNameEditorWidget->setTextMargins(0, 0, 0, 0);
+    m_pNameEditorWidget->setFont(data(GroupItemData_NameFont).value<QFont>());
+    connect(m_pNameEditorWidget, SIGNAL(editingFinished()), this, SLOT(sltNameEditingFinished()));
+    m_pNameEditor = new QGraphicsProxyWidget(this);
+    m_pNameEditor->setWidget(m_pNameEditorWidget);
+    m_pNameEditor->hide();
+}
+
+/* static */
+void UIGSelectorItemGroup::copyContent(UIGSelectorItemGroup *pFrom, UIGSelectorItemGroup *pTo)
+{
+    /* Copy group items: */
+    foreach (UIGSelectorItem *pGroupItem, pFrom->items(UIGSelectorItemType_Group))
+        new UIGSelectorItemGroup(pTo, pGroupItem->toGroupItem());
+    /* Copy machine items: */
+    foreach (UIGSelectorItem *pMachineItem, pFrom->items(UIGSelectorItemType_Machine))
+        new UIGSelectorItemMachine(pTo, pMachineItem->toMachineItem());
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemGroup.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemGroup.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemGroup.h	(revision 42529)
@@ -0,0 +1,170 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGSelectorItemGroup class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGSelectorItemGroup_h__
+#define __UIGSelectorItemGroup_h__
+
+/* Qt includes: */
+#include <QPointer>
+
+/* GUI includes: */
+#include "UIGSelectorItem.h"
+
+/* Forward declarations: */
+class UIGSelectorItemMachine;
+class UIGraphicsRotatorButton;
+class QLineEdit;
+class QGraphicsProxyWidget;
+
+/* Graphics group item
+ * for graphics selector model/view architecture: */
+class UIGSelectorItemGroup : public UIGSelectorItem
+{
+    Q_OBJECT;
+    Q_PROPERTY(int additionalHeight READ additionalHeight WRITE setAdditionalHeight);
+
+public slots:
+
+    /* API: Loading stuff: */
+    void sltOpen();
+
+public:
+
+    /* Class-name used for drag&drop mime-data format: */
+    static QString className();
+
+    /* Graphics-item type: */
+    enum { Type = UIGSelectorItemType_Group };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGSelectorItemGroup(UIGSelectorItem *pParent = 0, const QString &strName = QString(), int iPosition = -1);
+    UIGSelectorItemGroup(UIGSelectorItem *pParent, UIGSelectorItemGroup *pCopyFrom, int iPosition = -1);
+    ~UIGSelectorItemGroup();
+
+    /* API: Basic stuff: */
+    QString name() const;
+    bool closed() const;
+    bool opened() const;
+    void close();
+    void open();
+
+    /* API: Children stuff: */
+    bool contains(const QString &strId, bool fRecursively = false) const;
+
+private slots:
+
+    /* Slot to handle group name editing: */
+    void sltNameEditingFinished();
+
+    /* Slot to handle group collapse/expand: */
+    void sltGroupToggleStart();
+    void sltGroupToggleFinish(bool fToggled);
+
+private:
+
+    /* Data enumerator: */
+    enum GroupItemData
+    {
+        /* Layout hints: */
+        GroupItemData_HorizonalMargin,
+        GroupItemData_VerticalMargin,
+        GroupItemData_MajorSpacing,
+        GroupItemData_MinorSpacing,
+        /* Pixmaps: */
+        GroupItemData_ButtonPixmap,
+        GroupItemData_GroupPixmap,
+        GroupItemData_MachinePixmap,
+        /* Fonts: */
+        GroupItemData_NameFont,
+        GroupItemData_InfoFont,
+        /* Text: */
+        GroupItemData_Name,
+        GroupItemData_GroupCountText,
+        GroupItemData_MachineCountText,
+        /* Sizes: */
+        GroupItemData_ButtonSize,
+        GroupItemData_NameSize,
+        GroupItemData_NameEditorSize,
+        GroupItemData_GroupPixmapSize,
+        GroupItemData_MachinePixmapSize,
+        GroupItemData_GroupCountTextSize,
+        GroupItemData_MachineCountTextSize,
+        GroupItemData_FullHeaderSize
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Basic stuff: */
+    void startEditing();
+
+    /* Children stuff: */
+    void addItem(UIGSelectorItem *pItem, int iPosition);
+    void removeItem(UIGSelectorItem *pItem);
+    void moveItemTo(UIGSelectorItem *pItem, int iPosition);
+    QList<UIGSelectorItem*> items(UIGSelectorItemType type = UIGSelectorItemType_Any) const;
+    bool hasItems(UIGSelectorItemType type = UIGSelectorItemType_Any) const;
+    void clearItems(UIGSelectorItemType type = UIGSelectorItemType_Any);
+
+    /* Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+    int minimumWidthHint(bool fClosedGroup) const;
+    int minimumHeightHint(bool fClosedGroup) const;
+    int minimumWidthHint() const;
+    int minimumHeightHint() const;
+    QSizeF minimumSizeHint(bool fClosedGroup) const;
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* API: Drag and drop stuff: */
+    QPixmap toPixmap();
+    bool isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const;
+    void processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGSelectorItem *pFromWho, DragToken where);
+    void resetDragToken();
+    QMimeData* createMimeData();
+
+    /* Paint stuff: */
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool fClosedGroup);
+    void paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+    void paintGroupInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, bool fClosedGroup);
+
+    /* Animation stuff: */
+    void updateAnimationParameters();
+    void setAdditionalHeight(int iAdditionalHeight);
+    int additionalHeight() const;
+
+    /* Helpers: */
+    void prepare();
+    static void copyContent(UIGSelectorItemGroup *pFrom, UIGSelectorItemGroup *pTo);
+
+    /* Variables: */
+    QString m_strName;
+    bool m_fClosed;
+    UIGraphicsRotatorButton *m_pButton;
+    QLineEdit *m_pNameEditorWidget;
+    QGraphicsProxyWidget *m_pNameEditor;
+    QList<UIGSelectorItem*> m_groupItems;
+    QList<UIGSelectorItem*> m_machineItems;
+    int m_iAdditionalHeight;
+    int m_iCornerRadius;
+};
+
+#endif /* __UIGSelectorItemGroup_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemMachine.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemMachine.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemMachine.cpp	(revision 42529)
@@ -0,0 +1,628 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGSelectorItemMachine class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QGraphicsSceneMouseEvent>
+
+/* GUI includes: */
+#include "UIGSelectorItemMachine.h"
+#include "UIGSelectorItemGroup.h"
+#include "UIGraphicsSelectorModel.h"
+#include "UIGraphicsToolBar.h"
+#include "UIGraphicsZoomButton.h"
+#include "VBoxGlobal.h"
+#include "UIConverter.h"
+#include "UIIconPool.h"
+#include "UIActionPoolSelector.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+#include "CMachine.h"
+
+/* static */
+QString UIGSelectorItemMachine::className() { return "UIGSelectorItemMachine"; }
+
+UIGSelectorItemMachine::UIGSelectorItemMachine(UIGSelectorItem *pParent,
+                                               const CMachine &machine,
+                                               int iPosition /* = -1 */)
+    : UIGSelectorItem(pParent)
+    , UIVMItem(machine)
+    , m_pToolBar(0)
+    , m_pSettingsButton(0)
+    , m_pStartButton(0)
+    , m_pPauseButton(0)
+    , m_pCloseButton(0)
+    , m_iCornerRadius(6)
+{
+    /* Add item to the parent: */
+    AssertMsg(parentItem(), ("No parent set for machine item!"));
+    parentItem()->addItem(this, iPosition);
+
+    /* Prepare: */
+    prepare();
+}
+
+UIGSelectorItemMachine::UIGSelectorItemMachine(UIGSelectorItem *pParent,
+                                               UIGSelectorItemMachine *pCopyFrom,
+                                               int iPosition /* = -1 */)
+    : UIGSelectorItem(pParent)
+    , UIVMItem(pCopyFrom->machine())
+    , m_pToolBar(0)
+    , m_pSettingsButton(0)
+    , m_pStartButton(0)
+    , m_pPauseButton(0)
+    , m_pCloseButton(0)
+    , m_iCornerRadius(6)
+{
+    /* Add item to the parent: */
+    AssertMsg(parentItem(), ("No parent set for machine item!"));
+    parentItem()->addItem(this, iPosition);
+
+    /* Prepare: */
+    prepare();
+}
+
+UIGSelectorItemMachine::~UIGSelectorItemMachine()
+{
+    /* Remove item from the parent: */
+    AssertMsg(parentItem(), ("No parent set for machine item!"));
+    parentItem()->removeItem(this);
+}
+
+QString UIGSelectorItemMachine::name() const
+{
+    return UIVMItem::name();
+}
+
+QVariant UIGSelectorItemMachine::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case MachineItemData_Margin: return 5;
+        case MachineItemData_MajorSpacing: return 10;
+        case MachineItemData_MinorSpacing: return 4;
+        case MachineItemData_TextSpacing: return 2;
+        /* Pixmaps: */
+        case MachineItemData_Pixmap: return osIcon();
+        case MachineItemData_StatePixmap: return machineStateIcon();
+        case MachineItemData_SettingsButtonPixmap: return UIIconPool::iconSet(":/settings_16px.png");
+        case MachineItemData_StartButtonPixmap: return UIIconPool::iconSet(":/start_16px.png");
+        case MachineItemData_PauseButtonPixmap: return UIIconPool::iconSet(":/pause_16px.png");
+        case MachineItemData_CloseButtonPixmap: return UIIconPool::iconSet(":/exit_16px.png");
+        /* Fonts: */
+        case MachineItemData_NameFont:
+        {
+            QFont machineNameFont = qApp->font();
+            machineNameFont.setPointSize(machineNameFont.pointSize() + 1);
+            machineNameFont.setWeight(QFont::Bold);
+            return machineNameFont;
+        }
+        case MachineItemData_SnapshotNameFont:
+        {
+            QFont snapshotStateFont = qApp->font();
+            snapshotStateFont.setPointSize(snapshotStateFont.pointSize() + 1);
+            return snapshotStateFont;
+        }
+        case MachineItemData_StateTextFont:
+        {
+            QFont machineStateFont = qApp->font();
+            machineStateFont.setPointSize(machineStateFont.pointSize() + 1);
+            return machineStateFont;
+        }
+        /* Texts: */
+        case MachineItemData_Name: return name();
+        case MachineItemData_SnapshotName: return snapshotName();
+        case MachineItemData_StateText: return gpConverter->toString(machineState());
+        /* Sizes: */
+        case MachineItemData_PixmapSize: return osIcon().availableSizes().at(0);
+        case MachineItemData_StatePixmapSize: return machineStateIcon().availableSizes().at(0);
+        case MachineItemData_NameSize:
+        {
+            QFontMetrics fm(data(MachineItemData_NameFont).value<QFont>());
+            return QSize(fm.width(data(MachineItemData_Name).toString()), fm.height());
+        }
+        case MachineItemData_SnapshotNameSize:
+        {
+            QFontMetrics fm(data(MachineItemData_SnapshotNameFont).value<QFont>());
+            return QSize(fm.width(QString("(%1)").arg(data(MachineItemData_SnapshotName).toString())), fm.height());
+        }
+        case MachineItemData_StateTextSize:
+        {
+            QFontMetrics fm(data(MachineItemData_StateTextFont).value<QFont>());
+            return QSize(fm.width(data(MachineItemData_StateText).toString()), fm.height());
+        }
+        case MachineItemData_ToolBarSize: return m_pToolBar->minimumSizeHint().toSize();
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGSelectorItemMachine::startEditing()
+{
+    AssertMsgFailed(("Machine graphics item do NOT support editing yet!"));
+}
+
+void UIGSelectorItemMachine::addItem(UIGSelectorItem*, int)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+void UIGSelectorItemMachine::removeItem(UIGSelectorItem*)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+void UIGSelectorItemMachine::moveItemTo(UIGSelectorItem*, int)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+QList<UIGSelectorItem*> UIGSelectorItemMachine::items(UIGSelectorItemType) const
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+    return QList<UIGSelectorItem*>();
+}
+
+bool UIGSelectorItemMachine::hasItems(UIGSelectorItemType) const
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+    return false;
+}
+
+void UIGSelectorItemMachine::clearItems(UIGSelectorItemType)
+{
+    AssertMsgFailed(("Machine graphics item do NOT support children!"));
+}
+
+void UIGSelectorItemMachine::updateSizeHint()
+{
+    updateGeometry();
+}
+
+void UIGSelectorItemMachine::updateLayout()
+{
+    /* Prepare variables: */
+    QSize size = geometry().size().toSize();
+
+    /* Prepare variables: */
+    int iMachineItemWidth = size.width();
+    int iMachineItemHeight = size.height();
+    int iToolBarHeight = data(MachineItemData_ToolBarSize).toSize().height();
+
+    /* Configure tool-bar: */
+    QSize toolBarSize = m_pToolBar->minimumSizeHint().toSize();
+    int iToolBarX = iMachineItemWidth - 1 - toolBarSize.width();
+    int iToolBarY = (iMachineItemHeight - iToolBarHeight) / 2;
+    m_pToolBar->setPos(iToolBarX, iToolBarY);
+    m_pToolBar->resize(toolBarSize);
+    m_pToolBar->updateLayout();
+
+    /* Configure buttons: */
+    m_pStartButton->updateAnimation();
+    m_pSettingsButton->updateAnimation();
+    m_pCloseButton->updateAnimation();
+    m_pPauseButton->updateAnimation();
+}
+
+int UIGSelectorItemMachine::minimumWidthHint() const
+{
+    /* First of all, we have to prepare few variables: */
+    int iMachineItemMargin = data(MachineItemData_Margin).toInt();
+    int iMachineItemMajorSpacing = data(MachineItemData_MajorSpacing).toInt();
+    int iMachineItemMinorSpacing = data(MachineItemData_MinorSpacing).toInt();
+    QSize machinePixmapSize = data(MachineItemData_PixmapSize).toSize();
+    QSize machineNameSize = data(MachineItemData_NameSize).toSize();
+    QSize snapshotNameSize = data(MachineItemData_SnapshotNameSize).toSize();
+    QSize machineStatePixmapSize = data(MachineItemData_StatePixmapSize).toSize();
+    QSize machineStateTextSize = data(MachineItemData_StateTextSize).toSize();
+    QSize toolBarSize = data(MachineItemData_ToolBarSize).toSize();
+
+    /* Calculating proposed width: */
+    int iProposedWidth = 0;
+
+    /* We are taking into account only left margin,
+     * tool-bar contains right one: */
+    iProposedWidth += iMachineItemMargin;
+    /* And machine item content to take into account: */
+    int iFirstLineWidth = machineNameSize.width() +
+                          iMachineItemMinorSpacing +
+                          snapshotNameSize.width();
+    int iSecondLineWidth = machineStatePixmapSize.width() +
+                           iMachineItemMinorSpacing +
+                           machineStateTextSize.width();
+    int iSecondColumnWidth = qMax(iFirstLineWidth, iSecondLineWidth);
+    int iMachineItemWidth = machinePixmapSize.width() +
+                            iMachineItemMajorSpacing +
+                            iSecondColumnWidth +
+                            iMachineItemMajorSpacing +
+                            toolBarSize.width() + 1;
+    iProposedWidth += iMachineItemWidth;
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGSelectorItemMachine::minimumHeightHint() const
+{
+    /* First of all, we have to prepare few variables: */
+    int iMachineItemMargin = data(MachineItemData_Margin).toInt();
+    int iMachineItemTextSpacing = data(MachineItemData_TextSpacing).toInt();
+    QSize machinePixmapSize = data(MachineItemData_PixmapSize).toSize();
+    QSize machineNameSize = data(MachineItemData_NameSize).toSize();
+    QSize snapshotNameSize = data(MachineItemData_SnapshotNameSize).toSize();
+    QSize machineStatePixmapSize = data(MachineItemData_StatePixmapSize).toSize();
+    QSize machineStateTextSize = data(MachineItemData_StateTextSize).toSize();
+    QSize toolBarSize = data(MachineItemData_ToolBarSize).toSize();
+
+    /* Calculating proposed height: */
+    int iProposedHeight = 0;
+
+    /* Simple machine item have 2 margins - top and bottom: */
+    iProposedHeight += 2 * iMachineItemMargin;
+    /* And machine item content to take into account: */
+    int iFirstLineHeight = qMax(machineNameSize.height(), snapshotNameSize.height());
+    int iSecondLineHeight = qMax(machineStatePixmapSize.height(), machineStateTextSize.height());
+    int iSecondColumnHeight = iFirstLineHeight +
+                              iMachineItemTextSpacing +
+                              iSecondLineHeight;
+    QList<int> heights;
+    heights << machinePixmapSize.height() << iSecondColumnHeight
+            << (toolBarSize.height() - 2 * iMachineItemMargin + 2);
+    int iMaxHeight = 0;
+    foreach (int iHeight, heights)
+        iMaxHeight = qMax(iMaxHeight, iHeight);
+    iProposedHeight += iMaxHeight;
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+QSizeF UIGSelectorItemMachine::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    /* If Qt::MinimumSize requested: */
+    if (which == Qt::MinimumSize)
+    {
+        /* Return wrappers: */
+        return QSizeF(minimumWidthHint(), minimumHeightHint());
+    }
+
+    /* Call to base-class: */
+    return UIGSelectorItem::sizeHint(which, constraint);
+}
+
+QPixmap UIGSelectorItemMachine::toPixmap()
+{
+    /* Ask item to paint itself into pixmap: */
+    QSize minimumSize = minimumSizeHint().toSize();
+    QPixmap pixmap(minimumSize);
+    QPainter painter(&pixmap);
+    QStyleOptionGraphicsItem options;
+    options.rect = QRect(QPoint(0, 0), minimumSize);
+    paint(&painter, &options);
+    return pixmap;
+}
+
+bool UIGSelectorItemMachine::isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const
+{
+    /* Get mime: */
+    const QMimeData *pMimeData = pEvent->mimeData();
+    /* If drag token is shown, its up to parent to decide: */
+    if (where != DragToken_Off)
+        return parentItem()->isDropAllowed(pEvent);
+    /* Else we should try to cast mime to known classes: */
+    if (pMimeData->hasFormat(UIGSelectorItemMachine::className()))
+    {
+        /* Make sure passed item id is not ours: */
+        const UIGSelectorItemMimeData *pCastedMimeData = qobject_cast<const UIGSelectorItemMimeData*>(pMimeData);
+        AssertMsg(pCastedMimeData, ("Can't cast passed mime-data to UIGSelectorItemMimeData!"));
+        UIGSelectorItem *pItem = pCastedMimeData->item();
+        return pItem->toMachineItem()->id() != id();
+    }
+    /* That was invalid mime: */
+    return false;
+}
+
+void UIGSelectorItemMachine::processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGSelectorItem *pFromWho, DragToken where)
+{
+    /* Get mime: */
+    const QMimeData *pMime = pEvent->mimeData();
+    /* Make sure this handler called by this item (not by children): */
+    AssertMsg(!pFromWho && where == DragToken_Off, ("Machine graphics item do NOT support children!"));
+    Q_UNUSED(pFromWho);
+    Q_UNUSED(where);
+    if (pMime->hasFormat(UIGSelectorItemMachine::className()))
+    {
+        switch (pEvent->proposedAction())
+        {
+            case Qt::MoveAction:
+            case Qt::CopyAction:
+            {
+                /* Remember scene: */
+                UIGraphicsSelectorModel *pModel = model();
+
+                /* Get passed item: */
+                const UIGSelectorItemMimeData *pCastedMime = qobject_cast<const UIGSelectorItemMimeData*>(pMime);
+                AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIGSelectorItemMimeData!"));
+                UIGSelectorItem *pItem = pCastedMime->item();
+
+                /* Group passed item with current item into the new group: */
+                UIGSelectorItemGroup *pNewGroupItem = new UIGSelectorItemGroup(parentItem(), "New group");
+                new UIGSelectorItemMachine(pNewGroupItem, this);
+                new UIGSelectorItemMachine(pNewGroupItem, pItem->toMachineItem());
+
+                /* If proposed action is 'move': */
+                if (pEvent->proposedAction() == Qt::MoveAction)
+                {
+                    /* Delete passed item: */
+                    delete pItem;
+                }
+                /* Delete this item: */
+                delete this;
+
+                /* Update scene: */
+                pModel->updateGroupTree();
+                pModel->updateNavigation();
+                pModel->updateLayout();
+                pModel->setCurrentItem(pNewGroupItem);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+void UIGSelectorItemMachine::resetDragToken()
+{
+    /* Reset drag token for this item: */
+    if (dragTokenPlace() != DragToken_Off)
+    {
+        setDragTokenPlace(DragToken_Off);
+        update();
+    }
+}
+
+QMimeData* UIGSelectorItemMachine::createMimeData()
+{
+    return new UIGSelectorItemMimeData(this);
+}
+
+void UIGSelectorItemMachine::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget * /* pWidget = 0 */)
+{
+    /* Non-root item: */
+    if (parentItem())
+    {
+        /* Configure painter shape: */
+        configurePainterShape(pPainter, pOption, m_iCornerRadius);
+    }
+
+    /* Any item: */
+    {
+        /* Paint decorations: */
+        paintDecorations(pPainter, pOption);
+    }
+
+    /* Non-root item: */
+    if (parentItem())
+    {
+        /* Paint machine info: */
+        paintMachineInfo(pPainter, pOption);
+    }
+}
+
+void UIGSelectorItemMachine::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Prepare variables: */
+    QRect fullRect = pOption->rect;
+
+    /* Any item: */
+    {
+        /* Paint background: */
+        paintBackground(/* Painter: */
+                        pPainter,
+                        /* Rectangle to paint in: */
+                        fullRect,
+                        /* Has parent? */
+                        parentItem(),
+                        /* Is item selected? */
+                        model()->selectionList().contains(this),
+                        /* Gradient darkness for animation: */
+                        gradient(),
+                        /* Show drag where? */
+                        dragTokenPlace(),
+                        /* Rounded corners radius: */
+                        m_iCornerRadius);
+    }
+
+    /* Non-root item: */
+    if (parentItem())
+    {
+        /* Paint frame: */
+        paintFrameRect(/* Painter: */
+                       pPainter,
+                       /* Rectangle to paint in: */
+                       fullRect,
+                       /* Is item selected? */
+                       model()->selectionList().contains(this),
+                       /* Rounded corner radius: */
+                       m_iCornerRadius);
+    }
+}
+
+void UIGSelectorItemMachine::paintMachineInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Initialize some necessary variables: */
+    QRect fullRect = pOption->rect;
+    int iMachineItemMargin = data(MachineItemData_Margin).toInt();
+    int iMachineItemMajorSpacing = data(MachineItemData_MajorSpacing).toInt();
+    int iMachineItemMinorSpacing = data(MachineItemData_MinorSpacing).toInt();
+    int iMachineItemTextSpacing = data(MachineItemData_TextSpacing).toInt();
+    QSize machinePixmapSize = data(MachineItemData_PixmapSize).toSize();
+    QSize machineNameSize = data(MachineItemData_NameSize).toSize();
+    QString strSnapshotName = data(MachineItemData_SnapshotName).toString();
+    QSize snapshotNameSize = data(MachineItemData_SnapshotNameSize).toSize();
+    QSize machineStatePixmapSize = data(MachineItemData_StatePixmapSize).toSize();
+    QSize machineStateTextSize = data(MachineItemData_StateTextSize).toSize();
+
+    /* Paint pixmap: */
+    {
+        /* Calculate attributes: */
+        int iMachinePixmapHeight = machinePixmapSize.height();
+        int iFirstLineHeight = qMax(machineNameSize.height(), snapshotNameSize.height());
+        int iSecondLineHeight = qMax(machineStatePixmapSize.height(), machineStateTextSize.height());
+        int iRightSizeHeight = iFirstLineHeight + iMachineItemTextSpacing + iSecondLineHeight;
+        int iMinimumHeight = qMin(iMachinePixmapHeight, iRightSizeHeight);
+        int iMaximumHeight = qMax(iMachinePixmapHeight, iRightSizeHeight);
+        int iDelta = iMaximumHeight - iMinimumHeight;
+        int iHalfDelta = iDelta / 2;
+        int iMachinePixmapX = iMachineItemMargin;
+        int iMachinePixmapY = iMachinePixmapHeight >= iRightSizeHeight ?
+                              iMachineItemMargin : iMachineItemMargin + iHalfDelta;
+
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(fullRect.topLeft() +
+                          QPoint(iMachinePixmapX, iMachinePixmapY),
+                          machinePixmapSize),
+                    /* Pixmap to paint: */
+                    data(MachineItemData_Pixmap).value<QIcon>().pixmap(machinePixmapSize));
+    }
+
+    /* Paint name: */
+    {
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(fullRect.topLeft() +
+                        QPoint(iMachineItemMargin, iMachineItemMargin) +
+                        QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0),
+                        machineNameSize),
+                  /* Font to paint text: */
+                  data(MachineItemData_NameFont).value<QFont>(),
+                  /* Text to paint: */
+                  data(MachineItemData_Name).toString());
+    }
+
+    /* Paint snapshot name (if necessary): */
+    if (!strSnapshotName.isEmpty())
+    {
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(fullRect.topLeft() +
+                        QPoint(iMachineItemMargin, iMachineItemMargin) +
+                        QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0) +
+                        QPoint(machineNameSize.width() + iMachineItemMinorSpacing, 0),
+                        snapshotNameSize),
+                  /* Font to paint text: */
+                  data(MachineItemData_SnapshotNameFont).value<QFont>(),
+                  /* Text to paint: */
+                  QString("(%1)").arg(strSnapshotName));
+    }
+
+    /* Paint state pixmap: */
+    {
+        paintPixmap(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    QRect(fullRect.topLeft() +
+                          QPoint(iMachineItemMargin, iMachineItemMargin) +
+                          QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0) +
+                          QPoint(0, machineNameSize.height() + iMachineItemTextSpacing),
+                          machineStatePixmapSize),
+                    /* Pixmap to paint: */
+                    data(MachineItemData_StatePixmap).value<QIcon>().pixmap(machineStatePixmapSize));
+    }
+
+    /* Paint state text: */
+    {
+        paintText(/* Painter: */
+                  pPainter,
+                  /* Rectangle to paint in: */
+                  QRect(fullRect.topLeft() +
+                        QPoint(iMachineItemMargin, iMachineItemMargin) +
+                        QPoint(machinePixmapSize.width() + iMachineItemMajorSpacing, 0) +
+                        QPoint(0, machineNameSize.height() + iMachineItemTextSpacing) +
+                        QPoint(machineStatePixmapSize.width() + iMachineItemMinorSpacing, 0),
+                        machineStateTextSize),
+                  /* Font to paint text: */
+                  data(MachineItemData_StateTextFont).value<QFont>(),
+                  /* Text to paint: */
+                  data(MachineItemData_StateText).toString());
+    }
+
+    /* Show/hide start-button: */
+    if (model()->focusItem() == this)
+    {
+        if (!m_pToolBar->isVisible())
+            m_pToolBar->show();
+    }
+    else
+    {
+        if (m_pToolBar->isVisible())
+            m_pToolBar->hide();
+    }
+}
+
+void UIGSelectorItemMachine::prepare()
+{
+    /* Create tool-bar: */
+    m_pToolBar = new UIGraphicsToolBar(this, 2, 2);
+
+    /* Create buttons: */
+    m_pSettingsButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Top | UIGraphicsZoomDirection_Left);
+    m_pSettingsButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pSettingsButton->setIcon(data(MachineItemData_SettingsButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pSettingsButton, 0, 0);
+
+    m_pStartButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Top | UIGraphicsZoomDirection_Right);
+    m_pStartButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pStartButton->setIcon(data(MachineItemData_StartButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pStartButton, 0, 1);
+
+    m_pPauseButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Bottom | UIGraphicsZoomDirection_Left);
+    m_pPauseButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pPauseButton->setIcon(data(MachineItemData_PauseButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pPauseButton, 1, 0);
+
+    m_pCloseButton = new UIGraphicsZoomButton(m_pToolBar, UIGraphicsZoomDirection_Bottom | UIGraphicsZoomDirection_Right);
+    m_pCloseButton->setIndent(m_pToolBar->toolBarMargin() - 1);
+    m_pCloseButton->setIcon(data(MachineItemData_CloseButtonPixmap).value<QIcon>());
+    m_pToolBar->insertItem(m_pCloseButton, 1, 1);
+
+    connect(m_pSettingsButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_Simple_Machine_SettingsDialog), SLOT(trigger()),
+            Qt::QueuedConnection);
+    connect(m_pStartButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow), SLOT(trigger()),
+            Qt::QueuedConnection);
+    connect(m_pPauseButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_Toggle_Machine_PauseAndResume), SLOT(trigger()),
+            Qt::QueuedConnection);
+    connect(m_pCloseButton, SIGNAL(sigButtonClicked()),
+            gActionPool->action(UIActionIndexSelector_Simple_Machine_Close_PowerOff), SLOT(trigger()),
+            Qt::QueuedConnection);
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemMachine.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemMachine.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGSelectorItemMachine.h	(revision 42529)
@@ -0,0 +1,134 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGSelectorItemMachine class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGSelectorItemMachine_h__
+#define __UIGSelectorItemMachine_h__
+
+/* GUI includes: */
+#include "UIVMItem.h"
+#include "UIGSelectorItem.h"
+
+/* Forward declarations: */
+class CMachine;
+class UIGraphicsToolBar;
+class UIGraphicsZoomButton;
+
+/* Graphics machine item
+ * for graphics selector model/view architecture: */
+class UIGSelectorItemMachine : public UIGSelectorItem, public UIVMItem
+{
+    Q_OBJECT;
+
+public:
+
+    /* Class-name used for drag&drop mime-data format: */
+    static QString className();
+
+    /* Graphics-item type: */
+    enum { Type = UIGSelectorItemType_Machine };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGSelectorItemMachine(UIGSelectorItem *pParent, const CMachine &machine, int iPosition = -1);
+    UIGSelectorItemMachine(UIGSelectorItem *pParent, UIGSelectorItemMachine *pCopyFrom, int iPosition = -1);
+    ~UIGSelectorItemMachine();
+
+    /* API: Basic stuff: */
+    QString name() const;
+
+private:
+
+    /* Data enumerator: */
+    enum MachineItemData
+    {
+        /* Layout hints: */
+        MachineItemData_Margin,
+        MachineItemData_MajorSpacing,
+        MachineItemData_MinorSpacing,
+        MachineItemData_TextSpacing,
+        /* Pixmaps: */
+        MachineItemData_Pixmap,
+        MachineItemData_StatePixmap,
+        MachineItemData_SettingsButtonPixmap,
+        MachineItemData_StartButtonPixmap,
+        MachineItemData_PauseButtonPixmap,
+        MachineItemData_CloseButtonPixmap,
+        /* Fonts: */
+        MachineItemData_NameFont,
+        MachineItemData_SnapshotNameFont,
+        MachineItemData_StateTextFont,
+        /* Text: */
+        MachineItemData_Name,
+        MachineItemData_SnapshotName,
+        MachineItemData_StateText,
+        /* Sizes: */
+        MachineItemData_PixmapSize,
+        MachineItemData_StatePixmapSize,
+        MachineItemData_NameSize,
+        MachineItemData_SnapshotNameSize,
+        MachineItemData_StateTextSize,
+        MachineItemData_ToolBarSize
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Basic stuff: */
+    void startEditing();
+
+    /* Children stuff: */
+    void addItem(UIGSelectorItem *pItem, int iPosition);
+    void removeItem(UIGSelectorItem *pItem);
+    void moveItemTo(UIGSelectorItem *pItem, int iPosition);
+    QList<UIGSelectorItem*> items(UIGSelectorItemType type) const;
+    bool hasItems(UIGSelectorItemType type) const;
+    void clearItems(UIGSelectorItemType type);
+
+    /* Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+    int minimumWidthHint() const;
+    int minimumHeightHint() const;
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* Drag and drop stuff: */
+    QPixmap toPixmap();
+    bool isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, DragToken where) const;
+    void processDrop(QGraphicsSceneDragDropEvent *pEvent, UIGSelectorItem *pFromWho, DragToken where);
+    void resetDragToken();
+    QMimeData* createMimeData();
+
+    /* Paint stuff: */
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
+    void paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+    void paintMachineInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+
+    /* Helpers: Prepare stuff: */
+    void prepare();
+
+    /* Variables: */
+    UIGraphicsToolBar *m_pToolBar;
+    UIGraphicsZoomButton *m_pSettingsButton;
+    UIGraphicsZoomButton *m_pStartButton;
+    UIGraphicsZoomButton *m_pPauseButton;
+    UIGraphicsZoomButton *m_pCloseButton;
+    int m_iCornerRadius;
+};
+
+#endif /* __UIGSelectorItemMachine_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorKeyboardHandler.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorKeyboardHandler.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorKeyboardHandler.cpp	(revision 42529)
@@ -0,0 +1,253 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorKeyboardHandler class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QKeyEvent>
+
+/* GUI incluedes: */
+#include "UIGraphicsSelectorKeyboardHandler.h"
+#include "UIGraphicsSelectorModel.h"
+#include "UIGSelectorItemGroup.h"
+
+UIGraphicsSelectorKeyboardHandler::UIGraphicsSelectorKeyboardHandler(UIGraphicsSelectorModel *pParent)
+    : QObject(pParent)
+    , m_pModel(pParent)
+{
+}
+
+bool UIGraphicsSelectorKeyboardHandler::handle(QKeyEvent *pEvent, UIKeyboardEventType type) const
+{
+    /* Process passed event: */
+    switch (type)
+    {
+        case UIKeyboardEventType_Press: return handleKeyPress(pEvent);
+        case UIKeyboardEventType_Release: return handleKeyRelease(pEvent);
+    }
+    /* Pass event if unknown: */
+    return false;
+}
+
+UIGraphicsSelectorModel* UIGraphicsSelectorKeyboardHandler::model() const
+{
+    return m_pModel;
+}
+
+bool UIGraphicsSelectorKeyboardHandler::handleKeyPress(QKeyEvent *pEvent) const
+{
+    /* Which key it was? */
+    switch (pEvent->key())
+    {
+        /* Key UP? */
+        case Qt::Key_Up:
+        {
+            /* Determine focus item position: */
+            int iPosition = model()->navigationList().indexOf(model()->focusItem());
+            /* Determine 'previous' item: */
+            UIGSelectorItem *pPreviousItem = iPosition > 0 ?
+                                             model()->navigationList().at(iPosition - 1) : 0;
+            if (pPreviousItem)
+            {
+                /* Make sure 'previous' item is visible: */
+                pPreviousItem->makeSureItsVisible();
+                /* Move focus to 'previous' item: */
+                model()->setFocusItem(pPreviousItem);
+                /* Was 'shift' modifier pressed? */
+                if (pEvent->modifiers() == Qt::ShiftModifier)
+                {
+                    /* Calculate positions: */
+                    UIGSelectorItem *pFirstItem = model()->selectionList().first();
+                    int iFirstPosition = model()->navigationList().indexOf(pFirstItem);
+                    int iPreviousPosition = model()->navigationList().indexOf(pPreviousItem);
+                    /* Clear selection: */
+                    model()->clearSelectionList();
+                    /* Select all the items from 'first' to 'previous': */
+                    if (iFirstPosition <= iPreviousPosition)
+                        for (int i = iFirstPosition; i <= iPreviousPosition; ++i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                    else
+                        for (int i = iFirstPosition; i >= iPreviousPosition; --i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                }
+                /* There is no modifiers pressed? */
+                else if (pEvent->modifiers() == Qt::NoModifier)
+                {
+                    /* Move selection to 'previous' item: */
+                    model()->clearSelectionList();
+                    model()->addToSelectionList(pPreviousItem);
+                }
+                /* Notify selection changed: */
+                model()->notifySelectionChanged();
+                /* Filter-out this event: */
+                return true;
+            }
+            /* Pass this event: */
+            return false;
+        }
+        /* Key DOWN? */
+        case Qt::Key_Down:
+        {
+            /* Determine focus item position: */
+            int iPosition = model()->navigationList().indexOf(model()->focusItem());
+            /* Determine 'next' item: */
+            UIGSelectorItem *pNextItem = iPosition < model()->navigationList().size() - 1 ?
+                                          model()->navigationList().at(iPosition + 1) : 0;
+            if (pNextItem)
+            {
+                /* Make sure 'next' item is visible: */
+                pNextItem->makeSureItsVisible();
+                /* Move focus to 'next' item: */
+                model()->setFocusItem(pNextItem);
+                /* Was shift modifier pressed? */
+                if (pEvent->modifiers() == Qt::ShiftModifier)
+                {
+                    /* Calculate positions: */
+                    UIGSelectorItem *pFirstItem = model()->selectionList().first();
+                    int iFirstPosition = model()->navigationList().indexOf(pFirstItem);
+                    int iNextPosition = model()->navigationList().indexOf(pNextItem);
+                    /* Clear selection: */
+                    model()->clearSelectionList();
+                    /* Select all the items from 'first' to 'next': */
+                    if (iFirstPosition <= iNextPosition)
+                        for (int i = iFirstPosition; i <= iNextPosition; ++i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                    else
+                        for (int i = iFirstPosition; i >= iNextPosition; --i)
+                            model()->addToSelectionList(model()->navigationList().at(i));
+                }
+                /* There is no modifiers pressed? */
+                else if (pEvent->modifiers() == Qt::NoModifier)
+                {
+                    /* Move selection to 'next' item: */
+                    model()->clearSelectionList();
+                    model()->addToSelectionList(pNextItem);
+                }
+                /* Notify selection changed: */
+                model()->notifySelectionChanged();
+                /* Filter-out this event: */
+                return true;
+            }
+            /* Pass this event: */
+            return false;
+        }
+        /* Key LEFT? */
+        case Qt::Key_Left:
+        {
+            /* If there is focus item: */
+            if (UIGSelectorItem *pFocusItem = model()->focusItem())
+            {
+                /* Known item type? */
+                switch (pFocusItem->type())
+                {
+                    /* Group one? */
+                    case UIGSelectorItemType_Group:
+                    {
+                        /* Get focus group: */
+                        UIGSelectorItemGroup *pFocusGroup = pFocusItem->toGroupItem();
+                        /* If focus group is opened: */
+                        if (pFocusGroup->opened())
+                        {
+                            /* Close it: */
+                            pFocusGroup->close();
+                            /* Filter that event out: */
+                            return true;
+                        }
+                        /* If focus group is closed and not from root-group: */
+                        else if (pFocusItem->parentItem() && pFocusItem->parentItem()->parentItem())
+                        {
+                            /* Move focus to parent item: */
+                            model()->setFocusItem(pFocusItem->parentItem(), true);
+                            /* Filter that event out: */
+                            return true;
+                        }
+                        break;
+                    }
+                    /* Machine one? */
+                    case UIGSelectorItemType_Machine:
+                    {
+                        /* If focus machine is not from root-group: */
+                        if (pFocusItem->parentItem() && pFocusItem->parentItem()->parentItem())
+                        {
+                            /* Move focus to parent item: */
+                            model()->setFocusItem(pFocusItem->parentItem(), true);
+                            /* Filter that event out: */
+                            return true;
+                        }
+                        break;
+                    }
+                    default:
+                        break;
+                }
+            }
+            /* Pass that event: */
+            return false;
+        }
+        /* Key RIGHT? */
+        case Qt::Key_Right:
+        {
+            /* If there is focus item: */
+            if (UIGSelectorItem *pFocusItem = model()->focusItem())
+            {
+                /* And focus item is of 'group' type and opened: */
+                if (pFocusItem->type() == UIGSelectorItemType_Group &&
+                    pFocusItem->toGroupItem()->closed())
+                {
+                    /* Open it: */
+                    pFocusItem->toGroupItem()->open();
+                    /* And filter out that event: */
+                    return true;
+                }
+            }
+            /* Pass that event: */
+            return false;
+        }
+        /* Key F2? */
+        case Qt::Key_F2:
+        {
+            /* If this item is of group type: */
+            if (model()->focusItem()->type() == UIGSelectorItemType_Group)
+            {
+                /* Start embedded editing focus item: */
+                model()->focusItem()->startEditing();
+                /* Filter that event out: */
+                return true;
+            }
+            /* Pass event to other items: */
+            return false;
+        }
+        case Qt::Key_Return:
+        case Qt::Key_Enter:
+        {
+            /* Activate item: */
+            model()->activate();
+            /* And filter out that event: */
+            return true;
+        }
+        default:
+            break;
+    }
+    /* Pass all other events: */
+    return false;
+}
+
+bool UIGraphicsSelectorKeyboardHandler::handleKeyRelease(QKeyEvent*) const
+{
+    /* Pass all events: */
+    return false;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorKeyboardHandler.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorKeyboardHandler.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorKeyboardHandler.h	(revision 42529)
@@ -0,0 +1,63 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorKeyboardHandler class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGraphicsSelectorKeyboardHandler_h__
+#define __UIGraphicsSelectorKeyboardHandler_h__
+
+/* Qt includes: */
+#include <QObject>
+
+/* Forward declarations: */
+class UIGraphicsSelectorModel;
+class QKeyEvent;
+
+/* Keyboard event type: */
+enum UIKeyboardEventType
+{
+    UIKeyboardEventType_Press,
+    UIKeyboardEventType_Release
+};
+
+/* Keyboard handler for graphics selector: */
+class UIGraphicsSelectorKeyboardHandler : public QObject
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGraphicsSelectorKeyboardHandler(UIGraphicsSelectorModel *pParent);
+
+    /* API: Model keyboard-event handler delegate: */
+    bool handle(QKeyEvent *pEvent, UIKeyboardEventType type) const;
+
+private:
+
+    /* Model wrapper: */
+    UIGraphicsSelectorModel* model() const;
+
+    /* Helpers: Model keyboard-event handler delegates: */
+    bool handleKeyPress(QKeyEvent *pEvent) const;
+    bool handleKeyRelease(QKeyEvent *pEvent) const;
+
+    /* Variables: */
+    UIGraphicsSelectorModel *m_pModel;
+};
+
+#endif /* __UIGraphicsSelectorKeyboardHandler_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorModel.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorModel.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorModel.cpp	(revision 42529)
@@ -0,0 +1,1013 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorModel class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsScene>
+#include <QGraphicsWidget>
+#include <QGraphicsView>
+#include <QRegExp>
+#include <QTimer>
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsSceneContextMenuEvent>
+
+/* GUI includes: */
+#include "UIGraphicsSelectorModel.h"
+#include "UIGSelectorItemGroup.h"
+#include "UIGSelectorItemMachine.h"
+#include "UIDefs.h"
+#include "VBoxGlobal.h"
+#include "UIMessageCenter.h"
+#include "UIActionPoolSelector.h"
+#include "UIGraphicsSelectorMouseHandler.h"
+#include "UIGraphicsSelectorKeyboardHandler.h"
+
+/* COM includes: */
+#include "CMachine.h"
+
+UIGraphicsSelectorModel::UIGraphicsSelectorModel(QObject *pParent)
+    : QObject(pParent)
+    , m_pScene(0)
+    , m_pRoot(0)
+    , m_pMouseHandler(0)
+    , m_pKeyboardHandler(0)
+    , m_pContextMenuRoot(0)
+    , m_pContextMenuGroup(0)
+    , m_pContextMenuMachine(0)
+{
+    /* Prepare scene: */
+    prepareScene();
+
+    /* Prepare root: */
+    prepareRoot();
+
+    /* Prepare context-menu: */
+    prepareContextMenu();
+
+    /* Prepare handlers: */
+    prepareHandlers();
+}
+
+UIGraphicsSelectorModel::~UIGraphicsSelectorModel()
+{
+    /* Cleanup handlers: */
+    cleanupHandlers();
+
+    /* Prepare context-menu: */
+    cleanupContextMenu();
+
+    /* Cleanup root: */
+    cleanupRoot();
+
+    /* Cleanup scene: */
+    cleanupScene();
+ }
+
+void UIGraphicsSelectorModel::load()
+{
+    /* Prepare group-tree: */
+    prepareGroupTree();
+}
+
+void UIGraphicsSelectorModel::save()
+{
+    /* Cleanup group-tree: */
+    cleanupGroupTree();
+}
+
+QGraphicsScene* UIGraphicsSelectorModel::scene() const
+{
+    return m_pScene;
+}
+
+void UIGraphicsSelectorModel::setCurrentItem(int iItemIndex)
+{
+    /* Make sure passed index feats the bounds: */
+    if (iItemIndex >= 0 && iItemIndex < navigationList().size())
+    {
+        /* And call for other wrapper: */
+        setCurrentItem(navigationList().at(iItemIndex));
+    }
+    else
+        AssertMsgFailed(("Passed index out of bounds!"));
+}
+
+void UIGraphicsSelectorModel::setCurrentItem(UIGSelectorItem *pItem)
+{
+    /* If navigation list contains passed item: */
+    if (navigationList().contains(pItem))
+    {
+        /* Pass focus/selection to that item: */
+        setFocusItem(pItem, true);
+    }
+    else
+        AssertMsgFailed(("Passed item not in navigation list!"));
+}
+
+void UIGraphicsSelectorModel::unsetCurrentItem()
+{
+    /* Clear focus/selection: */
+    setFocusItem(0, true);
+}
+
+UIVMItem* UIGraphicsSelectorModel::currentItem() const
+{
+    /* Search for the first selected machine: */
+    return searchCurrentItem(selectionList());
+}
+
+QList<UIVMItem*> UIGraphicsSelectorModel::currentItems() const
+{
+    /* Populate list of selected machines: */
+    QList<UIVMItem*> currentItemList;
+    enumerateCurrentItems(selectionList(), currentItemList);
+    return currentItemList;
+}
+
+void UIGraphicsSelectorModel::setFocusItem(UIGSelectorItem *pItem, bool fWithSelection /* = false */)
+{
+    /* Make sure real focus unset: */
+    clearRealFocus();
+
+    /* Something changed? */
+    if (m_pFocusItem != pItem || !pItem)
+    {
+        /* Remember previous focus item: */
+        QPointer<UIGSelectorItem> pPreviousFocusItem = m_pFocusItem;
+        /* Set new focus item: */
+        m_pFocusItem = pItem;
+
+        /* Should we move selection too? */
+        if (fWithSelection)
+        {
+            /* Clear selection: */
+            clearSelectionList();
+            /* Add focus item into selection (if any): */
+            if (m_pFocusItem)
+                addToSelectionList(m_pFocusItem);
+            /* Notify selection changed: */
+            notifySelectionChanged();
+        }
+
+        /* Update previous focus item (if any): */
+        if (pPreviousFocusItem)
+        {
+            pPreviousFocusItem->disconnect(this);
+            pPreviousFocusItem->update();
+        }
+        /* Update new focus item (if any): */
+        if (m_pFocusItem)
+        {
+            connect(m_pFocusItem, SIGNAL(destroyed(QObject*)), this, SLOT(sltFocusItemDestroyed()));
+            m_pFocusItem->update();
+        }
+    }
+}
+
+UIGSelectorItem* UIGraphicsSelectorModel::focusItem() const
+{
+    return m_pFocusItem;
+}
+
+QGraphicsItem* UIGraphicsSelectorModel::itemAt(const QPointF &position, const QTransform &deviceTransform /* = QTransform() */) const
+{
+    return scene()->itemAt(position, deviceTransform);
+}
+
+void UIGraphicsSelectorModel::updateGroupTree()
+{
+    updateGroupTree(m_pRoot);
+}
+
+const QList<UIGSelectorItem*>& UIGraphicsSelectorModel::navigationList() const
+{
+    return m_navigationList;
+}
+
+void UIGraphicsSelectorModel::removeFromNavigationList(UIGSelectorItem *pItem)
+{
+    AssertMsg(pItem, ("Passed item is invalid!"));
+    m_navigationList.removeAll(pItem);
+}
+
+void UIGraphicsSelectorModel::clearNavigationList()
+{
+    m_navigationList.clear();
+}
+
+void UIGraphicsSelectorModel::updateNavigation()
+{
+    /* Recreate navigation list: */
+    clearNavigationList();
+    m_navigationList = createNavigationList(m_pRoot);
+}
+
+const QList<UIGSelectorItem*>& UIGraphicsSelectorModel::selectionList() const
+{
+    return m_selectionList;
+}
+
+void UIGraphicsSelectorModel::addToSelectionList(UIGSelectorItem *pItem)
+{
+    AssertMsg(pItem, ("Passed item is invalid!"));
+    m_selectionList << pItem;
+    pItem->update();
+}
+
+void UIGraphicsSelectorModel::removeFromSelectionList(UIGSelectorItem *pItem)
+{
+    AssertMsg(pItem, ("Passed item is invalid!"));
+    m_selectionList.removeAll(pItem);
+    pItem->update();
+}
+
+void UIGraphicsSelectorModel::clearSelectionList()
+{
+    QList<UIGSelectorItem*> oldSelectedList = m_selectionList;
+    m_selectionList.clear();
+    foreach (UIGSelectorItem *pItem, oldSelectedList)
+        pItem->update();
+}
+
+void UIGraphicsSelectorModel::notifySelectionChanged()
+{
+    /* Make sure selection item list is never empty
+     * if at least one item (for example 'focus') present: */
+    if (selectionList().isEmpty() && focusItem())
+        addToSelectionList(focusItem());
+    /* Notify listeners about selection change: */
+    emit sigSelectionChanged();
+}
+
+void UIGraphicsSelectorModel::updateLayout()
+{
+    /* Initialize variables: */
+    int iSceneMargin = data(SelectorModelData_Margin).toInt();
+    QSize viewportSize = scene()->views()[0]->viewport()->size();
+    int iViewportWidth = viewportSize.width() - 2 * iSceneMargin;
+    int iViewportHeight = viewportSize.height() - 2 * iSceneMargin;
+    /* Update all the size-hints recursively: */
+    m_pRoot->updateSizeHint();
+    /* Set root item position: */
+    m_pRoot->setPos(iSceneMargin, iSceneMargin);
+    /* Set root item size: */
+    m_pRoot->resize(iViewportWidth, iViewportHeight);
+    /* Relayout root item: */
+    m_pRoot->updateLayout();
+    /* Notify listener about root-item relayouted: */
+    emit sigRootItemResized(m_pRoot->geometry().size(), m_pRoot->minimumWidthHint());
+}
+
+void UIGraphicsSelectorModel::setCurrentDragObject(QDrag *pDragObject)
+{
+    /* Make sure real focus unset: */
+    clearRealFocus();
+
+    /* Remember new drag-object: */
+    m_pCurrentDragObject = pDragObject;
+    connect(m_pCurrentDragObject, SIGNAL(destroyed(QObject*)), this, SLOT(sltCurrentDragObjectDestroyed()));
+}
+
+void UIGraphicsSelectorModel::activate()
+{
+    gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow)->activate(QAction::Trigger);
+}
+
+void UIGraphicsSelectorModel::sltMachineStateChanged(QString strId, KMachineState)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, m_pRoot);
+}
+
+void UIGraphicsSelectorModel::sltMachineDataChanged(QString strId)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, m_pRoot);
+}
+
+void UIGraphicsSelectorModel::sltMachineRegistered(QString strId, bool fRegistered)
+{
+    /* New VM registered? */
+    if (fRegistered)
+    {
+        /* Search for corresponding machine: */
+        CMachine machine = vboxGlobal().virtualBox().FindMachine(strId);
+        /* Machine was found? */
+        if (!machine.isNull())
+        {
+            /* Add new machine item: */
+            addMachineIntoTheTree(machine);
+            /* And update model: */
+            updateNavigation();
+            updateLayout();
+            setCurrentItem(getMachineItem(strId, m_pRoot));
+        }
+    }
+    /* Existing VM unregistered? */
+    else
+    {
+        /* Remove machine items with passed id: */
+        removeMachineItems(strId, m_pRoot);
+        /* And update model: */
+        updateGroupTree();
+        updateNavigation();
+        updateLayout();
+        if (m_pRoot->hasItems())
+            setCurrentItem(0);
+        else
+            unsetCurrentItem();
+    }
+}
+
+void UIGraphicsSelectorModel::sltSessionStateChanged(QString strId, KSessionState)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, m_pRoot);
+}
+
+void UIGraphicsSelectorModel::sltSnapshotChanged(QString strId, QString)
+{
+    /* Update machine items with passed id: */
+    updateMachineItems(strId, m_pRoot);
+}
+
+void UIGraphicsSelectorModel::sltHandleViewResized()
+{
+    /* Relayout: */
+    updateLayout();
+}
+
+void UIGraphicsSelectorModel::sltCurrentDragObjectDestroyed()
+{
+    /* Reset drag tokens starting from the root item: */
+    m_pRoot->resetDragToken();
+}
+
+void UIGraphicsSelectorModel::sltRemoveCurrentlySelectedGroup()
+{
+    /* Check which item is focused now: */
+    if (focusItem()->type() == UIGSelectorItemType_Group)
+    {
+        /* Delete that item: */
+        delete focusItem();
+        /* And update model: */
+        updateGroupTree();
+        updateNavigation();
+        updateLayout();
+        if (m_pRoot->hasItems())
+            setCurrentItem(0);
+        else
+            unsetCurrentItem();
+    }
+}
+
+void UIGraphicsSelectorModel::sltActionHovered(QAction *pAction)
+{
+    emit sigShowStatusMessage(pAction->statusTip());
+}
+
+void UIGraphicsSelectorModel::sltFocusItemDestroyed()
+{
+    AssertMsgFailed(("Focus item destroyed!"));
+}
+
+QVariant UIGraphicsSelectorModel::data(int iKey) const
+{
+    switch (iKey)
+    {
+        case SelectorModelData_Margin: return 0;
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGraphicsSelectorModel::prepareScene()
+{
+    m_pScene = new QGraphicsScene(this);
+    m_pScene->installEventFilter(this);
+}
+
+void UIGraphicsSelectorModel::prepareRoot()
+{
+    m_pRoot = new UIGSelectorItemGroup;
+    scene()->addItem(m_pRoot);
+}
+
+void UIGraphicsSelectorModel::prepareContextMenu()
+{
+    /* Context menu for empty group: */
+    m_pContextMenuRoot = new QMenu;
+    m_pContextMenuRoot->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_NewWizard));
+    m_pContextMenuRoot->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_AddDialog));
+
+    /* Context menu for group: */
+    m_pContextMenuGroup = new QMenu;
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_NewWizard));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_AddDialog));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_RemoveGroupDialog));
+    m_pContextMenuGroup->addSeparator();
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Toggle_Machine_PauseAndResume));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Reset));
+    m_pContextMenuGroup->addMenu(gActionPool->action(UIActionIndexSelector_Menu_Machine_Close)->menu());
+    m_pContextMenuGroup->addSeparator();
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndex_Simple_LogDialog));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Refresh));
+    m_pContextMenuGroup->addSeparator();
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_ShowInFileManager));
+    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_CreateShortcut));
+//    m_pContextMenuGroup->addSeparator();
+//    m_pContextMenuGroup->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Sort));
+
+    /* Context menu for machine(s): */
+    m_pContextMenuMachine = new QMenu;
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_SettingsDialog));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_CloneWizard));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_RemoveDialog));
+    m_pContextMenuMachine->addSeparator();
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_State_Machine_StartOrShow));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Toggle_Machine_PauseAndResume));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Reset));
+    m_pContextMenuMachine->addMenu(gActionPool->action(UIActionIndexSelector_Menu_Machine_Close)->menu());
+    m_pContextMenuMachine->addSeparator();
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Discard));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndex_Simple_LogDialog));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Refresh));
+    m_pContextMenuMachine->addSeparator();
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_ShowInFileManager));
+    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_CreateShortcut));
+//    m_pContextMenuMachine->addSeparator();
+//    m_pContextMenuMachine->addAction(gActionPool->action(UIActionIndexSelector_Simple_Machine_Sort));
+
+    connect(m_pContextMenuRoot, SIGNAL(hovered(QAction*)), this, SLOT(sltActionHovered(QAction*)));
+    connect(m_pContextMenuGroup, SIGNAL(hovered(QAction*)), this, SLOT(sltActionHovered(QAction*)));
+    connect(m_pContextMenuMachine, SIGNAL(hovered(QAction*)), this, SLOT(sltActionHovered(QAction*)));
+}
+
+void UIGraphicsSelectorModel::prepareHandlers()
+{
+    m_pMouseHandler = new UIGraphicsSelectorMouseHandler(this);
+    m_pKeyboardHandler = new UIGraphicsSelectorKeyboardHandler(this);
+}
+
+void UIGraphicsSelectorModel::prepareGroupTree()
+{
+    /* Load group tree: */
+    loadGroupTree();
+    /* Load order: */
+    loadGroupsOrder();
+
+    /* Update model: */
+    updateNavigation();
+    updateLayout();
+    if (m_pRoot->hasItems())
+        setCurrentItem(0);
+    else
+        unsetCurrentItem();
+}
+
+void UIGraphicsSelectorModel::cleanupGroupTree()
+{
+    /* Save group tree: */
+    saveGroupTree();
+    /* Save order: */
+    saveGroupsOrder();
+}
+
+void UIGraphicsSelectorModel::cleanupHandlers()
+{
+    delete m_pKeyboardHandler;
+    m_pKeyboardHandler = 0;
+    delete m_pMouseHandler;
+    m_pMouseHandler = 0;
+}
+
+void UIGraphicsSelectorModel::cleanupContextMenu()
+{
+    delete m_pContextMenuRoot;
+    m_pContextMenuRoot = 0;
+    delete m_pContextMenuGroup;
+    m_pContextMenuGroup = 0;
+    delete m_pContextMenuMachine;
+    m_pContextMenuMachine = 0;
+}
+
+void UIGraphicsSelectorModel::cleanupRoot()
+{
+    delete m_pRoot;
+    m_pRoot = 0;
+}
+
+void UIGraphicsSelectorModel::cleanupScene()
+{
+    delete m_pScene;
+    m_pScene = 0;
+}
+
+bool UIGraphicsSelectorModel::eventFilter(QObject *pWatched, QEvent *pEvent)
+{
+    /* Process only scene events: */
+    if (pWatched != m_pScene)
+        return QObject::eventFilter(pWatched, pEvent);
+
+    /* Process only item is focused by model, not by scene: */
+    if (scene()->focusItem())
+        return QObject::eventFilter(pWatched, pEvent);
+
+    /* Checking event-type: */
+    switch (pEvent->type())
+    {
+        /* Keyboard handler: */
+        case QEvent::KeyPress:
+            return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Press);
+        case QEvent::KeyRelease:
+            return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Release);
+        /* Mouse handler: */
+        case QEvent::GraphicsSceneMousePress:
+            return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Press);
+        case QEvent::GraphicsSceneMouseRelease:
+            return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Release);
+        case QEvent::GraphicsSceneMouseDoubleClick:
+            return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_DoubleClick);
+        /* Context menu: */
+        case QEvent::GraphicsSceneContextMenu:
+            return processContextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(pEvent));
+    }
+
+    /* Call to base-class: */
+    return QObject::eventFilter(pWatched, pEvent);
+}
+
+void UIGraphicsSelectorModel::clearRealFocus()
+{
+    /* Set real focus to null: */
+    scene()->setFocusItem(0);
+}
+
+UIVMItem* UIGraphicsSelectorModel::searchCurrentItem(const QList<UIGSelectorItem*> &list) const
+{
+    /* Iterate over all the passed items: */
+    foreach (UIGSelectorItem *pItem, list)
+    {
+        /* If item is machine, just return it: */
+        if (pItem->type() == UIGSelectorItemType_Machine)
+        {
+            if (UIGSelectorItemMachine *pMachineItem = pItem->toMachineItem())
+                return pMachineItem;
+        }
+        /* If item is group: */
+        else if (pItem->type() == UIGSelectorItemType_Group)
+        {
+            /* If it have at least one machine item: */
+            if (pItem->hasItems(UIGSelectorItemType_Machine))
+                /* Iterate over all the machine items recursively: */
+                return searchCurrentItem(pItem->items(UIGSelectorItemType_Machine));
+            /* If it have at least one group item: */
+            else if (pItem->hasItems(UIGSelectorItemType_Group))
+                /* Iterate over all the group items recursively: */
+                return searchCurrentItem(pItem->items(UIGSelectorItemType_Group));
+        }
+    }
+    return 0;
+}
+
+void UIGraphicsSelectorModel::enumerateCurrentItems(const QList<UIGSelectorItem*> &il, QList<UIVMItem*> &ol) const
+{
+    /* Enumerate all the passed items: */
+    foreach (UIGSelectorItem *pItem, il)
+    {
+        /* If item is machine, add if missed: */
+        if (pItem->type() == UIGSelectorItemType_Machine)
+        {
+            if (UIGSelectorItemMachine *pMachineItem = pItem->toMachineItem())
+                if (!contains(ol, pMachineItem))
+                    ol << pMachineItem;
+        }
+        /* If item is group: */
+        else if (pItem->type() == UIGSelectorItemType_Group)
+        {
+            /* Enumerate all the machine items recursively: */
+            enumerateCurrentItems(pItem->items(UIGSelectorItemType_Machine), ol);
+            /* Enumerate all the group items recursively: */
+            enumerateCurrentItems(pItem->items(UIGSelectorItemType_Group), ol);
+        }
+    }
+}
+
+bool UIGraphicsSelectorModel::contains(const QList<UIVMItem*> &list, UIVMItem *pItem) const
+{
+    /* Check if passed list contains passed item: */
+    foreach (UIVMItem *pIteratedItem, list)
+        if (pIteratedItem->id() == pItem->id())
+            return true;
+    return false;
+}
+
+void UIGraphicsSelectorModel::loadGroupTree()
+{
+    /* Add all the machines we have into the group-tree: */
+    foreach (const CMachine &machine, vboxGlobal().virtualBox().GetMachines())
+        addMachineIntoTheTree(machine);
+}
+
+void UIGraphicsSelectorModel::loadGroupsOrder()
+{
+    /* Load order starting form the root-item: */
+    loadGroupsOrder(m_pRoot);
+}
+
+void UIGraphicsSelectorModel::loadGroupsOrder(UIGSelectorItem *pParentItem)
+{
+    /* Prepare extra-data key for current group: */
+    QString strExtraDataKey = UIDefs::GUI_GroupDefinitions + fullName(pParentItem);
+    /* Read groups order: */
+    QStringList order = vboxGlobal().virtualBox().GetExtraDataStringList(strExtraDataKey);
+    /* Current groups list: */
+    const QList<UIGSelectorItem*> groupItems = pParentItem->items(UIGSelectorItemType_Group);
+    /* Current machine list: */
+    const QList<UIGSelectorItem*> machineItems = pParentItem->items(UIGSelectorItemType_Machine);
+    /* Iterate order list in backward direction: */
+    for (int i = order.size() - 1; i >= 0; --i)
+    {
+        /* Get current element: */
+        QString strOrderElement = order.at(i);
+        /* Get corresponding list of items: */
+        QList<UIGSelectorItem*> items;
+        QRegExp groupDescriptorRegExp("g(\\S)*=");
+        QRegExp machineDescriptorRegExp("m=");
+        if (groupDescriptorRegExp.indexIn(strOrderElement) == 0)
+            items = groupItems;
+        else if (machineDescriptorRegExp.indexIn(strOrderElement) == 0)
+            items = machineItems;
+        if (items.isEmpty())
+            continue;
+        /* Get element name: */
+        QString strElementName = strOrderElement.section('=', 1, -1);
+        /* Search for corresponding item: */
+        for (int i = 0; i < items.size(); ++i)
+        {
+            /* Get current item: */
+            UIGSelectorItem *pItem = items[i];
+            /* If item found: */
+            if (pItem->name() == strElementName)
+            {
+                /* Move it to the start of list: */
+                pParentItem->moveItemTo(pItem, 0);
+                /* If item is group: */
+                if (pItem->type() == UIGSelectorItemType_Group)
+                {
+                    /* Check descriptors we have: */
+                    QString strDescriptor(groupDescriptorRegExp.cap(1));
+                    if (strDescriptor.contains('o'))
+                        QTimer::singleShot(0, pItem, SLOT(sltOpen()));
+                }
+                break;
+            }
+        }
+    }
+    /* Update groups order for the sub-groups: */
+    foreach (UIGSelectorItem *pItem, pParentItem->items(UIGSelectorItemType_Group))
+        loadGroupsOrder(pItem);
+}
+
+void UIGraphicsSelectorModel::addMachineIntoTheTree(const CMachine &machine)
+{
+    /* Which groups current machine attached to? */
+    QVector<QString> groups = machine.GetGroups();
+    foreach (QString strGroup, groups)
+    {
+        /* Remove last '/' if any: */
+        if (strGroup.right(1) == "/")
+            strGroup.remove(strGroup.size() - 1, 1);
+        /* Search for the group item, create machine item: */
+        createMachineItem(machine, getGroupItem(strGroup, m_pRoot));
+    }
+    /* Update group definitions: */
+    m_groups[machine.GetId()] = UIStringSet::fromList(groups.toList());
+}
+
+UIGSelectorItem* UIGraphicsSelectorModel::getGroupItem(const QString &strName, UIGSelectorItem *pParent)
+{
+    /* Check passed stuff: */
+    if (pParent->name() == strName)
+        return pParent;
+
+    /* Prepare variables: */
+    QString strFirstSubName = strName.section('/', 0, 0);
+    QString strFirstSuffix = strName.section('/', 1, -1);
+    QString strSecondSubName = strFirstSuffix.section('/', 0, 0);
+    QString strSecondSuffix = strFirstSuffix.section('/', 1, -1);
+
+    /* Passed group name equal to first sub-name: */
+    if (pParent->name() == strFirstSubName)
+    {
+        /* Make sure first-suffix is NOT empty: */
+        AssertMsg(!strFirstSuffix.isEmpty(), ("Invalid group name!"));
+        /* Trying to get group item among our children: */
+        foreach (UIGSelectorItem *pGroupItem, pParent->items(UIGSelectorItemType_Group))
+            if (pGroupItem->name() == strSecondSubName)
+                return getGroupItem(strFirstSuffix, pGroupItem);
+    }
+
+    /* Found nothing? Creating: */
+    UIGSelectorItemGroup *pNewGroupItem = new UIGSelectorItemGroup(pParent, strSecondSubName);
+    return strSecondSuffix.isEmpty() ? pNewGroupItem : getGroupItem(strFirstSuffix, pNewGroupItem);
+}
+
+void UIGraphicsSelectorModel::createMachineItem(const CMachine &machine, UIGSelectorItem *pWhere)
+{
+    /* Create corresponding item: */
+    new UIGSelectorItemMachine(pWhere, machine);
+}
+
+void UIGraphicsSelectorModel::saveGroupTree()
+{
+    /* Prepare machine map: */
+    QMap<QString, QStringList> groups;
+    /* Iterate over all the items: */
+    gatherGroupTree(groups, m_pRoot);
+    /* Saving groups: */
+    foreach (const QString &strId, groups.keys())
+    {
+        /* Get new group list: */
+        const QStringList &newGroupList = groups.value(strId);
+        /* Get old group set: */
+        AssertMsg(m_groups.contains(strId), ("Invalid group set!"));
+        const UIStringSet &oldGroupSet = m_groups.value(strId);
+        /* Get new group set: */
+        const UIStringSet &newGroupSet = UIStringSet::fromList(newGroupList);
+        /* Is group set changed? */
+        if (oldGroupSet != newGroupSet)
+        {
+            /* Open session to save machine settings: */
+            CSession session = vboxGlobal().openSession(strId);
+            if (session.isNull())
+                return;
+            /* Get machine: */
+            CMachine machine = session.GetMachine();
+            /* Save groups: */
+            printf(" Saving groups for machine {%s}: {%s}\n",
+                   machine.GetName().toAscii().constData(),
+                   newGroupList.join(",").toAscii().constData());
+            machine.SetGroups(newGroupList.toVector());
+            machine.SaveSettings();
+            if (!machine.isOk())
+                msgCenter().cannotSaveMachineSettings(machine);
+            /* Close the session: */
+            session.UnlockMachine();
+        }
+    }
+}
+
+void UIGraphicsSelectorModel::saveGroupsOrder()
+{
+    /* Clear all the extra-data records related to group-definitions: */
+    const QVector<QString> extraDataKeys = vboxGlobal().virtualBox().GetExtraDataKeys();
+    foreach (const QString &strKey, extraDataKeys)
+        if (strKey.startsWith(UIDefs::GUI_GroupDefinitions))
+            vboxGlobal().virtualBox().SetExtraData(strKey, QString());
+    /* Save order starting from the root-item: */
+    saveGroupsOrder(m_pRoot);
+}
+
+void UIGraphicsSelectorModel::saveGroupsOrder(UIGSelectorItem *pParentItem)
+{
+    /* Prepare extra-data key for current group: */
+    QString strExtraDataKey = UIDefs::GUI_GroupDefinitions + fullName(pParentItem);
+    /* Gather item order: */
+    QStringList order;
+    foreach (UIGSelectorItem *pItem, pParentItem->items(UIGSelectorItemType_Group))
+    {
+        saveGroupsOrder(pItem);
+        QString strGroupDescriptor(pItem->toGroupItem()->opened() ? "go" : "gc");
+        order << QString("%1=%2").arg(strGroupDescriptor, pItem->name());
+    }
+    foreach (UIGSelectorItem *pItem, pParentItem->items(UIGSelectorItemType_Machine))
+        order << QString("m=%1").arg(pItem->name());
+    vboxGlobal().virtualBox().SetExtraDataStringList(strExtraDataKey, order);
+}
+
+void UIGraphicsSelectorModel::gatherGroupTree(QMap<QString, QStringList> &groups,
+                                              UIGSelectorItem *pParentGroup)
+{
+    /* Iterate over all the machine items: */
+    foreach (UIGSelectorItem *pItem, pParentGroup->items(UIGSelectorItemType_Machine))
+        if (UIGSelectorItemMachine *pMachineItem = pItem->toMachineItem())
+            groups[pMachineItem->id()] << fullName(pParentGroup);
+    /* Iterate over all the group items: */
+    foreach (UIGSelectorItem *pItem, pParentGroup->items(UIGSelectorItemType_Group))
+        gatherGroupTree(groups, pItem);
+}
+
+QString UIGraphicsSelectorModel::fullName(UIGSelectorItem *pItem)
+{
+    /* Return '/' for root-group: */
+    if (!pItem->parentItem())
+        return QString("/");
+    /* Get full parent name, append with '/' if not yet appended: */
+    QString strParentFullName = fullName(pItem->parentItem());
+    if (!strParentFullName.endsWith("/"))
+        strParentFullName += QString("/");
+    /* Return full item name based on parent prefix: */
+    return strParentFullName + pItem->name();
+}
+
+void UIGraphicsSelectorModel::updateGroupTree(UIGSelectorItem *pGroupItem)
+{
+    /* Cleanup all the group items first: */
+    foreach (UIGSelectorItem *pSubGroupItem, pGroupItem->items(UIGSelectorItemType_Group))
+        updateGroupTree(pSubGroupItem);
+    /* Cleanup only non-root items: */
+    if (pGroupItem->parentItem() && !pGroupItem->hasItems())
+        delete pGroupItem;
+}
+
+QList<UIGSelectorItem*> UIGraphicsSelectorModel::createNavigationList(UIGSelectorItem *pItem)
+{
+    /* Prepare navigation list: */
+    QList<UIGSelectorItem*> navigationItems;
+
+    /* Iterate over all the group items: */
+    foreach (UIGSelectorItem *pGroupItem, pItem->items(UIGSelectorItemType_Group))
+    {
+        navigationItems << pGroupItem;
+        if (pGroupItem->toGroupItem()->opened())
+            navigationItems << createNavigationList(pGroupItem);
+    }
+    /* Iterate over all the machine items: */
+    foreach (UIGSelectorItem *pMachineItem, pItem->items(UIGSelectorItemType_Machine))
+        navigationItems << pMachineItem;
+
+    /* Return navigation list: */
+    return navigationItems;
+}
+
+void UIGraphicsSelectorModel::updateMachineItems(const QString &strId, UIGSelectorItem *pParent)
+{
+    /* For each group item in passed parent: */
+    foreach (UIGSelectorItem *pItem, pParent->items(UIGSelectorItemType_Group))
+        updateMachineItems(strId, pItem->toGroupItem());
+    /* For each machine item in passed parent: */
+    foreach (UIGSelectorItem *pItem, pParent->items(UIGSelectorItemType_Machine))
+        if (UIGSelectorItemMachine *pMachineItem = pItem->toMachineItem())
+            if (pMachineItem->id() == strId)
+            {
+                pMachineItem->recache();
+                pMachineItem->update();
+            }
+}
+
+void UIGraphicsSelectorModel::removeMachineItems(const QString &strId, UIGSelectorItem *pParent)
+{
+    /* For each group item in passed parent: */
+    foreach (UIGSelectorItem *pItem, pParent->items(UIGSelectorItemType_Group))
+        removeMachineItems(strId, pItem->toGroupItem());
+    /* For each machine item in passed parent: */
+    foreach (UIGSelectorItem *pItem, pParent->items(UIGSelectorItemType_Machine))
+        if (pItem->toMachineItem()->id() == strId)
+            delete pItem;
+}
+
+UIGSelectorItem* UIGraphicsSelectorModel::getMachineItem(const QString &strId, UIGSelectorItem *pParent)
+{
+    /* Search among all the machine items of passed parent: */
+    foreach (UIGSelectorItem *pItem, pParent->items(UIGSelectorItemType_Machine))
+        if (UIGSelectorItemMachine *pMachineItem = pItem->toMachineItem())
+            if (pMachineItem->id() == strId)
+                return pMachineItem;
+    /* Search among all the group items of passed parent: */
+    foreach (UIGSelectorItem *pItem, pParent->items(UIGSelectorItemType_Group))
+        if (UIGSelectorItem *pMachineItem = getMachineItem(strId, pItem))
+            return pMachineItem;
+    /* Nothing found? */
+    return 0;
+}
+
+bool UIGraphicsSelectorModel::processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent)
+{
+    /* Whats the reason? */
+    switch (pEvent->reason())
+    {
+        case QGraphicsSceneContextMenuEvent::Mouse:
+        {
+            /* First of all we should look for an item under cursor: */
+            if (QGraphicsItem *pItem = itemAt(pEvent->scenePos()))
+            {
+                /* If this item of known type? */
+                switch (pItem->type())
+                {
+                    case UIGSelectorItemType_Group:
+                    {
+                        /* Get group item: */
+                        UIGSelectorItem *pGroupItem = qgraphicsitem_cast<UIGSelectorItemGroup*>(pItem);
+                        /* Is this group item only the one selected? */
+                        if (selectionList().contains(pGroupItem) && selectionList().size() == 1)
+                        {
+                            /* Group context menu in that case: */
+                            popupContextMenu(UIGraphicsSelectorContextMenuType_Group, pEvent->screenPos());
+                            return true;
+                        }
+                        /* Is this root-group item? */
+                        else if (!pGroupItem->parentItem())
+                        {
+                            /* Root context menu in that cases: */
+                            popupContextMenu(UIGraphicsSelectorContextMenuType_Root, pEvent->screenPos());
+                            return true;
+                        }
+                    }
+                    case UIGSelectorItemType_Machine:
+                    {
+                        /* Machine context menu for other Group/Machine cases: */
+                        popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
+                        return true;
+                    }
+                    default:
+                        break;
+                }
+            }
+            /* Root context menu for all the other cases: */
+            popupContextMenu(UIGraphicsSelectorContextMenuType_Root, pEvent->screenPos());
+            return true;
+        }
+        case QGraphicsSceneContextMenuEvent::Keyboard:
+        {
+            /* Get first selected item: */
+            if (UIGSelectorItem *pItem = selectionList().first())
+            {
+                /* If this item of known type? */
+                switch (pItem->type())
+                {
+                    case UIGSelectorItemType_Group:
+                    {
+                        /* Is this group item only the one selected? */
+                        if (selectionList().size() == 1)
+                        {
+                            /* Group context menu in that case: */
+                            popupContextMenu(UIGraphicsSelectorContextMenuType_Group, pEvent->screenPos());
+                            return true;
+                        }
+                    }
+                    case UIGSelectorItemType_Machine:
+                    {
+                        /* Machine context menu for other Group/Machine cases: */
+                        popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
+                        return true;
+                    }
+                    default:
+                        break;
+                }
+            }
+            /* Root context menu for all the other cases: */
+            popupContextMenu(UIGraphicsSelectorContextMenuType_Root, pEvent->screenPos());
+            return true;
+        }
+        default:
+            break;
+    }
+    /* Pass others context menu events: */
+    return false;
+}
+
+void UIGraphicsSelectorModel::popupContextMenu(UIGraphicsSelectorContextMenuType type, QPoint point)
+{
+    /* Which type of context-menu requested? */
+    switch (type)
+    {
+        /* For empty group? */
+        case UIGraphicsSelectorContextMenuType_Root:
+        {
+            m_pContextMenuRoot->exec(point);
+            break;
+        }
+        /* For group? */
+        case UIGraphicsSelectorContextMenuType_Group:
+        {
+            m_pContextMenuGroup->exec(point);
+            break;
+        }
+        /* For machine(s)? */
+        case UIGraphicsSelectorContextMenuType_Machine:
+        {
+            m_pContextMenuMachine->exec(point);
+            break;
+        }
+    }
+    /* Clear status-bar: */
+    emit sigClearStatusMessage();
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorModel.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorModel.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorModel.h	(revision 42529)
@@ -0,0 +1,232 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorModel class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGraphicsSelectorModel_h__
+#define __UIGraphicsSelectorModel_h__
+
+/* Qt includes: */
+#include <QObject>
+#include <QPointer>
+#include <QTransform>
+#include <QMap>
+#include <QSet>
+
+/* COM includes: */
+#include "COMEnums.h"
+
+/* Forward declaration: */
+class QGraphicsScene;
+class QGraphicsItem;
+class QDrag;
+class QMenu;
+class QAction;
+class QGraphicsSceneContextMenuEvent;
+class CMachine;
+class UIGSelectorItem;
+class UIVMItem;
+class UIGraphicsSelectorMouseHandler;
+class UIGraphicsSelectorKeyboardHandler;
+
+/* Type defs: */
+typedef QSet<QString> UIStringSet;
+
+/* Context-menu type: */
+enum UIGraphicsSelectorContextMenuType
+{
+    UIGraphicsSelectorContextMenuType_Root,
+    UIGraphicsSelectorContextMenuType_Group,
+    UIGraphicsSelectorContextMenuType_Machine
+};
+
+/* Graphics selector model: */
+class UIGraphicsSelectorModel : public QObject
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notify listeners about root-item height changed: */
+    void sigRootItemResized(const QSizeF &size, int iMinimumWidth);
+
+    /* Notify listeners about selection change: */
+    void sigSelectionChanged();
+
+    /* Notify listeners to show corresponding status-bar message: */
+    void sigClearStatusMessage();
+    void sigShowStatusMessage(const QString &strStatusMessage);
+
+public:
+
+    /* Constructor/destructor: */
+    UIGraphicsSelectorModel(QObject *pParent);
+    ~UIGraphicsSelectorModel();
+
+    /* API: Load/save stuff: */
+    void load();
+    void save();
+
+    /* API: Scene getter: */
+    QGraphicsScene* scene() const;
+
+    /* API: Current item stuff: */
+    void setCurrentItem(int iItemIndex);
+    void setCurrentItem(UIGSelectorItem *pItem);
+    void unsetCurrentItem();
+    UIVMItem* currentItem() const;
+    QList<UIVMItem*> currentItems() const;
+
+    /* API: Focus item stuff: */
+    void setFocusItem(UIGSelectorItem *pItem, bool fWithSelection = false);
+    UIGSelectorItem* focusItem() const;
+
+    /* API: Positioning item stuff: */
+    QGraphicsItem* itemAt(const QPointF &position, const QTransform &deviceTransform = QTransform()) const;
+
+    /* API: Update stuff: */
+    void updateGroupTree();
+
+    /* API: Navigation stuff: */
+    const QList<UIGSelectorItem*>& navigationList() const;
+    void removeFromNavigationList(UIGSelectorItem *pItem);
+    void clearNavigationList();
+    void updateNavigation();
+
+    /* API: Selection stuff: */
+    const QList<UIGSelectorItem*>& selectionList() const;
+    void addToSelectionList(UIGSelectorItem *pItem);
+    void removeFromSelectionList(UIGSelectorItem *pItem);
+    void clearSelectionList();
+    void notifySelectionChanged();
+
+    /* API: Layout stuff: */
+    void updateLayout();
+
+    /* API: Drag and drop stuff: */
+    void setCurrentDragObject(QDrag *pDragObject);
+
+    /* API: Activate stuff: */
+    void activate();
+
+private slots:
+
+    /* Handlers: Global events: */
+    void sltMachineStateChanged(QString strId, KMachineState state);
+    void sltMachineDataChanged(QString strId);
+    void sltMachineRegistered(QString strId, bool fRegistered);
+    void sltSessionStateChanged(QString strId, KSessionState state);
+    void sltSnapshotChanged(QString strId, QString strSnapshotId);
+
+    /* Handler: View-resize: */
+    void sltHandleViewResized();
+
+    /* Handler: Drag object destruction: */
+    void sltCurrentDragObjectDestroyed();
+
+    /* Handler: Remove currently selected group: */
+    void sltRemoveCurrentlySelectedGroup();
+
+    /* Handler: Context menu hovering: */
+    void sltActionHovered(QAction *pAction);
+
+    /* Handler: Focus item destruction: */
+    void sltFocusItemDestroyed();
+
+private:
+
+    /* Data enumerator: */
+    enum SelectorModelData
+    {
+        /* Layout hints: */
+        SelectorModelData_Margin
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Helpers: Prepare stuff: */
+    void prepareScene();
+    void prepareRoot();
+    void prepareContextMenu();
+    void prepareHandlers();
+    void prepareGroupTree();
+
+    /* Helpers: Cleanup stuff: */
+    void cleanupGroupTree();
+    void cleanupHandlers();
+    void cleanupContextMenu();
+    void cleanupRoot();
+    void cleanupScene();
+
+    /* Event handlers: */
+    bool eventFilter(QObject *pWatched, QEvent *pEvent);
+
+    /* Helpers: Focus item stuff: */
+    void clearRealFocus();
+
+    /* Helpers: Current item stuff: */
+    UIVMItem* searchCurrentItem(const QList<UIGSelectorItem*> &list) const;
+    void enumerateCurrentItems(const QList<UIGSelectorItem*> &il, QList<UIVMItem*> &ol) const;
+    bool contains(const QList<UIVMItem*> &list, UIVMItem *pItem) const;
+
+    /* Helpers: Loading: */
+    void loadGroupTree();
+    void loadGroupsOrder();
+    void loadGroupsOrder(UIGSelectorItem *pParentItem);
+    void addMachineIntoTheTree(const CMachine &machine);
+    UIGSelectorItem* getGroupItem(const QString &strName, UIGSelectorItem *pParent);
+    void createMachineItem(const CMachine &machine, UIGSelectorItem *pWhere);
+
+    /* Helpers: Saving: */
+    void saveGroupTree();
+    void saveGroupsOrder();
+    void saveGroupsOrder(UIGSelectorItem *pParentItem);
+    void gatherGroupTree(QMap<QString, QStringList> &groups, UIGSelectorItem *pParentGroup);
+    QString fullName(UIGSelectorItem *pItem);
+
+    /* Helpers: Update stuff: */
+    void updateGroupTree(UIGSelectorItem *pGroupItem);
+
+    /* Helpers: Navigation stuff: */
+    QList<UIGSelectorItem*> createNavigationList(UIGSelectorItem *pItem);
+
+    /* Helpers: Global event stuff: */
+    void updateMachineItems(const QString &strId, UIGSelectorItem *pParent);
+    void removeMachineItems(const QString &strId, UIGSelectorItem *pParent);
+    UIGSelectorItem* getMachineItem(const QString &strId, UIGSelectorItem *pParent);
+
+    /* Helpers: Context menu stuff: */
+    bool processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent);
+    void popupContextMenu(UIGraphicsSelectorContextMenuType type, QPoint point);
+
+    /* Variables: */
+    QGraphicsScene *m_pScene;
+    UIGSelectorItem *m_pRoot;
+    QMap<QString, UIStringSet> m_groups;
+    QList<UIGSelectorItem*> m_navigationList;
+    QList<UIGSelectorItem*> m_selectionList;
+    UIGraphicsSelectorMouseHandler *m_pMouseHandler;
+    UIGraphicsSelectorKeyboardHandler *m_pKeyboardHandler;
+    QPointer<QDrag> m_pCurrentDragObject;
+    QPointer<UIGSelectorItem> m_pFocusItem;
+    QMenu *m_pContextMenuRoot;
+    QMenu *m_pContextMenuGroup;
+    QMenu *m_pContextMenuMachine;
+};
+
+#endif /* __UIGraphicsSelectorModel_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorMouseHandler.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorMouseHandler.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorMouseHandler.cpp	(revision 42529)
@@ -0,0 +1,223 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorMouseHandler class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsSceneMouseEvent>
+
+/* GUI incluedes: */
+#include "UIGraphicsSelectorMouseHandler.h"
+#include "UIGraphicsSelectorModel.h"
+#include "UIGSelectorItemGroup.h"
+#include "UIGSelectorItemMachine.h"
+
+UIGraphicsSelectorMouseHandler::UIGraphicsSelectorMouseHandler(UIGraphicsSelectorModel *pParent)
+    : QObject(pParent)
+    , m_pModel(pParent)
+{
+}
+
+bool UIGraphicsSelectorMouseHandler::handle(QGraphicsSceneMouseEvent *pEvent, UIMouseEventType type) const
+{
+    /* Process passed event: */
+    switch (type)
+    {
+        case UIMouseEventType_Press: return handleMousePress(pEvent);
+        case UIMouseEventType_Release: return handleMouseRelease(pEvent);
+        case UIMouseEventType_DoubleClick: return handleMouseDoubleClick(pEvent);
+    }
+    /* Pass event if unknown: */
+    return false;
+}
+
+UIGraphicsSelectorModel* UIGraphicsSelectorMouseHandler::model() const
+{
+    return m_pModel;
+}
+
+bool UIGraphicsSelectorMouseHandler::handleMousePress(QGraphicsSceneMouseEvent *pEvent) const
+{
+    /* Get item under mouse cursor: */
+    QPointF scenePos = pEvent->scenePos();
+    if (QGraphicsItem *pItemUnderMouse = model()->itemAt(scenePos))
+    {
+        /* Which button it was? */
+        switch (pEvent->button())
+        {
+            /* Left one? */
+            case Qt::LeftButton:
+            {
+                /* Which item we just clicked? */
+                UIGSelectorItem *pClickedItem = 0;
+                /* Was that a group item? */
+                if (UIGSelectorItemGroup *pGroupItem = qgraphicsitem_cast<UIGSelectorItemGroup*>(pItemUnderMouse))
+                    pClickedItem = pGroupItem;
+                /* Or a machine one? */
+                else if (UIGSelectorItemMachine *pMachineItem = qgraphicsitem_cast<UIGSelectorItemMachine*>(pItemUnderMouse))
+                    pClickedItem = pMachineItem;
+                /* If we had clicked one of the required item types: */
+                if (pClickedItem)
+                {
+                    /* For non-root items: */
+                    if (pClickedItem->parentItem())
+                    {
+                        /* Move focus to clicked item: */
+                        model()->setFocusItem(pClickedItem);
+                        /* Was 'shift' modifier pressed? */
+                        if (pEvent->modifiers() == Qt::ShiftModifier)
+                        {
+                            /* Calculate positions: */
+                            UIGSelectorItem *pFirstItem = model()->selectionList().first();
+                            int iFirstPosition = model()->navigationList().indexOf(pFirstItem);
+                            int iClickedPosition = model()->navigationList().indexOf(pClickedItem);
+                            /* Clear selection: */
+                            model()->clearSelectionList();
+                            /* Select all the items from 'first' to 'clicked': */
+                            if (iFirstPosition <= iClickedPosition)
+                                for (int i = iFirstPosition; i <= iClickedPosition; ++i)
+                                    model()->addToSelectionList(model()->navigationList().at(i));
+                            else
+                                for (int i = iFirstPosition; i >= iClickedPosition; --i)
+                                    model()->addToSelectionList(model()->navigationList().at(i));
+                        }
+                        /* Was 'control' modifier pressed? */
+                        else if (pEvent->modifiers() == Qt::ControlModifier)
+                        {
+                            /* Select clicked item, inverting if necessary: */
+                            if (model()->selectionList().contains(pClickedItem))
+                                model()->removeFromSelectionList(pClickedItem);
+                            else
+                                model()->addToSelectionList(pClickedItem);
+                        }
+                        /* Was no modifiers pressed? */
+                        else if (pEvent->modifiers() == Qt::NoModifier)
+                        {
+                            /* Move selection to clicked item: */
+                            model()->clearSelectionList();
+                            model()->addToSelectionList(pClickedItem);
+                        }
+                        /* Notify selection changed: */
+                        model()->notifySelectionChanged();
+                    }
+                }
+                break;
+            }
+            /* Right one? */
+            case Qt::RightButton:
+            {
+                /* Which item we just clicked? */
+                UIGSelectorItem *pClickedItem = 0;
+                /* Was that a group item? */
+                if (UIGSelectorItemGroup *pGroupItem = qgraphicsitem_cast<UIGSelectorItemGroup*>(pItemUnderMouse))
+                    pClickedItem = pGroupItem;
+                /* Or a machine one? */
+                else if (UIGSelectorItemMachine *pMachineItem = qgraphicsitem_cast<UIGSelectorItemMachine*>(pItemUnderMouse))
+                    pClickedItem = pMachineItem;
+                /* If we had clicked one of the required item types: */
+                if (pClickedItem)
+                {
+                    /* For non-root items: */
+                    if (pClickedItem->parentItem())
+                    {
+                        /* Is clicked item in selection list: */
+                        bool fIsClickedItemInSelectionList = contains(model()->selectionList(), pClickedItem);
+                        /* Move focus to clicked item (with selection if not selected yet): */
+                        model()->setFocusItem(pClickedItem, !fIsClickedItemInSelectionList);
+                    }
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    /* Pass all other events: */
+    return false;
+}
+
+bool UIGraphicsSelectorMouseHandler::handleMouseRelease(QGraphicsSceneMouseEvent*) const
+{
+    /* Pass all events: */
+    return false;
+}
+
+bool UIGraphicsSelectorMouseHandler::handleMouseDoubleClick(QGraphicsSceneMouseEvent *pEvent) const
+{
+    /* Get item under mouse cursor: */
+    QPointF scenePos = pEvent->scenePos();
+    if (QGraphicsItem *pItemUnderMouse = model()->itemAt(scenePos))
+    {
+        /* Which button it was? */
+        switch (pEvent->button())
+        {
+            /* Left one? */
+            case Qt::LeftButton:
+            {
+                /* Was that a group item? */
+                if (UIGSelectorItemGroup *pGroupItem = qgraphicsitem_cast<UIGSelectorItemGroup*>(pItemUnderMouse))
+                {
+                    /* Toggle group item: */
+                    if (pGroupItem->opened())
+                        pGroupItem->close();
+                    else if (pGroupItem->closed())
+                        pGroupItem->open();
+                    /* Filter that event out: */
+                    return true;
+                }
+                /* Or a machine one? */
+                else if (qgraphicsitem_cast<UIGSelectorItemMachine*>(pItemUnderMouse))
+                {
+                    /* Activate machine item: */
+                    model()->activate();
+                    /* Filter that event out: */
+                    return true;
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    /* Pass all other events: */
+    return false;
+}
+
+bool UIGraphicsSelectorMouseHandler::contains(QList<UIGSelectorItem*> list,
+                                              UIGSelectorItem *pRequiredItem,
+                                              bool fRecursively /* = false */) const
+{
+    /* Search throught the all passed list items: */
+    foreach (UIGSelectorItem *pItem, list)
+    {
+        /* Check item first: */
+        if (pItem == pRequiredItem)
+            return true;
+        /* Check if this item supports children: */
+        if (fRecursively && pItem->type() == UIGSelectorItemType_Group)
+        {
+            /* Check machine items recursively: */
+            if (contains(pItem->items(UIGSelectorItemType_Machine), pRequiredItem))
+                return true;
+            /* Check group items recursively: */
+            if (contains(pItem->items(UIGSelectorItemType_Group), pRequiredItem))
+                return true;
+        }
+    }
+    return false;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorMouseHandler.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorMouseHandler.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorMouseHandler.h	(revision 42529)
@@ -0,0 +1,69 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorMouseHandler class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGraphicsSelectorMouseHandler_h__
+#define __UIGraphicsSelectorMouseHandler_h__
+
+/* Qt includes: */
+#include <QObject>
+
+/* Forward declarations: */
+class UIGraphicsSelectorModel;
+class QGraphicsSceneMouseEvent;
+class UIGSelectorItem;
+
+/* Mouse event type: */
+enum UIMouseEventType
+{
+    UIMouseEventType_Press,
+    UIMouseEventType_Release,
+    UIMouseEventType_DoubleClick
+};
+
+/* Mouse handler for graphics selector: */
+class UIGraphicsSelectorMouseHandler : public QObject
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGraphicsSelectorMouseHandler(UIGraphicsSelectorModel *pParent);
+
+    /* API: Model mouse-event handler delegate: */
+    bool handle(QGraphicsSceneMouseEvent *pEvent, UIMouseEventType type) const;
+
+private:
+
+    /* Model wrapper: */
+    UIGraphicsSelectorModel* model() const;
+
+    /* Helpers: Model mouse-event handler delegates: */
+    bool handleMousePress(QGraphicsSceneMouseEvent *pEvent) const;
+    bool handleMouseRelease(QGraphicsSceneMouseEvent *pEvent) const;
+    bool handleMouseDoubleClick(QGraphicsSceneMouseEvent *pEvent) const;
+
+    /* Helpers: Others: */
+    bool contains(QList<UIGSelectorItem*> list, UIGSelectorItem *pRequiredItem, bool fRecursively = false) const;
+
+    /* Variables: */
+    UIGraphicsSelectorModel *m_pModel;
+};
+
+#endif /* __UIGraphicsSelectorMouseHandler_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorView.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorView.cpp	(revision 42529)
@@ -0,0 +1,59 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorView class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* GUI includes: */
+#include "UIGraphicsSelectorView.h"
+#include "UIGraphicsSelectorModel.h"
+
+UIGraphicsSelectorView::UIGraphicsSelectorView(QWidget *pParent)
+    : QGraphicsView(pParent)
+{
+    /* Scrollbars policy: */
+    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+    /* Update scene-rect: */
+    updateSceneRect();
+}
+
+void UIGraphicsSelectorView::sltHandleRootItemResized(const QSizeF &size, int iMinimumWidth)
+{
+    /* Update scene-rect: */
+    updateSceneRect(size);
+
+    /* Set minimum width: */
+    setMinimumWidth(2 * frameWidth() + iMinimumWidth + 10);
+}
+
+void UIGraphicsSelectorView::resizeEvent(QResizeEvent*)
+{
+    /* Update scene-rect: */
+    updateSceneRect();
+    /* Notify listeners: */
+    emit sigResized();
+}
+
+void UIGraphicsSelectorView::updateSceneRect(const QSizeF &sizeHint /* = QSizeF() */)
+{
+    QPointF topLeft = QPointF(0, 0);
+    QSizeF rectSize = viewport()->size();
+    if (!sizeHint.isNull())
+        rectSize = rectSize.expandedTo(sizeHint);
+    setSceneRect(QRectF(topLeft, rectSize));
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorView.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorView.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsSelectorView.h	(revision 42529)
@@ -0,0 +1,59 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsSelectorView class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGraphicsSelectorView_h__
+#define __UIGraphicsSelectorView_h__
+
+/* Qt includes: */
+#include <QGraphicsView>
+
+/* Forward declaration: */
+class UIGraphicsSelectorModel;
+class QKeyEvent;
+
+/* Graphics selector view: */
+class UIGraphicsSelectorView : public QGraphicsView
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notify listeners about size change: */
+    void sigResized();
+
+public:
+
+    /* Constructor: */
+    UIGraphicsSelectorView(QWidget *pParent);
+
+private slots:
+
+    /* Handles root item height change: */
+    void sltHandleRootItemResized(const QSizeF &size, int iMinimumWidth);
+
+private:
+
+    /* Resize-event handler: */
+    void resizeEvent(QResizeEvent *pEvent);
+
+    /* Helpers: */
+    void updateSceneRect(const QSizeF &sizeHint = QSizeF());
+};
+
+#endif /* __UIGraphicsSelectorView_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsViewChooser.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsViewChooser.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsViewChooser.cpp	(revision 42529)
@@ -0,0 +1,123 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsViewChooser class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QVBoxLayout>
+#include <QStatusBar>
+
+/* GUI includes: */
+#include "UIGraphicsViewChooser.h"
+#include "UIGraphicsSelectorModel.h"
+#include "UIGraphicsSelectorView.h"
+#include "UIVirtualBoxEventHandler.h"
+#include "UIIconPool.h"
+#include "UIActionPoolSelector.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+#include "CMachine.h"
+
+UIGraphicsViewChooser::UIGraphicsViewChooser(QWidget *pParent)
+    : QWidget(pParent)
+    , m_pMainLayout(0)
+    , m_pSelectorModel(0)
+    , m_pSelectorView(0)
+    , m_pStatusBar(0)
+{
+    /* Create main-layout: */
+    m_pMainLayout = new QVBoxLayout(this);
+    m_pMainLayout->setContentsMargins(0, 0, 0, 0);
+    m_pMainLayout->setSpacing(0);
+
+    /* Create selector-model: */
+    m_pSelectorModel = new UIGraphicsSelectorModel(this);
+
+    /* Create selector-view: */
+    m_pSelectorView = new UIGraphicsSelectorView(this);
+    m_pSelectorView->setFrameShape(QFrame::NoFrame);
+    m_pSelectorView->setFrameShadow(QFrame::Plain);
+    m_pSelectorView->setScene(m_pSelectorModel->scene());
+    m_pSelectorView->show();
+    setFocusProxy(m_pSelectorView);
+
+    /* Add tool-bar into layout: */
+    m_pMainLayout->addWidget(m_pSelectorView);
+
+    /* Prepare connections: */
+    prepareConnections();
+
+    /* Load model: */
+    m_pSelectorModel->load();
+}
+
+UIGraphicsViewChooser::~UIGraphicsViewChooser()
+{
+    /* Save model: */
+    m_pSelectorModel->save();
+}
+
+void UIGraphicsViewChooser::setCurrentItem(int iCurrentItemIndex)
+{
+    m_pSelectorModel->setCurrentItem(iCurrentItemIndex);
+}
+
+UIVMItem* UIGraphicsViewChooser::currentItem() const
+{
+    return m_pSelectorModel->currentItem();
+}
+
+QList<UIVMItem*> UIGraphicsViewChooser::currentItems() const
+{
+    return m_pSelectorModel->currentItems();
+}
+
+void UIGraphicsViewChooser::setStatusBar(QStatusBar *pStatusBar)
+{
+    /* Old status-bar set? */
+    if (m_pStatusBar)
+       m_pSelectorModel->disconnect(m_pStatusBar);
+
+    /* Connect new status-bar: */
+    m_pStatusBar = pStatusBar;
+    connect(m_pSelectorModel, SIGNAL(sigClearStatusMessage()), m_pStatusBar, SLOT(clearMessage()));
+    connect(m_pSelectorModel, SIGNAL(sigShowStatusMessage(const QString&)), m_pStatusBar, SLOT(showMessage(const QString&)));
+}
+
+void UIGraphicsViewChooser::prepareConnections()
+{
+    /* Selector-model connections: */
+    connect(m_pSelectorModel, SIGNAL(sigRootItemResized(const QSizeF&, int)),
+            m_pSelectorView, SLOT(sltHandleRootItemResized(const QSizeF&, int)));
+    connect(m_pSelectorModel, SIGNAL(sigSelectionChanged()), this, SIGNAL(sigSelectionChanged()));
+
+    /* Selector-view connections: */
+    connect(m_pSelectorView, SIGNAL(sigResized()), m_pSelectorModel, SLOT(sltHandleViewResized()));
+
+    /* Global connections: */
+    connect(gVBoxEvents, SIGNAL(sigMachineStateChange(QString, KMachineState)), m_pSelectorModel, SLOT(sltMachineStateChanged(QString, KMachineState)));
+    connect(gVBoxEvents, SIGNAL(sigMachineDataChange(QString)), m_pSelectorModel, SLOT(sltMachineDataChanged(QString)));
+    connect(gVBoxEvents, SIGNAL(sigMachineRegistered(QString, bool)), m_pSelectorModel, SLOT(sltMachineRegistered(QString, bool)));
+    connect(gVBoxEvents, SIGNAL(sigSessionStateChange(QString, KSessionState)), m_pSelectorModel, SLOT(sltSessionStateChanged(QString, KSessionState)));
+    connect(gVBoxEvents, SIGNAL(sigSnapshotChange(QString, QString)), m_pSelectorModel, SLOT(sltSnapshotChanged(QString, QString)));
+
+    /* Context menu connections: */
+    connect(gActionPool->action(UIActionIndexSelector_Simple_Machine_RemoveGroupDialog), SIGNAL(triggered()),
+            m_pSelectorModel, SLOT(sltRemoveCurrentlySelectedGroup()));
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsViewChooser.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsViewChooser.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGraphicsViewChooser.h	(revision 42529)
@@ -0,0 +1,72 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGraphicsViewChooser class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGraphicsViewChooser_h__
+#define __UIGraphicsViewChooser_h__
+
+/* Qt includes: */
+#include <QWidget>
+
+/* GUI includes: */
+#include "UIGSelectorItem.h"
+
+/* Forward declartions: */
+class UIVMItem;
+class QVBoxLayout;
+class UIGraphicsSelectorModel;
+class UIGraphicsSelectorView;
+class QStatusBar;
+
+/* Graphics selector widget: */
+class UIGraphicsViewChooser : public QWidget
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notify listeners about selection changes: */
+    void sigSelectionChanged();
+
+public:
+
+    /* Constructor/destructor: */
+    UIGraphicsViewChooser(QWidget *pParent);
+    ~UIGraphicsViewChooser();
+
+    /* API: Current item stuff: */
+    void setCurrentItem(int iCurrentItemIndex);
+    UIVMItem* currentItem() const;
+    QList<UIVMItem*> currentItems() const;
+
+    /* API: Status bar stuff: */
+    void setStatusBar(QStatusBar *pStatusBar);
+
+private:
+
+    /* Helpers: */
+    void prepareConnections();
+
+    /* Variables: */
+    QVBoxLayout *m_pMainLayout;
+    UIGraphicsSelectorModel *m_pSelectorModel;
+    UIGraphicsSelectorView *m_pSelectorView;
+    QStatusBar *m_pStatusBar;
+};
+
+#endif /* __UIGraphicsViewChooser_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetails.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetails.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetails.cpp	(revision 42529)
@@ -0,0 +1,73 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetails class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QVBoxLayout>
+
+/* GUI includes: */
+#include "UIGDetails.h"
+#include "UIGDetailsModel.h"
+#include "UIGDetailsView.h"
+
+UIGDetails::UIGDetails(QWidget *pParent)
+    : QWidget(pParent)
+    , m_pMainLayout(0)
+    , m_pDetailsModel(0)
+    , m_pDetailsView(0)
+{
+    /* Create main-layout: */
+    m_pMainLayout = new QVBoxLayout(this);
+    m_pMainLayout->setContentsMargins(0, 0, 0, 0);
+    m_pMainLayout->setSpacing(0);
+
+    /* Create details-model: */
+    m_pDetailsModel = new UIGDetailsModel(this);
+
+    /* Create details-view: */
+    m_pDetailsView = new UIGDetailsView(this);
+    m_pDetailsView->setFrameShape(QFrame::NoFrame);
+    m_pDetailsView->setFrameShadow(QFrame::Plain);
+    m_pDetailsView->setScene(m_pDetailsModel->scene());
+    m_pDetailsView->show();
+    setFocusProxy(m_pDetailsView);
+
+    /* Add tool-bar into layout: */
+    m_pMainLayout->addWidget(m_pDetailsView);
+
+    /* Prepare connections: */
+    prepareConnections();
+}
+
+void UIGDetails::setItems(const QList<UIVMItem*> &items)
+{
+    m_pDetailsModel->setItems(items);
+}
+
+void UIGDetails::prepareConnections()
+{
+    /* Selector-model connections: */
+    connect(m_pDetailsModel, SIGNAL(sigRootItemResized(const QSizeF&, int)),
+            m_pDetailsView, SLOT(sltHandleRootItemResized(const QSizeF&, int)));
+    connect(m_pDetailsModel, SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)),
+            this, SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)));
+
+    /* Selector-view connections: */
+    connect(m_pDetailsView, SIGNAL(sigResized()), m_pDetailsModel, SLOT(sltHandleViewResized()));
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetails.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetails.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetails.h	(revision 42529)
@@ -0,0 +1,61 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetails class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetails_h__
+#define __UIGDetails_h__
+
+/* Qt includes: */
+#include <QWidget>
+
+/* Forward declartions: */
+class QVBoxLayout;
+class UIGDetailsModel;
+class UIGDetailsView;
+class UIVMItem;
+
+/* Details widget: */
+class UIGDetails : public QWidget
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Link-click stuff: */
+    void sigLinkClicked(const QString &strCategory, const QString &strControl, const QString &strId);
+
+public:
+
+    /* Constructor: */
+    UIGDetails(QWidget *pParent);
+
+    /* API: Group/machine stuff: */
+    void setItems(const QList<UIVMItem*> &items);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void prepareConnections();
+
+    /* Variables: */
+    QVBoxLayout *m_pMainLayout;
+    UIGDetailsModel *m_pDetailsModel;
+    UIGDetailsView *m_pDetailsView;
+};
+
+#endif /* __UIGDetails_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp	(revision 42529)
@@ -0,0 +1,659 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsElement class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QTextLayout>
+#include <QGraphicsSceneMouseEvent>
+
+/* GUI includes: */
+#include "UIGDetailsElement.h"
+#include "UIGDetailsSet.h"
+#include "UIGDetailsModel.h"
+#include "UIGraphicsRotatorButton.h"
+#include "VBoxGlobal.h"
+#include "UIVirtualBoxEventHandler.h"
+#include "UIIconPool.h"
+#include "UIConverter.h"
+
+UIGDetailsElement::UIGDetailsElement(UIGDetailsSet *pParent, DetailsElementType type, bool fOpened)
+    : UIGDetailsItem(pParent)
+    , m_pSet(pParent)
+    , m_type(type)
+    , m_fClosed(!fOpened)
+    , m_pButton(0)
+    , m_iAdditionalHeight(0)
+    , m_iCornerRadius(6)
+    , m_fHovered(false)
+    , m_fNameHoveringAccessible(false)
+    , m_fNameHovered(false)
+{
+    /* Prepare element: */
+    prepareElement();
+    /* Prepare button: */
+    prepareButton();
+
+    /* Update size-policy/hint: */
+    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+    /* Update: */
+    updateHoverAccessibility();
+
+    /* Add item to the parent: */
+    parentItem()->addItem(this);
+}
+
+UIGDetailsElement::~UIGDetailsElement()
+{
+    /* Remove item from the parent: */
+    AssertMsg(parentItem(), ("No parent set for details element!"));
+    parentItem()->removeItem(this);
+}
+
+DetailsElementType UIGDetailsElement::elementType() const
+{
+    return m_type;
+}
+
+bool UIGDetailsElement::closed() const
+{
+    return m_fClosed;
+}
+
+bool UIGDetailsElement::opened() const
+{
+    return !m_fClosed;
+}
+
+void UIGDetailsElement::close()
+{
+    m_pButton->setToggled(false, false);
+}
+
+void UIGDetailsElement::open()
+{
+    m_pButton->setToggled(true, false);
+}
+
+int UIGDetailsElement::minimumWidthHint() const
+{
+    /* First of all, we have to prepare few variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iHeaderWidth = data(ElementData_HeaderSize).toSize().width();
+    int iTextWidth = data(ElementData_TextSize).toSize().width();
+
+    /* Calculating proposed width: */
+    int iProposedWidth = 0;
+
+    /* Maximum width: */
+    iProposedWidth = qMax(iHeaderWidth, iTextWidth);
+
+    /* And 4 margins: 2 left and 2 right: */
+    iProposedWidth += 4 * iMargin;
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGDetailsElement::minimumHeightHint() const
+{
+    return minimumHeightHint(m_fClosed);
+}
+
+void UIGDetailsElement::sltElementToggleStart()
+{
+    /* Setup animation: */
+    updateAnimationParameters();
+
+    /* Element closed, we are opening it: */
+    if (m_fClosed)
+    {
+        /* Toggle-state will be updated
+         * on toggle finish signal! */
+    }
+    /* Group opened, we are closing it: */
+    else
+    {
+        /* Update toggle-state: */
+        m_fClosed = true;
+    }
+}
+
+void UIGDetailsElement::sltElementToggleFinish(bool fToggled)
+{
+    /* Update toggle-state: */
+    m_fClosed = !fToggled;
+    /* Relayout model: */
+    model()->updateLayout();
+    update();
+}
+
+void UIGDetailsElement::sltMachineStateChange(QString strId)
+{
+    /* Is this our VM changed? */
+    if (machine().GetId() == strId)
+        updateHoverAccessibility();
+
+    /* Finally, update appearance: */
+    sltShouldWeUpdateAppearance(strId);
+}
+
+void UIGDetailsElement::sltShouldWeUpdateAppearance(QString strId)
+{
+    if (machine().GetId() == strId)
+        sltUpdateAppearance();
+}
+
+QVariant UIGDetailsElement::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case ElementData_Margin: return 5;
+        case ElementData_Spacing: return 10;
+        /* Pixmaps: */
+        case ElementData_Pixmap: return m_icon;
+        case ElementData_ButtonPixmap: return m_buttonIcon;
+        /* Fonts: */
+        case ElementData_NameFont:
+        {
+            QFont nameFont = qApp->font();
+            nameFont.setWeight(QFont::Bold);
+            return nameFont;
+        }
+        case ElementData_TextFont:
+        {
+            QFont textFont = qApp->font();
+            return textFont;
+        }
+        /* Sizes: */
+        case ElementData_PixmapSize: return m_icon.availableSizes().at(0);
+        case ElementData_NameSize:
+        {
+            QFontMetrics fm(data(ElementData_NameFont).value<QFont>());
+            return QSize(fm.width(m_strName), fm.height());
+        }
+        case ElementData_ButtonSize: return m_pButton->minimumSizeHint();
+        case ElementData_HeaderSize:
+        {
+            /* Prepare variables: */
+            int iMargin = data(ElementData_Margin).toInt();
+            int iSpacing = data(ElementData_Spacing).toInt();
+            QSize pixmapSize = data(ElementData_PixmapSize).toSize();
+            QSize nameSize = data(ElementData_NameSize).toSize();
+            QSize buttonSize = data(ElementData_ButtonSize).toSize();
+            /* Header width: */
+            int iHeaderWidth = iMargin + pixmapSize.width() + iSpacing +
+                               nameSize.width() + iSpacing + buttonSize.width();
+            /* Header height: */
+            int iHeaderHeight = qMax(pixmapSize.height(), nameSize.height());
+            iHeaderHeight = qMax(iHeaderHeight, buttonSize.height());
+            /* Return value: */
+            return QSize(iHeaderWidth, iHeaderHeight);
+        }
+        case ElementData_TextSize:
+        {
+            int iSpacing = data(ElementData_Spacing).toInt();
+            QFontMetrics fm(data(ElementData_TextFont).value<QFont>());
+            int iLongestFirst = 0;
+            int iLongestSecond = 0;
+            foreach (const UITextTableLine &line, m_text)
+            {
+                iLongestFirst = qMax(iLongestFirst, fm.width(line.first));
+                iLongestSecond = qMax(iLongestSecond, fm.width(line.second));
+            }
+            int iLongestLine = iLongestFirst + iSpacing + iLongestSecond;
+            int iSummaryHeight = fm.height() * m_text.size();
+            return QSize(iLongestLine, iSummaryHeight);
+        }
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGDetailsElement::setIcon(const QIcon &icon)
+{
+    m_icon = icon;
+}
+
+void UIGDetailsElement::setName(const QString &strName)
+{
+    m_strName = strName;
+}
+
+void UIGDetailsElement::setText(const UITextTable &text)
+{
+    m_text = text;
+}
+
+const CMachine& UIGDetailsElement::machine()
+{
+    return m_pSet->machine();
+}
+
+void UIGDetailsElement::addItem(UIGDetailsItem*)
+{
+    AssertMsgFailed(("Details element do NOT support children!"));
+}
+
+void UIGDetailsElement::removeItem(UIGDetailsItem*)
+{
+    AssertMsgFailed(("Details element do NOT support children!"));
+}
+
+QList<UIGDetailsItem*> UIGDetailsElement::items(UIGDetailsItemType) const
+{
+    AssertMsgFailed(("Details element do NOT support children!"));
+    return QList<UIGDetailsItem*>();
+}
+
+bool UIGDetailsElement::hasItems(UIGDetailsItemType) const
+{
+    AssertMsgFailed(("Details element do NOT support children!"));
+    return false;
+}
+
+void UIGDetailsElement::clearItems(UIGDetailsItemType)
+{
+    AssertMsgFailed(("Details element do NOT support children!"));
+}
+
+void UIGDetailsElement::prepareElement()
+{
+    connect(gVBoxEvents, SIGNAL(sigMachineStateChange(QString, KMachineState)), this, SLOT(sltMachineStateChange(QString)));
+    connect(gVBoxEvents, SIGNAL(sigMachineDataChange(QString)), this, SLOT(sltShouldWeUpdateAppearance(QString)));
+    connect(gVBoxEvents, SIGNAL(sigSessionStateChange(QString, KSessionState)), this, SLOT(sltShouldWeUpdateAppearance(QString)));
+    connect(gVBoxEvents, SIGNAL(sigSnapshotChange(QString, QString)), this, SLOT(sltShouldWeUpdateAppearance(QString)));
+    connect(&vboxGlobal(), SIGNAL(mediumEnumStarted()), this, SLOT(sltUpdateAppearance()));
+    connect(&vboxGlobal(), SIGNAL(mediumEnumFinished(const VBoxMediaList &)), this, SLOT(sltUpdateAppearance()));
+    connect(this, SIGNAL(sigToggleElement(DetailsElementType, bool)), model(), SLOT(sltToggleElements(DetailsElementType, bool)));
+    connect(this, SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)),
+            model(), SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)));
+}
+
+void UIGDetailsElement::prepareButton()
+{
+    /* Setup toggle-button: */
+    m_buttonIcon = UIIconPool::iconSet(":/arrow_right_10px.png");
+    m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed, true /* reflected */);
+    m_pButton->setIcon(m_buttonIcon);
+    connect(m_pButton, SIGNAL(sigRotationStart()), this, SLOT(sltElementToggleStart()));
+    connect(m_pButton, SIGNAL(sigRotationFinish(bool)), this, SLOT(sltElementToggleFinish(bool)));
+}
+
+void UIGDetailsElement::updateSizeHint()
+{
+    updateGeometry();
+}
+
+void UIGDetailsElement::updateLayout()
+{
+    /* Prepare variables: */
+    QSize size = geometry().size().toSize();
+    int iMargin = data(ElementData_Margin).toInt();
+    QSize buttonSize = data(ElementData_ButtonSize).toSize();
+    int iButtonWidth = buttonSize.width();
+    int iButtonHeight = buttonSize.height();
+    int iFullHeaderHeight = data(ElementData_HeaderSize).toSize().height();
+
+    /* Layout button: */
+    int iButtonX = size.width() - 2 * iMargin - iButtonWidth;
+    int iButtonY = iButtonHeight == iFullHeaderHeight ? iMargin :
+                   iMargin + (iFullHeaderHeight - iButtonHeight) / 2;
+    m_pButton->setPos(iButtonX, iButtonY);
+}
+
+void UIGDetailsElement::setAdditionalHeight(int iAdditionalHeight)
+{
+    m_iAdditionalHeight = iAdditionalHeight;
+    model()->updateLayout();
+}
+
+int UIGDetailsElement::additionalHeight() const
+{
+    return m_iAdditionalHeight;
+}
+
+UIGraphicsRotatorButton* UIGDetailsElement::button() const
+{
+    return m_pButton;
+}
+
+int UIGDetailsElement::minimumHeightHint(bool fClosed) const
+{
+    /* First of all, we have to prepare few variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iHeaderHeight = data(ElementData_HeaderSize).toSize().height();
+    int iTextHeight = data(ElementData_TextSize).toSize().height();
+
+    /* Calculating proposed height: */
+    int iProposedHeight = 0;
+
+    /* Two margins: */
+    iProposedHeight += 2 * iMargin;
+
+    /* Header height: */
+    iProposedHeight += iHeaderHeight;
+
+    /* Element is opened? */
+    if (!fClosed)
+    {
+        /* Add text height: */
+        if (!m_text.isEmpty())
+            iProposedHeight += iMargin + iTextHeight;
+    }
+    else
+    {
+        /* Additional height during animation: */
+        if (m_pButton->isAnimationRunning())
+            iProposedHeight += m_iAdditionalHeight;
+    }
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+QSizeF UIGDetailsElement::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    /* If Qt::MinimumSize requested: */
+    if (which == Qt::MinimumSize || which == Qt::PreferredSize)
+    {
+        /* Return wrappers: */
+        return QSizeF(minimumWidthHint(), minimumHeightHint());
+    }
+
+    /* Call to base-class: */
+    return UIGDetailsItem::sizeHint(which, constraint);
+}
+
+void UIGDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget*)
+{
+    /* Update button visibility: */
+    updateButtonVisibility();
+
+    /* Configure painter shape: */
+    configurePainterShape(pPainter, pOption, m_iCornerRadius);
+
+    /* Paint decorations: */
+    paintDecorations(pPainter, pOption);
+
+    /* Paint machine info: */
+    paintElementInfo(pPainter, pOption);
+}
+
+void UIGDetailsElement::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption)
+{
+    /* Prepare variables: */
+    QRect fullRect = pOption->rect;
+
+    /* Paint background: */
+    paintBackground(/* Painter: */
+                    pPainter,
+                    /* Rectangle to paint in: */
+                    fullRect,
+                    /* Rounded corners radius: */
+                    m_iCornerRadius,
+                    /* Header height: */
+                    data(ElementData_Margin).toInt() +
+                    data(ElementData_HeaderSize).toSize().height() +
+                    1);
+
+    /* Paint frame: */
+    paintFrameRect(/* Painter: */
+                   pPainter,
+                   /* Rectangle to paint in: */
+                   fullRect,
+                   /* Rounded corner radius: */
+                   m_iCornerRadius);
+}
+
+void UIGDetailsElement::paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem*)
+{
+    /* Initialize some necessary variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iSpacing = data(ElementData_Spacing).toInt();
+    QSize pixmapSize = data(ElementData_PixmapSize).toSize();
+    QSize nameSize = data(ElementData_NameSize).toSize();
+    int iHeaderHeight = data(ElementData_HeaderSize).toSize().height();
+
+    /* Calculate attributes: */
+    int iPixmapHeight = pixmapSize.height();
+    int iNameHeight = nameSize.height();
+    int iMaximumHeight = qMax(iPixmapHeight, iNameHeight);
+
+    /* Paint pixmap: */
+    int iMachinePixmapX = 2 * iMargin;
+    int iMachinePixmapY = iPixmapHeight == iMaximumHeight ?
+                          iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2;
+    paintPixmap(/* Painter: */
+                pPainter,
+                /* Rectangle to paint in: */
+                QRect(QPoint(iMachinePixmapX, iMachinePixmapY), pixmapSize),
+                /* Pixmap to paint: */
+                data(ElementData_Pixmap).value<QIcon>().pixmap(pixmapSize));
+
+    /* Paint name: */
+    int iMachineNameX = iMachinePixmapX +
+                        pixmapSize.width() +
+                        iSpacing;
+    int iMachineNameY = iNameHeight == iMaximumHeight ?
+                        iMargin : iMargin + (iMaximumHeight - iNameHeight) / 2;
+    paintText(/* Painter: */
+              pPainter,
+              /* Rectangle to paint in: */
+              QRect(QPoint(iMachineNameX, iMachineNameY), nameSize),
+              /* Font to paint text: */
+              data(ElementData_NameFont).value<QFont>(),
+              /* Text to paint: */
+              m_strName,
+              /* Name hovered? */
+              m_fNameHovered);
+
+    /* Paint text: */
+    if (!m_fClosed && !m_text.isEmpty())
+    {
+        /* Where to paint? */
+        int iMachineTextX = iMachinePixmapX;
+        int iMachineTextY = iMachinePixmapY + iHeaderHeight + iMargin;
+
+        /* Font metrics: */
+        QFontMetrics fm(data(ElementData_TextFont).value<QFont>());
+
+        /* For each the line, get longest 'first': */
+        int iLongestFirst = 0;
+        foreach (const UITextTableLine line, m_text)
+            iLongestFirst = qMax(iLongestFirst, fm.width(line.first));
+
+        /* For each the line: */
+        foreach (const UITextTableLine line, m_text)
+        {
+            /* Do we have a key-value pair? */
+            bool fKeyValueRow = !line.second.isEmpty();
+
+            /* First layout: */
+            QTextLayout keyLayout(fKeyValueRow ? line.first + ":" : line.first);
+            keyLayout.beginLayout();
+            keyLayout.createLine();
+            keyLayout.endLayout();
+            keyLayout.draw(pPainter, QPointF(iMachineTextX, iMachineTextY));
+
+            /* Second layout: */
+            if (!line.second.isEmpty())
+            {
+                QTextLayout valueLayout(line.second);
+                valueLayout.beginLayout();
+                valueLayout.createLine();
+                valueLayout.endLayout();
+                valueLayout.draw(pPainter, QPointF(iMachineTextX + iLongestFirst + iSpacing, iMachineTextY));
+            }
+
+            /* Append the Y: */
+            iMachineTextY += fm.height();
+        }
+    }
+}
+
+/* static */
+void UIGDetailsElement::paintBackground(QPainter *pPainter, const QRect &rect, int iRadius, int iHeaderHeight)
+{
+    /* Save painter: */
+    pPainter->save();
+
+    /* Fill rectangle with white color: */
+    QPalette pal = QApplication::palette();
+    pPainter->fillRect(rect, Qt::white);
+
+    /* Prepare color: */
+    QColor windowColor = pal.color(QPalette::Active, QPalette::Window);
+
+    /* Make even less rectangle: */
+    QRect backGroundRect = rect;
+    backGroundRect.setTopLeft(backGroundRect.topLeft() + QPoint(2, 2));
+    backGroundRect.setBottomRight(backGroundRect.bottomRight() - QPoint(2, 2));
+    /* Add even more clipping: */
+    QPainterPath roundedPath;
+    roundedPath.addRoundedRect(backGroundRect, iRadius, iRadius);
+    pPainter->setClipPath(roundedPath);
+
+    /* Calculate top rectangle: */
+    QRect tRect = backGroundRect;
+    tRect.setBottom(tRect.top() + iHeaderHeight);
+    /* Calculate bottom rectangle: */
+    QRect bRect = backGroundRect;
+    bRect.setTop(tRect.bottom());
+
+    /* Prepare top gradient: */
+    QLinearGradient tGradient(tRect.bottomLeft(), tRect.topLeft());
+    tGradient.setColorAt(0, windowColor.darker(115));
+    tGradient.setColorAt(1, windowColor.darker(103));
+
+    /* Paint all the stuff: */
+    pPainter->fillRect(bRect, windowColor.darker(99));
+    pPainter->fillRect(tRect, tGradient);
+
+    /* Restore painter: */
+    pPainter->restore();
+}
+
+void UIGDetailsElement::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
+{
+    /* Update hover state: */
+    if (!m_fHovered)
+    {
+        m_fHovered = true;
+        update();
+    }
+
+    /* Update name-hover state: */
+    updateNameHoverRepresentation(pEvent);
+}
+
+void UIGDetailsElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
+{
+    /* Update hover state: */
+    if (m_fHovered)
+    {
+        m_fHovered = false;
+        update();
+    }
+
+    /* Update name-hover state: */
+    updateNameHoverRepresentation(pEvent);
+}
+
+void UIGDetailsElement::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
+{
+    if (m_fNameHovered)
+    {
+        pEvent->accept();
+        QString strCategory;
+        if (m_type >= DetailsElementType_General &&
+            m_type <= DetailsElementType_SF)
+            strCategory = QString("#%1").arg(gpConverter->toInternalString(m_type));
+        else if (m_type == DetailsElementType_Description)
+            strCategory = QString("#%1%%mTeDescription").arg(gpConverter->toInternalString(m_type));
+        emit sigLinkClicked(strCategory, QString(), machine().GetId());
+    }
+}
+
+void UIGDetailsElement::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent)
+{
+    /* Process left-button double-click: */
+    if (pEvent->button() == Qt::LeftButton)
+        emit sigToggleElement(m_type, closed());
+}
+
+void UIGDetailsElement::updateButtonVisibility()
+{
+    if (m_fHovered && !m_pButton->isVisible())
+        m_pButton->show();
+    else if (!m_fHovered && m_pButton->isVisible())
+        m_pButton->hide();
+}
+
+void UIGDetailsElement::updateHoverAccessibility()
+{
+    /* Check if name-hovering should be available: */
+    m_fNameHoveringAccessible = machine().isNull() || !machine().GetAccessible() ? false :
+                                machine().GetState() != KMachineState_Stuck &&
+                                machine().GetState() != KMachineState_Saved;
+}
+
+void UIGDetailsElement::updateNameHoverRepresentation(QGraphicsSceneHoverEvent *pEvent)
+{
+    /* Not for 'preview' element type: */
+    if (m_type == DetailsElementType_Preview)
+        return;
+
+    /* Prepare variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iSpacing = data(ElementData_Spacing).toInt();
+    int iPixmapWidth = data(ElementData_PixmapSize).toSize().width();
+    QSize nameSize = data(ElementData_NameSize).toSize();
+    int iNameHeight = nameSize.height();
+    int iHeaderHeight = data(ElementData_HeaderSize).toSize().height();
+    int iMachineNameX = 2 * iMargin + iPixmapWidth + iSpacing;
+    int iMachineNameY = iNameHeight == iHeaderHeight ?
+                        iMargin : iMargin + (iHeaderHeight - iNameHeight) / 2;
+
+    /* Simulate hyperlink hovering: */
+    QPoint point = pEvent->pos().toPoint();
+    bool fNameHovered = QRect(QPoint(iMachineNameX, iMachineNameY), nameSize).contains(point);
+    if (m_fNameHoveringAccessible && m_fNameHovered != fNameHovered)
+    {
+        m_fNameHovered = fNameHovered;
+        if (m_fNameHovered)
+            setCursor(Qt::PointingHandCursor);
+        else
+            unsetCursor();
+        update();
+    }
+}
+
+void UIGDetailsElement::updateAnimationParameters()
+{
+    /* Recalculate animation parameters: */
+    int iOpenedHeight = minimumHeightHint(false);
+    int iClosedHeight = minimumHeightHint(true);
+    int iAdditionalHeight = iOpenedHeight - iClosedHeight;
+    m_pButton->setAnimationRange(0, iAdditionalHeight);
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.h	(revision 42529)
@@ -0,0 +1,192 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsElement class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsElement_h__
+#define __UIGDetailsElement_h__
+
+/* Qt includes: */
+#include <QIcon>
+
+/* GUI includes: */
+#include "UIGDetailsItem.h"
+#include "UIDefs.h"
+
+/* Forward declarations: */
+class UIGDetailsSet;
+class CMachine;
+class UIGraphicsRotatorButton;
+
+/* Typedefs: */
+typedef QPair<QString, QString> UITextTableLine;
+typedef QList<UITextTableLine> UITextTable;
+Q_DECLARE_METATYPE(UITextTable);
+
+/* Details element
+ * for graphics details model/view architecture: */
+class UIGDetailsElement : public UIGDetailsItem
+{
+    Q_OBJECT;
+    Q_PROPERTY(int additionalHeight READ additionalHeight WRITE setAdditionalHeight);
+
+signals:
+
+    /* Notifier: Toggle stuff: */
+    void sigToggleElement(DetailsElementType type, bool fToggled);
+
+    /* Notifier: Link-click stuff: */
+    void sigLinkClicked(const QString &strCategory, const QString &strControl, const QString &strId);
+
+public:
+
+    /* Graphics-item type: */
+    enum { Type = UIGDetailsItemType_Element };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGDetailsElement(UIGDetailsSet *pParent, DetailsElementType type, bool fOpened);
+    ~UIGDetailsElement();
+
+    /* API: Element type: */
+    DetailsElementType elementType() const;
+
+    /* API: Open/close stuff: */
+    bool closed() const;
+    bool opened() const;
+    void close();
+    void open();
+
+    /* API: Layout stuff: */
+    virtual int minimumWidthHint() const;
+    virtual int minimumHeightHint() const;
+
+public slots:
+
+    /* API: Update stuff: */
+    virtual void sltUpdateAppearance() = 0;
+
+protected:
+
+    /* Data enumerator: */
+    enum ElementData
+    {
+        /* Layout hints: */
+        ElementData_Margin,
+        ElementData_Spacing,
+        /* Pixmaps: */
+        ElementData_Pixmap,
+        ElementData_ButtonPixmap,
+        /* Fonts: */
+        ElementData_NameFont,
+        ElementData_TextFont,
+        /* Sizes: */
+        ElementData_PixmapSize,
+        ElementData_NameSize,
+        ElementData_ButtonSize,
+        ElementData_HeaderSize,
+        ElementData_TextSize
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* API: Icon stuff: */
+    void setIcon(const QIcon &icon);
+
+    /* API: Name stuff: */
+    void setName(const QString &strName);
+
+    /* API: Text stuff: */
+    void setText(const UITextTable &text);
+
+    /* API: Machine stuff: */
+    const CMachine& machine();
+
+    /* Helpers: Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+
+    /* Helpers: Animation stuff: */
+    void setAdditionalHeight(int iAdditionalHeight);
+    int additionalHeight() const;
+    UIGraphicsRotatorButton* button() const;
+
+private slots:
+
+    /* Handlers: Collapse/expand stuff: */
+    void sltElementToggleStart();
+    void sltElementToggleFinish(bool fToggled);
+
+    /* Handlers: Global event stuff: */
+    void sltMachineStateChange(QString strId);
+    void sltShouldWeUpdateAppearance(QString strId);
+
+private:
+
+    /* API: Children stuff: */
+    void addItem(UIGDetailsItem *pItem);
+    void removeItem(UIGDetailsItem *pItem);
+    QList<UIGDetailsItem*> items(UIGDetailsItemType type) const;
+    bool hasItems(UIGDetailsItemType type) const;
+    void clearItems(UIGDetailsItemType type);
+
+    /* Helpers: Prepare stuff: */
+    void prepareElement();
+    void prepareButton();
+
+    /* Helpers: Layout stuff: */
+    virtual int minimumHeightHint(bool fClosed) const;
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* Helpers: Paint stuff: */
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
+    void paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+    void paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);
+    static void paintBackground(QPainter *pPainter, const QRect &rect, int iRadius, int iHeaderHeight);
+
+    /* Handlers: Mouse stuff: */
+    void hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent);
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent);
+    void mousePressEvent(QGraphicsSceneMouseEvent *pEvent);
+    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent);
+
+    /* Helpers: Mouse stuff: */
+    void updateButtonVisibility();
+    void updateHoverAccessibility();
+    void updateNameHoverRepresentation(QGraphicsSceneHoverEvent *pEvent);
+
+    /* Helper: Animation stuff: */
+    void updateAnimationParameters();
+
+    /* Variables: */
+    UIGDetailsSet *m_pSet;
+    DetailsElementType m_type;
+    QIcon m_icon;
+    QString m_strName;
+    QIcon m_buttonIcon;
+    bool m_fClosed;
+    UIGraphicsRotatorButton *m_pButton;
+    UITextTable m_text;
+    int m_iAdditionalHeight;
+    int m_iCornerRadius;
+    bool m_fHovered;
+    bool m_fNameHoveringAccessible;
+    bool m_fNameHovered;
+};
+
+#endif /* __UIGDetailsElement_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp	(revision 42529)
@@ -0,0 +1,899 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsDetails class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsLinearLayout>
+#include <QTimer>
+#include <QDir>
+
+/* GUI includes: */
+#include "UIGDetailsElements.h"
+#include "UIGDetailsModel.h"
+#include "UIGMachinePreview.h"
+#include "UIGraphicsRotatorButton.h"
+#include "VBoxGlobal.h"
+#include "UIIconPool.h"
+#include "UIConverter.h"
+
+/* COM includes: */
+#include "CSystemProperties.h"
+#include "CVRDEServer.h"
+#include "CStorageController.h"
+#include "CMediumAttachment.h"
+#include "CAudioAdapter.h"
+#include "CNetworkAdapter.h"
+#include "CSerialPort.h"
+#include "CParallelPort.h"
+#include "CUSBController.h"
+#include "CUSBDeviceFilter.h"
+#include "CSharedFolder.h"
+
+/* Constructor: */
+UIGDetailsUpdateThread::UIGDetailsUpdateThread(const CMachine &machine)
+    : m_machine(machine)
+{
+    qRegisterMetaType<UITextTable>();
+}
+
+UIGDetailsElementInterface::UIGDetailsElementInterface(UIGDetailsSet *pParent, DetailsElementType elementType, bool fOpened)
+    : UIGDetailsElement(pParent, elementType, fOpened)
+    , m_pThread(0)
+{
+}
+
+UIGDetailsElementInterface::~UIGDetailsElementInterface()
+{
+    cleanupThread();
+}
+
+void UIGDetailsElementInterface::sltUpdateAppearance()
+{
+    if (!m_pThread)
+    {
+        m_pThread = createUpdateThread();
+        connect(m_pThread, SIGNAL(sigComplete(const UITextTable&)),
+                this, SLOT(sltUpdateAppearanceFinished(const UITextTable&)));
+        m_pThread->start();
+    }
+}
+
+void UIGDetailsElementInterface::sltUpdateAppearanceFinished(const UITextTable &text)
+{
+    setText(text);
+    cleanupThread();
+    model()->updateLayout();
+}
+
+void UIGDetailsElementInterface::cleanupThread()
+{
+    if (m_pThread)
+    {
+        m_pThread->wait();
+        delete m_pThread;
+        m_pThread = 0;
+    }
+}
+
+
+UIGDetailsUpdateThreadGeneral::UIGDetailsUpdateThreadGeneral(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadGeneral::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Machine name: */
+            m_text << UITextTableLine(tr("Name", "details"), machine().GetName());
+
+            /* Operating system type: */
+            m_text << UITextTableLine(tr("Operating system", "details"),
+                                       vboxGlobal().vmGuestOSTypeDescription(machine().GetOSTypeId()));
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementGeneral::UIGDetailsElementGeneral(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_General, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_General));
+    setIcon(UIIconPool::iconSet(":/machine_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementGeneral::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadGeneral(machine());
+}
+
+
+UIGDetailsElementPreview::UIGDetailsElementPreview(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElement(pParent, DetailsElementType_Preview, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Preview));
+    setIcon(UIIconPool::iconSet(":/machine_16px.png"));
+
+    /* Prepare variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iHeaderHeight = data(ElementData_HeaderSize).toSize().height();
+    /* Prepare layout: */
+    QGraphicsLinearLayout *pLayout = new QGraphicsLinearLayout;
+    pLayout->setContentsMargins(iMargin, 2 * iMargin + iHeaderHeight, iMargin, iMargin);
+    setLayout(pLayout);
+
+    /* Create preview: */
+    m_pPreview = new UIGMachinePreview(this);
+    pLayout->addItem(m_pPreview);
+    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    m_pPreview->setMachine(machine());
+}
+
+void UIGDetailsElementPreview::sltUpdateAppearance()
+{
+}
+
+int UIGDetailsElementPreview::minimumWidthHint() const
+{
+    /* Prepare variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iHeaderWidth = data(ElementData_HeaderSize).toSize().width();
+
+    /* Calculating proposed width: */
+    int iProposedWidth = 0;
+
+    /* Maximum between header width and preview width: */
+    iProposedWidth += qMax(iHeaderWidth, m_pPreview->minimumSizeHint().toSize().width());
+
+    /* Two margins: */
+    iProposedWidth += 2 * iMargin;
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGDetailsElementPreview::minimumHeightHint(bool fClosed) const
+{
+    /* Prepare variables: */
+    int iMargin = data(ElementData_Margin).toInt();
+    int iHeaderHeight = data(ElementData_HeaderSize).toSize().height();
+
+    /* Calculating proposed height: */
+    int iProposedHeight = 0;
+
+    /* Two margins: */
+    iProposedHeight += 2 * iMargin;
+
+    /* Header height: */
+    iProposedHeight += iHeaderHeight;
+
+    /* Element is opened? */
+    if (!fClosed)
+    {
+        iProposedHeight += iMargin;
+        iProposedHeight += m_pPreview->minimumSizeHint().toSize().height();
+    }
+    else
+    {
+        /* Additional height during animation: */
+        if (button()->isAnimationRunning())
+            iProposedHeight += additionalHeight();
+    }
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+void UIGDetailsElementPreview::updateLayout()
+{
+    /* Call to base-class: */
+    UIGDetailsElement::updateLayout();
+
+    /* Show/hide preview: */
+    if (closed() && m_pPreview->isVisible())
+        m_pPreview->hide();
+    if (opened() && !m_pPreview->isVisible())
+        m_pPreview->show();
+}
+
+
+UIGDetailsUpdateThreadSystem::UIGDetailsUpdateThreadSystem(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadSystem::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Base memory: */
+            m_text << UITextTableLine(tr("Base Memory", "details"), tr("%1 MB", "details").arg(machine().GetMemorySize()));
+
+            /* CPU count: */
+            int cCPU = machine().GetCPUCount();
+            if (cCPU > 1)
+                m_text << UITextTableLine(tr("Processors", "details"), QString::number(cCPU));
+
+            /* CPU execution cap: */
+            int iCPUExecCap = machine().GetCPUExecutionCap();
+            if (iCPUExecCap < 100)
+                m_text << UITextTableLine(tr("Execution Cap", "details"), tr("%1%", "details").arg(iCPUExecCap));
+
+            /* Boot-order: */
+            QStringList bootOrder;
+            for (ulong i = 1; i <= vboxGlobal().virtualBox().GetSystemProperties().GetMaxBootPosition(); ++i)
+            {
+                KDeviceType device = machine().GetBootOrder(i);
+                if (device == KDeviceType_Null)
+                    continue;
+                bootOrder << gpConverter->toString(device);
+            }
+            if (bootOrder.isEmpty())
+                bootOrder << gpConverter->toString(KDeviceType_Null);
+            m_text << UITextTableLine(tr("Boot Order", "details"), bootOrder.join(", "));
+
+            /* Acceleration: */
+            QStringList acceleration;
+            if (vboxGlobal().virtualBox().GetHost().GetProcessorFeature(KProcessorFeature_HWVirtEx))
+            {
+                /* VT-x/AMD-V: */
+                if (machine().GetHWVirtExProperty(KHWVirtExPropertyType_Enabled))
+                {
+                    acceleration << tr("VT-x/AMD-V", "details report");
+                    /* Nested Paging (only when hw virt is enabled): */
+                    if (machine().GetHWVirtExProperty(KHWVirtExPropertyType_NestedPaging))
+                        acceleration << tr("Nested Paging", "details");
+                }
+            }
+            if (machine().GetCPUProperty(KCPUPropertyType_PAE))
+                acceleration << tr("PAE/NX", "details report");
+            if (!acceleration.isEmpty())
+                m_text << UITextTableLine(tr("Acceleration", "details"), acceleration.join(", "));
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementSystem::UIGDetailsElementSystem(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_System, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_System));
+    setIcon(UIIconPool::iconSet(":/chipset_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementSystem::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadSystem(machine());
+}
+
+
+UIGDetailsUpdateThreadDisplay::UIGDetailsUpdateThreadDisplay(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadDisplay::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Video memory: */
+            m_text << UITextTableLine(tr("Video Memory", "details"), tr("%1 MB", "details").arg(machine().GetVRAMSize()));
+
+            /* Screen count: */
+            int cGuestScreens = machine().GetMonitorCount();
+            if (cGuestScreens > 1)
+                m_text << UITextTableLine(tr("Screens", "details"), QString::number(cGuestScreens));
+
+            QStringList acceleration;
+#ifdef VBOX_WITH_VIDEOHWACCEL
+            /* 2D acceleration: */
+            if (machine().GetAccelerate2DVideoEnabled())
+                acceleration << tr("2D Video", "details report");
+#endif /* VBOX_WITH_VIDEOHWACCEL */
+            /* 3D acceleration: */
+            if (machine().GetAccelerate3DEnabled())
+                acceleration << tr("3D", "details report");
+            if (!acceleration.isEmpty())
+                m_text << UITextTableLine(tr("Acceleration", "details"), acceleration.join(", "));
+
+            /* VRDE info: */
+            CVRDEServer srv = machine().GetVRDEServer();
+            if (!srv.isNull())
+            {
+                if (srv.GetEnabled())
+                    m_text << UITextTableLine(tr("Remote Desktop Server Port", "details"), srv.GetVRDEProperty("TCP/Ports"));
+                else
+                    m_text << UITextTableLine(tr("Remote Desktop Server", "details"), tr("Disabled", "details report (VRDE Server)"));
+            }
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementDisplay::UIGDetailsElementDisplay(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Display, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Display));
+    setIcon(UIIconPool::iconSet(":/vrdp_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementDisplay::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadDisplay(machine());
+}
+
+
+UIGDetailsUpdateThreadStorage::UIGDetailsUpdateThreadStorage(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadStorage::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Iterate over all the machine controllers: */
+            bool fSomeInfo = false;
+            foreach (const CStorageController &controller, machine().GetStorageControllers())
+            {
+                /* Add controller information: */
+                m_text << UITextTableLine(controller.GetName(), QString());
+                fSomeInfo = true;
+                /* Populate map (its sorted!): */
+                QMap<StorageSlot, QString> attachmentsMap;
+                foreach (const CMediumAttachment &attachment, machine().GetMediumAttachmentsOfController(controller.GetName()))
+                {
+                    /* Prepare current storage slot: */
+                    StorageSlot attachmentSlot(controller.GetBus(), attachment.GetPort(), attachment.GetDevice());
+                    /* Prepare attachment information: */
+                    QString strAttachmentInfo = vboxGlobal().details(attachment.GetMedium(), false, false);
+                    /* Append 'device slot name' with 'device type name' for CD/DVD devices only: */
+                    QString strDeviceType = attachment.GetType() == KDeviceType_DVD ? tr("[CD/DVD]") : QString();
+                    if (!strDeviceType.isNull())
+                        strDeviceType.append(' ');
+                    /* Insert that attachment information into the map: */
+                    if (!strAttachmentInfo.isNull())
+                        attachmentsMap.insert(attachmentSlot, strDeviceType + strAttachmentInfo);
+                }
+                /* Iterate over the sorted map: */
+                QList<StorageSlot> storageSlots = attachmentsMap.keys();
+                QList<QString> storageInfo = attachmentsMap.values();
+                for (int i = 0; i < storageSlots.size(); ++i)
+                    m_text << UITextTableLine(QString("  ") + gpConverter->toString(storageSlots[i]), storageInfo[i]);
+            }
+            if (!fSomeInfo)
+                m_text << UITextTableLine(tr("Not attached", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementStorage::UIGDetailsElementStorage(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Storage, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Storage));
+    setIcon(UIIconPool::iconSet(":/attachment_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementStorage::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadStorage(machine());
+}
+
+
+UIGDetailsUpdateThreadAudio::UIGDetailsUpdateThreadAudio(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadAudio::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            const CAudioAdapter &audio = machine().GetAudioAdapter();
+            if (audio.GetEnabled())
+            {
+                /* Driver: */
+                m_text << UITextTableLine(tr("Host driver", "details"), gpConverter->toString(audio.GetAudioDriver()));
+
+                /* Controller: */
+                m_text << UITextTableLine(tr("Controller", "details"), gpConverter->toString(audio.GetAudioController()));
+            }
+            else
+                m_text << UITextTableLine(tr("Disabled", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementAudio::UIGDetailsElementAudio(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Audio, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Audio));
+    setIcon(UIIconPool::iconSet(":/sound_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementAudio::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadAudio(machine());
+}
+
+
+UIGDetailsUpdateThreadNetwork::UIGDetailsUpdateThreadNetwork(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadNetwork::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Iterate over all the adapters: */
+            bool fSomeInfo = false;
+            ulong uSount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
+            for (ulong uSlot = 0; uSlot < uSount; ++uSlot)
+            {
+                const CNetworkAdapter &adapter = machine().GetNetworkAdapter(uSlot);
+                if (adapter.GetEnabled())
+                {
+                    KNetworkAttachmentType type = adapter.GetAttachmentType();
+                    QString strAttachmentType = gpConverter->toString(adapter.GetAdapterType())
+                                                .replace(QRegExp("\\s\\(.+\\)"), " (%1)");
+                    switch (type)
+                    {
+                        case KNetworkAttachmentType_Bridged:
+                        {
+                            strAttachmentType = strAttachmentType.arg(tr("Bridged adapter, %1", "details report (network)")
+                                                                      .arg(adapter.GetBridgedInterface()));
+                            break;
+                        }
+                        case KNetworkAttachmentType_Internal:
+                        {
+                            strAttachmentType = strAttachmentType.arg(tr("Internal network, '%1'", "details report (network)")
+                                                                      .arg(adapter.GetInternalNetwork()));
+                            break;
+                        }
+                        case KNetworkAttachmentType_HostOnly:
+                        {
+                            strAttachmentType = strAttachmentType.arg(tr("Host-only adapter, '%1'", "details report (network)")
+                                                                      .arg(adapter.GetHostOnlyInterface()));
+                            break;
+                        }
+                        case KNetworkAttachmentType_Generic:
+                        {
+                            QString strGenericDriverProperties(summarizeGenericProperties(adapter));
+                            strAttachmentType = strGenericDriverProperties.isNull() ?
+                                      strAttachmentType.arg(tr("Generic driver, '%1'", "details report (network)").arg(adapter.GetGenericDriver())) :
+                                      strAttachmentType.arg(tr("Generic driver, '%1' {&nbsp;%2&nbsp;}", "details report (network)")
+                                                            .arg(adapter.GetGenericDriver(), strGenericDriverProperties));
+                            break;
+                        }
+                        default:
+                        {
+                            strAttachmentType = strAttachmentType.arg(gpConverter->toString(type));
+                            break;
+                        }
+                    }
+                    m_text << UITextTableLine(tr("Adapter %1", "details").arg(adapter.GetSlot() + 1), strAttachmentType);
+                    fSomeInfo = true;
+                }
+            }
+            if (!fSomeInfo)
+                m_text << UITextTableLine(tr("Disabled", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+/* static */
+QString UIGDetailsUpdateThreadNetwork::summarizeGenericProperties(const CNetworkAdapter &adapter)
+{
+    QVector<QString> names;
+    QVector<QString> props;
+    props = adapter.GetProperties(QString(), names);
+    QString strResult;
+    for (int i = 0; i < names.size(); ++i)
+    {
+        strResult += names[i] + "=" + props[i];
+        if (i < names.size() - 1)
+            strResult += ", ";
+    }
+    return strResult;
+}
+
+UIGDetailsElementNetwork::UIGDetailsElementNetwork(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Network, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Network));
+    setIcon(UIIconPool::iconSet(":/nw_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementNetwork::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadNetwork(machine());
+}
+
+
+UIGDetailsUpdateThreadSerial::UIGDetailsUpdateThreadSerial(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadSerial::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Iterate over all the ports: */
+            bool fSomeInfo = false;
+            ulong uCount = vboxGlobal().virtualBox().GetSystemProperties().GetSerialPortCount();
+            for (ulong uSlot = 0; uSlot < uCount; ++uSlot)
+            {
+                const CSerialPort &port = machine().GetSerialPort(uSlot);
+                if (port.GetEnabled())
+                {
+                    KPortMode mode = port.GetHostMode();
+                    QString data = vboxGlobal().toCOMPortName(port.GetIRQ(), port.GetIOBase()) + ", ";
+                    if (mode == KPortMode_HostPipe || mode == KPortMode_HostDevice || mode == KPortMode_RawFile)
+                        data += QString("%1 (%2)").arg(gpConverter->toString(mode)).arg(QDir::toNativeSeparators(port.GetPath()));
+                    else
+                        data += gpConverter->toString(mode);
+                    m_text << UITextTableLine(tr("Port %1", "details").arg(port.GetSlot() + 1), data);
+                    fSomeInfo = true;
+                }
+            }
+            if (!fSomeInfo)
+                m_text << UITextTableLine(tr("Disabled", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementSerial::UIGDetailsElementSerial(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Serial, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Serial));
+    setIcon(UIIconPool::iconSet(":/serial_port_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementSerial::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadSerial(machine());
+}
+
+
+#ifdef VBOX_WITH_PARALLEL_PORTS
+UIGDetailsUpdateThreadParallel::UIGDetailsUpdateThreadParallel(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadParallel::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            bool fSomeInfo = false;
+            ulong uCount = vboxGlobal().virtualBox().GetSystemProperties().GetParallelPortCount();
+            for (ulong uSlot = 0; uSlot < uCount; ++uSlot)
+            {
+                const CParallelPort &port = machine().GetParallelPort(uSlot);
+                if (port.GetEnabled())
+                {
+                    QString data = vboxGlobal().toLPTPortName(port.GetIRQ(), port.GetIOBase()) +
+                                   QString(" (<nobr>%1</nobr>)").arg(QDir::toNativeSeparators(port.GetPath()));
+                    m_text << UITextTableLine(tr("Port %1", "details").arg(port.GetSlot() + 1), data);
+                    fSomeInfo = true;
+                }
+            }
+            if (!fSomeInfo)
+                m_text << UITextTableLine(tr("Disabled", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementParallel::UIGDetailsElementParallel(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Parallel, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Parallel));
+    setIcon(UIIconPool::iconSet(":/parallel_port_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementParallel::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadParallel(machine());
+}
+#endif /* VBOX_WITH_PARALLEL_PORTS */
+
+
+UIGDetailsUpdateThreadUSB::UIGDetailsUpdateThreadUSB(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadUSB::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Iterate over all the USB filters: */
+            const CUSBController &ctl = machine().GetUSBController();
+            if (!ctl.isNull() && ctl.GetProxyAvailable())
+            {
+                if (ctl.GetEnabled())
+                {
+                    const CUSBDeviceFilterVector &coll = ctl.GetDeviceFilters();
+                    uint uActive = 0;
+                    for (int i = 0; i < coll.size(); ++i)
+                        if (coll[i].GetActive())
+                            ++uActive;
+                    m_text << UITextTableLine(tr("Device filters", "details"), tr("%1 (%2 active)", "details").arg(coll.size()).arg(uActive));
+                }
+                else
+                    m_text << UITextTableLine(tr("Disabled", "details"), QString());
+            }
+            else
+                m_text << UITextTableLine(tr("USB controller inaccessible", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementUSB::UIGDetailsElementUSB(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_USB, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_USB));
+    setIcon(UIIconPool::iconSet(":/usb_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementUSB::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadUSB(machine());
+}
+
+
+UIGDetailsUpdateThreadSF::UIGDetailsUpdateThreadSF(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadSF::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Iterate over all the shared folders: */
+            ulong uCount = machine().GetSharedFolders().size();
+            if (uCount > 0)
+                m_text << UITextTableLine(tr("Shared folders", "details"), QString::number(uCount));
+            else
+                m_text << UITextTableLine(tr("None", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementSF::UIGDetailsElementSF(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_SF, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_SF));
+    setIcon(UIIconPool::iconSet(":/shared_folder_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementSF::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadSF(machine());
+}
+
+
+UIGDetailsUpdateThreadDescription::UIGDetailsUpdateThreadDescription(const CMachine &machine)
+    : UIGDetailsUpdateThread(machine)
+{
+}
+
+void UIGDetailsUpdateThreadDescription::run()
+{
+    COMBase::InitializeCOM(false);
+
+    if (!machine().isNull())
+    {
+        /* Prepare table: */
+        UITextTable m_text;
+
+        /* Gather information: */
+        if (machine().GetAccessible())
+        {
+            /* Get description: */
+            const QString &strDesc = machine().GetDescription();
+            if (!strDesc.isEmpty())
+                m_text << UITextTableLine(strDesc, QString());
+            else
+                m_text << UITextTableLine(tr("None", "details"), QString());
+        }
+        else
+            m_text << UITextTableLine(tr("Information inaccessible", "details"), QString());
+
+        /* Send information into GUI thread: */
+        emit sigComplete(m_text);
+    }
+
+    COMBase::CleanupCOM();
+}
+
+UIGDetailsElementDescription::UIGDetailsElementDescription(UIGDetailsSet *pParent, bool fOpened)
+    : UIGDetailsElementInterface(pParent, DetailsElementType_Description, fOpened)
+{
+    /* Name/icon: */
+    setName(gpConverter->toString(DetailsElementType_Description));
+    setIcon(UIIconPool::iconSet(":/description_16px.png"));
+}
+
+UIGDetailsUpdateThread* UIGDetailsElementDescription::createUpdateThread()
+{
+    return new UIGDetailsUpdateThreadDescription(machine());
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.h	(revision 42529)
@@ -0,0 +1,488 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsElements class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsElements_h__
+#define __UIGDetailsElements_h__
+
+/* Qt includes: */
+#include <QThread>
+
+/* GUI includes: */
+#include "UIGDetailsElement.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+#include "CMachine.h"
+
+/* Forward declarations: */
+class UIGMachinePreview;
+
+/* Element update thread: */
+class UIGDetailsUpdateThread : public QThread
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifier: Prepare stuff: */
+    void sigComplete(const UITextTable &text);
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThread(const CMachine &machine);
+
+protected:
+
+    /* Internal API: Machine stuff: */
+    const CMachine& machine() const { return m_machine; }
+
+private:
+
+    /* Variables: */
+    const CMachine &m_machine;
+};
+
+/* Details element interface: */
+class UIGDetailsElementInterface : public UIGDetailsElement
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor/destructor: */
+    UIGDetailsElementInterface(UIGDetailsSet *pParent, DetailsElementType elementType, bool fOpened);
+    ~UIGDetailsElementInterface();
+
+protected slots:
+
+    /* Handlers: Update stuff: */
+    void sltUpdateAppearance();
+    virtual void sltUpdateAppearanceFinished(const UITextTable &text);
+
+protected:
+
+    /* Helpers: Update stuff: */
+    virtual UIGDetailsUpdateThread* createUpdateThread() = 0;
+
+private:
+
+    /* Helpers: Cleanup stuff: */
+    void cleanupThread();
+
+    /* Variables: */
+    UIGDetailsUpdateThread *m_pThread;
+};
+
+
+/* Thread 'General': */
+class UIGDetailsUpdateThreadGeneral : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadGeneral(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'General': */
+class UIGDetailsElementGeneral : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementGeneral(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Element 'Preview': */
+class UIGDetailsElementPreview : public UIGDetailsElement
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementPreview(UIGDetailsSet *pParent, bool fOpened);
+
+private slots:
+
+    /* Handlers: Update stuff: */
+    void sltUpdateAppearance();
+
+private:
+
+    /* Helpers: Size-hint stuff: */
+    int minimumWidthHint() const;
+    int minimumHeightHint(bool fClosed) const;
+
+    /* Helpers: Layout stuff: */
+    void updateLayout();
+
+    /* Variables: */
+    UIGMachinePreview *m_pPreview;
+};
+
+
+/* Thread 'System': */
+class UIGDetailsUpdateThreadSystem : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadSystem(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'System': */
+class UIGDetailsElementSystem : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementSystem(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'Display': */
+class UIGDetailsUpdateThreadDisplay : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadDisplay(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'Display': */
+class UIGDetailsElementDisplay : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementDisplay(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'Storage': */
+class UIGDetailsUpdateThreadStorage : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadStorage(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'Storage': */
+class UIGDetailsElementStorage : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementStorage(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'Audio': */
+class UIGDetailsUpdateThreadAudio : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadAudio(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'Audio': */
+class UIGDetailsElementAudio : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementAudio(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'Network': */
+class UIGDetailsUpdateThreadNetwork : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadNetwork(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+    static QString summarizeGenericProperties(const CNetworkAdapter &adapter);
+};
+
+/* Element 'Network': */
+class UIGDetailsElementNetwork : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementNetwork(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'Serial': */
+class UIGDetailsUpdateThreadSerial : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadSerial(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'Serial': */
+class UIGDetailsElementSerial : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementSerial(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+#ifdef VBOX_WITH_PARALLEL_PORTS
+/* Thread 'Parallel': */
+class UIGDetailsUpdateThreadParallel : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadParallel(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'Parallel': */
+class UIGDetailsElementParallel : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementParallel(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+#endif /* VBOX_WITH_PARALLEL_PORTS */
+
+
+/* Thread 'USB': */
+class UIGDetailsUpdateThreadUSB : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadUSB(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'USB': */
+class UIGDetailsElementUSB : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementUSB(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'SF': */
+class UIGDetailsUpdateThreadSF : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadSF(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'SF': */
+class UIGDetailsElementSF : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementSF(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+
+/* Thread 'Description': */
+class UIGDetailsUpdateThreadDescription : public UIGDetailsUpdateThread
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsUpdateThreadDescription(const CMachine &machine);
+
+private:
+
+    /* Helpers: Prepare stuff: */
+    void run();
+};
+
+/* Element 'Description': */
+class UIGDetailsElementDescription : public UIGDetailsElementInterface
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsElementDescription(UIGDetailsSet *pParent, bool fOpened);
+
+private:
+
+    /* Helpers: Update stuff: */
+    UIGDetailsUpdateThread* createUpdateThread();
+};
+
+#endif /* __UIGDetailsElements_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsGroup.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsGroup.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsGroup.cpp	(revision 42529)
@@ -0,0 +1,258 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsGroup class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsLinearLayout>
+
+/* GUI includes: */
+#include "UIGDetailsGroup.h"
+#include "UIGDetailsSet.h"
+#include "UIGDetailsModel.h"
+#include "UIConverter.h"
+#include "VBoxGlobal.h"
+
+/* Other VBox includes: */
+#include <iprt/assert.h>
+
+UIGDetailsGroup::UIGDetailsGroup()
+    : UIGDetailsItem(0)
+    , m_pMainLayout(0)
+    , m_pLayout(0)
+    , m_pStep(0)
+    , m_iStep(0)
+{
+    /* Prepare layout: */
+    prepareLayout();
+
+    /* Prepare connections: */
+    connect(this, SIGNAL(sigStartFirstStep(QString)), this, SLOT(sltFirstStep(QString)), Qt::QueuedConnection);
+}
+
+UIGDetailsGroup::~UIGDetailsGroup()
+{
+    /* Clear items: */
+    clearItems();
+}
+
+void UIGDetailsGroup::setItems(const QList<UIVMItem*> &items)
+{
+    prepareSets(items);
+}
+
+void UIGDetailsGroup::rebuildItems()
+{
+    recreateSets();
+}
+
+void UIGDetailsGroup::addItem(UIGDetailsItem *pItem)
+{
+    switch (pItem->type())
+    {
+        case UIGDetailsItemType_Set: m_sets.append(pItem); m_pLayout->addItem(pItem); break;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+}
+
+void UIGDetailsGroup::removeItem(UIGDetailsItem *pItem)
+{
+    switch (pItem->type())
+    {
+        case UIGDetailsItemType_Set: m_sets.removeAt(m_sets.indexOf(pItem)); m_pLayout->removeItem(pItem); break;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+}
+
+QList<UIGDetailsItem*> UIGDetailsGroup::items(UIGDetailsItemType type /* = UIGDetailsItemType_Set */) const
+{
+    switch (type)
+    {
+        case UIGDetailsItemType_Any: return items(UIGDetailsItemType_Set);
+        case UIGDetailsItemType_Set: return m_sets;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+    return QList<UIGDetailsItem*>();
+}
+
+bool UIGDetailsGroup::hasItems(UIGDetailsItemType type /* = UIGDetailsItemType_Set */) const
+{
+    switch (type)
+    {
+        case UIGDetailsItemType_Any: return hasItems(UIGDetailsItemType_Set);
+        case UIGDetailsItemType_Set: return !m_sets.isEmpty();
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+    return false;
+}
+
+void UIGDetailsGroup::clearItems(UIGDetailsItemType type /* = UIGDetailsItemType_Set */)
+{
+    switch (type)
+    {
+        case UIGDetailsItemType_Any: clearItems(UIGDetailsItemType_Set); break;
+        case UIGDetailsItemType_Set: while (!m_sets.isEmpty()) { delete m_sets.last(); } break;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+}
+
+QVariant UIGDetailsGroup::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case GroupData_Margin: return 1;
+        case GroupData_Spacing: return 10;
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGDetailsGroup::updateSizeHint()
+{
+    /* Update size-hints for all the items: */
+    foreach (UIGDetailsItem *pItem, items())
+        pItem->updateSizeHint();
+    /* Update size-hint for this item: */
+    updateGeometry();
+}
+
+void UIGDetailsGroup::updateLayout()
+{
+    m_pMainLayout->activate();
+    m_pLayout->activate();
+    foreach (UIGDetailsItem *pItem, items())
+        pItem->updateLayout();
+}
+
+void UIGDetailsGroup::sltFirstStep(QString strId)
+{
+    /* Prepare first set: */
+    if (strId == m_strCurrentId)
+    {
+        m_iStep = 0;
+        prepareSet();
+    }
+}
+
+void UIGDetailsGroup::sltStepDone()
+{
+    /* Clear step: */
+    delete m_pStep;
+    m_pStep = 0;
+
+    /* Prepare next set: */
+    ++m_iStep;
+    prepareSet();
+}
+
+void UIGDetailsGroup::loadSettings()
+{
+    /* Load settings: */
+    m_settings = vboxGlobal().virtualBox().GetExtraDataStringList(GUI_DetailsPageBoxes);
+    /* If settings are empty: */
+    if (m_settings.isEmpty())
+    {
+        /* Propose the defaults: */
+        m_settings << gpConverter->toInternalString(DetailsElementType_General);
+        m_settings << gpConverter->toInternalString(DetailsElementType_Preview);
+        m_settings << gpConverter->toInternalString(DetailsElementType_System);
+        m_settings << gpConverter->toInternalString(DetailsElementType_Display);
+        m_settings << gpConverter->toInternalString(DetailsElementType_Storage);
+        m_settings << gpConverter->toInternalString(DetailsElementType_Audio);
+        m_settings << gpConverter->toInternalString(DetailsElementType_Network);
+        m_settings << gpConverter->toInternalString(DetailsElementType_USB);
+        m_settings << gpConverter->toInternalString(DetailsElementType_SF);
+        m_settings << gpConverter->toInternalString(DetailsElementType_Description);
+        vboxGlobal().virtualBox().SetExtraDataStringList(GUI_DetailsPageBoxes, m_settings);
+    }
+}
+
+void UIGDetailsGroup::prepareLayout()
+{
+    /* Prepare variables: */
+    int iMargin = data(GroupData_Margin).toInt();
+    int iSpacing = data(GroupData_Spacing).toInt();
+
+    /* Prepare layout: */
+    m_pMainLayout = new QGraphicsLinearLayout(Qt::Vertical);
+    m_pMainLayout->setContentsMargins(0, 0, 0, 0);
+    m_pMainLayout->setSpacing(0);
+    m_pLayout = new QGraphicsLinearLayout(Qt::Vertical);
+    m_pLayout->setContentsMargins(iMargin, iMargin, iMargin, iMargin);
+    m_pLayout->setSpacing(iSpacing);
+    m_pMainLayout->addItem(m_pLayout);
+    m_pMainLayout->addStretch();
+    setLayout(m_pMainLayout);
+}
+
+void UIGDetailsGroup::prepareSets(const QList<UIVMItem*> &items)
+{
+    /* Clear sets first: */
+    clearItems();
+    /* Clear step: */
+    if (m_pStep)
+    {
+        delete m_pStep;
+        m_pStep = 0;
+    }
+
+    /* Load settings: */
+    loadSettings();
+
+    /* Remember new items: */
+    m_items = items;
+
+    /* Prepare first set: */
+    m_strCurrentId = QUuid::createUuid().toString();
+    emit sigStartFirstStep(m_strCurrentId);
+}
+
+void UIGDetailsGroup::recreateSets()
+{
+    /* Clear sets first: */
+    clearItems();
+    /* Clear step: */
+    if (m_pStep)
+    {
+        delete m_pStep;
+        m_pStep = 0;
+    }
+
+    /* Load settings: */
+    loadSettings();
+
+    /* Prepare first set: */
+    m_strCurrentId = QUuid::createUuid().toString();
+    emit sigStartFirstStep(m_strCurrentId);
+}
+
+void UIGDetailsGroup::prepareSet()
+{
+    /* Step number feats the bounds: */
+    if (m_iStep >= 0 && m_iStep < m_items.size())
+    {
+        /* Create prepare step & set: */
+        m_pStep = new UIPrepareStep(this);
+        UIGDetailsSet *pSet = new UIGDetailsSet(this, m_items[m_iStep], m_settings, m_items.size() == 1);
+        connect(pSet, SIGNAL(sigSetCreationDone()), m_pStep, SLOT(sltStepDone()), Qt::QueuedConnection);
+        model()->updateLayout();
+    }
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsGroup.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsGroup.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsGroup.h	(revision 42529)
@@ -0,0 +1,105 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsGroup class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsGroup_h__
+#define __UIGDetailsGroup_h__
+
+/* GUI includes: */
+#include "UIGDetailsItem.h"
+
+/* Forward declarations: */
+class QGraphicsLinearLayout;
+class UIVMItem;
+
+/* Details group
+ * for graphics details model/view architecture: */
+class UIGDetailsGroup : public UIGDetailsItem
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifiers: Prepare stuff: */
+    void sigStartFirstStep(QString strId);
+
+public:
+
+    /* Graphics-item type: */
+    enum { Type = UIGDetailsItemType_Group };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGDetailsGroup();
+    ~UIGDetailsGroup();
+
+    /* API: Prepare stuff: */
+    void setItems(const QList<UIVMItem*> &items);
+    void rebuildItems();
+
+    /* API: Children stuff: */
+    void addItem(UIGDetailsItem *pItem);
+    void removeItem(UIGDetailsItem *pItem);
+    QList<UIGDetailsItem*> items(UIGDetailsItemType type = UIGDetailsItemType_Set) const;
+    bool hasItems(UIGDetailsItemType type = UIGDetailsItemType_Set) const;
+    void clearItems(UIGDetailsItemType type = UIGDetailsItemType_Set);
+
+    /* API: Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+
+private slots:
+
+    /* Handlers: Prepare stuff: */
+    void sltFirstStep(QString strId);
+    void sltStepDone();
+
+private:
+
+    /* Data enumerator: */
+    enum GroupItemData
+    {
+        /* Layout hints: */
+        GroupData_Margin,
+        GroupData_Spacing
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Helpers: Prepare stuff: */
+    void loadSettings();
+    void prepareLayout();
+    void prepareSets(const QList<UIVMItem*> &items);
+    void recreateSets();
+    void prepareSet();
+
+    /* Main variables: */
+    QGraphicsLinearLayout *m_pMainLayout;
+    QGraphicsLinearLayout *m_pLayout;
+    QList<UIGDetailsItem*> m_sets;
+
+    /* Prepare variables: */
+    QList<UIVMItem*> m_items;
+    UIPrepareStep *m_pStep;
+    int m_iStep;
+    QString m_strCurrentId;
+    QStringList m_settings;
+};
+
+#endif /* __UIGDetailsGroup_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsItem.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsItem.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsItem.cpp	(revision 42529)
@@ -0,0 +1,154 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsItem class definition
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QApplication>
+#include <QPainter>
+#include <QGraphicsScene>
+#include <QStyleOptionGraphicsItem>
+
+/* GUI includes: */
+#include "UIGDetailsGroup.h"
+#include "UIGDetailsSet.h"
+#include "UIGDetailsElement.h"
+#include "UIGDetailsModel.h"
+
+UIGDetailsItem::UIGDetailsItem(UIGDetailsItem *pParent)
+    : QIGraphicsWidget(pParent)
+    , m_pParent(pParent)
+{
+    /* Basic item setup: */
+    setOwnedByLayout(false);
+    setAcceptDrops(false);
+    setFocusPolicy(Qt::NoFocus);
+    setFlag(QGraphicsItem::ItemIsSelectable, false);
+
+    /* Non-root item? */
+    if (parentItem())
+    {
+        /* Non-root item setup: */
+        setAcceptHoverEvents(true);
+    }
+}
+
+UIGDetailsGroup* UIGDetailsItem::toGroup()
+{
+    UIGDetailsGroup *pItem = qgraphicsitem_cast<UIGDetailsGroup*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGDetailsGroup!"));
+    return pItem;
+}
+
+UIGDetailsSet* UIGDetailsItem::toSet()
+{
+    UIGDetailsSet *pItem = qgraphicsitem_cast<UIGDetailsSet*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGDetailsSet!"));
+    return pItem;
+}
+
+UIGDetailsElement* UIGDetailsItem::toElement()
+{
+    UIGDetailsElement *pItem = qgraphicsitem_cast<UIGDetailsElement*>(this);
+    AssertMsg(pItem, ("Trying to cast invalid item type to UIGDetailsElement!"));
+    return pItem;
+}
+
+UIGDetailsModel* UIGDetailsItem::model() const
+{
+    UIGDetailsModel *pModel = qobject_cast<UIGDetailsModel*>(QIGraphicsWidget::scene()->parent());
+    AssertMsg(pModel, ("Incorrect graphics scene parent set!"));
+    return pModel;
+}
+
+UIGDetailsItem* UIGDetailsItem::parentItem() const
+{
+    return m_pParent;
+}
+
+#if 0
+void UIGDetailsItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
+{
+}
+
+void UIGDetailsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
+{
+}
+#endif
+
+/* static */
+void UIGDetailsItem::configurePainterShape(QPainter *pPainter,
+                                           const QStyleOptionGraphicsItem *pOption,
+                                           int iRadius)
+{
+    /* Rounded corners? */
+    if (iRadius)
+    {
+        /* Setup clipping: */
+        QPainterPath roundedPath;
+        roundedPath.addRoundedRect(pOption->rect, iRadius, iRadius);
+        pPainter->setRenderHint(QPainter::Antialiasing);
+        pPainter->setClipPath(roundedPath);
+    }
+}
+
+/* static */
+void UIGDetailsItem::paintFrameRect(QPainter *pPainter, const QRect &rect, int iRadius)
+{
+    pPainter->save();
+    QPalette pal = QApplication::palette();
+    QColor base = pal.color(QPalette::Active, QPalette::Window);
+    pPainter->setPen(base.darker(160));
+    if (iRadius)
+        pPainter->drawRoundedRect(rect, iRadius, iRadius);
+    else
+        pPainter->drawRect(rect);
+    pPainter->restore();
+}
+
+/* static */
+void UIGDetailsItem::paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap)
+{
+    pPainter->drawPixmap(rect, pixmap);
+}
+
+/* static */
+void UIGDetailsItem::paintText(QPainter *pPainter, const QRect &rect, const QFont &font,
+                               const QString &strText, bool fUrl /* = false */)
+{
+    pPainter->save();
+    pPainter->setFont(font);
+    if (fUrl)
+    {
+        QPalette pal = QApplication::palette();
+        pPainter->setPen(pal.color(QPalette::Link));
+    }
+    pPainter->drawText(rect, strText);
+    pPainter->restore();
+}
+
+UIPrepareStep::UIPrepareStep(QObject *pParent)
+    : QObject(pParent)
+{
+    connect(this, SIGNAL(sigStepDone()), pParent, SLOT(sltStepDone()), Qt::QueuedConnection);
+}
+
+void UIPrepareStep::sltStepDone()
+{
+    emit sigStepDone();
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsItem.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsItem.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsItem.h	(revision 42529)
@@ -0,0 +1,119 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsItem class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsItem_h__
+#define __UIGDetailsItem_h__
+
+/* GUI includes: */
+#include "QIGraphicsWidget.h"
+
+/* Forward declaration: */
+class UIGDetailsModel;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneMouseEvent;
+class UIGDetailsGroup;
+class UIGDetailsSet;
+class UIGDetailsElement;
+
+/* UIGDetailsItem types: */
+enum UIGDetailsItemType
+{
+    UIGDetailsItemType_Any     = QGraphicsItem::UserType,
+    UIGDetailsItemType_Group   = QGraphicsItem::UserType + 1,
+    UIGDetailsItemType_Set     = QGraphicsItem::UserType + 2,
+    UIGDetailsItemType_Element = QGraphicsItem::UserType + 3,
+    UIGDetailsItemType_Preview = QGraphicsItem::UserType + 10
+};
+
+/* Details item interface
+ * for graphics details model/view architecture: */
+class UIGDetailsItem : public QIGraphicsWidget
+{
+    Q_OBJECT;
+
+public:
+
+    /* Constructor: */
+    UIGDetailsItem(UIGDetailsItem *pParent);
+
+    /* API: Cast stuff: */
+    UIGDetailsGroup* toGroup();
+    UIGDetailsSet* toSet();
+    UIGDetailsElement* toElement();
+
+    /* API: Model stuff: */
+    UIGDetailsModel* model() const;
+
+    /* API: Parent stuff: */
+    UIGDetailsItem* parentItem() const;
+
+    /* API: Children stuff: */
+    virtual void addItem(UIGDetailsItem *pItem) = 0;
+    virtual void removeItem(UIGDetailsItem *pItem) = 0;
+    virtual QList<UIGDetailsItem*> items(UIGDetailsItemType type = UIGDetailsItemType_Any) const = 0;
+    virtual bool hasItems(UIGDetailsItemType type = UIGDetailsItemType_Any) const = 0;
+    virtual void clearItems(UIGDetailsItemType type = UIGDetailsItemType_Any) = 0;
+
+    /* API: Layout stuff: */
+    virtual void updateSizeHint() = 0;
+    virtual void updateLayout() = 0;
+
+protected:
+
+#if 0
+    /* Hover-enter event: */
+    void hoverEnterEvent(QGraphicsSceneHoverEvent *pEvent);
+    /* Hover-leave event: */
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent);
+#endif
+
+    /* Helpers: Paint stuff: */
+    static void configurePainterShape(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, int iRadius);
+    static void paintFrameRect(QPainter *pPainter, const QRect &rect, int iRadius);
+    static void paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap);
+    static void paintText(QPainter *pPainter, const QRect &rect, const QFont &font, const QString &strText, bool fUrl = false);
+
+private:
+
+    /* Variables: */
+    UIGDetailsItem *m_pParent;
+};
+
+/* Allows to prepare item synchronously: */
+class UIPrepareStep : public QObject
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifiers: Prepare stuff: */
+    void sigStepDone();
+
+public:
+
+    /* Constructor: */
+    UIPrepareStep(QObject *pParent);
+
+private slots:
+
+    /* Handlers: Prepare stuff: */
+    void sltStepDone();
+};
+
+#endif /* __UIGDetailsItem_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsModel.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsModel.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsModel.cpp	(revision 42529)
@@ -0,0 +1,234 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsModel class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QGraphicsSceneContextMenuEvent>
+
+/* GUI includes: */
+#include "UIGDetailsModel.h"
+#include "UIGDetailsGroup.h"
+#include "UIGDetailsElement.h"
+#include "UIGChooserItemGroup.h"
+#include "UIGChooserItemMachine.h"
+#include "VBoxGlobal.h"
+#include "UIMessageCenter.h"
+#include "UIConverter.h"
+
+/* COM includes: */
+#include "CMachine.h"
+
+UIGDetailsModel::UIGDetailsModel(QObject *pParent)
+    : QObject(pParent)
+    , m_pScene(0)
+    , m_pRoot(0)
+{
+    /* Prepare scene: */
+    prepareScene();
+
+    /* Prepare root: */
+    prepareRoot();
+}
+
+UIGDetailsModel::~UIGDetailsModel()
+{
+    /* Cleanup root: */
+    cleanupRoot();
+
+    /* Cleanup scene: */
+    cleanupScene();
+ }
+
+QGraphicsScene* UIGDetailsModel::scene() const
+{
+    return m_pScene;
+}
+
+QGraphicsItem* UIGDetailsModel::itemAt(const QPointF &position, const QTransform &deviceTransform /* = QTransform() */) const
+{
+    return scene()->itemAt(position, deviceTransform);
+}
+
+void UIGDetailsModel::setItems(const QList<UIVMItem*> &items)
+{
+    m_pRoot->setItems(items);
+}
+
+void UIGDetailsModel::updateLayout()
+{
+    /* Initialize variables: */
+    int iSceneMargin = data(DetailsModelData_Margin).toInt();
+    QSize viewportSize = scene()->views()[0]->viewport()->size();
+    int iViewportWidth = viewportSize.width() - 2 * iSceneMargin;
+    int iViewportHeight = viewportSize.height() - 2 * iSceneMargin;
+    /* Update all the size-hints recursively: */
+    m_pRoot->updateSizeHint();
+    /* Set root item position: */
+    m_pRoot->setPos(iSceneMargin, iSceneMargin);
+    /* Set root item size: */
+    m_pRoot->resize(iViewportWidth, iViewportHeight);
+    /* Relayout root item: */
+    m_pRoot->updateLayout();
+    /* Notify listener about root-item relayouted: */
+    emit sigRootItemResized(m_pRoot->geometry().size(), m_pRoot->minimumSizeHint().toSize().width());
+}
+
+void UIGDetailsModel::sltHandleViewResized()
+{
+    /* Relayout: */
+    updateLayout();
+}
+
+void UIGDetailsModel::sltToggleElements(DetailsElementType type, bool fToggled)
+{
+    /* For each the set of the group: */
+    foreach (UIGDetailsItem *pSetItem, m_pRoot->items())
+    {
+        /* For each the element of the set: */
+        foreach (UIGDetailsItem *pElementItem, pSetItem->items())
+        {
+            /* Get each element: */
+            UIGDetailsElement *pElement = pElementItem->toElement();
+            /* Check if this element is of required type: */
+            if (pElement->elementType() == type)
+            {
+                if (fToggled && pElement->closed())
+                    pElement->open();
+                else if (!fToggled && pElement->opened())
+                    pElement->close();
+            }
+        }
+    }
+
+    /* Update details settings: */
+    QStringList detailsSettings = vboxGlobal().virtualBox().GetExtraDataStringList(GUI_DetailsPageBoxes);
+    QString strOldElementName = gpConverter->toInternalString(type);
+    QString strNewElementName = strOldElementName;
+    if (fToggled)
+        strOldElementName += "Closed";
+    else
+        strNewElementName += "Closed";
+    int iIndex = detailsSettings.indexOf(strOldElementName);
+    if (iIndex != -1)
+    {
+        detailsSettings[iIndex] = strNewElementName;
+        vboxGlobal().virtualBox().SetExtraDataStringList(GUI_DetailsPageBoxes, detailsSettings);
+    }
+}
+
+void UIGDetailsModel::sltElementTypeToggled()
+{
+    /* Which item was toggled? */
+    QAction *pAction = qobject_cast<QAction*>(sender());
+    DetailsElementType elementType = pAction->data().value<DetailsElementType>();
+    QString strElementTypeOpened = gpConverter->toInternalString(elementType);
+    QString strElementTypeClosed = strElementTypeOpened + "Closed";
+    QStringList detailsSettings = vboxGlobal().virtualBox().GetExtraDataStringList(GUI_DetailsPageBoxes);
+    /* Update details settings: */
+    bool fElementExists = detailsSettings.contains(strElementTypeOpened) ||
+                          detailsSettings.contains(strElementTypeClosed);
+    if (fElementExists)
+    {
+        detailsSettings.removeAll(strElementTypeOpened);
+        detailsSettings.removeAll(strElementTypeClosed);
+    }
+    else
+    {
+        detailsSettings.append(strElementTypeClosed);
+    }
+    vboxGlobal().virtualBox().SetExtraDataStringList(GUI_DetailsPageBoxes, detailsSettings);
+    m_pRoot->rebuildItems();
+}
+
+QVariant UIGDetailsModel::data(int iKey) const
+{
+    switch (iKey)
+    {
+        case DetailsModelData_Margin: return 0;
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGDetailsModel::prepareScene()
+{
+    m_pScene = new QGraphicsScene(this);
+    m_pScene->installEventFilter(this);
+}
+
+void UIGDetailsModel::prepareRoot()
+{
+    m_pRoot = new UIGDetailsGroup;
+    scene()->addItem(m_pRoot);
+}
+
+void UIGDetailsModel::cleanupRoot()
+{
+    delete m_pRoot;
+    m_pRoot = 0;
+}
+
+void UIGDetailsModel::cleanupScene()
+{
+    delete m_pScene;
+    m_pScene = 0;
+}
+
+bool UIGDetailsModel::eventFilter(QObject *pObject, QEvent *pEvent)
+{
+    /* Ignore if no scene object: */
+    if (pObject != scene())
+        return QObject::eventFilter(pObject, pEvent);
+
+    /* Ignore if no context-menu event: */
+    if (pEvent->type() != QEvent::GraphicsSceneContextMenu)
+        return QObject::eventFilter(pObject, pEvent);
+
+    /* Process context menu event: */
+    return processContextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(pEvent));
+}
+
+bool UIGDetailsModel::processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent)
+{
+    /* Pass preview context menu instead: */
+    if (QGraphicsItem *pItem = itemAt(pEvent->scenePos()))
+        if (pItem->type() == UIGDetailsItemType_Preview)
+            return false;
+
+    /* Prepare context-menu: */
+    QMenu contextMenu;
+    QStringList detailsSettings = vboxGlobal().virtualBox().GetExtraDataStringList(GUI_DetailsPageBoxes);
+    for (int iType = DetailsElementType_General; iType <= DetailsElementType_Description; ++iType)
+    {
+        DetailsElementType currentElementType = (DetailsElementType)iType;
+        QAction *pAction = contextMenu.addAction(gpConverter->toString(currentElementType), this, SLOT(sltElementTypeToggled()));
+        pAction->setCheckable(true);
+        QString strTypeIdOpened = gpConverter->toInternalString(currentElementType);
+        QString strTypeIdClosed = strTypeIdOpened + "Closed";
+        pAction->setChecked(detailsSettings.contains(strTypeIdOpened) || detailsSettings.contains(strTypeIdClosed));
+        pAction->setData(QVariant::fromValue(currentElementType));
+    }
+    /* Exec context-menu: */
+    contextMenu.exec(pEvent->screenPos());
+
+    /* Filter: */
+    return true;
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsModel.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsModel.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsModel.h	(revision 42529)
@@ -0,0 +1,116 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsModel class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsModel_h__
+#define __UIGDetailsModel_h__
+
+/* Qt includes: */
+#include <QObject>
+#include <QPointer>
+#include <QTransform>
+#include <QMap>
+#include <QSet>
+
+/* GUI includes: */
+#include "UIDefs.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+
+/* Forward declaration: */
+class QGraphicsItem;
+class QGraphicsScene;
+class QGraphicsSceneContextMenuEvent;
+class UIGDetailsGroup;
+class UIVMItem;
+
+/* Graphics selector model: */
+class UIGDetailsModel : public QObject
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notify listeners about root-item height changed: */
+    void sigRootItemResized(const QSizeF &size, int iMinimumWidth);
+
+    /* Link-click stuff: */
+    void sigLinkClicked(const QString &strCategory, const QString &strControl, const QString &strId);
+
+public:
+
+    /* Constructor/destructor: */
+    UIGDetailsModel(QObject *pParent);
+    ~UIGDetailsModel();
+
+    /* API: Scene getter: */
+    QGraphicsScene* scene() const;
+
+    /* API: Item positioning stuff: */
+    QGraphicsItem* itemAt(const QPointF &position, const QTransform &deviceTransform = QTransform()) const;
+
+    /* API: Group/machine stuff: */
+    void setItems(const QList<UIVMItem*> &items);
+
+    /* API: Layout stuff: */
+    void updateLayout();
+
+private slots:
+
+    /* Handler: View-resize: */
+    void sltHandleViewResized();
+
+    /* Handler: Toggle stuff: */
+    void sltToggleElements(DetailsElementType type, bool fToggled);
+
+    /* Handler: Context-menu stuff: */
+    void sltElementTypeToggled();
+
+private:
+
+    /* Data enumerator: */
+    enum DetailsModelData
+    {
+        /* Layout hints: */
+        DetailsModelData_Margin
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Helpers: Prepare stuff: */
+    void prepareScene();
+    void prepareRoot();
+
+    /* Helpers: Cleanup stuff: */
+    void cleanupRoot();
+    void cleanupScene();
+
+    /* Handler: Event-filter stuff: */
+    bool eventFilter(QObject *pObject, QEvent *pEvent);
+
+    /* Handler: Context menu stuff: */
+    bool processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent);
+
+    /* Variables: */
+    QGraphicsScene *m_pScene;
+    UIGDetailsGroup *m_pRoot;
+};
+
+#endif /* __UIGDetailsModel_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.cpp	(revision 42529)
@@ -0,0 +1,486 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsSet class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* GUI includes: */
+#include "UIGDetailsSet.h"
+#include "UIGDetailsModel.h"
+#include "UIGDetailsElements.h"
+#include "UIVMItem.h"
+#include "UIConverter.h"
+
+/* COM includes: */
+#include "CUSBController.h"
+
+UIGDetailsSet::UIGDetailsSet(UIGDetailsItem *pParent, UIVMItem *pItem,
+                             const QStringList &settings, bool fFullSet)
+    : UIGDetailsItem(pParent)
+    , m_machine(pItem->machine())
+    , m_iStep(-1)
+    , m_iLastStep(-1)
+    , m_settings(settings)
+{
+    /* Setup size-policy: */
+    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+
+    /* Create elements step-by-step: */
+    prepareElements(fFullSet);
+
+    /* Add item to the parent: */
+    parentItem()->addItem(this);
+}
+
+UIGDetailsSet::~UIGDetailsSet()
+{
+    /* Delete all the items: */
+    clearItems();
+
+    /* Remove item from the parent: */
+    parentItem()->removeItem(this);
+}
+
+const CMachine& UIGDetailsSet::machine() const
+{
+    return m_machine;
+}
+
+void UIGDetailsSet::sltElementPrepared()
+{
+    /* Prepare next element: */
+    ++m_iStep;
+    prepareElement();
+}
+
+void UIGDetailsSet::sltSetPrepared()
+{
+    m_iStep = -1;
+    /* Notify parent group: */
+    emit sigSetCreationDone();
+}
+
+QVariant UIGDetailsSet::data(int iKey) const
+{
+    /* Provide other members with required data: */
+    switch (iKey)
+    {
+        /* Layout hints: */
+        case SetData_Margin: return 0;
+        case SetData_Spacing: return 1;
+        /* Default: */
+        default: break;
+    }
+    return QVariant();
+}
+
+void UIGDetailsSet::addItem(UIGDetailsItem *pItem)
+{
+    switch (pItem->type())
+    {
+        case UIGDetailsItemType_Element: m_elements.append(pItem); break;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+}
+
+void UIGDetailsSet::removeItem(UIGDetailsItem *pItem)
+{
+    switch (pItem->type())
+    {
+        case UIGDetailsItemType_Element: m_elements.removeAt(m_elements.indexOf(pItem)); break;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+}
+
+QList<UIGDetailsItem*> UIGDetailsSet::items(UIGDetailsItemType type /* = UIGDetailsItemType_Element */) const
+{
+    switch (type)
+    {
+        case UIGDetailsItemType_Any: return items(UIGDetailsItemType_Element);
+        case UIGDetailsItemType_Element: return m_elements;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+    return QList<UIGDetailsItem*>();
+}
+
+bool UIGDetailsSet::hasItems(UIGDetailsItemType type /* = UIGDetailsItemType_Element */) const
+{
+    switch (type)
+    {
+        case UIGDetailsItemType_Any: return hasItems(UIGDetailsItemType_Element);
+        case UIGDetailsItemType_Element: return !m_elements.isEmpty();
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+    return false;
+}
+
+void UIGDetailsSet::clearItems(UIGDetailsItemType type /* = UIGDetailsItemType_Element */)
+{
+    switch (type)
+    {
+        case UIGDetailsItemType_Any: clearItems(UIGDetailsItemType_Element); break;
+        case UIGDetailsItemType_Element: while (!m_elements.isEmpty()) { delete m_elements.last(); } break;
+        default: AssertMsgFailed(("Invalid item type!")); break;
+    }
+}
+
+UIGDetailsElement* UIGDetailsSet::element(DetailsElementType elementType) const
+{
+    foreach (UIGDetailsItem *pItem, items())
+        if (UIGDetailsElement *pElementItem = pItem->toElement())
+            if (pElementItem->elementType() == elementType)
+                return pElementItem;
+    return 0;
+}
+
+void UIGDetailsSet::updateSizeHint()
+{
+    /* Update size-hints for all the items: */
+    foreach (UIGDetailsItem *pItem, items())
+        pItem->updateSizeHint();
+    /* Update size-hint for this item: */
+    updateGeometry();
+}
+
+void UIGDetailsSet::updateLayout()
+{
+    /* Prepare variables: */
+    int iMargin = data(SetData_Margin).toInt();
+    int iSpacing = data(SetData_Spacing).toInt();
+    int iMaximumWidth = geometry().size().toSize().width();
+    int iVerticalIndent = iMargin;
+
+    /* Layout all the elements: */
+    foreach (UIGDetailsItem *pItem, items())
+    {
+        /* Get particular element: */
+        UIGDetailsElement *pElement = pItem->toElement();
+
+        /* For each particular element: */
+        switch (pElement->elementType())
+        {
+            case DetailsElementType_General:
+            case DetailsElementType_System:
+            {
+                UIGDetailsElement *pPreviewElement = element(DetailsElementType_Preview);
+                int iPreviewWidth = pPreviewElement ? pPreviewElement->minimumWidthHint() : 0;
+                int iWidth = iPreviewWidth == 0 ? iMaximumWidth - 2 * iMargin :
+                                                  iMaximumWidth - 2 * iMargin - iSpacing - iPreviewWidth;
+                int iHeight = pElement->minimumHeightHint();
+                pElement->setPos(iMargin, iVerticalIndent);
+                pElement->resize(iWidth, iHeight);
+                pItem->updateLayout();
+                iVerticalIndent += (iHeight + iSpacing);
+                break;
+            }
+            case DetailsElementType_Preview:
+            {
+                int iWidth = pElement->minimumWidthHint();
+                int iHeight = pElement->minimumHeightHint();
+                pElement->setPos(iMaximumWidth - iMargin - iWidth, iMargin);
+                pElement->resize(iWidth, iHeight);
+                pItem->updateLayout();
+                iVerticalIndent = qMax(iVerticalIndent, iHeight + iSpacing);
+                break;
+            }
+            case DetailsElementType_Display:
+            case DetailsElementType_Storage:
+            case DetailsElementType_Audio:
+            case DetailsElementType_Network:
+            case DetailsElementType_Serial:
+#ifdef VBOX_WITH_PARALLEL_PORTS
+            case DetailsElementType_Parallel:
+#endif /* VBOX_WITH_PARALLEL_PORTS */
+            case DetailsElementType_USB:
+            case DetailsElementType_SF:
+            case DetailsElementType_Description:
+            {
+                int iWidth = iMaximumWidth - 2 * iMargin;
+                int iHeight = pElement->minimumHeightHint();
+                pElement->setPos(iMargin, iVerticalIndent);
+                pElement->resize(iWidth, iHeight);
+                iVerticalIndent += (iHeight + iSpacing);
+                pItem->updateLayout();
+                break;
+            }
+        }
+    }
+}
+
+int UIGDetailsSet::minimumWidthHint() const
+{
+    /* Prepare variables: */
+    int iMargin = data(SetData_Margin).toInt();
+    int iSpacing = data(SetData_Spacing).toInt();
+    int iProposedWidth = 0;
+
+    /* Layout all the elements: */
+    foreach (UIGDetailsItem *pItem, items())
+    {
+        /* Get particular element: */
+        UIGDetailsElement *pElement = pItem->toElement();
+
+        /* For each particular element: */
+        switch (pElement->elementType())
+        {
+            case DetailsElementType_General:
+            case DetailsElementType_System:
+            case DetailsElementType_Display:
+            case DetailsElementType_Storage:
+            case DetailsElementType_Audio:
+            case DetailsElementType_Network:
+            case DetailsElementType_Serial:
+#ifdef VBOX_WITH_PARALLEL_PORTS
+            case DetailsElementType_Parallel:
+#endif /* VBOX_WITH_PARALLEL_PORTS */
+            case DetailsElementType_USB:
+            case DetailsElementType_SF:
+            case DetailsElementType_Description:
+            {
+                iProposedWidth = qMax(iProposedWidth, pElement->minimumWidthHint());
+                break;
+            }
+            case DetailsElementType_Preview:
+            {
+                UIGDetailsElement *pGeneralElement = element(DetailsElementType_General);
+                UIGDetailsElement *pSystemElement = element(DetailsElementType_System);
+                int iGeneralElementWidth = pGeneralElement ? pGeneralElement->minimumWidthHint() : 0;
+                int iSystemElementWidth = pSystemElement ? pSystemElement->minimumWidthHint() : 0;
+                int iFirstColumnWidth = qMax(iGeneralElementWidth, iSystemElementWidth);
+                iProposedWidth = qMax(iProposedWidth, iFirstColumnWidth + iSpacing + pElement->minimumWidthHint());
+                break;
+            }
+        }
+    }
+
+    /* Two margins finally: */
+    iProposedWidth += 2 * iMargin;
+
+    /* Return result: */
+    return iProposedWidth;
+}
+
+int UIGDetailsSet::minimumHeightHint() const
+{
+    /* Prepare variables: */
+    int iMargin = data(SetData_Margin).toInt();
+    int iSpacing = data(SetData_Spacing).toInt();
+    int iProposedHeight = 0;
+
+    /* Layout all the elements: */
+    foreach (UIGDetailsItem *pItem, items())
+    {
+        /* Get particular element: */
+        UIGDetailsElement *pElement = pItem->toElement();
+
+        /* For each particular element: */
+        switch (pElement->elementType())
+        {
+            case DetailsElementType_General:
+            case DetailsElementType_System:
+            case DetailsElementType_Display:
+            case DetailsElementType_Storage:
+            case DetailsElementType_Audio:
+            case DetailsElementType_Network:
+            case DetailsElementType_Serial:
+#ifdef VBOX_WITH_PARALLEL_PORTS
+            case DetailsElementType_Parallel:
+#endif /* VBOX_WITH_PARALLEL_PORTS */
+            case DetailsElementType_USB:
+            case DetailsElementType_SF:
+            case DetailsElementType_Description:
+            {
+                iProposedHeight += (pElement->minimumHeightHint() + iSpacing);
+                break;
+            }
+            case DetailsElementType_Preview:
+            {
+                iProposedHeight = qMax(iProposedHeight, pElement->minimumHeightHint() + iSpacing);
+                break;
+            }
+        }
+    }
+
+    /* Minus last spacing: */
+    iProposedHeight -= iSpacing;
+
+    /* Two margins finally: */
+    iProposedHeight += 2 * iMargin;
+
+    /* Return result: */
+    return iProposedHeight;
+}
+
+QSizeF UIGDetailsSet::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    /* If Qt::MinimumSize requested: */
+    if (which == Qt::MinimumSize || which == Qt::PreferredSize)
+    {
+        /* Return wrappers: */
+        return QSizeF(minimumWidthHint(), minimumHeightHint());
+    }
+
+    /* Call to base-class: */
+    return UIGDetailsItem::sizeHint(which, constraint);
+}
+
+void UIGDetailsSet::prepareElements(bool fFullSet)
+{
+    /* Prepare steps: */
+    m_iStep = DetailsElementType_General;
+    m_iLastStep = fFullSet ? DetailsElementType_Description : DetailsElementType_Preview;
+
+    /* Prepare connections: */
+    connect(this, SIGNAL(sigElementPrepared()), this, SLOT(sltElementPrepared()), Qt::QueuedConnection);
+    connect(this, SIGNAL(sigSetPrepared()), this, SLOT(sltSetPrepared()), Qt::QueuedConnection);
+
+    /* Per-set configuration: */
+    {
+        /* USB controller restrictions: */
+        const CUSBController &ctl = machine().GetUSBController();
+        if (ctl.isNull() || !ctl.GetProxyAvailable())
+        {
+            QString strElementTypeOpened = gpConverter->toInternalString(DetailsElementType_USB);
+            QString strElementTypeClosed = strElementTypeOpened + "Closed";
+            m_settings.removeAll(strElementTypeOpened);
+            m_settings.removeAll(strElementTypeClosed);
+        }
+    }
+
+    /* Prepare first step: */
+    prepareElement();
+}
+
+void UIGDetailsSet::prepareElement()
+{
+    /* Step number feats the bounds: */
+    if (m_iStep <= m_iLastStep)
+    {
+        /* Load details settings: */
+        DetailsElementType elementType = (DetailsElementType)m_iStep;
+        QString strElementTypeOpened = gpConverter->toInternalString(elementType);
+        QString strElementTypeClosed = strElementTypeOpened + "Closed";
+
+        /* Should be element visible? */
+        bool fVisible = m_settings.contains(strElementTypeOpened) || m_settings.contains(strElementTypeClosed);
+        if (!fVisible)
+        {
+            /* Skip that element: */
+            emit sigElementPrepared();
+            return;
+        }
+
+        /* Should be element opened? */
+        bool fOpen = fVisible && m_settings.contains(strElementTypeOpened);
+
+        /* Create element: */
+        UIGDetailsElement *pElement = 0;
+        switch (m_iStep)
+        {
+            case DetailsElementType_General:
+            {
+                /* Create 'general' element: */
+                pElement = new UIGDetailsElementGeneral(this, fOpen);
+                break;
+            }
+            case DetailsElementType_System:
+            {
+                /* Create 'system' element: */
+                pElement = new UIGDetailsElementSystem(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Preview:
+            {
+                /* Create 'preview' element: */
+                pElement = new UIGDetailsElementPreview(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Display:
+            {
+                /* Create 'display' element: */
+                pElement = new UIGDetailsElementDisplay(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Storage:
+            {
+                /* Create 'storage' element: */
+                pElement = new UIGDetailsElementStorage(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Audio:
+            {
+                /* Create 'audio' element: */
+                pElement = new UIGDetailsElementAudio(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Network:
+            {
+                /* Create 'network' element: */
+                pElement = new UIGDetailsElementNetwork(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Serial:
+            {
+                /* Create 'serial' element: */
+                pElement = new UIGDetailsElementSerial(this, fOpen);
+                break;
+            }
+#ifdef VBOX_WITH_PARALLEL_PORTS
+            case DetailsElementType_Parallel:
+            {
+                /* Create 'parallel' element: */
+                pElement = new UIGDetailsElementParallel(this, fOpen);
+                break;
+            }
+#endif /* VBOX_WITH_PARALLEL_PORTS */
+            case DetailsElementType_USB:
+            {
+                /* Create 'usb' element: */
+                pElement = new UIGDetailsElementUSB(this, fOpen);
+                break;
+            }
+            case DetailsElementType_SF:
+            {
+                /* Create 'sf' element: */
+                pElement = new UIGDetailsElementSF(this, fOpen);
+                break;
+            }
+            case DetailsElementType_Description:
+            {
+                /* Create 'description' element: */
+                pElement = new UIGDetailsElementDescription(this, fOpen);
+                break;
+            }
+            default:
+            {
+                AssertMsgFailed(("Incorrect step type!"));
+                break;
+            }
+        }
+        /* Prepare element: */
+        pElement->sltUpdateAppearance();
+        model()->updateLayout();
+        /* Mark element prepared: */
+        emit sigElementPrepared();
+    }
+    /* Step number out of bounds: */
+    else
+    {
+        /* Mark whole set prepared: */
+        emit sigSetPrepared();
+    }
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.h	(revision 42529)
@@ -0,0 +1,109 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsSet class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsSet_h__
+#define __UIGDetailsSet_h__
+
+/* GUI includes: */
+#include "UIGDetailsItem.h"
+#include "UIDefs.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+#include "CMachine.h"
+
+/* Forward declarations: */
+class UIVMItem;
+
+/* Details set
+ * for graphics details model/view architecture: */
+class UIGDetailsSet : public UIGDetailsItem
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifiers: Prepare stuff: */
+    void sigElementPrepared();
+    void sigSetPrepared();
+    void sigSetCreationDone();
+
+public:
+
+    /* Graphics-item type: */
+    enum { Type = UIGDetailsItemType_Set };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGDetailsSet(UIGDetailsItem *pParent, UIVMItem *pItem,
+                  const QStringList &settings, bool fFullSet);
+    ~UIGDetailsSet();
+
+    /* API: Machine stuff: */
+    const CMachine& machine() const;
+
+private slots:
+
+    /* Handlers: Prepare stuff: */
+    void sltElementPrepared();
+    void sltSetPrepared();
+
+private:
+
+    /* Data enumerator: */
+    enum SetItemData
+    {
+        /* Layout hints: */
+        SetData_Margin,
+        SetData_Spacing
+    };
+
+    /* Data provider: */
+    QVariant data(int iKey) const;
+
+    /* Children stuff: */
+    void addItem(UIGDetailsItem *pItem);
+    void removeItem(UIGDetailsItem *pItem);
+    QList<UIGDetailsItem*> items(UIGDetailsItemType type = UIGDetailsItemType_Element) const;
+    bool hasItems(UIGDetailsItemType type = UIGDetailsItemType_Element) const;
+    void clearItems(UIGDetailsItemType type = UIGDetailsItemType_Element);
+    UIGDetailsElement* element(DetailsElementType elementType) const;
+
+    /* Helpers: Layout stuff: */
+    void updateSizeHint();
+    void updateLayout();
+    int minimumWidthHint() const;
+    int minimumHeightHint() const;
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* Helpers: Prepare stuff: */
+    void prepareElements(bool fFullSet);
+    void prepareElement();
+
+    /* Main variables: */
+    CMachine m_machine;
+    QList<UIGDetailsItem*> m_elements;
+
+    /* Prepare variables: */
+    int m_iStep;
+    int m_iLastStep;
+    QStringList m_settings;
+};
+
+#endif /* __UIGDetailsSet_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsView.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsView.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsView.cpp	(revision 42529)
@@ -0,0 +1,68 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsView class implementation
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QScrollBar>
+
+/* GUI includes: */
+#include "UIGDetailsView.h"
+#include "UIGChooserModel.h"
+
+UIGDetailsView::UIGDetailsView(QWidget *pParent)
+    : QGraphicsView(pParent)
+{
+    /* Fix palette: */
+    QPalette pal = palette();
+    pal.setColor(QPalette::Base, pal.color(QPalette::Window));
+    setPalette(pal);
+
+    /* Scrollbars policy: */
+    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+    /* Update scene-rect: */
+    updateSceneRect();
+}
+
+void UIGDetailsView::sltHandleRootItemResized(const QSizeF &size, int iMinimumWidth)
+{
+    /* Update scene-rect: */
+    updateSceneRect(size);
+
+    /* Set minimum width: */
+    setMinimumWidth(2 * frameWidth() + iMinimumWidth +
+                    verticalScrollBar()->sizeHint().width());
+}
+
+void UIGDetailsView::resizeEvent(QResizeEvent*)
+{
+    /* Update scene-rect: */
+    updateSceneRect();
+    /* Notify listeners: */
+    emit sigResized();
+}
+
+void UIGDetailsView::updateSceneRect(const QSizeF &sizeHint /* = QSizeF() */)
+{
+    QPointF topLeft = QPointF(0, 0);
+    QSizeF rectSize = viewport()->size();
+    if (!sizeHint.isNull())
+        rectSize = rectSize.expandedTo(sizeHint);
+    setSceneRect(QRectF(topLeft, rectSize));
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsView.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsView.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsView.h	(revision 42529)
@@ -0,0 +1,55 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGDetailsView class declaration
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGDetailsView_h__
+#define __UIGDetailsView_h__
+
+/* Qt includes: */
+#include <QGraphicsView>
+
+/* Graphics details view: */
+class UIGDetailsView : public QGraphicsView
+{
+    Q_OBJECT;
+
+signals:
+
+    /* Notifiers: Resize stuff: */
+    void sigResized();
+
+public:
+
+    /* Constructor: */
+    UIGDetailsView(QWidget *pParent);
+
+private slots:
+
+    /* Handlers: Resize stuff: */
+    void sltHandleRootItemResized(const QSizeF &size, int iMinimumWidth);
+
+private:
+
+    /* Event handlers: Resize stuff: */
+    void resizeEvent(QResizeEvent *pEvent);
+
+    /* Helpers: Update stuff: */
+    void updateSceneRect(const QSizeF &sizeHint = QSizeF());
+};
+
+#endif /* __UIGDetailsView_h__ */
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp	(revision 42529)
@@ -0,0 +1,487 @@
+/* $Id$ */
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGMachinePreview class implementation
+ */
+
+/*
+ * Copyright (C) 2010-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* Qt includes: */
+#include <QGraphicsSceneContextMenuEvent>
+#include <QMenu>
+#include <QPainter>
+#include <QTimer>
+
+/* GUI includes: */
+#include "UIGMachinePreview.h"
+#include "UIVirtualBoxEventHandler.h"
+#include "UIImageTools.h"
+#include "VBoxGlobal.h"
+
+/* COM includes: */
+#include "CConsole.h"
+#include "CDisplay.h"
+
+UpdateIntervalMap CreateUpdateIntervalMap()
+{
+    UpdateIntervalMap map;
+    map[UpdateInterval_Disabled] = "disabled";
+    map[UpdateInterval_500ms]    = "500";
+    map[UpdateInterval_1000ms]   = "1000";
+    map[UpdateInterval_2000ms]   = "2000";
+    map[UpdateInterval_5000ms]   = "5000";
+    map[UpdateInterval_10000ms]  = "10000";
+    return map;
+}
+UpdateIntervalMap UIGMachinePreview::m_intervals = CreateUpdateIntervalMap();
+
+UIGMachinePreview::UIGMachinePreview(QIGraphicsWidget *pParent)
+    : QIGraphicsWidget(pParent)
+    , m_machineState(KMachineState_Null)
+    , m_pUpdateTimer(new QTimer(this))
+    , m_pUpdateTimerMenu(0)
+    , m_vMargin(10)
+    , m_pbgImage(0)
+    , m_pPreviewImg(0)
+    , m_pGlossyImg(0)
+{
+    /* Setup contents: */
+    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+    /* Create session instance: */
+    m_session.createInstance(CLSID_Session);
+
+    /* Create the context menu: */
+    m_pUpdateTimerMenu = new QMenu;
+    QActionGroup *pUpdateTimeG = new QActionGroup(this);
+    pUpdateTimeG->setExclusive(true);
+    for(int i = 0; i < UpdateInterval_Max; ++i)
+    {
+        QAction *pUpdateTime = new QAction(pUpdateTimeG);
+        pUpdateTime->setData(i);
+        pUpdateTime->setCheckable(true);
+        pUpdateTimeG->addAction(pUpdateTime);
+        m_pUpdateTimerMenu->addAction(pUpdateTime);
+        m_actions[static_cast<UpdateInterval>(i)] = pUpdateTime;
+    }
+    m_pUpdateTimerMenu->insertSeparator(m_actions[static_cast<UpdateInterval>(UpdateInterval_500ms)]);
+
+    /* Load preview update interval: */
+    QString strInterval = vboxGlobal().virtualBox().GetExtraData(GUI_PreviewUpdate);
+    /* Parse loaded value: */
+    UpdateInterval interval = m_intervals.key(strInterval, UpdateInterval_1000ms);
+    /* Initialize with the new update interval: */
+    setUpdateInterval(interval, false);
+
+    /* Setup connections: */
+    connect(m_pUpdateTimer, SIGNAL(timeout()), this, SLOT(sltRecreatePreview()));
+    connect(gVBoxEvents, SIGNAL(sigMachineStateChange(QString, KMachineState)),
+            this, SLOT(sltMachineStateChange(QString, KMachineState)));
+
+    /* Retranslate the UI */
+    retranslateUi();
+}
+
+UIGMachinePreview::~UIGMachinePreview()
+{
+    /* Close any open session: */
+    if (m_session.GetState() == KSessionState_Locked)
+        m_session.UnlockMachine();
+    if (m_pbgImage)
+        delete m_pbgImage;
+    if (m_pGlossyImg)
+        delete m_pGlossyImg;
+    if (m_pPreviewImg)
+        delete m_pPreviewImg;
+    if (m_pUpdateTimerMenu)
+        delete m_pUpdateTimerMenu;
+}
+
+void UIGMachinePreview::setMachine(const CMachine& machine)
+{
+    stop();
+    m_machine = machine;
+    restart();
+}
+
+CMachine UIGMachinePreview::machine() const
+{
+    return m_machine;
+}
+
+void UIGMachinePreview::sltMachineStateChange(QString strId, KMachineState state)
+{
+    if (!m_machine.isNull() && m_machine.GetId() == strId)
+    {
+        /* Cache the machine state: */
+        m_machineState = state;
+        restart();
+    }
+}
+
+void UIGMachinePreview::sltRecreatePreview()
+{
+    /* Only do this if we are visible: */
+    if (!isVisible())
+        return;
+
+    /* Remove preview if any: */
+    if (m_pPreviewImg)
+    {
+        delete m_pPreviewImg;
+        m_pPreviewImg = 0;
+    }
+
+    /* We are not creating preview for inaccessible VMs: */
+    if (m_machineState == KMachineState_Null)
+        return;
+
+    if (!m_machine.isNull() && m_vRect.width() > 0 && m_vRect.height() > 0)
+    {
+        QImage image(size().toSize(), QImage::Format_ARGB32);
+        image.fill(Qt::transparent);
+        QPainter painter(&image);
+        bool fDone = false;
+
+        /* Preview enabled? */
+        if (m_pUpdateTimer->interval() > 0)
+        {
+            /* Use the image which may be included in the save state. */
+            if (m_machineState == KMachineState_Saved || m_machineState == KMachineState_Restoring)
+            {
+                ULONG width = 0, height = 0;
+                QVector<BYTE> screenData = m_machine.ReadSavedScreenshotPNGToArray(0, width, height);
+                if (screenData.size() != 0)
+                {
+                    QImage shot = QImage::fromData(screenData.data(), screenData.size(), "PNG")
+                            .scaled(m_vRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+                    dimImage(shot);
+                    painter.drawImage(m_vRect.x(), m_vRect.y(), shot);
+                    fDone = true;
+                }
+            }
+            /* Use the current VM output. */
+            else if (m_machineState == KMachineState_Running || m_machineState == KMachineState_Paused)
+            {
+                if (m_session.GetState() == KSessionState_Locked)
+                {
+                    CVirtualBox vbox = vboxGlobal().virtualBox();
+                    if (vbox.isOk())
+                    {
+                        const CConsole& console = m_session.GetConsole();
+                        if (!console.isNull())
+                        {
+                            CDisplay display = console.GetDisplay();
+                            /* Todo: correct aspect radio */
+//                            ULONG w, h, bpp;
+//                            display.GetScreenResolution(0, w, h, bpp);
+//                            QImage shot = QImage(w, h, QImage::Format_RGB32);
+//                            shot.fill(Qt::black);
+//                            display.TakeScreenShot(0, shot.bits(), shot.width(), shot.height());
+                            QVector<BYTE> screenData = display.TakeScreenShotToArray(0, m_vRect.width(), m_vRect.height());
+                            if (display.isOk() && screenData.size() != 0)
+                            {
+                                /* Unfortunately we have to reorder the pixel
+                                 * data, cause the VBox API returns RGBA data,
+                                 * which is not a format QImage understand.
+                                 * Todo: check for 32bit alignment, for both
+                                 * the data and the scanlines. Maybe we need to
+                                 * copy the data in any case. */
+                                uint32_t *d = (uint32_t*)screenData.data();
+                                for (int i = 0; i < screenData.size() / 4; ++i)
+                                {
+                                    uint32_t e = d[i];
+                                    d[i] = RT_MAKE_U32_FROM_U8(RT_BYTE3(e), RT_BYTE2(e), RT_BYTE1(e), RT_BYTE4(e));
+                                }
+
+                                QImage shot = QImage((uchar*)d, m_vRect.width(), m_vRect.height(), QImage::Format_RGB32);
+
+                                if (m_machineState == KMachineState_Paused)
+                                    dimImage(shot);
+                                painter.drawImage(m_vRect.x(), m_vRect.y(), shot);
+                                fDone = true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (fDone)
+            m_pPreviewImg = new QImage(image);
+    }
+    update();
+}
+
+void UIGMachinePreview::resizeEvent(QGraphicsSceneResizeEvent *pEvent)
+{
+    repaintBGImages();
+    sltRecreatePreview();
+    QIGraphicsWidget::resizeEvent(pEvent);
+}
+
+void UIGMachinePreview::showEvent(QShowEvent *pEvent)
+{
+    restart();
+    QIGraphicsWidget::showEvent(pEvent);
+}
+
+void UIGMachinePreview::hideEvent(QHideEvent *pEvent)
+{
+    stop();
+    QIGraphicsWidget::hideEvent(pEvent);
+}
+
+void UIGMachinePreview::contextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent)
+{
+    QAction *pReturn = m_pUpdateTimerMenu->exec(pEvent->screenPos(), 0);
+    if (pReturn)
+    {
+        UpdateInterval interval = static_cast<UpdateInterval>(pReturn->data().toInt());
+        setUpdateInterval(interval, true);
+        restart();
+    }
+}
+
+void UIGMachinePreview::retranslateUi()
+{
+    m_actions.value(UpdateInterval_Disabled)->setText(tr("Update Disabled"));
+    m_actions.value(UpdateInterval_500ms)->setText(tr("Every 0.5 s"));
+    m_actions.value(UpdateInterval_1000ms)->setText(tr("Every 1 s"));
+    m_actions.value(UpdateInterval_2000ms)->setText(tr("Every 2 s"));
+    m_actions.value(UpdateInterval_5000ms)->setText(tr("Every 5 s"));
+    m_actions.value(UpdateInterval_10000ms)->setText(tr("Every 10 s"));
+}
+
+QSizeF UIGMachinePreview::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
+{
+    if (which == Qt::MinimumSize)
+        return QSize(220, (int)(220 * 3.0/4.0));
+    return QIGraphicsWidget::sizeHint(which, constraint);
+}
+
+void UIGMachinePreview::paint(QPainter *pPainter, const QStyleOptionGraphicsItem*, QWidget*)
+{
+    /* Where should the content go: */
+    QRect cr = contentsRect().toRect();
+    if (!cr.isValid())
+        return;
+    /* Draw the background with the monitor and the shadow: */
+    if (m_pbgImage)
+        pPainter->drawImage(cr.x(), cr.y(), *m_pbgImage);
+
+    /* If there is a preview image available: */
+    if (m_pPreviewImg)
+    {
+        /* Draw that image: */
+        pPainter->drawImage(0, 0, *m_pPreviewImg);
+    }
+    else
+    {
+        /* Fill rectangle with black color: */
+        pPainter->fillRect(m_vRect, Qt::black);
+
+        /* Compose name: */
+        QString strName = tr("No Preview");
+        if (!m_machine.isNull())
+            strName = m_machine.GetAccessible() ? m_machine.GetName() :
+                      QApplication::translate("UIVMListView", "Inaccessible");
+        /* Paint that name: */
+        QFont font = pPainter->font();
+        font.setBold(true);
+        int fFlags = Qt::AlignCenter | Qt::TextWordWrap;
+        float h = m_vRect.size().height() * .2;
+        QRect r;
+        /* Make a little magic to find out if the given text fits into our rectangle.
+         * Decrease the font pixel size as long as it doesn't fit. */
+        int cMax = 30;
+        do
+        {
+            h = h * .8;
+            font.setPixelSize((int)h);
+            pPainter->setFont(font);
+            r = pPainter->boundingRect(m_vRect, fFlags, strName);
+        }
+        while ((r.height() > m_vRect.height() || r.width() > m_vRect.width()) && cMax-- != 0);
+        pPainter->setPen(Qt::white);
+        pPainter->drawText(m_vRect, fFlags, strName);
+    }
+
+    /* Draw the glossy overlay last: */
+    if (m_pGlossyImg)
+        pPainter->drawImage(m_vRect.x(), m_vRect.y(), *m_pGlossyImg);
+}
+
+void UIGMachinePreview::setUpdateInterval(UpdateInterval interval, bool fSave)
+{
+    switch (interval)
+    {
+        case UpdateInterval_Disabled:
+        {
+            m_pUpdateTimer->setInterval(0);
+            m_pUpdateTimer->stop();
+            m_actions[interval]->setChecked(true);
+            break;
+        }
+        case UpdateInterval_500ms:
+        {
+            m_pUpdateTimer->setInterval(500);
+            m_actions[interval]->setChecked(true);
+            break;
+        }
+        case UpdateInterval_1000ms:
+        {
+            m_pUpdateTimer->setInterval(1000);
+            m_actions[interval]->setChecked(true);
+            break;
+        }
+        case UpdateInterval_2000ms:
+        {
+            m_pUpdateTimer->setInterval(2000);
+            m_actions[interval]->setChecked(true);
+            break;
+        }
+        case UpdateInterval_5000ms:
+        {
+            m_pUpdateTimer->setInterval(5000);
+            m_actions[interval]->setChecked(true);
+            break;
+        }
+        case UpdateInterval_10000ms:
+        {
+            m_pUpdateTimer->setInterval(10000);
+            m_actions[interval]->setChecked(true);
+            break;
+        }
+        case UpdateInterval_Max: break;
+    }
+    if (fSave && m_intervals.contains(interval))
+        vboxGlobal().virtualBox().SetExtraData(GUI_PreviewUpdate, m_intervals[interval]);
+}
+
+void UIGMachinePreview::repaintBGImages()
+{
+    /* Delete the old images: */
+    if (m_pbgImage)
+    {
+        delete m_pbgImage;
+        m_pbgImage = 0;
+    }
+    if (m_pGlossyImg)
+    {
+        delete m_pGlossyImg;
+        m_pGlossyImg = 0;
+    }
+
+    /* Check that there is enough room for our fancy stuff.
+     * If not we just draw nothing (the border and the blur radius). */
+    QRect cr = contentsRect().toRect();
+    if (cr.width()  < 41 || cr.height() < 41)
+        return;
+
+    QPalette pal = palette();
+    m_wRect = cr.adjusted(10, 10, -10, -10);
+    m_vRect = m_wRect.adjusted(m_vMargin, m_vMargin, -m_vMargin, -m_vMargin).adjusted(-3, -3, 3, 3);
+
+    /* First draw the shadow. Its a rounded rectangle which get blurred: */
+    QImage imageW(cr.size(), QImage::Format_ARGB32);
+    QColor bg = pal.color(QPalette::Base);
+    bg.setAlpha(0); /* We want blur to transparent _and_ whatever the base color is. */
+    imageW.fill(bg.rgba());
+    QPainter pW(&imageW);
+    pW.setBrush(QColor(30, 30, 30)); /* Dark gray */
+    pW.setPen(Qt::NoPen);
+    pW.drawRoundedRect(QRect(QPoint(0, 0), cr.size()).adjusted(10, 10, -10, -10), m_vMargin, m_vMargin);
+    pW.end();
+    /* Blur the rectangle */
+    QImage imageO(cr.size(), QImage::Format_ARGB32);
+    blurImage(imageW, imageO, 10);
+    QPainter pO(&imageO);
+
+    /* Now paint the border with a gradient to get a look of a monitor: */
+    QRect rr = QRect(QPoint(0, 0), cr.size()).adjusted(10, 10, -10, -10);
+    QLinearGradient lg(0, rr.y(), 0, rr.height());
+    QColor base(200, 200, 200); /* light variant */
+    // QColor base(80, 80, 80); /* Dark variant */
+    lg.setColorAt(0, base);
+    lg.setColorAt(0.4, base.darker(300));
+    lg.setColorAt(0.5, base.darker(400));
+    lg.setColorAt(0.7, base.darker(300));
+    lg.setColorAt(1, base);
+    pO.setBrush(lg);
+    pO.setPen(QPen(base.darker(150), 1));
+    pO.drawRoundedRect(rr, m_vMargin, m_vMargin);
+    pO.end();
+
+    /* Make a copy of the new bg image: */
+    m_pbgImage = new QImage(imageO);
+
+    /* Now the glossy overlay has to be created.
+     * Start with defining a nice looking painter path. */
+    QRect gRect = QRect(QPoint(0, 0), m_vRect.size());
+    QPainterPath glossyPath(QPointF(gRect.x(), gRect.y()));
+    glossyPath.lineTo(gRect.x() + gRect.width(), gRect.y());
+    glossyPath.lineTo(gRect.x() + gRect.width(), gRect.y() + gRect.height() * 1.0/3.0);
+    glossyPath.cubicTo(gRect.x() + gRect.width() / 2.0, gRect.y() + gRect.height() * 1.0/3.0,
+                       gRect.x() + gRect.width() / 2.0, gRect.y() + gRect.height() * 2.0/3.0,
+                       gRect.x(), gRect.y() + gRect.height() * 2.0/3.0);
+    glossyPath.closeSubpath();
+
+    /* Paint the glossy path on a QImage: */
+    QImage image(m_vRect.size(), QImage::Format_ARGB32);
+    QColor bg1(Qt::white); /* We want blur to transparent _and_ white. */
+    bg1.setAlpha(0);
+    image.fill(bg1.rgba());
+    QPainter painter(&image);
+    painter.fillPath(glossyPath, QColor(255, 255, 255, 80));
+    painter.end();
+    /* Blur the image to get a much more smooth feeling */
+    QImage image1(m_vRect.size(), QImage::Format_ARGB32);
+    blurImage(image, image1, 7);
+    m_pGlossyImg = new QImage(image1);
+
+    /* Repaint: */
+    update();
+}
+
+void UIGMachinePreview::restart()
+{
+    /* Reopen session if necessary: */
+    if (m_session.GetState() == KSessionState_Locked)
+        m_session.UnlockMachine();
+    if (!m_machine.isNull())
+    {
+        /* Fetch the latest machine state: */
+        m_machineState = m_machine.GetState();
+        /* Lock the session for the current machine: */
+        if (m_machineState == KMachineState_Running || m_machineState == KMachineState_Paused)
+            m_machine.LockMachine(m_session, KLockType_Shared);
+    }
+
+    /* Recreate the preview image: */
+    sltRecreatePreview();
+
+    /* Start the timer if necessary: */
+    if (!m_machine.isNull())
+    {
+        if (m_pUpdateTimer->interval() > 0 && m_machineState == KMachineState_Running)
+            m_pUpdateTimer->start();
+    }
+}
+
+void UIGMachinePreview::stop()
+{
+    /* Stop the timer: */
+    m_pUpdateTimer->stop();
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.h	(revision 42529)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.h	(revision 42529)
@@ -0,0 +1,119 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * UIGMachinePreview class declaration
+ */
+
+/*
+ * Copyright (C) 2010-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __UIGMachinePreview_h__
+#define __UIGMachinePreview_h__
+
+/* Qt includes: */
+#include <QHash>
+
+/* GUI includes: */
+#include "UIGDetailsItem.h"
+
+/* COM includes: */
+#include "COMEnums.h"
+#include "CSession.h"
+#include "CMachine.h"
+
+/* Forward declarations: */
+class QAction;
+class QImage;
+class QMenu;
+class QTimer;
+
+/* Update interval type: */
+enum UpdateInterval
+{
+    UpdateInterval_Disabled,
+    UpdateInterval_500ms,
+    UpdateInterval_1000ms,
+    UpdateInterval_2000ms,
+    UpdateInterval_5000ms,
+    UpdateInterval_10000ms,
+    UpdateInterval_Max
+};
+typedef QMap<UpdateInterval, QString> UpdateIntervalMap;
+
+/* Preview window class: */
+class UIGMachinePreview : public QIGraphicsWidget
+{
+    Q_OBJECT;
+
+public:
+
+    /* Graphics-item type: */
+    enum { Type = UIGDetailsItemType_Preview };
+    int type() const { return Type; }
+
+    /* Constructor/destructor: */
+    UIGMachinePreview(QIGraphicsWidget *pParent);
+    ~UIGMachinePreview();
+
+    /* API: Machine stuff: */
+    void setMachine(const CMachine& machine);
+    CMachine machine() const;
+
+private slots:
+
+    /* Handler: Global-event listener: */
+    void sltMachineStateChange(QString strId, KMachineState state);
+
+    /* Handler: Preview recreator: */
+    void sltRecreatePreview();
+
+private:
+
+    /* Helpers: Event handlers: */
+    void resizeEvent(QGraphicsSceneResizeEvent *pEvent);
+    void showEvent(QShowEvent *pEvent);
+    void hideEvent(QHideEvent *pEvent);
+    void contextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent);
+
+    /* Helpers: Translate stuff; */
+    void retranslateUi();
+
+    /* Helpers: Layout stuff: */
+    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+    /* Helpers: Paint stuff: */
+    void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
+
+    /* Helpers: Update stuff: */
+    void setUpdateInterval(UpdateInterval interval, bool fSave);
+    void repaintBGImages();
+    void restart();
+    void stop();
+
+    /* Variables: */
+    CSession m_session;
+    CMachine m_machine;
+    KMachineState m_machineState;
+    QTimer *m_pUpdateTimer;
+    QMenu *m_pUpdateTimerMenu;
+    QHash<UpdateInterval, QAction*> m_actions;
+    const int m_vMargin;
+    QRect m_wRect;
+    QRect m_vRect;
+    QImage *m_pbgImage;
+    QImage *m_pPreviewImg;
+    QImage *m_pGlossyImg;
+    static UpdateIntervalMap m_intervals;
+};
+
+#endif /* !__UIGMachinePreview_h__ */
+
