Index: /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxDefs.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxDefs.h	(revision 8158)
+++ /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxDefs.h	(revision 8159)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -172,4 +172,6 @@
 };
 
+#define MAC_LEOPARD_STYLE defined(Q_WS_MAC) && (QT_VERSION >= 0x040300)
+
 #endif // __VBoxDefs_h__
 
Index: /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxSelectorWnd.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxSelectorWnd.h	(revision 8158)
+++ /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxSelectorWnd.h	(revision 8159)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -31,16 +31,18 @@
 #include <QMainWindow>
 
-class VBoxVMListBox;
 class VBoxSnapshotsWgt;
 class VBoxVMDetailsView;
 class VBoxVMDescriptionPage;
 class VBoxVMLogViewer;
+class VBoxVMListView;
+class VBoxVMModel;
+class VBoxVMItem;
 
 class QTabWidget;
-class Q3ListBoxItem;
+class QListView;
 class QEvent;
 class QUuid;
 
-class VBoxSelectorWnd : public QMainWindow
+class VBoxSelectorWnd: public QMainWindow
 {
     Q_OBJECT
@@ -76,5 +78,5 @@
                                           bool aDescription);
 
-    void showContextMenu (Q3ListBoxItem *, const QPoint &);
+    void showContextMenu (VBoxVMItem *aItem, const QPoint &aPoint);
 
 protected:
@@ -91,7 +93,7 @@
 private slots:
 
-    void vmListBoxCurrentChanged (bool aRefreshDetails = true,
-                                  bool aRefreshSnapshots = true,
-                                  bool aRefreshDescription = true);
+    void vmListViewCurrentChanged (bool aRefreshDetails = true,
+                                   bool aRefreshSnapshots = true,
+                                   bool aRefreshDescription = true);
 
     void mediaEnumStarted();
@@ -133,6 +135,9 @@
     QAction *helpResetMessagesAction;
 
-    /* widgets */
-    VBoxVMListBox *vmListBox;
+    /* The vm list view/model */
+    VBoxVMListView *mVMListView;
+    VBoxVMModel *mVMModel;
+
+    /* The right information widgets */
     QTabWidget *vmTabWidget;
     VBoxVMDetailsView *vmDetailsView;
Index: /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxVMListBox.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxVMListBox.h	(revision 8158)
+++ /trunk/src/VBox/Frontends/VirtualBox4/include/VBoxVMListBox.h	(revision 8159)
@@ -2,9 +2,9 @@
  *
  * VBox frontends: Qt GUI ("VirtualBox"):
