KIO

dropjob.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2014 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "dropjob.h"
9
10#include "job_p.h"
11#include "jobuidelegate.h"
12#include "jobuidelegateextension.h"
13#include "kio_widgets_debug.h"
14#include "pastejob.h"
15#include "pastejob_p.h"
16
17#include <KConfigGroup>
18#include <KCoreDirLister>
19#include <KDesktopFile>
20#include <KFileItem>
21#include <KFileItemListProperties>
22#include <KIO/ApplicationLauncherJob>
23#include <KIO/CopyJob>
24#include <KIO/DndPopupMenuPlugin>
25#include <KIO/FileUndoManager>
26#include <KJobWidgets>
27#include <KLocalizedString>
28#include <KPluginFactory>
29#include <KPluginMetaData>
30#include <KProtocolManager>
31#include <KService>
32#include <KUrlMimeData>
33
34#ifdef WITH_QTDBUS
35#include <QDBusConnection>
36#include <QDBusPendingCall>
37#endif
38
39#include <QDropEvent>
40#include <QFileInfo>
41#include <QMenu>
42#include <QMimeData>
43#include <QProcess>
44#include <QTimer>
45
46using namespace KIO;
47
48Q_DECLARE_METATYPE(Qt::DropAction)
49
50namespace KIO
51{
52class DropMenu;
53}
54
55class KIO::DropMenu : public QMenu
56{
58public:
59 explicit DropMenu(QWidget *parent = nullptr);
60 ~DropMenu() override;
61
62 void addCancelAction();
63 void addExtraActions(const QList<QAction *> &appActions, const QList<QAction *> &pluginActions);
64
65private:
66 QList<QAction *> m_appActions;
67 QList<QAction *> m_pluginActions;
68 QAction *m_lastSeparator;
69 QAction *m_extraActionsSeparator;
70 QAction *m_cancelAction;
71};
72
73static const QString s_applicationSlashXDashKDEDashArkDashDnDExtractDashService = //
74 QStringLiteral("application/x-kde-ark-dndextract-service");
75static const QString s_applicationSlashXDashKDEDashArkDashDnDExtractDashPath = //
76 QStringLiteral("application/x-kde-ark-dndextract-path");
77
78class KIO::DropJobPrivate : public KIO::JobPrivate
79{
80public:
81 DropJobPrivate(const QDropEvent *dropEvent, const QUrl &destUrl, DropJobFlags dropjobFlags, JobFlags flags)
82 : JobPrivate()
83 , m_mimeData(dropEvent->mimeData()) // Extract everything from the dropevent, since it will be deleted before the job starts
84 , m_urls(KUrlMimeData::urlsFromMimeData(m_mimeData, KUrlMimeData::PreferLocalUrls, &m_metaData))
85 , m_dropAction(dropEvent->dropAction())
86 , m_relativePos(dropEvent->position().toPoint())
87 , m_keyboardModifiers(dropEvent->modifiers())
88 , m_hasArkFormat(m_mimeData->hasFormat(s_applicationSlashXDashKDEDashArkDashDnDExtractDashService)
89 && m_mimeData->hasFormat(s_applicationSlashXDashKDEDashArkDashDnDExtractDashPath))
90 , m_destUrl(destUrl)
91 , m_destItem(KCoreDirLister::cachedItemForUrl(destUrl))
92 , m_flags(flags)
93 , m_dropjobFlags(dropjobFlags)
94 , m_triggered(false)
95 {
96 // Check for the drop of a bookmark -> we want a Link action
97 if (m_mimeData->hasFormat(QStringLiteral("application/x-xbel"))) {
99 m_dropAction = Qt::LinkAction;
100 }
101 if (m_destItem.isNull() && m_destUrl.isLocalFile()) {
102 m_destItem = KFileItem(m_destUrl);
103 }
104
105 if (m_hasArkFormat) {
106 m_remoteArkDBusClient = QString::fromUtf8(m_mimeData->data(s_applicationSlashXDashKDEDashArkDashDnDExtractDashService));
107 m_remoteArkDBusPath = QString::fromUtf8(m_mimeData->data(s_applicationSlashXDashKDEDashArkDashDnDExtractDashPath));
108 }
109
110 if (!(m_flags & KIO::NoPrivilegeExecution)) {
111 m_privilegeExecutionEnabled = true;
112 switch (m_dropAction) {
113 case Qt::CopyAction:
114 m_operationType = Copy;
115 break;
116 case Qt::MoveAction:
117 m_operationType = Move;
118 break;
119 case Qt::LinkAction:
120 m_operationType = Symlink;
121 break;
122 default:
123 m_operationType = Other;
124 break;
125 }
126 }
127 }
128
129 bool destIsDirectory() const
130 {
131 if (!m_destItem.isNull()) {
132 return m_destItem.isDir();
133 }
134 // We support local dir, remote dir, local desktop file, local executable.
135 // So for remote URLs, we just assume they point to a directory, the user will get an error from KIO::copy if not.
136 return true;
137 }
138 void handleCopyToDirectory();
139 void slotDropActionDetermined(int error);
140 void handleDropToDesktopFile();
141 void handleDropToExecutable();
142 void fillPopupMenu(KIO::DropMenu *popup);
143 void addPluginActions(KIO::DropMenu *popup, const KFileItemListProperties &itemProps);
144 void doCopyToDirectory();
145
146 QPointer<const QMimeData> m_mimeData;
147 const QList<QUrl> m_urls;
148 QMap<QString, QString> m_metaData;
149 Qt::DropAction m_dropAction;
150 QPoint m_relativePos;
151 Qt::KeyboardModifiers m_keyboardModifiers;
152 bool m_hasArkFormat;
153 QString m_remoteArkDBusClient;
154 QString m_remoteArkDBusPath;
155 QUrl m_destUrl;
156 KFileItem m_destItem; // null for remote URLs not found in the dirlister cache
157 const JobFlags m_flags;
158 const DropJobFlags m_dropjobFlags;
159 QList<QAction *> m_appActions;
160 QList<QAction *> m_pluginActions;
161 bool m_triggered; // Tracks whether an action has been triggered in the popup menu.
162 QSet<KIO::DropMenu *> m_menus;
163
164 Q_DECLARE_PUBLIC(DropJob)
165
166 void slotStart();
167 void slotTriggered(QAction *);
168 void slotAboutToHide();
169
170 static inline DropJob *newJob(const QDropEvent *dropEvent, const QUrl &destUrl, DropJobFlags dropjobFlags, JobFlags flags)
171 {
172 DropJob *job = new DropJob(*new DropJobPrivate(dropEvent, destUrl, dropjobFlags, flags));
174 // Note: never KIO::getJobTracker()->registerJob here.
175 // We don't want a progress dialog during the copy/move/link popup, it would in fact close
176 // the popup
177 return job;
178 }
179};
180
181DropMenu::DropMenu(QWidget *parent)
182 : QMenu(parent)
183 , m_extraActionsSeparator(nullptr)
184{
185 m_cancelAction = new QAction(i18n("C&ancel") + QLatin1Char('\t') + QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText), this);
186 m_cancelAction->setIcon(QIcon::fromTheme(QStringLiteral("process-stop")));
187
188 m_lastSeparator = new QAction(this);
189 m_lastSeparator->setSeparator(true);
190}
191
192DropMenu::~DropMenu()
193{
194}
195
196void DropMenu::addExtraActions(const QList<QAction *> &appActions, const QList<QAction *> &pluginActions)
197{
198 removeAction(m_lastSeparator);
199 removeAction(m_cancelAction);
200
201 removeAction(m_extraActionsSeparator);
202 for (QAction *action : std::as_const(m_appActions)) {
203 removeAction(action);
204 }
205 for (QAction *action : std::as_const(m_pluginActions)) {
206 removeAction(action);
207 }
208
209 m_appActions = appActions;
210 m_pluginActions = pluginActions;
211
212 if (!m_appActions.isEmpty() || !m_pluginActions.isEmpty()) {
213 QAction *firstExtraAction = m_appActions.value(0, m_pluginActions.value(0, nullptr));
214 if (firstExtraAction && !firstExtraAction->isSeparator()) {
215 if (!m_extraActionsSeparator) {
216 m_extraActionsSeparator = new QAction(this);
217 m_extraActionsSeparator->setSeparator(true);
218 }
219 addAction(m_extraActionsSeparator);
220 }
221 addActions(appActions);
222 addActions(pluginActions);
223 }
224
225 addAction(m_lastSeparator);
226 addAction(m_cancelAction);
227}
228
229DropJob::DropJob(DropJobPrivate &dd)
230 : Job(dd)
231{
232 Q_D(DropJob);
233
234 QTimer::singleShot(0, this, [d]() {
235 d->slotStart();
236 });
237}
238
239DropJob::~DropJob()
240{
241}
242
243void DropJobPrivate::slotStart()
244{
245 Q_Q(DropJob);
246
247#ifdef WITH_QTDBUS
248 if (m_hasArkFormat) {
249 QDBusMessage message = QDBusMessage::createMethodCall(m_remoteArkDBusClient,
250 m_remoteArkDBusPath,
251 QStringLiteral("org.kde.ark.DndExtract"),
252 QStringLiteral("extractSelectedFilesTo"));
254 const auto pending = QDBusConnection::sessionBus().asyncCall(message);
255 auto watcher = std::make_shared<QDBusPendingCallWatcher>(pending);
256 QObject::connect(watcher.get(), &QDBusPendingCallWatcher::finished, q, [this, watcher] {
257 Q_Q(DropJob);
258
259 if (watcher->isError()) {
260 q->setError(KIO::ERR_UNKNOWN);
261 }
262 q->emitResult();
263 });
264
265 return;
266 }
267#endif
268
269 if (!m_urls.isEmpty()) {
270 if (destIsDirectory()) {
271 handleCopyToDirectory();
272 } else { // local file
273 const QString destFile = m_destUrl.toLocalFile();
274 if (KDesktopFile::isDesktopFile(destFile)) {
275 handleDropToDesktopFile();
276 } else if (QFileInfo(destFile).isExecutable()) {
277 handleDropToExecutable();
278 } else {
279 // should not happen, if KDirModel::flags is correct
280 q->setError(KIO::ERR_ACCESS_DENIED);
281 q->emitResult();
282 }
283 }
284 } else if (m_mimeData) {
285 // Dropping raw data
286 KIO::PasteJob *job = KIO::PasteJobPrivate::newJob(m_mimeData, m_destUrl, KIO::HideProgressInfo, false /*not clipboard*/);
288 q->addSubjob(job);
289 }
290}
291
292void DropJobPrivate::fillPopupMenu(KIO::DropMenu *popup)
293{
294 Q_Q(DropJob);
295
296 // Check what the source can do
297 // TODO: Determining the MIME type of the source URLs is difficult for remote URLs,
298 // we would need to KIO::stat each URL in turn, asynchronously....
299 KFileItemList fileItems;
300 fileItems.reserve(m_urls.size());
301 for (const QUrl &url : m_urls) {
302 fileItems.append(KFileItem(url));
303 }
304 const KFileItemListProperties itemProps(fileItems);
305
306 Q_EMIT q->popupMenuAboutToShow(itemProps);
307
308 const bool sReading = itemProps.supportsReading();
309 const bool sDeleting = itemProps.supportsDeleting();
310 const bool sMoving = itemProps.supportsMoving();
311
312 const int separatorLength = QCoreApplication::translate("QShortcut", "+").size();
314 seq.chop(separatorLength); // chop superfluous '+'
315 QAction *popupMoveAction = new QAction(i18n("&Move Here") + QLatin1Char('\t') + seq, popup);
316 popupMoveAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))));
317 popupMoveAction->setData(QVariant::fromValue(Qt::MoveAction));
319 seq.chop(separatorLength);
320 QAction *popupCopyAction = new QAction(i18n("&Copy Here") + QLatin1Char('\t') + seq, popup);
321 popupCopyAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
322 popupCopyAction->setData(QVariant::fromValue(Qt::CopyAction));
324 seq.chop(separatorLength);
325 QAction *popupLinkAction = new QAction(i18n("&Link Here") + QLatin1Char('\t') + seq, popup);
326 popupLinkAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-link")));
327 popupLinkAction->setData(QVariant::fromValue(Qt::LinkAction));
328
329 if (sMoving || (sReading && sDeleting)) {
330 const bool equalDestination = std::all_of(m_urls.cbegin(), m_urls.cend(), [this](const QUrl &src) {
331 return m_destUrl.matches(src.adjusted(QUrl::RemoveFilename), QUrl::StripTrailingSlash);
332 });
333
334 if (!equalDestination) {
335 popup->addAction(popupMoveAction);
336 }
337 }
338
339 if (sReading) {
340 popup->addAction(popupCopyAction);
341 }
342
343 popup->addAction(popupLinkAction);
344
345 addPluginActions(popup, itemProps);
346}
347
348void DropJobPrivate::addPluginActions(KIO::DropMenu *popup, const KFileItemListProperties &itemProps)
349{
350 const QList<KPluginMetaData> plugin_offers = KPluginMetaData::findPlugins(QStringLiteral("kf6/kio_dnd"));
351 for (const KPluginMetaData &data : plugin_offers) {
352 if (auto plugin = KPluginFactory::instantiatePlugin<KIO::DndPopupMenuPlugin>(data).plugin) {
353 const auto actions = plugin->setup(itemProps, m_destUrl);
354 for (auto action : actions) {
355 action->setParent(popup);
356 }
357 m_pluginActions += actions;
358 }
359 }
360
361 popup->addExtraActions(m_appActions, m_pluginActions);
362}
363
365{
366 Q_D(DropJob);
367
368 d->m_appActions = actions;
369
370 for (KIO::DropMenu *menu : std::as_const(d->m_menus)) {
371 menu->addExtraActions(d->m_appActions, d->m_pluginActions);
372 }
373}
374
375void DropJob::showMenu(const QPoint &p, QAction *atAction)
376{
377 Q_D(DropJob);
378
379 if (!(d->m_dropjobFlags & KIO::ShowMenuManually)) {
380 return;
381 }
382
383 for (KIO::DropMenu *menu : std::as_const(d->m_menus)) {
384 menu->popup(p, atAction);
385 }
386}
387
388void DropJobPrivate::slotTriggered(QAction *action)
389{
390 Q_Q(DropJob);
391 if (m_appActions.contains(action) || m_pluginActions.contains(action)) {
392 q->emitResult();
393 return;
394 }
395 const QVariant data = action->data();
396 if (!data.canConvert<Qt::DropAction>()) {
397 q->setError(KIO::ERR_USER_CANCELED);
398 q->emitResult();
399 return;
400 }
401 m_dropAction = data.value<Qt::DropAction>();
402 doCopyToDirectory();
403}
404
405void DropJobPrivate::slotAboutToHide()
406{
407 Q_Q(DropJob);
408 // QMenu emits aboutToHide before triggered.
409 // So we need to give the menu time in case it needs to emit triggered.
410 // If it does, the cleanup will be done by slotTriggered.
411 QTimer::singleShot(0, q, [=, this]() {
412 if (!m_triggered) {
413 q->setError(KIO::ERR_USER_CANCELED);
414 q->emitResult();
415 }
416 });
417}
418
419void DropJobPrivate::handleCopyToDirectory()
420{
421 Q_Q(DropJob);
422
423 // Process m_dropAction as set by Qt at the time of the drop event
424 if (!KProtocolManager::supportsWriting(m_destUrl)) {
425 slotDropActionDetermined(KIO::ERR_CANNOT_WRITE);
426 return;
427 }
428
429 if (!m_destItem.isNull() && !m_destItem.isWritable() && (m_flags & KIO::NoPrivilegeExecution)) {
430 slotDropActionDetermined(KIO::ERR_WRITE_ACCESS_DENIED);
431 return;
432 }
433
434 bool allItemsAreFromTrash = true;
435 bool containsTrashRoot = false;
436 for (const QUrl &url : m_urls) {
437 const bool local = url.isLocalFile();
438 if (!local /*optimization*/ && url.scheme() == QLatin1String("trash")) {
439 if (url.path().isEmpty() || url.path() == QLatin1String("/")) {
440 containsTrashRoot = true;
441 }
442 } else {
443 allItemsAreFromTrash = false;
444 }
445 if (url.matches(m_destUrl, QUrl::StripTrailingSlash)) {
446 slotDropActionDetermined(KIO::ERR_DROP_ON_ITSELF);
447 return;
448 }
449 }
450
451 const bool trashing = m_destUrl.scheme() == QLatin1String("trash");
452 if (trashing) {
453 if (allItemsAreFromTrash) {
454 qCDebug(KIO_WIDGETS) << "Dropping items from trash to trash";
455 slotDropActionDetermined(KIO::ERR_DROP_ON_ITSELF);
456 return;
457 }
458 m_dropAction = Qt::MoveAction;
459
460 auto *askUserInterface = KIO::delegateExtension<AskUserActionInterface *>(q);
461
462 // No UI Delegate set for this job, or a delegate that doesn't implement
463 // AskUserActionInterface, then just proceed with the job without asking.
464 // This is useful for non-interactive usage, (which doesn't actually apply
465 // here as a DropJob is always interactive), but this is useful for unittests,
466 // which are typically non-interactive.
467 if (!askUserInterface) {
468 slotDropActionDetermined(KJob::NoError);
469 return;
470 }
471
472 QObject::connect(askUserInterface, &KIO::AskUserActionInterface::askUserDeleteResult, q, [this](bool allowDelete) {
473 if (allowDelete) {
474 slotDropActionDetermined(KJob::NoError);
475 } else {
476 slotDropActionDetermined(KIO::ERR_USER_CANCELED);
477 }
478 });
479
481 return;
482 }
483
484 // If we can't determine the action below, we use ERR::UNKNOWN as we need to ask
485 // the user via a popup menu.
486 int err = KIO::ERR_UNKNOWN;
487 const bool implicitCopy = m_destUrl.scheme() == QLatin1String("stash");
488 if (implicitCopy) {
489 m_dropAction = Qt::CopyAction;
490 err = KJob::NoError; // Ok
491 } else if (containsTrashRoot) {
492 // Dropping a link to the trash: don't move the full contents, just make a link (#319660)
493 m_dropAction = Qt::LinkAction;
494 err = KJob::NoError; // Ok
495 } else if (allItemsAreFromTrash) {
496 // No point in asking copy/move/link when using dragging from the trash, just move the file out.
497 m_dropAction = Qt::MoveAction;
498 err = KJob::NoError; // Ok
499 } else if (m_keyboardModifiers & (Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier)) {
500 // Qt determined m_dropAction from the modifiers already
501 err = KJob::NoError; // Ok
502 }
503 slotDropActionDetermined(err);
504}
505
506void DropJobPrivate::slotDropActionDetermined(int error)
507{
508 Q_Q(DropJob);
509
510 if (error == KJob::NoError) {
511 doCopyToDirectory();
512 return;
513 }
514
515 // There was an error, handle it
516 if (error == KIO::ERR_UNKNOWN) {
517 auto *window = KJobWidgets::window(q);
518 KIO::DropMenu *menu = new KIO::DropMenu(window);
520
521 // If the user clicks outside the menu, it will be destroyed without emitting the triggered signal.
522 QObject::connect(menu, &QMenu::aboutToHide, q, [this]() {
523 slotAboutToHide();
524 });
525
526 fillPopupMenu(menu);
527 QObject::connect(menu, &QMenu::triggered, q, [this](QAction *action) {
528 m_triggered = true;
529 slotTriggered(action);
530 });
531
532 if (!(m_dropjobFlags & KIO::ShowMenuManually)) {
533 menu->popup(window ? window->mapToGlobal(m_relativePos) : QCursor::pos());
534 }
535 m_menus.insert(menu);
536 QObject::connect(menu, &QObject::destroyed, q, [this, menu]() {
537 m_menus.remove(menu);
538 });
539 } else {
540 q->setError(error);
541 q->emitResult();
542 }
543}
544
545void DropJobPrivate::doCopyToDirectory()
546{
547 Q_Q(DropJob);
548 KIO::CopyJob *job = nullptr;
549 switch (m_dropAction) {
550 case Qt::MoveAction:
551 job = KIO::move(m_urls, m_destUrl, m_flags);
552 KIO::FileUndoManager::self()->recordJob(m_destUrl.scheme() == QLatin1String("trash") ? KIO::FileUndoManager::Trash : KIO::FileUndoManager::Move,
553 m_urls,
554 m_destUrl,
555 job);
556 break;
557 case Qt::CopyAction:
558 job = KIO::copy(m_urls, m_destUrl, m_flags);
560 break;
561 case Qt::LinkAction:
562 job = KIO::link(m_urls, m_destUrl, m_flags);
564 break;
565 default:
566 qCWarning(KIO_WIDGETS) << "Unknown drop action" << int(m_dropAction);
567 q->setError(KIO::ERR_UNSUPPORTED_ACTION);
568 q->emitResult();
569 return;
570 }
571 Q_ASSERT(job);
572 job->setParentJob(q);
573 job->setMetaData(m_metaData);
574 QObject::connect(job, &KIO::CopyJob::copyingDone, q, [q](KIO::Job *, const QUrl &, const QUrl &to) {
575 Q_EMIT q->itemCreated(to);
576 });
577 QObject::connect(job, &KIO::CopyJob::copyingLinkDone, q, [q](KIO::Job *, const QUrl &, const QString &, const QUrl &to) {
578 Q_EMIT q->itemCreated(to);
579 });
580 q->addSubjob(job);
581
582 Q_EMIT q->copyJobStarted(job);
583}
584
585void DropJobPrivate::handleDropToDesktopFile()
586{
587 Q_Q(DropJob);
588 const QString urlKey = QStringLiteral("URL");
589 const QString destFile = m_destUrl.toLocalFile();
590 const KDesktopFile desktopFile(destFile);
591 const KConfigGroup desktopGroup = desktopFile.desktopGroup();
592 if (desktopFile.hasApplicationType()) {
593 // Drop to application -> start app with urls as argument
594 KService::Ptr service(new KService(destFile));
595 // Can't use setParentJob() because ApplicationLauncherJob isn't a KIO::Job,
596 // instead pass q as parent so that KIO::delegateExtension() can find a delegate
598 job->setUrls(m_urls);
599 QObject::connect(job, &KJob::result, q, [=]() {
600 if (job->error()) {
601 q->setError(KIO::ERR_CANNOT_LAUNCH_PROCESS);
602 q->setErrorText(destFile);
603 }
604 q->emitResult();
605 });
606 job->start();
607 } else if (desktopFile.hasLinkType() && desktopGroup.hasKey(urlKey)) {
608 // Drop to link -> adjust destination directory
609 m_destUrl = QUrl::fromUserInput(desktopGroup.readPathEntry(urlKey, QString()));
610 handleCopyToDirectory();
611 } else {
612 if (desktopFile.hasDeviceType()) {
613 qCWarning(KIO_WIDGETS) << "Not re-implemented; please email kde-frameworks-devel@kde.org if you need this.";
614 // take code from libkonq's old konq_operations.cpp
615 // for now, fallback
616 }
617 // Some other kind of .desktop file (service, servicetype...)
618 q->setError(KIO::ERR_UNSUPPORTED_ACTION);
619 q->emitResult();
620 }
621}
622
623void DropJobPrivate::handleDropToExecutable()
624{
625 Q_Q(DropJob);
626 // Launch executable for each of the files
627 QStringList args;
628 args.reserve(m_urls.size());
629 for (const QUrl &url : std::as_const(m_urls)) {
630 args << url.toLocalFile(); // assume local files
631 }
632 QProcess::startDetached(m_destUrl.toLocalFile(), args);
633 q->emitResult();
634}
635
636void DropJob::slotResult(KJob *job)
637{
638 if (job->error()) {
639 KIO::Job::slotResult(job); // will set the error and emit result(this)
640 return;
641 }
642 removeSubjob(job);
643 emitResult();
644}
645
646DropJob *KIO::drop(const QDropEvent *dropEvent, const QUrl &destUrl, JobFlags flags)
647{
648 return DropJobPrivate::newJob(dropEvent, destUrl, KIO::DropJobDefaultFlags, flags);
649}
650
651DropJob *KIO::drop(const QDropEvent *dropEvent, const QUrl &destUrl, DropJobFlags dropjobFlags, JobFlags flags)
652{
653 return DropJobPrivate::newJob(dropEvent, destUrl, dropjobFlags, flags);
654}
655
656#include "dropjob.moc"
657#include "moc_dropjob.cpp"
virtual void slotResult(KJob *job)
bool hasKey(const char *key) const
QString readPathEntry(const char *key, const QString &aDefault) const
Helper class for the kiojob used to list and update a directory.
static bool isDesktopFile(const QString &path)
Provides information about the common properties of a group of KFileItem objects.
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
Definition kfileitem.h:630
A KFileItem is a generic class to handle a file, local or remote.
Definition kfileitem.h:36
bool isNull() const
Return true if default-constructed.
ApplicationLauncherJob runs an application and watches it while running.
void start() override
Starts the job.
void setUrls(const QList< QUrl > &urls)
Specifies the URLs to be passed to the application.
void askUserDeleteResult(bool allowDelete, const QList< QUrl > &urls, KIO::AskUserActionInterface::DeletionType deletionType, QWidget *parent)
Implementations of this interface must emit this signal when the dialog invoked by askUserDelete() fi...
@ Trash
Delete the files/directories directly, i.e. without moving them to Trash.
@ DefaultConfirmation
Do not ask if the user has previously set the "Do not ask again" checkbox (which is is shown in the m...
CopyJob is used to move, copy or symlink files and directories.
Definition copyjob.h:41
void copyingLinkDone(KIO::Job *job, const QUrl &from, const QString &target, const QUrl &to)
The job is copying or moving a symbolic link, that points to target.
void copyingDone(KIO::Job *job, const QUrl &from, const QUrl &to, const QDateTime &mtime, bool directory, bool renamed)
The job emits this signal when copying or moving a file or directory successfully finished.
A KIO job that handles dropping into a file-manager-like view.
Definition dropjob.h:53
void setApplicationActions(const QList< QAction * > &actions)
Allows the application to set additional actions in the drop popup menu.
Definition dropjob.cpp:364
void itemCreated(const QUrl &url)
Signals that a file or directory was created.
void showMenu(const QPoint &p, QAction *atAction=nullptr)
Allows the application to show the menu manually.
Definition dropjob.cpp:375
FileUndoManager: makes it possible to undo kio jobs.
void recordCopyJob(KIO::CopyJob *copyJob)
Record this CopyJob while it's happening and add a command for it so that the user can undo it.
static FileUndoManager * self()
void recordJob(CommandType op, const QList< QUrl > &src, const QUrl &dst, KIO::Job *job)
Record this job while it's happening and add a command for it so that the user can undo it.
The base class for all jobs.
Definition job_base.h:45
void setMetaData(const KIO::MetaData &metaData)
Set meta data to be sent to the worker, replacing existing meta data.
Definition job.cpp:215
void setParentJob(Job *parentJob)
Set the parent Job.
Definition job.cpp:192
bool removeSubjob(KJob *job) override
Mark a sub job as being done.
Definition job.cpp:80
A KIO job that handles pasting the clipboard contents.
Definition pastejob.h:35
void itemCreated(const QUrl &url)
Signals that a file or directory was created.
void emitResult()
int error() const
void result(KJob *job)
void setUiDelegate(KJobUiDelegate *delegate)
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
static bool supportsWriting(const QUrl &url)
Returns whether the protocol can store data to URLs.
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
A namespace for KIO globals.
KIOCORE_EXPORT CopyJob * move(const QUrl &src, const QUrl &dest, JobFlags flags=DefaultFlags)
Moves a file or directory src to the given destination dest.
Definition copyjob.cpp:2626
KIOCORE_EXPORT CopyJob * link(const QUrl &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
Create a link.
Definition copyjob.cpp:2660
@ ShowMenuManually
show the menu manually with DropJob::showMenu
Definition dropjob.h:30
KIOCORE_EXPORT CopyJob * copy(const QUrl &src, const QUrl &dest, JobFlags flags=DefaultFlags)
Copy a file or directory src into the destination dest, which can be a file (including the final file...
Definition copyjob.cpp:2604
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
Convenience method: use default factory, if there's one, to create a delegate and return it.
KIOWIDGETS_EXPORT DropJob * drop(const QDropEvent *dropEvent, const QUrl &destUrl, JobFlags flags=DefaultFlags)
Drops the clipboard contents.
Definition dropjob.cpp:646
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition job_base.h:251
@ NoPrivilegeExecution
When set, notifies the worker that application/job does not want privilege execution.
Definition job_base.h:276
@ ERR_DROP_ON_ITSELF
from KIO::DropJob,
Definition global.h:194
QWidget * window(QObject *job)
KCOREADDONS_EXPORT QList< QUrl > urlsFromMimeData(const QMimeData *mimeData, DecodeOptions decodeOptions=PreferKdeUrls, MetaDataMap *metaData=nullptr)
QVariant data() const const
void setIcon(const QIcon &icon)
bool isSeparator() const const
void setData(const QVariant &data)
void setSeparator(bool b)
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
QPoint pos()
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout) const const
QDBusConnection sessionBus()
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
void setArguments(const QList< QVariant > &arguments)
void finished(QDBusPendingCallWatcher *self)
QIcon fromTheme(const QString &name)
QString toString(SequenceFormat format) const const
void append(QList< T > &&value)
const_iterator cbegin() const const
const_iterator cend() const const
bool contains(const AT &value) const const
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
T value(qsizetype i) const const
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
void aboutToHide()
void popup(const QPoint &p, QAction *atAction)
void triggered(QAction *action)
Q_OBJECTQ_OBJECT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
void destroyed(QObject *obj)
QObject * parent() const const
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
iterator insert(const T &value)
bool remove(const T &value)
void chop(qsizetype n)
QString fromUtf8(QByteArrayView str)
qsizetype size() const const
DropAction
Key_Escape
typedef KeyboardModifiers
PreferLocalFile
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
bool isLocalFile() const const
QString scheme() const const
QString toDisplayString(FormattingOptions options) const const
QString toLocalFile() const const
bool canConvert() const const
QVariant fromValue(T &&value)
T value() const const
void addActions(const QList< QAction * > &actions)
QPoint mapToGlobal(const QPoint &pos) const const
void removeAction(QAction *action)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 7 2024 11:58:22 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.