VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp

Last change on this file was 106061, checked in by vboxsync, 3 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 KB
Line 
1/* $Id: UIDnDMIMEData.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIDnDMIMEData class implementation.
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_GUEST_DND
29
30/* Qt includes: */
31#include <QFileInfo>
32#include <QMimeData>
33#include <QStringList>
34#include <QUrl>
35
36/* GUI includes: */
37#include "UIDnDMIMEData.h"
38
39/* Other VBox includes: */
40#include <VBox/log.h>
41#include <iprt/errcore.h>
42
43#include <VBox/GuestHost/DragAndDrop.h>
44
45
46UIDnDMIMEData::UIDnDMIMEData(UIDnDHandler *pDnDHandler,
47 QStringList lstFormats, Qt::DropAction defAction, Qt::DropActions actions)
48 : m_pDnDHandler(pDnDHandler)
49 , m_lstFormats(lstFormats)
50 , m_defAction(defAction)
51 , m_curAction(Qt::IgnoreAction)
52 , m_actions(actions)
53 , m_enmState(Dragging)
54{
55 LogFlowThisFuncEnter();
56#ifdef DEBUG
57 LogFlowFunc(("Number of formats: %d\n", m_lstFormats.size()));
58 for (int i = 0; i < m_lstFormats.size(); i++)
59 LogFlowFunc(("\tFormat %d: %s\n", i, m_lstFormats.at(i).toUtf8().constData()));
60#endif
61}
62
63QStringList UIDnDMIMEData::formats(void) const
64{
65 LogFlowFuncEnter();
66#ifdef DEBUG
67 for (int i = 0; i < m_lstFormats.size(); i++)
68 LogFlowFunc(("\tFormat %d: %s\n", i, m_lstFormats.at(i).toUtf8().constData()));
69#endif
70 return m_lstFormats;
71}
72
73bool UIDnDMIMEData::hasFormat(const QString &strMIMEType) const
74{
75 RT_NOREF(strMIMEType);
76
77 bool fRc;
78#ifdef RT_OS_DARWIN
79 fRc = m_lstFormats.contains(strMIMEType);
80#else
81 fRc = m_curAction != Qt::IgnoreAction;
82#endif
83
84 LogFlowFunc(("%s: %RTbool (QtMimeData: %RTbool, curAction=0x%x)\n",
85 strMIMEType.toUtf8().constData(), fRc, QMimeData::hasFormat(strMIMEType), m_curAction));
86
87 return fRc;
88}
89
90/**
91 * Called by Qt's drag'n drop operation (QDrag) for retrieving the actual drag'n drop
92 * data in case of a successful drag'n drop operation.
93 *
94 * @param strMIMEType MIME type string.
95 * @param vaType Variant containing the actual data based on the MIME type.
96 *
97 * @return QVariant
98 */
99QVariant UIDnDMIMEData::retrieveData(const QString &strMIMEType, QMetaType metaType) const
100{
101 /* Acquire QMetaType::Type: */
102 const QMetaType::Type vaType = (QMetaType::Type)metaType.id();
103
104 LogFlowFunc(("state=%RU32, curAction=0x%x, defAction=0x%x, mimeType=%s, type=%d (%s)\n",
105 m_enmState, m_curAction, m_defAction, strMIMEType.toUtf8().constData(), vaType, metaType.name()));
106
107 int rc = VINF_SUCCESS;
108
109#ifdef RT_OS_WINDOWS
110 /*
111 * On Windows this function will be called several times by Qt's
112 * OLE-specific internals to figure out which data formats we have
113 * to offer. So just assume we can drop data here for a start.
114 */
115#elif defined(RT_OS_DARWIN)
116# ifndef VBOX_WITH_DRAG_AND_DROP_PROMISES
117 /*
118 * Without VBOX_WITH_DRAG_AND_DROP_PROMISES being set in VBox *and* in our (patched) Qt
119 * libraries there's no reliable way to get this working on OS X. So just deny any dropping.
120 */
121 rc = VERR_NOT_IMPLEMENTED;
122
123 /* Let the user know. */
124 LogRel(("DnD: Drag and drop support for OS X is not available in this version\n"));
125# endif /* VBOX_WITH_DRAG_AND_DROP_PROMISES */
126#else /* !RT_OS_DARWIN */
127 /*
128 * On Linux/Solaris our state gets updated if the drop target has been
129 * changed. So query the current status if we're at the moment are able
130 * to drop something on the current target.
131 */
132 if (m_curAction == Qt::IgnoreAction)
133 {
134 LogFlowFunc(("Current drop action is 0x%x, so can't drop yet\n", m_curAction));
135 rc = VERR_NOT_FOUND;
136 }
137#endif
138
139 if (RT_SUCCESS(rc))
140 {
141 /* Silently ignore internal Qt types / converters. */
142 if (!strMIMEType.compare("application/x-qt-mime-type-name", Qt::CaseInsensitive))
143 {
144 rc = VERR_NOT_FOUND;
145 }
146 /* Do we support the requested MIME type? */
147 else if (!m_lstFormats.contains(strMIMEType))
148 {
149 LogRel(("DnD: Unsupported MIME type '%s'\n", strMIMEType.toUtf8().constData()));
150 rc = VERR_NOT_SUPPORTED;
151 }
152#ifndef RT_OS_DARWIN /* On OS X QMetaType::UnknownType can happen for drag and drop "promises" for "lazy requests". */
153 /* Check supported variant types. */
154 else if (!(
155 /* Plain text. */
156 vaType == QMetaType::QString
157 /* Binary data. */
158 || vaType == QMetaType::QByteArray
159 /* URI list. */
160 || vaType == QMetaType::QVariantList
161 || vaType == QMetaType::QStringList))
162 {
163 LogRel(("DnD: Unsupported data type '%s'\n", metaType.name()));
164 rc = VERR_NOT_SUPPORTED;
165 }
166#endif
167 }
168
169 LogRel3(("DnD: Retrieved data state is %ld (action=0x%x), rc=%Rrc\n", m_enmState, m_curAction, rc));
170
171 if (RT_SUCCESS(rc))
172 {
173 QVariant vaData;
174 rc = emit sigGetData(Qt::CopyAction, strMIMEType, vaType, vaData);
175 if (RT_SUCCESS(rc))
176 {
177 LogRel3(("DnD: Returning data for MIME type=%s, variant type=%s, rc=%Rrc\n",
178 strMIMEType.toUtf8().constData(), metaType.name(), rc));
179
180 return vaData;
181 }
182 }
183 else if (rc == VERR_NOT_FOUND) /* Silently skip internal entries. */
184 rc = VINF_SUCCESS;
185
186 if (RT_FAILURE(rc))
187 LogRel2(("DnD: Retrieving data failed with %Rrc\n", rc));
188
189 return QVariant();
190}
191
192/* static */
193QMetaType::Type UIDnDMIMEData::getMetaType(const QString &strMIMEType)
194{
195 QMetaType::Type vaType;
196
197 if ( !strMIMEType.compare("text/html")
198 || !strMIMEType.compare("text/plain;charset=utf-8")
199 || !strMIMEType.compare("text/plain;charset=utf-16")
200 || !strMIMEType.compare("text/plain")
201 || !strMIMEType.compare("text/richtext")
202 || !strMIMEType.compare("UTF8_STRING")
203 || !strMIMEType.compare("TEXT")
204 || !strMIMEType.compare("STRING"))
205 {
206 vaType = QMetaType::QString;
207 }
208 else if (!strMIMEType.compare("text/uri-list", Qt::CaseInsensitive))
209 vaType = QMetaType::QVariantList;
210 else
211 vaType = QMetaType::UnknownType;
212
213 LogFlowFunc(("strMIMEType=%s -> vaType=%s\n", qPrintable(strMIMEType), QMetaType(vaType).name()));
214 return vaType;
215}
216
217/* static */
218int UIDnDMIMEData::getDataAsVariant(const QVector<uint8_t> &vecData,
219 const QString &strMIMEType,
220 QMetaType::Type vaType,
221 QVariant &vaData)
222{
223 RT_NOREF(strMIMEType);
224 LogFlowFunc(("vecDataSize=%d, strMIMEType=%s vaType=%s\n",
225 vecData.size(), qPrintable(strMIMEType), QMetaType(vaType).name()));
226
227 int rc = VINF_SUCCESS;
228
229 switch (vaType)
230 {
231 case QMetaType::QString:
232 {
233 vaData = QVariant::fromValue(QString(reinterpret_cast<const char *>(vecData.constData())));
234 Assert(vaData.typeId() == QMetaType::QString);
235
236 break;
237 }
238
239 case QMetaType::QByteArray:
240 {
241 QByteArray ba(reinterpret_cast<const char*>(vecData.constData()), vecData.size());
242
243 vaData = QVariant::fromValue(ba);
244 Assert(vaData.typeId() == QMetaType::QByteArray);
245 break;
246 }
247
248 /* See: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html */
249 case QMetaType::QVariantList: /* Used on OS X for representing URI lists. */
250 {
251 const QString strData = QString(reinterpret_cast<const char*>(vecData.constData()));
252
253 QVariantList lstVariant;
254
255 Q_FOREACH(const QString& strCur, strData.split(DND_PATH_SEPARATOR_STR, Qt::SkipEmptyParts))
256 {
257 QVariant vaURL = QVariant::fromValue(QUrl(strCur));
258 Assert(vaURL.typeId() == QMetaType::QUrl);
259 lstVariant.append(vaURL);
260 }
261
262 vaData = QVariant::fromValue(lstVariant);
263 Assert(vaData.typeId() == QMetaType::QVariantList);
264 break;
265 }
266
267 case QMetaType::QStringList:
268 {
269 const QString strData = QString(reinterpret_cast<const char*>(vecData.constData()));
270 const QStringList lstString = strData.split(DND_PATH_SEPARATOR_STR, Qt::SkipEmptyParts);
271
272 LogFlowFunc(("\tStringList has %d entries\n", lstString.size()));
273#ifdef DEBUG
274 Q_FOREACH(const QString& strCur, lstString)
275 LogFlowFunc(("\t\tString: %s\n", qPrintable(strCur)));
276#endif
277 vaData = QVariant::fromValue(lstString);
278 Assert(vaData.typeId() == QMetaType::QStringList);
279 break;
280 }
281
282 default:
283 {
284 LogRel2(("DnD: Converting data (%d bytes) from guest to variant type '%s' not supported\n",
285 vecData.size(), QMetaType(vaType).name() ? QMetaType(vaType).name() : "<Invalid>"));
286
287 rc = VERR_NOT_SUPPORTED;
288 break;
289 }
290 }
291
292 LogFlowFuncLeaveRC(rc);
293 return rc;
294}
295
296/**
297 * Issued by the QDrag object as soon as the current drop action has changed.
298 *
299 * @param dropAction New drop action to use.
300 */
301void UIDnDMIMEData::sltDropActionChanged(Qt::DropAction dropAction)
302{
303 LogFlowFunc(("dropAction=0x%x\n", dropAction));
304 m_curAction = dropAction;
305}
306
Note: See TracBrowser for help on using the repository browser.

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