- * VBoxVMListBox, VBoxVMListBoxItem class declarations
+ * VBoxVMItem, VBoxVMModel, VBoxVMListView, VBoxVMItemPainter class declarations
  */
 
 /*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -24,132 +24,48 @@
 #define __VBoxVMListBox_h__
 
-#include "COMDefs.h"
-
-#include "VBoxSelectorWnd.h"
 #include "VBoxGlobal.h"
-
-#include <q3listbox.h>
-#include <qfont.h>
-#include <qdatetime.h>
-//Added by qt3to4:
-#include <QFocusEvent>
-
-struct QUuid;
-class QColorGroup;
-
-class VBoxVMListBoxTip;
-class VBoxVMListBoxItem;
-
-/**
- *
- *  The VBoxVMListBox class is a visual representation of the list of
- *  existing VMs in the VBox GUI.
- *
- *  Every item in the list box is an instance of the VBoxVMListBoxItem
- *  class.
- */
-class VBoxVMListBox : public Q3ListBox
-{
-    Q_OBJECT
-
-public:
-
-    VBoxVMListBox (QWidget *aParent = 0, const char *aName = NULL,
-                   Qt::WFlags aFlags = 0);
-
-    virtual ~VBoxVMListBox();
-
-    QFont nameFont() const { return mNameFont; }
-
-    QFont shotFont() const { return mShotFont; }
-
-    QFont stateFont (KSessionState aS) const
-    {
-        return aS == KSessionState_Closed ? font() : mStateBusyFont;
-    }
-
-    int margin() const { return mMargin; }
-
-    void refresh();
-    void refresh (const QUuid &aID);
-
-    VBoxVMListBoxItem *item (const QUuid &aID);
-
-    const QColorGroup &activeColorGroup() const;
-
-protected:
-
-    virtual void focusInEvent (QFocusEvent *aE);
-    virtual void focusOutEvent (QFocusEvent *aE);
-
-private:
-
-    CVirtualBox mVBox;
-    QFont mNameFont;
-    QFont mShotFont;
-    QFont mStateBusyFont;
-    int mMargin;
-
-    VBoxVMListBoxTip *mToolTip;
-    bool mGaveFocusToPopup;
-};
-
-/**
- *
- *  The VBoxVMListBoxItem class is a visual representation of the virtual
- *  machine in the VBoxVMListBox widget.
- *
- *  It holds a CMachine instance (passed to the constructor) to
- *  get an access to various VM data.
- */
-class VBoxVMListBoxItem : public Q3ListBoxItem
-{
-public:
-
-    VBoxVMListBoxItem (VBoxVMListBox *aLB, const CMachine &aM);
-    virtual ~VBoxVMListBoxItem();
-
-    QString text() const { return mName; }
-
-    VBoxVMListBox *vmListBox() const
-    {
-        return static_cast <VBoxVMListBox *> (listBox());
-    }
+#include "VBoxDefs.h"
+
+/* Qt includes */
+#include <QAbstractListModel>
+#include <QListView>
+#include <QItemDelegate>
+
+class VBoxVMItem
+{
+public:
+    VBoxVMItem (const CMachine &aM);
+    virtual ~VBoxVMItem();
 
     CMachine machine() const { return mMachine; }
-    void setMachine (const CMachine &aM);
-
-    void recache();
+
+    QString name() const { return mName; }
+    QIcon osIcon() const { return mAccessible ? vboxGlobal().vmGuestOSTypeIcon (mOSTypeId) :QPixmap (":/os_unknown.png"); }
+    QUuid id() const { return mId; }
+    
+    QString sessionStateName() const { return mAccessible ? vboxGlobal().toString (mState) : QObject::tr ("Inaccessible"); }
+    QIcon sessionStateIcon() const { return mAccessible ? vboxGlobal().toIcon (mState) : QPixmap (":/state_aborted_16px.png"); }
+
+    QString snapshotName() const { return mSnapshotName; }
+    ULONG snapshotCount() const { return mSnapshotCount; }
 
     QString toolTipText() const;
 
-    int height (const Q3ListBox *) const;
-    int width (const Q3ListBox *) const;
-
-    QUuid id() const { return mId; }
     bool accessible() const { return mAccessible; }
     const CVirtualBoxErrorInfo &accessError() const { return mAccessError; }
-    QString name() const { return mName; }
     KMachineState state() const { return mState; }
     KSessionState sessionState() const { return mSessionState; }
-    ULONG snapshotCount() const { return mSnapshotCount; }
-
-    /// @todo see comments in #switchTo() in VBoxVMListBox.cpp
-#if 0
-    bool canSwitchTo() const { return mWinId != (WId) ~0; }
-#endif
+
+    bool recache();
+
     bool canSwitchTo() const;
     bool switchTo();
 
-protected:
-
-    void paint (QPainter *aP);
-
 private:
 
+    /* Private member vars */
     CMachine mMachine;
 
-    /* cached machine data (to minimize server requests) */
-
+    /* Cached machine data (to minimize server requests) */
     QUuid mId;
     QString mSettingsFile;
@@ -167,9 +83,127 @@
 
     ULONG mPid;
-    /// @todo see comments in #switchTo() in VBoxVMListBox.cpp
-#if 0
-    WId mWinId;
-#endif
 };
 
+/* Make the pointer of this class public to the QVariant framework */
+Q_DECLARE_METATYPE(VBoxVMItem *);
+
+class VBoxVMModel: public QAbstractListModel
+{
+    Q_OBJECT;
+
+public:
+    enum { SnapShotDisplayRole = Qt::UserRole,
+           SnapShotFontRole,
+           SessionStateDisplayRole,
+           SessionStateDecorationRole,
+           SessionStateFontRole,
+           VBoxVMItemPtrRole };
+
+    VBoxVMModel(QObject *aParent = 0)
+        :QAbstractListModel (aParent) { refresh(); }
+
+    void addItem (VBoxVMItem *aItem);
+    void removeItem (VBoxVMItem *aItem);
+    void refreshItem (VBoxVMItem *aItem);
+
+    void itemChanged (VBoxVMItem *aItem);
+
+    void refresh();
+
+    VBoxVMItem *itemById (const QUuid &aId) const;
+    QModelIndex indexById (const QUuid &aId) const;
+
+    int rowById (const QUuid &aId) const;;
+
+    void sort (Qt::SortOrder aOrder = Qt::AscendingOrder) { sort (0, aOrder); }
+
+    /* The following are necessary model implementations */
+    void sort (int aColumn, Qt::SortOrder aOrder = Qt::AscendingOrder);
+
+    int rowCount (const QModelIndex &aParent = QModelIndex()) const;
+
+    QVariant data (const QModelIndex &aIndex, int aRole) const;
+    QVariant headerData (int aSection, Qt::Orientation aOrientation,
+                         int aRole = Qt::DisplayRole) const;
+
+    bool removeRows (int aRow, int aCount, const QModelIndex &aParent = QModelIndex());
+
+private:
+    static bool VBoxVMItemNameCompareLessThan (VBoxVMItem* aItem1, VBoxVMItem* aItem2);
+    static bool VBoxVMItemNameCompareGreaterThan (VBoxVMItem* aItem1, VBoxVMItem* aItem2);
+
+    /* Private member vars */
+    QList<VBoxVMItem *> mVMItemList;
+};
+
+class VBoxVMListView: public QListView
+{
+    Q_OBJECT;
+
+public:
+    VBoxVMListView (QWidget *aParent = 0);
+
+    void selectItemByRow (int row);
+    void selectItemById (const QUuid &aID);
+    void ensureSomeRowSelected (int aRowHint);
+    VBoxVMItem * selectedItem() const;
+
+    void ensureCurrentVisible();
+
+signals:
+    void currentChanged();
+    void activated();
+    void contextMenuRequested (VBoxVMItem *aItem, const QPoint &aPoint);
+
+protected slots:
+    void selectionChanged (const QItemSelection &aSelected, const QItemSelection &aDeselected);
+    void currentChanged (const QModelIndex &aCurrent, const QModelIndex &aPrevious);
+    void dataChanged (const QModelIndex &aTopLeft, const QModelIndex &aBottomRight);
+    void focusChanged (QWidget *aOld, QWidget *aNow);
+
+protected:
+    void mousePressEvent (QMouseEvent *aEvent);
+    bool selectCurrent();
+}; 
+
+class VBoxVMItemPainter: public QItemDelegate
+{
+public:
+    VBoxVMItemPainter (QObject *aParent = 0)
+      : QItemDelegate (aParent), mMargin (8), mSpacing (mMargin * 3 / 2) {}
+
+    QSize sizeHint (const QStyleOptionViewItem &aOption,
+                    const QModelIndex &aIndex) const;
+
+    void paint (QPainter *aPainter, const QStyleOptionViewItem &aOption,
+                const QModelIndex &aIndex) const;
+
+protected:
+    void drawBackground (QPainter *aPainter, const QStyleOptionViewItem &aOption, 
+                         const QModelIndex &aIndex) const;
+
+private:
+    inline QFontMetrics fontMetric (const QModelIndex &aIndex, int aRole) const { return QFontMetrics (aIndex.data (aRole).value<QFont>()); }
+    inline QIcon::Mode iconMode (QStyle::State aState) const
+    {
+        if (!(aState & QStyle::State_Enabled)) 
+            return QIcon::Disabled;
+        if (aState & QStyle::State_Selected) 
+            return QIcon::Selected;
+        return QIcon::Normal;
+    }
+    inline QIcon::State iconState (QStyle::State aState) const { return aState & QStyle::State_Open ? QIcon::On : QIcon::Off; }
+
+    QRect rect (const QStyleOptionViewItem &aOption,
+                const QModelIndex &aIndex, int aRole) const;
+
+    void calcLayout (const QModelIndex &aIndex,
+                     QRect *aOSType, QRect *aVMName, QRect *aShot,
+                     QRect *aStateIcon, QRect *aState) const;
+
+    /* Private member vars */
+    int mMargin;
+    int mSpacing;
+};
+
 #endif // __VBoxVMListItem_h__
Index: /trunk/src/VBox/Frontends/VirtualBox4/src/VBoxSelectorWnd.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox4/src/VBoxSelectorWnd.cpp	(revision 8158)
+++ /trunk/src/VBox/Frontends/VirtualBox4/src/VBoxSelectorWnd.cpp	(revision 8159)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -219,5 +219,5 @@
     ~VBoxVMDescriptionPage() {}
 
-    void setMachineItem (VBoxVMListBoxItem *aItem);
+    void setMachineItem (VBoxVMItem *aItem);
 
     void languageChange();
@@ -230,5 +230,5 @@
 private:
 
-    VBoxVMListBoxItem *mItem;
+    VBoxVMItem *mItem;
 
     VBoxSelectorWnd *mParent;
@@ -298,5 +298,5 @@
  * unnecessary RPC calls.
  */
-void VBoxVMDescriptionPage::setMachineItem (VBoxVMListBoxItem *aItem)
+void VBoxVMDescriptionPage::setMachineItem (VBoxVMItem *aItem)
 {
     mItem = aItem;
@@ -455,29 +455,36 @@
     QHBoxLayout *centralLayout =
         new QHBoxLayout (centralWidget());
-    centralLayout->setSpacing (9);
-    VBoxGlobal::setLayoutMargin (centralLayout, 5);
 
     /* left vertical box */
     QVBoxLayout *leftVLayout = new QVBoxLayout ();
-    leftVLayout->setSpacing (5);
     /* right vertical box */
     QVBoxLayout *rightVLayout = new QVBoxLayout ();
-    rightVLayout->setSpacing (5);
-    centralLayout->addLayout (leftVLayout, 3);
-    centralLayout->addLayout (rightVLayout, 3);
+    centralLayout->addLayout (leftVLayout, 1);
+    centralLayout->addLayout (rightVLayout, 2);
 
     /* VM list toolbar */
     VBoxToolBar *vmTools = new VBoxToolBar (this);
-#if defined (Q_WS_MAC) && (QT_VERSION >= 0x040300)
+#if MAC_LEOPARD_STYLE
     /* Enable unified toolbars on Mac OS X. Available on Qt >= 4.3 */
     setUnifiedTitleAndToolBarOnMac (true);
     addToolBar (vmTools);
-#else
+    /* No spacing/margin on the mac */
+    VBoxGlobal::setLayoutMargin (centralLayout, 0);
+    leftVLayout->setSpacing (0);
+    rightVLayout->setSpacing (0);
+#else /* MAC_LEOPARD_STYLE */
     leftVLayout->addWidget(vmTools);
-#endif
-
-    /* VM list box */
-    vmListBox = new VBoxVMListBox ();
-    leftVLayout->addWidget (vmListBox);
+    centralLayout->setSpacing (9);
+    VBoxGlobal::setLayoutMargin (centralLayout, 5);
+    leftVLayout->setSpacing (5);
+    rightVLayout->setSpacing (5);
+#endif /* MAC_LEOPARD_STYLE */
+
+    /* VM list view */
+    mVMListView = new VBoxVMListView();
+    mVMModel = new VBoxVMModel();
+    mVMListView->setModel (mVMModel);
+
+    leftVLayout->addWidget (mVMListView);
 
     /* VM tab widget containing details and snapshots tabs */
@@ -614,4 +621,6 @@
     }
 
+    /* Reset to the first item */
+    mVMListView->selectItemByRow (0);
     /* restore the position of vm selector */
     {
@@ -619,7 +628,5 @@
         QString prevVMId = vbox.GetExtraData (VBoxDefs::GUI_LastVMSelected);
 
-        VBoxVMListBoxItem *item = vmListBox->item (QUuid (prevVMId));
-        if (item)
-            vmListBox->setSelected (item, true);
+        mVMListView->selectItemById (QUuid (prevVMId));
     }
 
@@ -653,10 +660,10 @@
              &vboxProblem(), SLOT (resetSuppressedMessages()));
 
