Index: trunk/src/VBox/Frontends/VirtualBox4/Makefile.kmk
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/Makefile.kmk	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/Makefile.kmk	(revision 9245)
@@ -444,4 +444,5 @@
 	include/QIListView.h \
 	include/QITreeWidget.h \
+	include/QIMainDialog.h \
 	include/VBoxGlobalSettings.h \
 	include/VBoxUtils.h \
@@ -528,4 +529,5 @@
 	src/QIListView.cpp \
 	src/QITreeWidget.cpp \
+	src/QIMainDialog.cpp \
 	src/QILineEdit.cpp \
 	src/VBoxDefs.cpp \
Index: trunk/src/VBox/Frontends/VirtualBox4/include/QIMainDialog.h
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/include/QIMainDialog.h	(revision 9245)
+++ trunk/src/VBox/Frontends/VirtualBox4/include/QIMainDialog.h	(revision 9245)
@@ -0,0 +1,75 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * VirtualBox Qt extensions: QIMainDialog class implementation
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef __QIMainDialog_h__
+#define __QIMainDialog_h__
+
+/* Qt includes */
+#include <QMainWindow>
+#include <QDialog>
+#include <QPointer>
+
+class QEventLoop;
+
+class QIMainDialog: public QMainWindow
+{
+    Q_OBJECT;
+
+public:
+
+    QIMainDialog (QWidget *aParent = NULL, Qt::WindowFlags aFlags = Qt::Dialog);
+
+    QDialog::DialogCode exec();
+    QDialog::DialogCode result() const;
+
+    void setFileForProxyIcon (const QString& aFile);
+    QString fileForProxyIcon () const;
+
+public slots:
+
+    virtual void setVisible (bool aVisible);
+
+protected:
+
+    virtual bool event (QEvent *aEvent);
+
+protected slots:
+
+    void accept();
+    void reject();
+    void done (QDialog::DialogCode aRescode);
+
+    void setResult (QDialog::DialogCode aRescode);
+
+    void openAction (QAction *aAction);
+
+private:
+
+    /* Private member vars */
+    QDialog::DialogCode mRescode;
+    QPointer<QEventLoop> mEventLoop;
+
+    QString mFileForProxyIcon;
+};
+
+#endif /* __QIMainDialog_h__ */
+
Index: trunk/src/VBox/Frontends/VirtualBox4/include/VBoxDiskImageManagerDlg.h
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/include/VBoxDiskImageManagerDlg.h	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/include/VBoxDiskImageManagerDlg.h	(revision 9245)
@@ -25,4 +25,5 @@
 
 #include "VBoxDiskImageManagerDlg.gen.h"
+#include "QIMainDialog.h"
 #include "QIWithRetranslateUI.h"
 #include "COMDefs.h"
@@ -30,12 +31,9 @@
 #include "VBoxMediaComboBox.h"
 
-/* Qt includes */
-#include <QPointer>
-
 class DiskImageItem;
 class VBoxToolBar;
 class InfoPaneLabel;
 
-class VBoxDiskImageManagerDlg : public QIWithRetranslateUI2<QMainWindow>,
+class VBoxDiskImageManagerDlg : public QIWithRetranslateUI2<QIMainDialog>,
                                 public Ui::VBoxDiskImageManagerDlg
 {
@@ -48,7 +46,4 @@
 public:
 
-    enum ResultCode { Rejected, 
-                      Accepted };
-
     VBoxDiskImageManagerDlg (QWidget *aParent = NULL, Qt::WindowFlags aFlags = Qt::Dialog);
 
@@ -56,6 +51,4 @@
 
     static void showModeless (bool aRefresh = true);
-    int exec();
-    int result() const;
 
     QUuid selectedUuid() const;
@@ -69,5 +62,4 @@
 
     void refreshAll();
-    virtual void setVisible (bool aVisible);
 
 protected:
@@ -101,10 +93,4 @@
     void processDoubleClick (QTreeWidgetItem *aItem, int aColumn);
     void processRightClick (const QPoint &aPos, QTreeWidgetItem *aItem, int aColumn);
-
-    void accept();
-    void reject();
-    void done (int aRescode);
-
-    void setResult (int aRescode);
 
 private:
@@ -152,7 +138,5 @@
     /* Window status */
     bool mDoSelect;
-    int mRescode;
     static VBoxDiskImageManagerDlg *mModelessDialog;
-    QPointer<QEventLoop> mEventLoop;
 
     /* Type if we are in the select modus */
Index: trunk/src/VBox/Frontends/VirtualBox4/include/VBoxUtils.h
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/include/VBoxUtils.h	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/include/VBoxUtils.h	(revision 9245)
@@ -269,4 +269,7 @@
 }
 
