VirtualBox

Ignore:
Timestamp:
Aug 6, 2015 7:19:19 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
101974
Message:

DnD: Added support for "drag promises" on OS X for guest to host transfers, cleaned up MIME type conversion/handling, bugfixes.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r57112 r57221  
    118118        $(if $(VBOX_WITH_DRAG_AND_DROP),VBOX_WITH_DRAG_AND_DROP) \
    119119        $(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH) \
     120    $(if $(VBOX_WITH_DRAG_AND_DROP_PROMISES),VBOX_WITH_DRAG_AND_DROP_PROMISES) \
    120121        $(if $(VBOX_WITH_CRHGSMI),VBOX_WITH_CRHGSMI) \
    121122        $(if $(VBOX_WITH_VIRTIO),VBOX_WITH_VIRTIO) \
     
    807808endif
    808809
     810#
     811# Drag and drop support.
     812#
    809813ifdef VBOX_WITH_DRAG_AND_DROP
    810814 VirtualBox_SOURCES += \
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp

    r56779 r57221  
    6262#include <VBox/log.h>
    6363
     64#if 1
     65# ifdef DEBUG
     66#  include <QTextStream>
     67/** Enable this to log debug output of a Qt debug build to a file defined by DEBUG_DND_QT_LOGFILE. */
     68#  define DEBUG_DND_QT
     69/** File to log Qt debug output to. */
     70#  define DEBUG_DND_QT_LOGFILE "/var/tmp/qt.log"
     71# endif /* DEBUG */
     72#endif
    6473
    6574UIDnDHandler::UIDnDHandler(UISession *pSession, QWidget *pParent)
     
    6877    , m_enmMode(DNDMODE_UNKNOWN)
    6978    , m_fIsPending(false)
     79    , m_fDataRetrieved(false)
    7080#ifndef RT_OS_WINDOWS
    7181    , m_pMIMEData(NULL)
     
    264274}
    265275
     276#ifdef DEBUG_DND_QT
     277QTextStream *g_pStrmLogQt = NULL; /* Output stream for Qt debug logging. */
     278
     279/* static */
     280void UIDnDHandler::debugOutputQt(QtMsgType type, const char *pszMsg)
     281{
     282    AssertPtr(pszMsg);
     283
     284    QString strMsg;
     285    switch (type)
     286    {
     287    case QtWarningMsg:
     288        strMsg += "[W]";
     289        break;
     290    case QtCriticalMsg:
     291        strMsg += "[C]";
     292        break;
     293    case QtFatalMsg:
     294        strMsg += "[F]";
     295        break;
     296    case QtDebugMsg:
     297    default:
     298        strMsg += "[D]";
     299        break;
     300    }
     301
     302    if (g_pStrmLogQt)
     303        (*g_pStrmLogQt) << strMsg << " " << pszMsg << endl;
     304}
     305#endif /* DEBUG_DND_QT */
     306
    266307/*
    267308 * Source -> Frontend.
     
    327368    }
    328369
    329     /* Invoke this handler as data needs to be retrieved. */
    330     connect(m_pMIMEData, SIGNAL(getData(QString, QVariant::Type, QVariant&)),
    331             this, SLOT(sltGetData(QString, QVariant::Type, QVariant&)));
     370#ifdef DEBUG_DND_QT
     371    QFile *pFileDebugQt = new QFile(DEBUG_DND_QT_LOGFILE);
     372    if (pFileDebugQt->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
     373    {
     374        g_pStrmLogQt = new QTextStream(pFileDebugQt);
     375
     376        qInstallMsgHandler(UIDnDHandler::debugOutputQt);
     377        qDebug("========================================================================");
     378    }
     379#endif
    332380
    333381    /* Inform the MIME data object of any changes in the current action. */
     
    341389    pDrag->setMimeData(m_pMIMEData);
    342390    LogFlowFunc(("Executing modal drag'n drop operation ...\n"));
    343     Qt::DropAction dropAction = pDrag->exec(actions, defAction);
     391
     392    Qt::DropAction dropAction;
     393#ifdef RT_OS_DARWIN
     394# ifdef VBOX_WITH_DRAG_AND_DROP_PROMISES
     395    dropAction = pDrag->exec(actions, defAction, true /* fUsePromises */);
     396# else
     397    /* Without having VBOX_WITH_DRAG_AND_DROP_PROMISES enabled drag and drop
     398     * will not work on OS X! It also requires some handcrafted patches within Qt
     399     * (which also needs VBOX_WITH_DRAG_AND_DROP_PROMISES set there). */
     400    dropAction = DropAction::IgnoreAction;
     401    rc = VERR_NOT_SUPPORTED;
     402# endif
     403#else /* !RT_OS_DARWIN */
     404    dropAction = pDrag->exec(actions, defAction);
     405#endif
    344406    LogRel3(("DnD: Ended with dropAction=%ld\n", UIDnDHandler::toVBoxDnDAction(dropAction)));
    345407
     
    357419
    358420#endif
     421
     422#ifdef DEBUG_DND_QT
     423    if (g_pStrmLogQt)
     424    {
     425        delete g_pStrmLogQt;
     426        g_pStrmLogQt = NULL;
     427    }
     428
     429    if (pFileDebugQt)
     430    {
     431        pFileDebugQt->close();
     432        delete pFileDebugQt;
     433    }
     434#endif
     435
     436    reset();
    359437
    360438    LogFlowFuncLeaveRC(rc);
     
    405483    m_dataSource.defaultAction = m_dndSource.DragIsPending(screenID, vecFormats, m_dataSource.vecActions);
    406484
    407     LogRel3(("DnD: Default action is: 0x%x\n", m_dataSource.defaultAction));
    408     LogRel3(("DnD: Number of supported guest actions: %d\n", m_dataSource.vecActions.size()));
     485    LogRelMax3(10, ("DnD: Default action is: 0x%x\n", m_dataSource.defaultAction));
     486    LogRelMax3(10, ("DnD: Number of supported guest actions: %d\n", m_dataSource.vecActions.size()));
    409487        for (int i = 0; i < m_dataSource.vecActions.size(); i++)
    410             LogRel3(("DnD: \tAction %d: 0x%x\n", i, m_dataSource.vecActions.at(i)));
    411 
    412     LogRel3(("DnD: Number of supported guest formats: %d\n", vecFormats.size()));
     488            LogRelMax3(10, ("DnD: \tAction %d: 0x%x\n", i, m_dataSource.vecActions.at(i)));
     489
     490    LogRelMax3(10, ("DnD: Number of supported guest formats: %d\n", vecFormats.size()));
    413491        for (int i = 0; i < vecFormats.size(); i++)
    414492        {
    415493            const QString &strFmtGuest = vecFormats.at(i);
    416             LogRel3(("DnD: \tFormat %d: %s\n", i, strFmtGuest.toAscii().constData()));
     494            LogRelMax3(10, ("DnD: \tFormat %d: %s\n", i, strFmtGuest.toAscii().constData()));
    417495        }
    418496
     
    491569    NOREF(screenID);
    492570
    493     m_fIsPending = false;
     571    reset();
    494572    rc = VINF_SUCCESS;
    495573
     
    506584}
    507585
     586void UIDnDHandler::reset(void)
     587{
     588    LogFlowFuncEnter();
     589
     590    m_fDataRetrieved = false;
     591    m_fIsPending = false;
     592
     593    setMode(DNDMODE_UNKNOWN);
     594}
     595
     596int UIDnDHandler::retrieveData(Qt::DropAction          dropAction,
     597                               const QString          &strMIMEType,
     598                                     QVector<uint8_t> &vecData)
     599{
     600    if (!strMIMEType.compare("application/x-qt-mime-type-name", Qt::CaseInsensitive))
     601        return VINF_SUCCESS;
     602
     603    int rc;
     604    if (!m_fDataRetrieved)
     605    {
     606        /*
     607         * Retrieve the actual data from the guest.
     608         */
     609        rc = retrieveDataInternal(dropAction, strMIMEType, m_vecData);
     610        LogRel3(("DnD: Received data, rc=%Rrc\n", rc));
     611
     612        if (RT_SUCCESS(rc))
     613            m_fDataRetrieved = true;
     614    }
     615    else /* Data already received, supply cached version. */
     616        rc = VINF_SUCCESS;
     617
     618    if (RT_SUCCESS(rc))
     619        vecData = m_vecData;
     620
     621    return rc;
     622}
     623
    508624int UIDnDHandler::retrieveData(      Qt::DropAction  dropAction,
    509                                const QString        &strMimeType,
     625                               const QString        &strMIMEType,
    510626                                     QVariant::Type  vaType,
    511627                                     QVariant       &vaData)
    512628{
    513     return retrieveDataInternal(dropAction, strMimeType, vaType, vaData);
    514 }
    515 
    516 int UIDnDHandler::retrieveDataInternal(      Qt::DropAction  dropAction,
    517                                        const QString        &strMimeType,
    518                                              QVariant::Type  vaType,
    519                                              QVariant       &vaData)
    520 {
    521     LogFlowFunc(("Retrieving data as type=%s (variant type=%RU32)\n",
    522                  strMimeType.toAscii().constData(), vaType));
     629    QVector<uint8_t> vecData;
     630    int rc = retrieveData(dropAction, strMIMEType, vecData);
     631    if (RT_SUCCESS(rc))
     632    {
     633        /* If no/an invalid variant is set, try to guess the variant type.
     634         * This can happen on OS X. */
     635        if (vaType == QVariant::Invalid)
     636            vaType = UIDnDMIMEData::getVariantType(strMIMEType);
     637
     638        rc = UIDnDMIMEData::getDataAsVariant(vecData, strMIMEType, vaType, vaData);
     639    }
     640
     641    LogFlowFuncLeaveRC(rc);
     642    return rc;
     643}
     644
     645int UIDnDHandler::retrieveDataInternal(      Qt::DropAction    dropAction,
     646                                       const QString          &strMIMEType,
     647                                             QVector<uint8_t> &vecData)
     648{
     649    LogFlowFunc(("Retrieving data as '%s', dropAction=%d\n", qPrintable(strMIMEType), dropAction));
    523650
    524651    int rc = VINF_SUCCESS;
     
    527654     * from the source and display a modal progress dialog while doing this. */
    528655    Assert(!m_dndSource.isNull());
    529     CProgress progress = m_dndSource.Drop(strMimeType,
     656    CProgress progress = m_dndSource.Drop(strMIMEType,
    530657                                          UIDnDHandler::toVBoxDnDAction(dropAction));
     658
     659    LogFlowFunc(("Source: isOk=%RTbool\n", m_dndSource.isOk()));
    531660    if (m_dndSource.isOk())
    532661    {
     
    535664                                            m_pParent);
    536665
    537         LogFlowFunc(("fCanceled=%RTbool, fCompleted=%RTbool, isOk=%RTbool, hrc=%Rhrc\n",
     666        LogFlowFunc(("Progress: fCanceled=%RTbool, fCompleted=%RTbool, isOk=%RTbool, hrc=%Rhrc\n",
    538667                     progress.GetCanceled(), progress.GetCompleted(), progress.isOk(), progress.GetResultCode()));
    539668
     
    547676            {
    548677                /* After we successfully retrieved data from the source we query it from Main. */
    549                 QVector<uint8_t> vecData = m_dndSource.ReceiveData();
    550                 if (!vecData.isEmpty())
    551                 {
    552                     switch (vaType)
    553                     {
    554                         case QVariant::String:
    555                         {
    556                             vaData = QVariant::fromValue(QString(reinterpret_cast<const char *>(vecData.constData())));
    557                             Assert(vaData.type() == QVariant::String);
    558                             break;
    559                         }
    560 
    561                         case QVariant::ByteArray:
    562                         {
    563                             QByteArray ba(reinterpret_cast<const char*>(vecData.constData()), vecData.size());
    564 
    565                             vaData = QVariant::fromValue(ba);
    566                             Assert(vaData.type() == QVariant::ByteArray);
    567                             break;
    568                         }
    569 
    570                         case QVariant::StringList:
    571                         {
    572                             QString strData = QString(reinterpret_cast<const char*>(vecData.constData()));
    573                             QStringList lstString = strData.split("\r\n", QString::SkipEmptyParts);
    574 
    575                             vaData = QVariant::fromValue(lstString);
    576                             Assert(vaData.type() == QVariant::StringList);
    577                             break;
    578                         }
    579 
    580                         default:
    581                             rc = VERR_NOT_SUPPORTED;
    582                             break;
    583                     }
    584                 }
    585                 else
     678                vecData = m_dndSource.ReceiveData(); /** @todo QVector.size() is "int" only!? */
     679                if (vecData.isEmpty())
    586680                    rc = VERR_NO_DATA;
    587681            }
     
    609703    m_enmMode = enmMode;
    610704    LogFlowFunc(("Mode is now: %RU32\n", m_enmMode));
    611 }
    612 
    613 int UIDnDHandler::sltGetData(const QString        &strMimeType,
    614                                    QVariant::Type  vaType,
    615                                    QVariant       &vaData)
    616 {
    617     int rc = retrieveDataInternal(Qt::CopyAction, strMimeType, vaType, vaData);
    618     LogFlowFuncLeaveRC(rc);
    619     return rc;
    620705}
    621706
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h

    r56555 r57221  
    7676    } UIDnDDataSource;
    7777
     78    void                       reset(void);
     79
    7880    /* Frontend -> Target. */
    7981    Qt::DropAction             dragEnter(ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData);
     
    8688    int                        dragStart(ulong screenId);
    8789    int                        dragStop(ulong screenID);
    88     int                        retrieveData(Qt::DropAction  dropAction, const QString &strMimeType, QVariant::Type vaType, QVariant &vaData);
     90
     91    /* Data access. */
     92    int                        retrieveData(Qt::DropAction dropAction, const QString &strMIMEType, QVector<uint8_t> &vecData);
     93    int                        retrieveData(Qt::DropAction dropAction, const QString &strMIMEType, QVariant::Type vaType, QVariant &vaData);
    8994
    9095public:
     
    95100    static Qt::DropActions     toQtDnDActions(const QVector<KDnDAction> &vecActions);
    96101
    97 public slots:
     102protected:
    98103
    99     /**
    100      * Called by UIDnDMIMEData (Linux, OS X, Solaris) to start retrieving the actual data
    101      * from the guest. This function will block and show a modal progress dialog until
    102      * the data transfer is complete.
    103      *
    104      * @return IPRT status code.
    105      * @param strMimeType           MIME data type.
    106      * @param vaType                Qt's variant type of the MIME data.
    107      * @param vaData                Reference to QVariant where to store the retrieved data.
    108      */
    109     int                        sltGetData(const QString &strMimeType, QVariant::Type vaType, QVariant &vaData);
     104#ifdef DEBUG
     105    static void                debugOutputQt(QtMsgType type, const char *pszMsg);
     106#endif
    110107
    111108protected:
    112109
    113110    int                        dragStartInternal(const QStringList &lstFormats, Qt::DropAction defAction, Qt::DropActions actions);
    114     int                        retrieveDataInternal(Qt::DropAction dropAction, const QString &strMimeType, QVariant::Type vaType, QVariant &vaData);
     111    int                        retrieveDataInternal(Qt::DropAction dropAction, const QString &strMIMEType, QVector<uint8_t> &vecData);
    115112    void                       setMode(DNDMODE enmMode);
    116113
     
    133130    /** Flag indicating if a drag operation is pending currently. */
    134131    bool              m_fIsPending;
     132    /** Flag indicating whether data has been retrieved from
     133     *  the guest already or not. */
     134    bool              m_fDataRetrieved;
    135135    QMutex            m_ReadLock;
    136136    QMutex            m_WriteLock;
     137    /** Data received from the guest. */
     138    QVector<uint8_t>  m_vecData;
    137139
    138140#ifndef RT_OS_WINDOWS
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp

    r56865 r57221  
    4444    , m_actions(actions)
    4545    , m_enmState(Dragging)
    46     , m_vaData(QVariant::Invalid)
    47 #ifdef RT_OS_DARWIN
    48     , m_fCanDrop(false)
    49 #endif
    5046{
    5147    LogFlowThisFuncEnter();
    52 
    5348#ifdef DEBUG
    5449    LogFlowFunc(("Number of formats: %d\n", m_lstFormats.size()));
     
    5651        LogFlowFunc(("\tFormat %d: %s\n", i, m_lstFormats.at(i).toAscii().constData()));
    5752#endif
    58 
     53}
     54
     55QStringList UIDnDMIMEData::formats(void) const
     56{
     57    LogFlowFuncEnter();
     58#ifdef DEBUG
     59    for (int i = 0; i < m_lstFormats.size(); i++)
     60        LogFlowFunc(("\tFormat %d: %s\n", i, m_lstFormats.at(i).toAscii().constData()));
     61#endif
     62    return m_lstFormats;
     63}
     64
     65bool UIDnDMIMEData::hasFormat(const QString &strMIMEType) const
     66{
     67    bool fRc;
    5968#ifdef RT_OS_DARWIN
    60     connect(this, SIGNAL(notifyDropped()), this, SLOT(sltDropped()));
    61 #endif
    62 }
    63 
    64 QStringList UIDnDMIMEData::formats(void) const
    65 {
    66     LogFlowFuncEnter();
    67     return m_lstFormats;
    68 }
    69 
    70 bool UIDnDMIMEData::hasFormat(const QString &strMIMEType) const
    71 {
    72     bool fRc = false;
    73 
    74 #ifdef RT_OS_DARWIN
    75     if (strMIMEType.compare("application/x-qt-mime-type-name", Qt::CaseInsensitive) == 0)
    76         fRc = true;
    77 #endif
    78 
    79     if (!fRc)
    80         fRc = m_curAction != Qt::IgnoreAction;
     69    fRc = m_lstFormats.contains(strMIMEType);
     70#else
     71    fRc = m_curAction != Qt::IgnoreAction;
     72#endif
    8173
    8274    LogFlowFunc(("%s: %RTbool (QtMimeData: %RTbool, curAction=0x%x)\n",
    8375                 strMIMEType.toStdString().c_str(), fRc, QMimeData::hasFormat(strMIMEType), m_curAction));
    8476
    85 #ifdef RT_OS_DARWIN
    86     /*
    87      * On OS X hasFormat() only seems to get called on a successful
    88      * drop, that is, if the host knows (and the user accepts) the drop operation.
    89      * 
    90      * As we can't do here much since this is a const'ed function we're emitting a
    91      * signal to ourselves in order to let us know that we can start receiving data
    92      * from the guest within the next retrieveData() call.
    93      */
    94     emit notifyDropped();
    95 #endif
    96 
    9777    return fRc;
    9878}
    99 
    100 #ifdef RT_OS_DARWIN
    101 void UIDnDMIMEData::sltDropped(void)
    102 {
    103     LogFlowFuncEnter();
    104     m_fCanDrop = true;
    105 }
    106 #endif
    10779
    10880/**
     
    12092                 m_enmState, m_curAction, m_defAction, strMIMEType.toStdString().c_str(), vaType, QVariant::typeToName(vaType)));
    12193
    122     bool fCanDrop = true; /* Accept by default. */
     94    int rc = VINF_SUCCESS;
    12395
    12496#ifdef RT_OS_WINDOWS
    125     /* 
     97    /*
    12698     * On Windows this function will be called several times by Qt's
    12799     * OLE-specific internals to figure out which data formats we have
    128100     * to offer. So just assume we can drop data here for a start.
    129      */ 
     101     */
    130102#elif defined(RT_OS_DARWIN)
     103# ifndef VBOX_WITH_DRAG_AND_DROP_PROMISES
    131104    /*
    132      * On OS X we rely on an internal flag which gets set in the overriden
    133      * hasFormat() function. That function only gets called on a successful drop
    134      * so that we can tell if we have to start receiving data the next time
    135      * we come by here.
     105     * Without VBOX_WITH_DRAG_AND_DROP_PROMISES being set in VBox *and* in our (patched) Qt
     106     * libraries there's no reliable way to get this working on OS X. So just deny any dropping.
    136107     */
    137     fCanDrop = m_fCanDrop;
    138 #else
    139     /*
    140      * On non-Windows our state gets updated via an own event filter
    141      * (see UIDnDMimeData::eventFilter). This filter will update the current
    142      * operation state for us (based on the mouse buttons).
    143      */
     108    rc = VERR_NOT_IMPLEMENTED;
     109
     110    /* Let the user know. */
     111    LogRel(("Drag and drop support for OS X is disabled in this version."));
     112# endif /* VBOX_WITH_DRAG_AND_DROP_PROMISES */
     113#else /* !RT_OS_DARWIN */
     114    /*
     115     * On Linux/Solaris our state gets updated if the drop target has been
     116     * changed. So query the current status if we're at the moment are able
     117     * to drop something on the current target.
     118     */
    144119    if (m_curAction == Qt::IgnoreAction)
    145120    {
    146121        LogFlowFunc(("Current drop action is 0x%x, so can't drop yet\n", m_curAction));
    147         fCanDrop = false;
    148     }
    149 #endif
    150 
    151     if (fCanDrop)
    152     {
     122        rc = VERR_WRONG_ORDER;
     123    }
     124#endif
     125
     126    if (RT_SUCCESS(rc))
     127    {
     128        /* Silently ignore internal Qt types / converters. */
     129        if (!strMIMEType.compare("application/x-qt-mime-type-name", Qt::CaseInsensitive))
     130        {
     131            rc = VERR_NOT_FOUND;
     132        }
    153133        /* Do we support the requested MIME type? */
    154         if (!m_lstFormats.contains(strMIMEType))
     134        else if (!m_lstFormats.contains(strMIMEType))
    155135        {
    156136            LogRel(("DnD: Unsupported MIME type '%s'\n", strMIMEType.toStdString().c_str()));
    157             fCanDrop = false;
    158         }
    159 
    160         /* Supported types. See below in the switch statement. */
    161         if (!(
    162               /* Plain text. */
    163                  vaType == QVariant::String
    164               /* Binary data. */
    165               || vaType == QVariant::ByteArray
    166                  /* URI list. */
    167               || vaType == QVariant::List))
     137            rc = VERR_NOT_SUPPORTED;
     138        }
     139#ifndef RT_OS_DARWIN /* On OS X QVariant::Invalid can happen for drag and drop "promises" for "lazy requests".  */
     140        /* Check supported variant types. */
     141        else if (!(
     142                   /* Plain text. */
     143                      vaType == QVariant::String
     144                   /* Binary data. */
     145                   || vaType == QVariant::ByteArray
     146                   /* URI list. */
     147                   || vaType == QVariant::List
     148                   || vaType == QVariant::StringList))
    168149        {
    169150            LogRel(("DnD: Unsupported data type '%s'\n", QVariant::typeToName(vaType)));
    170             fCanDrop = false;
    171         }
    172     }
    173 
    174     LogRel3(("DnD: State=%ld, Action=0x%x, fCanDrop=%RTbool\n", m_enmState, m_curAction, fCanDrop));
    175 
    176     if (fCanDrop)
     151            rc = VERR_NOT_SUPPORTED;
     152        }
     153#endif
     154    }
     155
     156    LogRel3(("DnD: Retrieved data state is %ld (action=0x%x), rc=%Rrc\n", m_enmState, m_curAction, rc));
     157
     158    if (RT_SUCCESS(rc))
    177159    {
    178160        QVariant vaData;
    179         int rc = emit getData(strMIMEType, vaType, vaData);
    180 
    181         LogRel3(("DnD: Returning data of type=%s (requested MIME type=%s, requested type=%s), rc=%Rrc\n",
    182                  vaData.typeName() ? vaData.typeName() : "<Invalid>",
    183                  strMIMEType.toStdString().c_str(),
    184                  QVariant::typeToName(vaType) ? QVariant::typeToName(vaType) : "<Invalid>", rc));
    185 
     161        rc = m_pDnDHandler->retrieveData(Qt::CopyAction, strMIMEType, vaType, vaData);
    186162        if (RT_SUCCESS(rc))
     163        {
     164            LogRel3(("DnD: Returning data for MIME type=%s, variant type=%s, rc=%Rrc\n",
     165                     strMIMEType.toStdString().c_str(), QVariant::typeToName(vaData.type()), rc));
     166
    187167            return vaData;
    188     }
    189 
    190 #ifdef RT_OS_DARWIN
    191     LogFlowFunc(("Returning data for Cocoa\n"));
     168        }
     169    }
     170    else if (rc == VERR_NOT_FOUND) /* Silently skip internal entries. */
     171        rc = VINF_SUCCESS;
     172
     173    if (RT_FAILURE(rc))
     174        LogRel(("DnD: Retrieving data failed with %Rrc\n", rc));
     175
    192176    return QMimeData::retrieveData(strMIMEType, vaType);
    193 #else
    194     LogFlowFunc(("Skipping request, state=%RU32 ...\n", m_enmState));
    195     return QVariant(QVariant::Invalid); /* Return a NULL variant. */
    196 #endif
    197 }
    198 
    199 int UIDnDMIMEData::setData(const QString &strMIMEType, const QVariant &vaData)
    200 {
    201     LogFlowFunc(("mimeType=%s, dataType=%s\n",
    202                  strMIMEType.toAscii().constData(), vaData.typeName()));
     177}
     178
     179/* static */
     180QVariant::Type UIDnDMIMEData::getVariantType(const QString &strMIMEType)
     181{
     182    QVariant::Type vaType;
     183
     184    if (   !strMIMEType.compare("text/html")
     185        || !strMIMEType.compare("text/plain;charset=utf-8")
     186        || !strMIMEType.compare("text/plain;charset=utf-16")
     187        || !strMIMEType.compare("text/plain")
     188        || !strMIMEType.compare("text/richtext")
     189        || !strMIMEType.compare("UTF8_STRING")
     190        || !strMIMEType.compare("TEXT")
     191        || !strMIMEType.compare("STRING"))
     192    {
     193        vaType = QVariant::String;
     194    }
     195    else if (!strMIMEType.compare("text/uri-list", Qt::CaseInsensitive))
     196        vaType = QVariant::List;
     197    else
     198        vaType = QVariant::Invalid;
     199
     200    LogFlowFunc(("strMIMEType=%s -> vaType=%s\n", qPrintable(strMIMEType), QVariant::typeToName(vaType)));
     201    return vaType;
     202}
     203
     204/* static */
     205int UIDnDMIMEData::getDataAsVariant(const QVector<uint8_t> &vecData,
     206                                    const QString          &strMIMEType,
     207                                         QVariant::Type    vaType,
     208                                         QVariant         &vaData)
     209{
     210    LogFlowFunc(("vecDataSize=%d, strMIMEType=%s vaType=%s\n",
     211                 vecData.size(), qPrintable(strMIMEType), QVariant::typeToName(vaType)));
    203212
    204213    int rc = VINF_SUCCESS;
    205214
    206     switch (m_vaData.type())
    207     {
    208         case QVariant::String: /* Plain text. */
    209         {
    210             QMimeData::setText(vaData.toString());
    211             break;
    212         }
    213 
    214         case QVariant::ByteArray: /* Raw byte data. */
    215         {
    216             QMimeData::setData(strMIMEType, vaData.toByteArray());
    217             break;
    218         }
    219 
    220         case QVariant::StringList: /* URI. */
    221         {
    222             QList<QVariant> lstData = vaData.toList();
    223             QList<QUrl> lstURL;
    224             for (int i = 0; i < lstData.size(); i++)
     215    switch (vaType)
     216    {
     217        case QVariant::String:
     218        {
     219            vaData = QVariant::fromValue(QString(reinterpret_cast<const char *>(vecData.constData())));
     220            Assert(vaData.type() == QVariant::String);
     221            break;
     222        }
     223
     224        case QVariant::ByteArray:
     225        {
     226            QByteArray ba(reinterpret_cast<const char*>(vecData.constData()), vecData.size());
     227
     228            vaData = QVariant::fromValue(ba);
     229            Assert(vaData.type() == QVariant::ByteArray);
     230            break;
     231        }
     232
     233        /* See: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html */
     234        case QVariant::List: /* Used on OS X for representing URI lists. */
     235        {
     236            QString strData = QString(reinterpret_cast<const char*>(vecData.constData()));
     237            QStringList lstString = strData.split("\r\n", QString::SkipEmptyParts);
     238
     239            QVariantList lstVariant;
     240
     241            Q_FOREACH(const QString& strCur, lstString)
    225242            {
    226                 QFileInfo fileInfo(lstData.at(i).toString());
    227 
    228                 LogFlowFunc(("\tURL: %s (fExists=%RTbool, fIsDir=%RTbool, cb=%RU64)\n",
    229                              fileInfo.absoluteFilePath().constData(), fileInfo.exists(),
    230                              fileInfo.isDir(), fileInfo.size()));
    231 
    232                 lstURL << QUrl::fromLocalFile(fileInfo.absoluteFilePath());
     243                QVariant vaURL = QVariant::fromValue(QUrl(strCur));
     244                Assert(vaURL.type() == QVariant::Url);
     245                lstVariant.append(vaURL);
    233246            }
    234             LogFlowFunc(("Number of URLs: %d\n",  lstURL.size()));
    235 
    236             if (RT_SUCCESS(rc))
    237                 QMimeData::setUrls(lstURL);
     247
     248            vaData = QVariant::fromValue(lstVariant);
     249            Assert(vaData.type() == QVariant::List);
     250            break;
     251        }
     252
     253        case QVariant::StringList:
     254        {
     255            QString strData = QString(reinterpret_cast<const char*>(vecData.constData()));
     256            QStringList lstString = strData.split("\r\n", QString::SkipEmptyParts);
     257
     258            LogFlowFunc(("\tStringList has %d entries\n", lstString.size()));
     259# ifdef DEBUG
     260            Q_FOREACH(const QString& strCur, lstString)
     261                LogFlowFunc(("\t\tString: %s\n", qPrintable(strCur)));
     262# endif
     263            vaData = QVariant::fromValue(lstString);
     264            Assert(vaData.type() == QVariant::StringList);
    238265            break;
    239266        }
    240267
    241268        default:
     269        {
     270            LogRel2(("DnD: Converting data (%d bytes) from guest to variant type '%s' not supported\n",
     271                     vecData.size(), QVariant::typeToName(vaType) ? QVariant::typeToName(vaType) : "<Invalid>"));
     272
    242273            rc = VERR_NOT_SUPPORTED;
    243274            break;
     275        }
    244276    }
    245277
     
    258290    m_curAction = dropAction;
    259291}
     292
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.h

    r56865 r57221  
    6565signals:
    6666
    67      int getData(const QString &strMIMEType, QVariant::Type vaType, QVariant &vaData) const;
     67    /**
     68     * Signal which gets emitted if this object is ready to retrieve data
     69     * in the specified MIME type.
     70     *
     71     * @returns IPRT status code.
     72     * @param strMIMEType               MIME type to retrieve data for.
     73     */
     74    int getData(const QString &strMIMEType) const;
    6875
    6976#ifdef RT_OS_DARWIN
    70      void notifyDropped(void) const;
     77    void notifyDropped(void) const;
    7178#endif
    7279
     
    7481
    7582    /**
    76      * Slot indicating that the current drop target has been changed. 
    77      * @note Does not work on OS X. 
     83     * Slot indicating that the current drop target has been changed.
     84     * @note Does not work on OS X.
    7885     */
    7986    void sltDropActionChanged(Qt::DropAction dropAction);
    80 
    81 #ifdef RT_OS_DARWIN
    82     /**
    83      * Slot indicating that the host wants us to drop the
    84      * data from the guest to the host.
    85      */
    86     void sltDropped(void);
    87 #endif
    8887
    8988protected:
     
    9796    /** @}  */
    9897
    99 protected:
     98public:
    10099
    101100    /** @name Internal helper functions.
     
    103102
    104103    /**
    105      * Sets the object's MIME data according to the given
    106      * MIME type and data.
     104     * Returns the matching variant type of a given MIME type.
     105     *
     106     * @returns Variant type.
     107     * @param strMIMEType               MIME type to retrieve variant type for.
     108     */
     109    static QVariant::Type getVariantType(const QString &strMIMEType);
     110
     111    /**
     112     * Fills a QVariant with data according to the given type and data.
    107113     *
    108114     * @returns IPRT status code.
    109      * @param   strMIMEType             MIME type to set.
    110      * @param   vaData                  Data to set.
    111      * @remark
     115     * @param   vecData                 Bytes data to set.
     116     * @param   strMIMEType             MIME type to handle.
     117     * @param   vaType                  Variant type to set the variant to.
     118     * @param   vaData                  Variant holding the transformed result.
     119     *                                  Note: The variant's type might be different from the input vaType!
    112120     */
    113     int setData(const QString &strMIMEType, const QVariant &vaData);
     121    static int getDataAsVariant(const QVector<uint8_t> &vecData, const QString &strMIMEType, QVariant::Type vaType, QVariant &vaData);
    114122    /** @}  */
    115123
    116124protected:
    117125
     126    /** Pointer to the parent. */
    118127    UIDnDHandler     *m_pDnDHandler;
    119 
     128    /** Available formats. */
    120129    QStringList       m_lstFormats;
    121130    /** Default action on successful drop operation. */
     
    123132    /** Current action, based on QDrag's status. */
    124133    Qt::DropAction    m_curAction;
     134    /** Available actions. */
    125135    Qt::DropActions   m_actions;
    126 
     136    /** The current dragging state. */
    127137    mutable State     m_enmState;
    128     mutable QVariant  m_vaData;
    129 
    130 #ifdef RT_OS_DARWIN
    131     /** Flag indicating whether we can drop data from the
    132      *  guest to the host or not. */
    133     bool              m_fCanDrop;
    134 #endif
    135138};
    136139
Note: See TracChangeset for help on using the changeset viewer.

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