-    connect (vmListBox, SIGNAL (currentChanged(Q3ListBoxItem *)),
-             this, SLOT (vmListBoxCurrentChanged()));
-    connect (vmListBox, SIGNAL (selected (Q3ListBoxItem *)),
+    connect (mVMListView, SIGNAL (currentChanged()),
+             this, SLOT (vmListViewCurrentChanged()));
+    connect (mVMListView, SIGNAL (activated ()),
              this, SLOT (vmStart()));
-    connect (vmListBox, SIGNAL (contextMenuRequested (Q3ListBoxItem *, const QPoint &)),
-             this, SLOT (showContextMenu (Q3ListBoxItem *, const QPoint &)));
+    connect (mVMListView, SIGNAL (contextMenuRequested (VBoxVMItem *, const QPoint &)),
+             this, SLOT (showContextMenu (VBoxVMItem *, const QPoint &)));
 
     connect (vmDetailsView, SIGNAL (linkClicked (const QString &)),
@@ -682,5 +689,5 @@
 
     /* bring the VM list to the focus */
-    vmListBox->setFocus();
+    mVMListView->setFocus();
 }
 
@@ -702,7 +709,7 @@
     /* save vm selector position */
     {
-        Q3ListBoxItem *item = vmListBox->selectedItem();
+        VBoxVMItem *item = mVMListView->selectedItem();
         QString curVMId = item ?
-            QString (static_cast<VBoxVMListBoxItem*> (item)->id()) :
+            QString (item->id()) :
             QString::null;
         vbox.SetExtraData (VBoxDefs::GUI_LastVMSelected, curVMId);
@@ -755,20 +762,11 @@
 
         /* wait until the list is updated by OnMachineRegistered() */
-        VBoxVMListBoxItem *item = 0;
-        while (!item)
+        QModelIndex index;
+        while (!index.isValid())
         {
             qApp->processEvents();
-            item = vmListBox->item (m.GetId());
-        }
-        /*
-         *  we must use setSelected() instead of setCurrentItem() below because
-         *  setCurrentItem() does nothing after the first item has been added
-         *  to the list (since it is already the current one), but we still
-         *  need currentChanged() to be emitted to sync things (QListBox doesn't
-         *  emit currentChanged() when the current item index changes from -1
-         *  to 0, i.e. when the first item is being added -- seems to be a Qt
-         *  bug).
-         */
-        vmListBox->setSelected (item, true);
+            index = mVMModel->indexById (m.GetId());
+        }
+        mVMListView->setCurrentIndex (index);
     }
 }
@@ -791,5 +789,5 @@
     }
 
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     AssertMsgReturnVoid (item, ("Item must be always selected here"));
@@ -818,5 +816,5 @@
             {
                 if (oldName.compare (m.GetName()))
-                    vmListBox->sort();
+                    mVMModel->sort();
             }
             else
@@ -831,5 +829,5 @@
     }
 
-    vmListBox->setFocus();
+    mVMListView->setFocus();
 
     session.Close();
@@ -838,5 +836,5 @@
 void VBoxSelectorWnd::vmDelete()
 {
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     AssertMsgReturn (item, ("Item must be always selected here"), (void) 0);
@@ -884,5 +882,8 @@
                 machine.DeleteSettings();
                 /* remove the item shortly: cmachine it refers to is no longer valid! */
-                vmListBox->removeItem (vmListBox->index (item));
+#warning "port me: check this"
+                int row = mVMModel->rowById (item->id());
+                mVMModel->removeItem (item);
+                mVMListView->ensureSomeRowSelected (row);
             }
             if (!vbox.isOk() || !machine.isOk())