+/* Proxy icon creation */
+QPixmap darwinCreateDragPixmap (const QPixmap& aPixmap, const QString &aText);
+
 /* Special routines for the dock handling */
 CGImageRef darwinCreateDockBadge (const char *aSource);
Index: trunk/src/VBox/Frontends/VirtualBox4/src/QIMainDialog.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/src/QIMainDialog.cpp	(revision 9245)
+++ trunk/src/VBox/Frontends/VirtualBox4/src/QIMainDialog.cpp	(revision 9245)
@@ -0,0 +1,213 @@
+/** @file
+ *
+ * VBox frontends: Qt GUI ("VirtualBox"):
+ * VirtualBox Qt extensions: QIMainDialog class implementation
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#include "QIMainDialog.h"
+#include "VBoxUtils.h"
+
+#include <iprt/assert.h>
+
+/* Qt includes */
+#include <QProcess>
+#include <QEventLoop>
+#include <QApplication>
+#include <QFileIconProvider>
+#include <QDir>
+#include <QUrl>
+#include <QMenu>
+
+QIMainDialog::QIMainDialog (QWidget *aParent /* = NULL */, Qt::WindowFlags aFlags /* = Qt::Dialog */)
+    : QMainWindow (aParent, aFlags) 
+    , mRescode (QDialog::Rejected)
+{
+}
+
+QDialog::DialogCode QIMainDialog::exec()
+{
+    AssertMsg (!mEventLoop, ("exec is called recursively!\n"));
+
+    /* Reset the result code */
+    setResult (QDialog::Rejected);
+    bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
+    setAttribute(Qt::WA_DeleteOnClose, false);
+    /* Create a local event loop */
+    mEventLoop = new QEventLoop();
+    /* Show the window */
+    show();
+    /* A guard to ourself for the case we destroy ourself. */
+    QPointer<QIMainDialog> guard = this;
+    /* Start the event loop. This blocks. */
+    mEventLoop->exec();
+    /* Delete the event loop */
+    delete mEventLoop;
+    /* Are we valid anymore? */
+    if (guard.isNull())
+        return QDialog::Rejected;
+    QDialog::DialogCode res = result();
+    if (deleteOnClose)
+        delete this;
+    /* Return the final result */
+    return res;
+}
+
+QDialog::DialogCode QIMainDialog::result() const 
+{ 
+    return mRescode; 
+}
+
+void QIMainDialog::setFileForProxyIcon (const QString& aFile)
+{
+    mFileForProxyIcon = aFile;
+}
+
+QString QIMainDialog::fileForProxyIcon () const
+{
+    return mFileForProxyIcon;
+}
+
+void QIMainDialog::setVisible (bool aVisible)
+{
+    QMainWindow::setVisible (aVisible);
+    /* Exit from the event loop if there is any and we are changing our state
+     * from visible to invisible. */
+    if(mEventLoop && !aVisible)
+        mEventLoop->exit();
+}
+
+bool QIMainDialog::event (QEvent *aEvent)
+{
+#ifdef Q_WS_MAC
+     switch (aEvent->type()) 
+     {
+          case QEvent::IconDrag: 
+              {
+                  Qt::KeyboardModifiers currentModifiers = qApp->keyboardModifiers();
+
+                  if (currentModifiers == Qt::NoModifier) 
+                  {
+                      if (!mFileForProxyIcon.isEmpty())
+                      {
+                          aEvent->accept();
+                          /* Create a drag object we can use */
+                          QDrag *drag = new QDrag (this);
+                          QMimeData *data = new QMimeData();
+                          /* Set the appropriate url data */
+                          data->setUrls(QList<QUrl>() << QUrl::fromLocalFile (mFileForProxyIcon));
+                          drag->setMimeData (data);
+                          /* Make a nice looking DnD icon */
+                          QFileInfo fi (mFileForProxyIcon);
+                          QPixmap cursorPixmap (::darwinCreateDragPixmap (QPixmap (windowIcon().pixmap (16, 16)), fi.fileName()));
+                          drag->setPixmap (cursorPixmap);
+                          drag->setHotSpot (QPoint (5, cursorPixmap.height() - 5));
+                          /* Start the DnD action */
+                          drag->start (Qt::LinkAction | Qt::CopyAction);
+                          return true;
+                      }
+                  }
+#if QT_VERSION < 0x040400
+                  else if (currentModifiers == Qt::ShiftModifier) 
+#else
+                  else if (currentModifiers == Qt::ControlModifier) 
+#endif
+                  {
+                      if (!mFileForProxyIcon.isEmpty())
+                      {
+                          aEvent->accept();
+                          /* Create the proxy icon menu */
+                          QMenu menu(this);
+                          connect(&menu, SIGNAL (triggered (QAction *)), 
+                                  this, SLOT (openAction (QAction *)));
+                          /* Add the file with the disk icon to the menu */
+                          QFileInfo fi (mFileForProxyIcon);
+                          QAction *action = menu.addAction (fi.fileName());
+                          action->setIcon (windowIcon());
+                          /* Create some nice looking menu out of the other
+                           * directory parts. */
+                          QFileIconProvider fip;
+                          QDir dir (fi.absolutePath());
+                          do
+                          {
+                              if (dir.isRoot())
+                                  action = menu.addAction ("/");
+                              else
+                                  action = menu.addAction (dir.dirName());
+                              action->setIcon (fip.icon (QFileInfo (dir, "")));
+                          }
+                          while (dir.cdUp());
+                          /* Show the menu */
+                          menu.exec (QPoint (QCursor::pos().x() - 20, frameGeometry().y() - 5));
+                          return true;
+                      }
+                  }
+                  break;
+              }
+          default: 
+              break;
+     }
+#endif /* Q_WS_MAC */
+     return QMainWindow::event (aEvent);
+}
+
+void QIMainDialog::accept() 
+{ 
+    done (QDialog::Accepted); 
+}
+
+void QIMainDialog::reject() 
+{ 
+    done (QDialog::Rejected); 
+}
+
+void QIMainDialog::done (QDialog::DialogCode aResult)
+{
+    /* Set the final result */
+    setResult (aResult);
+    /* Hide this window */
+    hide();
+    /* And close the window */
+    close();
+}
+
+void QIMainDialog::setResult (QDialog::DialogCode aRescode) 
+{ 
+    mRescode = aRescode; 
+}
+
+void QIMainDialog::openAction (QAction *aAction)
+{
+#ifdef Q_WS_MAC
+    if (!mFileForProxyIcon.isEmpty())
+    {
+        QString path = mFileForProxyIcon.left (mFileForProxyIcon.indexOf (aAction->text())) + aAction->text();
+        /* Check for the first item */
+        if (mFileForProxyIcon != path)
+        {
+            /* @todo: vboxGlobal().openURL (path); should be able to open paths */
+            QProcess process;
+            process.start ("/usr/bin/open", QStringList() << path, QIODevice::ReadOnly);
+            process.waitForFinished();
+        }
+    }
+#else /* Q_WS_MAC */
+    NOREF (aAction);
+#endif /* Q_WS_MAC */
+}
+
Index: trunk/src/VBox/Frontends/VirtualBox4/src/VBoxConsoleWnd.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/src/VBoxConsoleWnd.cpp	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/src/VBoxConsoleWnd.cpp	(revision 9245)
@@ -2533,5 +2533,5 @@
     dlg.setup (VBoxDefs::FD, true, &id);
 
-    if (dlg.exec() == VBoxDiskImageManagerDlg::Accepted)
+    if (dlg.exec() == QDialog::Accepted)
     {
         CFloppyDrive drv = csession.GetMachine().GetFloppyDrive();
@@ -2577,5 +2577,5 @@
     dlg.setup (VBoxDefs::CD, true, &id);
 
-    if (dlg.exec() == VBoxDiskImageManagerDlg::Accepted)
+    if (dlg.exec() == QDialog::Accepted)
     {
         CDVDDrive drv = csession.GetMachine().GetDVDDrive();
Index: trunk/src/VBox/Frontends/VirtualBox4/src/VBoxDiskImageManagerDlg.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/src/VBoxDiskImageManagerDlg.cpp	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/src/VBoxDiskImageManagerDlg.cpp	(revision 9245)
@@ -209,6 +209,5 @@
 
 VBoxDiskImageManagerDlg::VBoxDiskImageManagerDlg (QWidget *aParent /* = NULL */,  Qt::WindowFlags aFlags /* = 0 */)
-    : QIWithRetranslateUI2<QMainWindow> (aParent, aFlags)
-    , mRescode (Rejected)
+    : QIWithRetranslateUI2<QIMainDialog> (aParent, aFlags)
     , mType (VBoxDefs::InvalidType)
 {
@@ -523,32 +522,4 @@
 }
 
-int VBoxDiskImageManagerDlg::exec()
-{
-    AssertMsg (!mEventLoop, ("exec is called recursively!\n"));
-
-    /* Reset the result code */
-    setResult (Rejected);
-    bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
-    setAttribute(Qt::WA_DeleteOnClose, false);
-    /* Create a local event loop */
-    mEventLoop = new QEventLoop();
-    /* Show the window */
-    show();
-    /* A guard to ourself for the case we destroy ourself. */
-    QPointer<VBoxDiskImageManagerDlg> guard = this;
-    /* Start the event loop. This blocks. */
-    mEventLoop->exec();
-    /* Delete the event loop */
-    delete mEventLoop;
-    /* Are we valid anymore? */
-    if (guard.isNull())
-        return Rejected;
-     int res = result();
-     if (deleteOnClose)
-         delete this;
-    /* Return the final result */
-    return res;
-}
-
 QUuid VBoxDiskImageManagerDlg::selectedUuid() const
 {
@@ -796,13 +767,4 @@
     /* Start enumerating media */
     vboxGlobal().startEnumeratingMedia();
-}
-
-void VBoxDiskImageManagerDlg::setVisible (bool aVisible)
-{
-    QMainWindow::setVisible (aVisible);
-    /* Exit from the event loop if there is any and we are changing our state
-     * from visible to invisible. */
-    if(mEventLoop && !aVisible)
-        mEventLoop->exit();
 }
 
@@ -1407,34 +1369,4 @@
 }
 
-void VBoxDiskImageManagerDlg::accept() 
-{ 
-    done (Accepted); 
-}
-
-void VBoxDiskImageManagerDlg::reject() 
-{ 
-    done (Rejected); 
-}
-
-void VBoxDiskImageManagerDlg::done (int aResult)
-{
-    /* Set the final result */
-    setResult (aResult);
-    /* Hide this window */
-    hide();
-    /* And close the window */
-    close();
-}
-
-int VBoxDiskImageManagerDlg::result() const 
-{ 
-    return mRescode; 
-}
-
-void VBoxDiskImageManagerDlg::setResult (int aRescode) 
-{ 
-    mRescode = aRescode; 
-}
-
 QTreeWidget* VBoxDiskImageManagerDlg::treeWidget (VBoxDefs::DiskType aType) const
 {
@@ -1552,4 +1484,7 @@
         return;
     }
+
+    /* Set the file for the proxy icon */ 
+    setFileForProxyIcon (item->path());
 
     /* Ensures current item visible every time we are switching page */
Index: trunk/src/VBox/Frontends/VirtualBox4/src/VBoxNewVMWzd.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/src/VBoxNewVMWzd.cpp	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/src/VBoxNewVMWzd.cpp	(revision 9245)
@@ -197,5 +197,5 @@
     VBoxDiskImageManagerDlg dlg (this);
     dlg.setup (VBoxDefs::HD, true);
-    QUuid newId = dlg.exec() == VBoxDiskImageManagerDlg::Accepted ?
+    QUuid newId = dlg.exec() == QDialog::Accepted ?
         dlg.selectedUuid() : mMediaCombo->getId();
 
Index: trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMFirstRunWzd.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMFirstRunWzd.cpp	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/src/VBoxVMFirstRunWzd.cpp	(revision 9245)
@@ -246,5 +246,5 @@
         mRbFdType->isChecked() ? VBoxDefs::FD : VBoxDefs::InvalidType;
     vdm.setup (type, true, &machineId);
-    if (vdm.exec() == VBoxDiskImageManagerDlg::Accepted)
+    if (vdm.exec() == QDialog::Accepted)
     {
         mCbImage->setCurrentItem (vdm.selectedUuid());
Index: trunk/src/VBox/Frontends/VirtualBox4/src/darwin/VBoxUtils-darwin.cpp
===================================================================
--- trunk/src/VBox/Frontends/VirtualBox4/src/darwin/VBoxUtils-darwin.cpp	(revision 9244)
+++ trunk/src/VBox/Frontends/VirtualBox4/src/darwin/VBoxUtils-darwin.cpp	(revision 9245)
@@ -32,4 +32,5 @@
 #include <QPixmap>
 #include <QPainter>
+#include <QApplication>
 
 /**
@@ -95,4 +96,20 @@
     Assert (!qpm.isNull());
     return ::darwinToCGImageRef (&qpm);
+}
+
+/* Proxy icon creation */
+QPixmap darwinCreateDragPixmap (const QPixmap& aPixmap, const QString &aText)
+{
+    QFontMetrics fm (qApp->font());
+    QRect tbRect = fm.boundingRect (aText);
+    const int h = qMax (aPixmap.height(), tbRect.height());
+    const int m = 2;
+    QPixmap dragPixmap (aPixmap.width() + tbRect.width() + m, h);
+    dragPixmap.fill (Qt::transparent);
+    QPainter painter (&dragPixmap);
+    painter.drawPixmap (0, qAbs (h - aPixmap.height()) / 2.0, aPixmap);
+    painter.drawText (aPixmap.width() + m, qAbs (h - aPixmap.height()) / 2.0 + aPixmap.height(), aText);
+    painter.end();
+    return dragPixmap;
 }
 