@@ -894,10 +895,10 @@
 void VBoxSelectorWnd::vmStart()
 {
-    /* we always get here when vmListBox emits the selected() signal,
+    /* we always get here when mVMListView emits the activated() signal,
      * so we must explicitly check if the action is enabled or not. */
     if (!vmStartAction->isEnabled())
         return;
 
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     AssertMsg (item, ("Item must be always selected here"));
@@ -971,5 +972,5 @@
 void VBoxSelectorWnd::vmDiscard()
 {
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     AssertMsgReturn (item, ("Item must be always selected here"), (void) 0);
@@ -1005,5 +1006,5 @@
 void VBoxSelectorWnd::vmPause (bool aPause)
 {
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     AssertMsgReturn (item, ("Item must be always selected here"), (void) 0);
@@ -1036,5 +1037,5 @@
 void VBoxSelectorWnd::vmRefresh()
 {
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     AssertMsgReturn (item, ("Item must be always selected here"), (void) 0);
@@ -1048,5 +1049,5 @@
 void VBoxSelectorWnd::vmShowLogs()
 {
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
     CMachine machine = item->machine();
     VBoxVMLogViewer::createLogViewer (machine);
@@ -1055,6 +1056,6 @@
 void VBoxSelectorWnd::refreshVMList()
 {
-    vmListBox->refresh();
-    vmListBoxCurrentChanged();
+    mVMModel->refresh();
+    vmListViewCurrentChanged();
 }
 
@@ -1063,11 +1064,14 @@
                                                        bool aDescription)
 {
-    vmListBox->refresh (aID);
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
-    if (item && item->id() == aID)
-        vmListBoxCurrentChanged (aDetails, aSnapshots, aDescription);
-}
-
-void VBoxSelectorWnd::showContextMenu (Q3ListBoxItem *aItem, const QPoint &aPoint)
+    VBoxVMItem *item = mVMModel->itemById (aID);
+    if (item)
+    {
+        mVMModel->refreshItem (item);
+        if (item && item->id() == aID)
+            vmListViewCurrentChanged (aDetails, aSnapshots, aDescription);
+    }
+}
+
+void VBoxSelectorWnd::showContextMenu (VBoxVMItem *aItem, const QPoint &aPoint)
 {
     if (aItem)
@@ -1131,8 +1135,8 @@
     vmTabWidget->setTabText (vmTabWidget->indexOf (vmDetailsView), tr ("&Details"));
     /* note: Snapshots and Details tabs are changed dynamically by
-     * vmListBoxCurrentChanged() */
+     * vmListViewCurrentChanged() */
 
     /* ensure the details and screenshot view are updated */
-    vmListBoxCurrentChanged();
+    vmListViewCurrentChanged();
 
     fileDiskMgrAction->setText (tr ("Virtual &Disk Manager..."));
@@ -1178,5 +1182,5 @@
     vmDeleteAction->setStatusTip (tr ("Delete the selected virtual machine"));
 
-    /* Note: vmStartAction text is set up in vmListBoxCurrentChanged() */
+    /* Note: vmStartAction text is set up in vmListViewCurrentChanged() */
 
     vmDiscardAction->setText (tr ("D&iscard"));
@@ -1225,16 +1229,9 @@
 /////////////////////////////////////////////////////////////////////////////
 
-void VBoxSelectorWnd::vmListBoxCurrentChanged (bool aRefreshDetails,
+void VBoxSelectorWnd::vmListViewCurrentChanged (bool aRefreshDetails,
                                                bool aRefreshSnapshots,
                                                bool aRefreshDescription)
 {
-    if (!vmListBox->selectedItem() && vmListBox->currentItem() >= 0)
-    {
-        /* selected always follows current */
-        vmListBox->setSelected (vmListBox->currentItem(), true);
-    }
-
-    vmListBox->ensureCurrentVisible();
-    VBoxVMListBoxItem *item = (VBoxVMListBoxItem *) vmListBox->selectedItem();
+    VBoxVMItem *item = mVMListView->selectedItem();
 
     if (item && item->accessible())
@@ -1395,5 +1392,5 @@
 {
     /* refresh the current details to pick up hard disk sizes */
-    vmListBoxCurrentChanged (true /* aRefreshDetails */);
+    vmListViewCurrentChanged (true /* aRefreshDetails */);
 }
 
@@ -1401,5 +1398,5 @@
 {
     /* refresh the current details to pick up hard disk sizes */
-    vmListBoxCurrentChanged (true /* aRefreshDetails */);
+    vmListViewCurrentChanged (true /* aRefreshDetails */);
 
     /* we warn about inaccessible media only once (after media emumeration
@@ -1465,6 +1462,11 @@
         if (!m.isNull())
         {
-            new VBoxVMListBoxItem (vmListBox, m);
-            vmListBox->sort();
+            mVMModel->addItem (new VBoxVMItem (m));
+            mVMModel->sort();
+            /* Make sure the description, ... pages are properly updated.
+             * Actualy we haven't call the next method, but unfortunately Qt
+             * seems buggy if the new item is on the same position as the
+             * previous one. So go on the safe side and call this by our self. */
+            vmListViewCurrentChanged();
         }
         /* m.isNull() is ok (theoretically, the machine could have been
@@ -1473,7 +1475,12 @@
     else
     {
-        VBoxVMListBoxItem *item = vmListBox->item (e.id);
+        VBoxVMItem *item = mVMModel->itemById (e.id);
         if (item)
-            vmListBox->removeItem (vmListBox->index (item));
+        {
+            int row = mVMModel->rowById (item->id());
+            mVMModel->removeItem (item);
+            mVMListView->ensureSomeRowSelected (row);
+        }
+
         /* item = 0 is ok (if we originated this event then the item
          * has been already removed) */
Index: /trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMListBox.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMListBox.cpp	(revision 8158)
+++ /trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMListBox.cpp	(revision 8159)
@@ -2,9 +2,9 @@
  *
  * VBox frontends: Qt GUI ("VirtualBox"):
- * VBoxVMListItem class implementation
+ * VBoxVMItem, VBoxVMModel, VBoxVMListView, VBoxVMItemPainter class implementation
  */
 
 /*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -22,22 +22,15 @@
 
 #include "VBoxVMListBox.h"
-
 #include "VBoxProblemReporter.h"
 
-#include <qpainter.h>
-#include <qfontmetrics.h>
-#include <qdrawutil.h>
-#include <qtooltip.h>
-#include <qmetaobject.h>
-#include <qstyle.h>
-
-#include <qfileinfo.h>
-//Added by qt3to4:
-#include <QPixmap>
-#include <q3mimefactory.h>
-#include <QFocusEvent>
+/* Qt includes */
+#include <QPainter>
+#include <QFileInfo>
 
 #if defined (Q_WS_MAC)
 # include <Carbon/Carbon.h>
+# if MAC_LEOPARD_STYLE
+#  include <qmacstyle_mac.h>
+# endif /* MAC_LEOPARD_STYLE */
 #endif
 
@@ -144,86 +137,12 @@
 #endif
 
-////////////////////////////////////////////////////////////////////////////////
-// VBoxVMListBoxItem class
-////////////////////////////////////////////////////////////////////////////////
-
-#warning port me
-//class VBoxVMListBoxTip : public QToolTip
-//{
-//public:
-//
-//    VBoxVMListBoxTip (VBoxVMListBox *aLB, QToolTipGroup *aTG = 0)
-//        : QToolTip (aLB, aTG)
-//    {}
-//
-//    virtual ~VBoxVMListBoxTip()
-//    {
-//        remove (parentWidget());
-//    }
-//
-//    void maybeTip (const QPoint &aPnt);
-//};
-//
-//void VBoxVMListBoxTip::maybeTip (const QPoint &aPnt)
-//{
-//    const VBoxVMListBox *lb = static_cast <VBoxVMListBox *> (parentWidget());
-//
-//    VBoxVMListBoxItem *vmi = static_cast <VBoxVMListBoxItem *> (lb->itemAt (aPnt));
-//    if (!vmi)
-//        return;
-//
-//    if (parentWidget()->topLevelWidget()->inherits ("QMainWindow"))
-//    {
-//        /*
-//         *  Ensure the main window doesn't show the text from the previous
-//         *  tooltip in the status bar.
-//         */
-//        QToolTipGroup *toolTipGroup =
-//            (::qt_cast <Q3MainWindow *> (parentWidget()->topLevelWidget()))->
-//                toolTipGroup();
-//        if (toolTipGroup)
-//        {
-//            int index = toolTipGroup->metaObject()->findSignal("removeTip()", false);
-//            toolTipGroup->qt_emit (index, 0);
-//        }
-//    }
-//
-//    tip (lb->itemRect (vmi), vmi->toolTipText());
-//}
-
-////////////////////////////////////////////////////////////////////////////////
-// VBoxVMListBox class
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- *  Creates a box with the list of all virtual machines in the
- *  VirtualBox installation.
- */
-VBoxVMListBox::
-VBoxVMListBox (QWidget *aParent /* = 0 */, const char *aName /* = NULL */,
-               Qt::WFlags aFlags /* = 0 */)
-    : Q3ListBox (aParent, aName, aFlags)
-{
-    mVBox = vboxGlobal().virtualBox();
-
-    mNameFont = QFont (font().family(), font().pointSize() + 1, QFont::Bold);
-    mShotFont = QFont (font().family(), font().pointSize() + 1);
-    mStateBusyFont = font();
-    mStateBusyFont.setItalic (true);
-
-    mMargin = QMAX (fontMetrics().width (' ') * 2, 8);
-
-#warning port me
-//    mToolTip = new VBoxVMListBoxTip (this);
-
-    mGaveFocusToPopup = false;
-
-    refresh();
-}
-
-VBoxVMListBox::~VBoxVMListBox()
-{
-#warning port me
-//    delete mToolTip;
+VBoxVMItem::VBoxVMItem (const CMachine &aM)
+    : mMachine (aM)
+{
+    recache();
+}
+
+VBoxVMItem::~VBoxVMItem()
+{
 }
 
@@ -231,196 +150,5 @@
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- *  Refreshes the box contents by rereading the list of VM's using
- *  the IVirtualBox instance.
- */
-void VBoxVMListBox::refresh()
-{
-    clear();
-
-    CMachineVector vec = mVBox.GetMachines2();
-    for (CMachineVector::ConstIterator m = vec.begin();
-         m != vec.end(); ++ m)
-        new VBoxVMListBoxItem (this, *m);
-
-    sort();
-    setCurrentItem (0);
-}
-
-/**
- *  Refreshes the item corresponding to the given UUID.
- */
-void VBoxVMListBox::refresh (const QUuid &aID)
-{
-    for (uint i = 0; i < count(); i++)
-    {
-        VBoxVMListBoxItem *vmi = (VBoxVMListBoxItem *) Q3ListBox::item (i);
-        if (vmi->id() == aID)
-        {
-            vmi->recache();
-            /* we call triggerUpdate() instead of updateItem() to cause the
-             * layout to be redone for the case when the item width changes */
-            triggerUpdate (true);
-            break;
-        }
-    }
-}
-
-/**
- *  Returns the list item with the given UUID.
- */
-VBoxVMListBoxItem *VBoxVMListBox::item (const QUuid &aID)
-{
-    for (uint i = 0; i < count(); i++)
-    {
-        VBoxVMListBoxItem *vmi = (VBoxVMListBoxItem *) Q3ListBox::item (i);
-        if (vmi->id() == aID)
-            return vmi;
-    }
-    return 0;
-}
-
-/**
- *  Returns the color group QListBox uses to prepare a place for painting
- *  a list box item (for example, to draw the highlighted rectangle of the
- *  currently selected item, etc.). Useful in item's QListBoxItem::paint()
- *  reimplementations to select correct colors that will contrast with the
- *  item rectangle.
- */
-const QColorGroup &VBoxVMListBox::activeColorGroup() const
-{
-    /* Too bad QListBox doesn't allow to determine what color group it uses
-     * to draw the item's rectangle before calling its paint() method. Not
-     * knowing that, we cannot choose correct colors that will contrast with
-     * that rectangle. So, we have to use the logic of QListBox itself.
-     * Here is a modified extract from qlistbox.cpp: */
-
-#warning port me
-//    bool drawActiveSelection =
-//        !style().styleHint (QStyle::SH_ItemView_ChangeHighlightOnFocus, this) ||
-//        hasFocus() ||
-//        mGaveFocusToPopup;
-//
-//    return (drawActiveSelection ? colorGroup() : palette().inactive());
-    return colorGroup();
-}
-
-// protected members
-////////////////////////////////////////////////////////////////////////////////
-
-void VBoxVMListBox::focusInEvent (QFocusEvent *aE)
-{
-    mGaveFocusToPopup = false;
-    Q3ListBox::focusInEvent (aE);
-}
-
-void VBoxVMListBox::focusOutEvent (QFocusEvent *aE)
-{
-    /* A modified extract from qlistbox.cpp (see #activeColorGroup()): */
-    mGaveFocusToPopup =
-#warning port me: check this
-        aE->reason() == QFocusEvent::Popup ||
-//        QFocusEvent::reason() == QFocusEvent::Popup ||
-        (qApp->focusWidget() && qApp->focusWidget()->inherits ("QMenuBar"));
-    Q3ListBox::focusOutEvent (aE);
-}
-
-// private members
-////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////////
-// VBoxVMListBoxItem class
-////////////////////////////////////////////////////////////////////////////////
-
-VBoxVMListBoxItem::VBoxVMListBoxItem (VBoxVMListBox *aLB, const CMachine &aM)
-    : Q3ListBoxItem (aLB), mMachine (aM)
-{
-    recache();
-}
-
-VBoxVMListBoxItem::~VBoxVMListBoxItem()
-{
-}
-
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-void VBoxVMListBoxItem::setMachine (const CMachine &aM)
-{
-    Assert (!aM.isNull());
-
-    mMachine = aM;
-    recache();
-    vmListBox()->triggerUpdate (true);
-}
-
-void VBoxVMListBoxItem::recache()
-{
-    bool needsResort = true;
-
-    mId = mMachine.GetId();
-    mSettingsFile = mMachine.GetSettingsFilePath();
-
-    mAccessible = mMachine.GetAccessible();
-    if (mAccessible)
-    {
-        QString name = mMachine.GetName();
-        CSnapshot snp = mMachine.GetCurrentSnapshot();
-        mSnapshotName = snp.isNull() ? QString::null : snp.GetName();
-        needsResort = name != mName;
-        mName = name;
-
-        mState = mMachine.GetState();
-        mLastStateChange.setTime_t (mMachine.GetLastStateChange() / 1000);
-        mSessionState = mMachine.GetSessionState();
-        mOSTypeId = mMachine.GetOSTypeId();
-        mSnapshotCount = mMachine.GetSnapshotCount();
-
-        if (mState >= KMachineState_Running)
-        {
-            mPid = mMachine.GetSessionPid();
-    /// @todo Remove. See @c todo in #switchTo() below.
-#if 0
-            mWinId = FindWindowIdFromPid (mPid);
-#endif
-        }
-        else
-        {
-            mPid = (ULONG) ~0;
-    /// @todo Remove. See @c todo in #switchTo() below.
-#if 0
-            mWinId = (WId) ~0;
-#endif
-        }
-    }
-    else
-    {
-        mAccessError = mMachine.GetAccessError();
-
-        /* this should be in sync with
-         * VBoxProblemReporter::confirmMachineDeletion() */
-        QFileInfo fi (mSettingsFile);
-        QString name = fi.extension().lower() == "xml" ?
-                       fi.baseName (true) : fi.fileName();
-        needsResort = name != mName;
-        mName = name;
-        mState = KMachineState_Null;
-        mSessionState = KSessionState_Null;
-        mLastStateChange = QDateTime::currentDateTime();
-        mOSTypeId = QString::null;
-        mSnapshotCount = 0;
-
-        mPid = (ULONG) ~0;
-    /// @todo Remove. See @c todo in #switchTo() below.
-#if 0
-        mWinId = (WId) ~0;
-#endif
-    }
-
-    if (needsResort)
-        vmListBox()->sort();
-}
-
-QString VBoxVMListBoxItem::toolTipText() const
+QString VBoxVMItem::toolTipText() const
 {
     QString dateTime = (mLastStateChange.date() == QDate::currentDate()) ?
@@ -435,5 +163,5 @@
         if (!mSnapshotName.isNull())
             toolTip += QString (" (%1)").arg (mSnapshotName);
-        toolTip = QString (VBoxVMListBox::tr (
+        toolTip = QString (QObject::tr (
             "<nobr>%1<br></nobr>"
             "<nobr>%2 since %3</nobr><br>"
@@ -447,5 +175,5 @@
     else
     {
-        toolTip = QString (VBoxVMListBox::tr (
+        toolTip = QString (QObject::tr (
             "<nobr><b>%1</b><br></nobr>"
             "<nobr>Inaccessible since %2</nobr>",
@@ -458,72 +186,68 @@
 }
 
-int VBoxVMListBoxItem::width (const Q3ListBox *) const
-{
-    /* see the picture below for dimensions */
-
-    const VBoxVMListBox *lb = vmListBox();
-
-    QFontMetrics fmName = QFontMetrics (lb->nameFont());
-    QFontMetrics fmShot = QFontMetrics (lb->shotFont());
-    QFontMetrics fmState = QFontMetrics (lb->stateFont (mSessionState));
-    const int marg = lb->margin();
-
-    QPixmap pmOSType;
-    QPixmap pmState;
-    QString strState;
-
+bool VBoxVMItem::recache()
+{
+    bool needsResort = true;
+
+    mId = mMachine.GetId();
+    mSettingsFile = mMachine.GetSettingsFilePath();
+
+    mAccessible = mMachine.GetAccessible();
     if (mAccessible)
     {
-        pmOSType = vboxGlobal().vmGuestOSTypeIcon (mOSTypeId);
-        pmState = vboxGlobal().toIcon (mState);
-        strState = vboxGlobal().toString (mState);
+        QString name = mMachine.GetName();
+        CSnapshot snp = mMachine.GetCurrentSnapshot();
+        mSnapshotName = snp.isNull() ? QString::null : snp.GetName();
+        needsResort = name != mName;
+        mName = name;
+
+        mState = mMachine.GetState();
+        mLastStateChange.setTime_t (mMachine.GetLastStateChange() / 1000);
+        mSessionState = mMachine.GetSessionState();
+        mOSTypeId = mMachine.GetOSTypeId();
+        mSnapshotCount = mMachine.GetSnapshotCount();
+
+        if (mState >= KMachineState_Running)
+        {
+            mPid = mMachine.GetSessionPid();
+    /// @todo Remove. See @c todo in #switchTo() below.
+#if 0
+            mWinId = FindWindowIdFromPid (mPid);
+#endif
+        }
+        else
+        {
+            mPid = (ULONG) ~0;
+    /// @todo Remove. See @c todo in #switchTo() below.
+#if 0
+            mWinId = (WId) ~0;
+#endif
+        }
     }
     else
     {
-        /// @todo (r=dmik) temporary
-        pmOSType = QPixmap (":/os_unknown.png");
-        pmState = QPixmap (":/state_aborted_16px.png");
-        strState = VBoxVMListBox::tr ("Inaccessible");
-    }
-
-    int nameWidth = fmName.width (mName);
-    if (!mSnapshotName.isNull())
-        nameWidth += fmShot.width (QString (" (%1)").arg (mSnapshotName));
-    int stateWidth = pmState.width() + fmState.width (' ') +
-                     fmState.width (strState);
-
-    return marg + pmOSType.width() + marg * 3 / 2 +
-           QMAX (nameWidth, stateWidth) + marg;
-}
-
-int VBoxVMListBoxItem::height (const Q3ListBox *) const
-{
-    /* see the picture below for dimensions */
-
-    const VBoxVMListBox *lb = vmListBox();
-
-    QFontMetrics fmName = QFontMetrics (lb->nameFont());
-    QFontMetrics fmState = QFontMetrics (lb->stateFont (mSessionState));
-    const int marg = lb->margin();
-
-    QPixmap pmOSType;
-    QPixmap pmState;
-
-    if (mAccessible)
-    {
-        pmOSType = vboxGlobal().vmGuestOSTypeIcon (mOSTypeId);
-        pmState = vboxGlobal().toIcon (mState);
-    }
-    else
-    {
-        /// @todo (r=dmik) temporary
-        pmOSType = QPixmap (":/os_unknown.png");
-        pmState = QPixmap (":/state_aborted_16px.png");
-    }
-
-    int strHeight = fmName.lineSpacing() +
-                    QMAX (pmState.height(), fmState.height());
-
-    return marg + QMAX (pmOSType.height(), strHeight) + marg;
+        mAccessError = mMachine.GetAccessError();
+
+        /* this should be in sync with
+         * VBoxProblemReporter::confirmMachineDeletion() */
+        QFileInfo fi (mSettingsFile);
+        QString name = fi.completeSuffix().toLower() == "xml" ?
+                       fi.completeBaseName() : fi.fileName();
+        needsResort = name != mName;
+        mName = name;
+        mState = KMachineState_Null;
+        mSessionState = KSessionState_Null;
+        mLastStateChange = QDateTime::currentDateTime();
+        mOSTypeId = QString::null;
+        mSnapshotCount = 0;
+
+        mPid = (ULONG) ~0;
+    /// @todo Remove. See @c todo in #switchTo() below.
+#if 0
+        mWinId = (WId) ~0;
+#endif
+    }
+
+    return needsResort;
 }
 
@@ -532,5 +256,5 @@
  * foreground, and @a false otherwise.
  */
-bool VBoxVMListBoxItem::canSwitchTo() const
+bool VBoxVMItem::canSwitchTo() const
 {
     return const_cast <CMachine &> (mMachine).CanShowConsoleWindow();
@@ -547,5 +271,5 @@
  * @return true if successfully switched and false otherwise.
  */
-bool VBoxVMListBoxItem::switchTo()
+bool VBoxVMItem::switchTo()
 {
 #ifdef Q_WS_MAC
@@ -659,7 +383,354 @@
 }
 
-// protected members
-////////////////////////////////////////////////////////////////////////////////
-
+/* VBoxVMModel class */
+
+void VBoxVMModel::addItem (VBoxVMItem *aItem) 
+{ 
+    Assert (aItem);
+    int row = mVMItemList.count();
+    emit layoutAboutToBeChanged();
+    beginInsertRows (QModelIndex(), row, row);
+    mVMItemList << aItem; 
+    endInsertRows();
+    refreshItem (aItem);
+}
+
+void VBoxVMModel::removeItem (VBoxVMItem *aItem)
+{
+    Assert (aItem);
+    int row = mVMItemList.indexOf (aItem);
+    removeRows (row, 1);
+}
+
+bool VBoxVMModel::removeRows (int aRow, int aCount, const QModelIndex &aParent /* = QModelIndex() */)
+{
+    emit layoutAboutToBeChanged();
+    beginRemoveRows (aParent, aRow, aRow + aCount);
+    mVMItemList.erase (mVMItemList.begin() + aRow, mVMItemList.begin() + aRow + aCount);
+    endRemoveRows();
+    emit layoutChanged();
+    return true;
+}
+
+/**
+ *  Refreshes the item corresponding to the given UUID.
+ */
+void VBoxVMModel::refreshItem (VBoxVMItem *aItem)
+{
+    Assert (aItem);
+    if (aItem->recache())
+        sort();
+    itemChanged (aItem);
+}
+
+void VBoxVMModel::itemChanged (VBoxVMItem *aItem)
+{
+    Assert (aItem);
+    int row = mVMItemList.indexOf (aItem);
+    /* Emit an layout change signal for the case some dimensions of the item
+     * has changed also. */
+    emit layoutChanged();
+    /* Emit an data changed signal. */
+    emit dataChanged (index (row), index (row));
+}
+
+/**
+ *  Refreshes the model contents by rereading the list of VM's using the
+ *  IVirtualBox instance.
+ */
+void VBoxVMModel::refresh()
+{
+    CVirtualBox vbox = vboxGlobal().virtualBox();
+    CMachineVector vec = vbox.GetMachines2();
+    for (CMachineVector::ConstIterator m = vec.begin();
+         m != vec.end(); ++ m)
+        addItem(new VBoxVMItem (*m));
+
+    sort();
+}
+
+/**
+ *  Returns the list item with the given UUID.
+ */
+VBoxVMItem *VBoxVMModel::itemById (const QUuid &aId) const
+{
+    foreach (VBoxVMItem *item, mVMItemList)
+        if (item->id() == aId)
+            return item;
+    return NULL;
+}
+
+QModelIndex VBoxVMModel::indexById (const QUuid &aId) const
+{
+    int row = rowById (aId);
+    if (row >= 0)
+        return index (row);
+    else
+        return QModelIndex();
+}
+
+int VBoxVMModel::rowById (const QUuid &aId) const
+{
+    for (int i=0; i < mVMItemList.count(); ++i)
+    {
+        VBoxVMItem *item = mVMItemList.at (i);
+        if (item->id() == aId)
+            return i;
+    }
+    return -1;
+}
+
+void VBoxVMModel::sort (int /* aColumn */, Qt::SortOrder aOrder /* = Qt::AscendingOrder */)
+{
+    emit layoutAboutToBeChanged();
+    switch (aOrder)
+    {
+        case Qt::AscendingOrder: qSort (mVMItemList.begin(), mVMItemList.end(), VBoxVMItemNameCompareLessThan); break;
+        case Qt::DescendingOrder: qSort (mVMItemList.begin(), mVMItemList.end(), VBoxVMItemNameCompareGreaterThan); break;
+    }
+    emit layoutChanged();
+}
+
+int VBoxVMModel::rowCount(const QModelIndex & /* aParent = QModelIndex() */) const 
+{ 
+    return mVMItemList.count(); 
+}
+
+QVariant VBoxVMModel::data(const QModelIndex &aIndex, int aRole) const
+{
+    if (!aIndex.isValid())
+        return QVariant();
+
+    if (aIndex.row() >= mVMItemList.size())
+        return QVariant();
+
+    QVariant v;
+    switch (aRole)
+    {
+        case Qt::DisplayRole:
+            {
+                v = mVMItemList.at (aIndex.row())->name();
+                break;
+            }
+        case Qt::DecorationRole:
+            {
+                v = mVMItemList.at (aIndex.row())->osIcon();
+                break;
+            }
+        case Qt::ToolTipRole:
+            {
+                v = mVMItemList.at (aIndex.row())->toolTipText();
+                break;
+            }
+        case Qt::FontRole:
+            {
+                QFont f = qApp->font();
+                f.setPointSize (f.pointSize() + 1);
+                f.setWeight (QFont::Bold);
+                v = f;
+                break;
+            }
+        case SnapShotDisplayRole:
+            {
+                v = mVMItemList.at (aIndex.row())->snapshotName();
+                break;
+            }
+        case SnapShotFontRole:
+            {
+                QFont f = qApp->font();
+                v = f;
+                break;
+            }
+        case SessionStateDisplayRole:
+            {
+                v = mVMItemList.at (aIndex.row())->sessionStateName();
+                break;
+            }
+        case SessionStateDecorationRole:
+            {
+                v = mVMItemList.at (aIndex.row())->sessionStateIcon();
+                break;
+            }
+        case SessionStateFontRole:
+            {
+                QFont f = qApp->font();
+                f.setPointSize (f.pointSize());
+                if (mVMItemList.at (aIndex.row())->sessionState() != KSessionState_Closed)
+                    f.setItalic (true);
+                v = f;
+                break;
+            }
+        case VBoxVMItemPtrRole:
+            {
+                v = qVariantFromValue (mVMItemList.at (aIndex.row()));
+            }
+    }
+    return v;
+}
+
+QVariant VBoxVMModel::headerData(int aSection, Qt::Orientation aOrientation,
+                                 int aRole /* = Qt::DisplayRole */) const
+{
+    if (aRole != Qt::DisplayRole)
+        return QVariant();
+
+    if (aOrientation == Qt::Horizontal)
+        return QString (tr ("VM"));
+    else
+        return QString ("%1").arg (aSection);
+}
+
+bool VBoxVMModel::VBoxVMItemNameCompareLessThan (VBoxVMItem* aItem1, VBoxVMItem* aItem2)
+{
+    Assert (aItem1);
+    Assert (aItem2);
+    return aItem1->name().toLower() < aItem2->name().toLower();
+}
+
+bool VBoxVMModel::VBoxVMItemNameCompareGreaterThan (VBoxVMItem* aItem1, VBoxVMItem* aItem2)
+{
+    Assert (aItem1);
+    Assert (aItem2);
+    return aItem2->name().toLower() < aItem1->name().toLower();
+}
+
+/* VBoxVMListBox class */
+
+VBoxVMListView::VBoxVMListView (QWidget *aParent /* = 0 */)
+    :QListView (aParent)
+{
+    /* Create & set our delegation class */
+    VBoxVMItemPainter *delegate = new VBoxVMItemPainter(this);
+    setItemDelegate(delegate);
+    /* Default icon size */
+    setIconSize (QSize (32, 32));
+    /* Publish the activation of items */
+    connect (this, SIGNAL (activated (const QModelIndex &)),
+             this, SIGNAL (activated ()));
+    /* Track if the application lost the focus */
+#if MAC_LEOPARD_STYLE
+    connect (QCoreApplication::instance(), SIGNAL (focusChanged (QWidget *, QWidget *)),
+             this, SLOT (focusChanged (QWidget *, QWidget *)));
+    /* 1 pixel line frame */
+    setMidLineWidth (1);
+    setLineWidth (0);
+    setFrameShape (QFrame::Box);
+    focusChanged (NULL, this);
+    /* Nesty hack to disable the focus rect on the list view. This interface
+     * may change at any time! */
+    static_cast<QMacStyle *> (style())->setFocusRectPolicy (this, QMacStyle::FocusDisabled);
+#endif /* MAC_LEOPARD_STYLE */
+}
+
+void VBoxVMListView::selectItemByRow (int row)
+{
+    setCurrentIndex (model()->index (row, 0));
+}
+
+void VBoxVMListView::selectItemById (const QUuid &aID)
+{
+    if (VBoxVMModel *m = qobject_cast<VBoxVMModel*> (model()))
+    {
+        QModelIndex i = m->indexById (aID);
+        if (i.isValid())
+            setCurrentIndex (i);
+    }
+}
+
+void VBoxVMListView::ensureSomeRowSelected (int aRowHint)
+{
+    VBoxVMItem *item = selectedItem();
+    if(!item)
+    {
+        aRowHint = qBound (0, aRowHint, model()->rowCount() - 1);
+        selectItemByRow (aRowHint);
+        item = selectedItem ();
+        if (!item)
+            selectItemByRow (0);
+    }
+}
+
+VBoxVMItem * VBoxVMListView::selectedItem() const
+{
+    QModelIndexList indexes = selectedIndexes();
+    if (indexes.isEmpty())
+        return NULL;
+    return model()->data (indexes.first(), VBoxVMModel::VBoxVMItemPtrRole).value<VBoxVMItem *>();
+}
+
+void VBoxVMListView::ensureCurrentVisible()
+{
+    scrollTo (currentIndex(), QAbstractItemView::EnsureVisible);
+}
+
+void VBoxVMListView::selectionChanged (const QItemSelection &aSelected, const QItemSelection &aDeselected) 
+{
+    QListView::selectionChanged (aSelected, aDeselected);
+    selectCurrent();
+    ensureCurrentVisible();
+    emit currentChanged(); 
+}
+
+void VBoxVMListView::currentChanged (const QModelIndex &aCurrent, const QModelIndex &aPrevious) 
+{ 
+    QListView::currentChanged (aCurrent, aPrevious);
+    selectCurrent();
+    ensureCurrentVisible();
+    emit currentChanged(); 
+} 
+
+void VBoxVMListView::dataChanged (const QModelIndex &aTopLeft, const QModelIndex &aBottomRight)
+{
+    QListView::dataChanged (aTopLeft, aBottomRight);
+    selectCurrent();
+    ensureCurrentVisible();
+    emit currentChanged(); 
+}
+
+void VBoxVMListView::focusChanged (QWidget * /* aOld */, QWidget *aNow)
+{
+#if MAC_LEOPARD_STYLE
+    QColor bgColor (212, 221, 229);
+    if (aNow == NULL)
+        bgColor.setRgb (232, 232, 232);
+    QPalette pal = viewport()->palette();
+    pal.setColor (QPalette::Base, bgColor);
+    viewport()->setPalette (pal);
+    viewport()->setAutoFillBackground (true);
+#else /* MAC_LEOPARD_STYLE */
+    NOREF (aNow);
+#endif /* MAC_LEOPARD_STYLE */
+}
+
+void VBoxVMListView::mousePressEvent (QMouseEvent *aEvent)
+{
+    /* First process event, in the case the user select a new item */
+    QListView::mousePressEvent (aEvent);
+    if (aEvent->button() == Qt::RightButton)
+    {
+        /* Send a context menu request if necessary */
+        const QModelIndex &index = indexAt (aEvent->pos());
+        if (index.isValid())
+        {
+            VBoxVMItem *item = model()->data (index, VBoxVMModel::VBoxVMItemPtrRole).value<VBoxVMItem *>();
+            emit contextMenuRequested (item, aEvent->globalPos());
+        }
+    }
+}
+
+bool VBoxVMListView::selectCurrent()
+{
+    QModelIndexList indexes = selectionModel()->selectedIndexes();
+    if (indexes.isEmpty() ||
+        indexes.first() != currentIndex())
+    {
+        /* Make sure that the current is always selected */
+        selectionModel()->select (currentIndex(), QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect);
+        return true;
+    }
+    return false;
+}
+
+/* VBoxVMItemPainter class */
 /*
  +----------------------------------------------+
@@ -678,71 +749,213 @@
 */
 
-void VBoxVMListBoxItem::paint (QPainter *aP)
-{
-    const VBoxVMListBox *lb = vmListBox();
-
-    QFontMetrics fmName = QFontMetrics (lb->nameFont());
-    QFontMetrics fmShot = QFontMetrics (lb->shotFont());
-    QFontMetrics fmState = QFontMetrics (lb->stateFont (mSessionState));
-    const int marg = lb->margin();
-
-    QPixmap pmOSType;
-    QPixmap pmState;
-    QString strState;
-
-    if (mAccessible)
-    {
-        pmOSType = vboxGlobal().vmGuestOSTypeIcon (mOSTypeId);
-        pmState = vboxGlobal().toIcon (mState);
-        strState = vboxGlobal().toString (mState);
-    }
-    else
-    {
-        /// @todo (r=dmik) temporary
-        pmOSType = QPixmap (":/os_unknown.png");
-        pmState = QPixmap (":/state_aborted_16px.png");
-        strState = VBoxVMListBox::tr ("Inaccessible");
-    }
-
-    const QPalette &pal = lb->palette();
-
-    int osTypeY = marg;
-    int strHeight = fmName.lineSpacing() +
-                    QMAX (pmState.height(), fmState.height());
-    if (strHeight > pmOSType.height())
-        osTypeY += (strHeight - pmOSType.height()) / 2;
-
-    /* draw the OS type icon with border, vertically centered */
-    aP->drawPixmap (marg, osTypeY, pmOSType);
-
-    aP->setPen (isSelected() ?
-                pal.color (QPalette::Active, QPalette::HighlightedText) :
-                pal.color (QPalette::Active, QPalette::Text));
-
-    int textX = marg + pmOSType.width() + marg * 3 / 2;
-
-    /* draw the VM name */
-    aP->setFont (lb->nameFont());
-    aP->drawText (textX, marg + fmName.ascent(), mName);
-
-    if (!mSnapshotName.isNull())
-    {
-        int nameWidth = fmName.width (mName);
-        aP->setFont (lb->shotFont());
-        QString shotName = QString (" (%1)").arg (mSnapshotName);
-        aP->drawText (textX + nameWidth, marg + fmName.ascent(), shotName);
-    }
-
-    int stateY = marg + fmName.lineSpacing();
-    int stateH = QMAX (pmState.height(), fmState.height());
-
-    /* draw the VM state icon */
-    aP->drawPixmap (textX, stateY + (stateH - pmState.height()) / 2,
-                    pmState);
-
-    /* draw the VM state text */
-    aP->setFont (lb->stateFont (mSessionState));
-    aP->drawText (textX + pmState.width() + fmState.width(' '),
-                  stateY + (stateH - fmState.height()) / 2 + fmState.ascent(),
-                  strState);
-}
+/* Little helper class for layout calculation */
+class QRectList: public QList<QRect *>
+{
+public:
+    void alignVCenterTo (QRect* aWhich)
+    {
+        QRect b;
+        foreach (QRect *rect, *this)
+            if(rect != aWhich)
+                b |= *rect;
+        if (b.width() > aWhich->width())
+            aWhich->moveCenter (QPoint (aWhich->center().x(), b.center().y()));
+        else
+        {
+            foreach (QRect *rect, *this)
+                if(rect != aWhich)
+                    rect->moveCenter (QPoint (rect->center().x(), aWhich->center().y()));
+        }
+    }
+};
+
+QSize VBoxVMItemPainter::sizeHint (const QStyleOptionViewItem &aOption,
+                                   const QModelIndex &aIndex) const
+{
+    /* Get the size of every item */
+    QRect osTypeRT = rect (aOption, aIndex, Qt::DecorationRole);
+    QRect vmNameRT = rect (aOption, aIndex, Qt::DisplayRole);
+    QRect shotRT = rect (aOption, aIndex, VBoxVMModel::SnapShotDisplayRole);
+    QRect stateIconRT = rect (aOption, aIndex, VBoxVMModel::SessionStateDecorationRole);
+    QRect stateRT = rect (aOption, aIndex, VBoxVMModel::SessionStateDisplayRole);
+    /* Calculate the position for every item */
+    calcLayout (aIndex, &osTypeRT, &vmNameRT, &shotRT, &stateIconRT, &stateRT);
+    /* Calc the bounding rect */
+    const QRect boundingRect = osTypeRT | vmNameRT | shotRT | stateIconRT | stateRT;
+    /* Return + left/top/right/bottom margin */
+    return (boundingRect.size() + QSize (2 * mMargin, 2 * mMargin));
+}
+
+void VBoxVMItemPainter::paint (QPainter *aPainter, const QStyleOptionViewItem &aOption,
+                               const QModelIndex &aIndex) const
+{
+    // Name and decoration
+    const QString vmName = aIndex.data(Qt::DisplayRole).toString();
+    const QFont nameFont = aIndex.data (Qt::FontRole).value<QFont>();
+    const QPixmap osType = aIndex.data(Qt::DecorationRole).value<QIcon>().pixmap (aOption.decorationSize, iconMode (aOption.state), iconState (aOption.state));
+
+    const QString shot = aIndex.data(VBoxVMModel::SnapShotDisplayRole).toString();
+    const QFont shotFont = aIndex.data (VBoxVMModel::SnapShotFontRole).value<QFont>();
+
+    const QString state = aIndex.data(VBoxVMModel::SessionStateDisplayRole).toString();
+    const QFont stateFont = aIndex.data (VBoxVMModel::SessionStateFontRole).value<QFont>();
+    const QPixmap stateIcon = aIndex.data(VBoxVMModel::SessionStateDecorationRole).value<QIcon>().pixmap (QSize (16, 16), iconMode (aOption.state), iconState (aOption.state));
+
+    /* Get the sizes for all items */
+    QRect osTypeRT = rect (aOption, aIndex, Qt::DecorationRole);
+    QRect vmNameRT = rect (aOption, aIndex, Qt::DisplayRole);
+    QRect shotRT = rect (aOption, aIndex, VBoxVMModel::SnapShotDisplayRole);
+    QRect stateIconRT = rect (aOption, aIndex, VBoxVMModel::SessionStateDecorationRole);
+    QRect stateRT = rect (aOption, aIndex, VBoxVMModel::SessionStateDisplayRole);
+
+    /* Calculate the positions for all items */
+    calcLayout (aIndex, &osTypeRT, &vmNameRT, &shotRT, &stateIconRT, &stateRT);
+
+    /* Get the appropiate pen for the current state */
+    QPalette pal = aOption.palette;
+    QPen pen = pal.color (QPalette::Active, QPalette::Text);
+    if (aOption.state & QStyle::State_Selected)
+        pen =  pal.color (QPalette::Active, QPalette::HighlightedText);
+    /* Start drawing */
+    drawBackground (aPainter, aOption, aIndex);
+    aPainter->save();
+    /* Set the current pen */
+    aPainter->setPen (pen);
+    /* Move the painter to the initial position */
+    aPainter->translate (aOption.rect.x(), aOption.rect.y());
+    /* os type icon */
+    aPainter->drawPixmap (osTypeRT, osType);
+    /* vm name */
+    aPainter->setFont (nameFont);
+    aPainter->drawText (vmNameRT, vmName);
+    /* current snapshot in braces */
+    if (!shot.isEmpty())
+    {
+        aPainter->setFont (shotFont);
+        aPainter->drawText (shotRT, QString ("(%1)").arg (shot));
+    }
+    /* state icon */
+    aPainter->drawPixmap (stateIconRT, stateIcon);
+    /* textual state */
+    aPainter->setFont (stateFont);
+    aPainter->drawText (stateRT, state);
+    /* For debugging */
+//    QRect boundingRect = osTypeRT | vmNameRT | shotRT | stateIconRT | stateRT;
+//    aPainter->drawRect (boundingRect);
+    aPainter->restore();
+    drawFocus(aPainter, aOption, aOption.rect);
+}
+
+void VBoxVMItemPainter::drawBackground (QPainter *aPainter, const QStyleOptionViewItem &aOption, 
+                                        const QModelIndex &aIndex) const
+{   
+#if MAC_LEOPARD_STYLE
+    NOREF (aIndex);
+    /* Macify for Leopard */
+    if (aOption.state & QStyle::State_Selected)
+    {   
+        /* Standard color for selected items and focus on the widget */
+        QColor topLineColor (69, 128, 200);
+        QColor topGradColor (92, 147, 214);
+        QColor bottomGradColor (21, 83, 169);
+        /* Color for selected items and no focus on the widget */
+        if (QWidget *p = qobject_cast<QWidget *> (parent()))
+            if (!p->hasFocus())
+            {
+                topLineColor.setRgb (145, 160, 192);
+                topGradColor.setRgb (162, 177, 207);
+                bottomGradColor.setRgb (110, 129, 169);
+            }
+        /* Color for selected items and no focus on the application at all */
+        if (qApp->focusWidget() == NULL)
+            {
+                topLineColor.setRgb (151, 151, 151);
+                topGradColor.setRgb (180, 180, 180);
+                bottomGradColor.setRgb (137, 137, 137);
+            }
+        /* Paint the background */
+        QRect r = aOption.rect;
+        r.setTop (r.top() + 1);
+        QLinearGradient linearGrad (QPointF(0, r.top()), QPointF(0, r.bottom()));
+        linearGrad.setColorAt (0, topGradColor);
+        linearGrad.setColorAt (1, bottomGradColor);
+        aPainter->setPen (topLineColor);
+        aPainter->drawLine (r.left(), r.top() - 1, r.right(), r.top() - 1);
+        aPainter->fillRect (r, linearGrad);
+    }
+#else /* MAC_LEOPARD_STYLE */
+    QItemDelegate::drawBackground (aPainter, aOption, aIndex);
+#endif /* MAC_LEOPARD_STYLE */
+}
+
+QRect VBoxVMItemPainter::rect (const QStyleOptionViewItem &aOption,
+                               const QModelIndex &aIndex, int aRole) const
+{
+    switch (aRole)
+    {
+        case Qt::DisplayRole:
+            {
+                QString text = aIndex.data (Qt::DisplayRole).toString();
+                QFontMetrics fm (fontMetric (aIndex, Qt::FontRole));
+                return QRect (QPoint (0, 0), fm.size (0, text));
+                break;
+            }
+        case Qt::DecorationRole:
+            {
+                QIcon icon = aIndex.data (Qt::DecorationRole).value<QIcon>();
+                return QRect (QPoint (0, 0), icon.actualSize (aOption.decorationSize, iconMode (aOption.state), iconState (aOption.state)));
+                break;
+            }
+        case VBoxVMModel::SnapShotDisplayRole:
+            {
+                QString text = aIndex.data (VBoxVMModel::SnapShotDisplayRole).toString();
+                if (!text.isEmpty())
+                {
+                    QFontMetrics fm (fontMetric (aIndex, VBoxVMModel::SnapShotFontRole));
+                    return QRect (QPoint (0, 0), fm.size (0, QString ("(%1)").arg (text)));
+                }else
+                    return QRect();
+                break;
+            }
+        case VBoxVMModel::SessionStateDisplayRole:
+            {
+                QString text = aIndex.data (VBoxVMModel::SessionStateDisplayRole).toString();
+                QFontMetrics fm (fontMetric (aIndex, VBoxVMModel::SessionStateFontRole));
+                return QRect (QPoint (0, 0), fm.size (0, text));
+                break;
+            }
+        case VBoxVMModel::SessionStateDecorationRole:
+            {
+                QIcon icon = aIndex.data (VBoxVMModel::SessionStateDecorationRole).value<QIcon>();
+                return QRect (QPoint (0, 0), icon.actualSize (QSize (16, 16), iconMode (aOption.state), iconState (aOption.state)));
+                break;
+            }
+    }
+    return QRect();
+}
+
+void VBoxVMItemPainter::calcLayout (const QModelIndex &aIndex,
+                                    QRect *aOSType, QRect *aVMName, QRect *aShot,
+                                    QRect *aStateIcon, QRect *aState) const
+{
+    const int nameSpaceWidth = fontMetric (aIndex, Qt::FontRole).width (' ');
+    const int stateSpaceWidth = fontMetric (aIndex, VBoxVMModel::SessionStateFontRole).width (' ');
+    /* Really basic layout managment. 
+     * First layout as usual */
+    aOSType->moveTo (mMargin, mMargin);
+    aVMName->moveTo (mMargin + aOSType->width() + mSpacing, mMargin);
+    aShot->moveTo (aVMName->right() + nameSpaceWidth, aVMName->top());
+    aStateIcon->moveTo (aVMName->left(), aVMName->bottom());
+    aState->moveTo (aStateIcon->right() + stateSpaceWidth, aStateIcon->top());
+    /* Do grouping for the automatic center routine.
+     * First the states group: */
+    QRectList statesLayout;
+    statesLayout << aStateIcon << aState;
+    /* All items in the layout: */
+    QRectList allLayout;
+    allLayout << aOSType << aVMName << aShot << statesLayout;
+    /* Now verticaly center the items based on the reference item */
+    statesLayout.alignVCenterTo (aStateIcon);
+    allLayout.alignVCenterTo (aOSType);
+}
+
