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#include <QDBusConnection>
35#include <QDBusPendingCall>
36#include <QDropEvent>
37#include <QFileInfo>
38#include <QMenu>
39#include <QMimeData>
40#include <QProcess>
41#include <QTimer>
42
43using namespace KIO;
44
45Q_DECLARE_METATYPE(Qt::DropAction)
46
47namespace KIO
48{
49class DropMenu;
50}
51
52class KIO::DropMenu : public QMenu
53{
55public:
56 explicit DropMenu(QWidget *parent = nullptr);
57 ~DropMenu() override;
58
59 void addCancelAction();
60 void addExtraActions(const QList<QAction *> &appActions, const QList<QAction *> &pluginActions);
61
62private:
63 QList<QAction *> m_appActions;
64 QList<QAction *> m_pluginActions;
65 QAction *m_lastSeparator;
66 QAction *m_extraActionsSeparator;
67 QAction *m_cancelAction;
68};
69
70static const QString s_applicationSlashXDashKDEDashArkDashDnDExtractDashService = //
71 QStringLiteral("application/x-kde-ark-dndextract-service");
72static const QString s_applicationSlashXDashKDEDashArkDashDnDExtractDashPath = //
73 QStringLiteral("application/x-kde-ark-dndextract-path");
74
75class KIO::DropJobPrivate : public KIO::JobPrivate
76{
77public:
78 DropJobPrivate(const QDropEvent *dropEvent, const QUrl &destUrl, DropJobFlags dropjobFlags, JobFlags flags)
79 : JobPrivate()
80 , m_mimeData(dropEvent->mimeData()) // Extract everything from the dropevent, since it will be deleted before the job starts
81 , m_urls(KUrlMimeData::urlsFromMimeData(m_mimeData, KUrlMimeData::PreferLocalUrls, &m_metaData))
82 , m_dropAction(dropEvent->dropAction())
83 , m_relativePos(dropEvent->position().toPoint())
84 , m_keyboardModifiers(dropEvent->modifiers())
85 , m_hasArkFormat(m_mimeData->hasFormat(s_applicationSlashXDashKDEDashArkDashDnDExtractDashService)
86 && m_mimeData->hasFormat(s_applicationSlashXDashKDEDashArkDashDnDExtractDashPath))
87 , m_destUrl(destUrl)
88 , m_destItem(KCoreDirLister::cachedItemForUrl(destUrl))
89 , m_flags(flags)
90 , m_dropjobFlags(dropjobFlags)
91 , m_triggered(false)
92 {
93 // Check for the drop of a bookmark -> we want a Link action
94 if (m_mimeData->hasFormat(QStringLiteral("application/x-xbel"))) {
96 m_dropAction = Qt::LinkAction;
97 }
98 if (m_destItem.isNull() && m_destUrl.isLocalFile()) {
99 m_destItem = KFileItem(m_destUrl);
100 }
101
102 if (m_hasArkFormat) {
103 m_remoteArkDBusClient = QString::fromUtf8(m_mimeData->data(s_applicationSlashXDashKDEDashArkDashDnDExtractDashService));
104 m_remoteArkDBusPath = QString::fromUtf8(m_mimeData->data(s_applicationSlashXDashKDEDashArkDashDnDExtractDashPath));
105 }
106
107 if (!(m_flags & KIO::NoPrivilegeExecution)) {
108 m_privilegeExecutionEnabled = true;
109 switch (m_dropAction) {
110 case Qt::CopyAction:
111 m_operationType = Copy;
112 break;
113 case Qt::MoveAction:
114 m_operationType = Move;
115 break;
116 case Qt::LinkAction:
117 m_operationType = Symlink;
118 break;
119 default:
120 m_operationType = Other;
121 break;
122 }
123 }
124 }
125
126 bool destIsDirectory() const
127 {
128 if (!m_destItem.isNull()) {
129 return m_destItem.isDir();
130 }
131 // We support local dir, remote dir, local desktop file, local executable.
132 // So for remote URLs, we just assume they point to a directory, the user will get an error from KIO::copy if not.
133 return true;
134 }
135 void handleCopyToDirectory();
136 void slotDropActionDetermined(int error);
137 void handleDropToDesktopFile();
138 void handleDropToExecutable();
139 void fillPopupMenu(KIO::DropMenu *popup);
140 void addPluginActions(KIO::DropMenu *popup, const KFileItemListProperties &itemProps);
141 void doCopyToDirectory();
142
143 QPointer<const QMimeData> m_mimeData;
144 const QList<QUrl> m_urls;
145 QMap<QString, QString> m_metaData;
146 Qt::DropAction m_dropAction;
147 QPoint m_relativePos;
148 Qt::KeyboardModifiers m_keyboardModifiers;
149 bool m_hasArkFormat;
150 QString m_remoteArkDBusClient;
151 QString m_remoteArkDBusPath;
152 QUrl m_destUrl;
153 KFileItem m_destItem; // null for remote URLs not found in the dirlister cache
154 const JobFlags m_flags;
155 const DropJobFlags m_dropjobFlags;
156 QList<QAction *> m_appActions;
157 QList<QAction *> m_pluginActions;
158 bool m_triggered; // Tracks whether an action has been triggered in the popup menu.
159 QSet<KIO::DropMenu *> m_menus;
160
161 Q_DECLARE_PUBLIC(DropJob)
162
163 void slotStart();
164 void slotTriggered(QAction *);
165 void slotAboutToHide();
166
167 static inline DropJob *newJob(const QDropEvent *dropEvent, const QUrl &destUrl, DropJobFlags dropjobFlags, JobFlags flags)
168 {
169 DropJob *job = new DropJob(*new DropJobPrivate(dropEvent, destUrl, dropjobFlags, flags));
171 // Note: never KIO::getJobTracker()->registerJob here.
172 // We don't want a progress dialog during the copy/move/link popup, it would in fact close
173 // the popup
174 return job;
175 }
176};
177
178DropMenu::DropMenu(QWidget *parent)
179 : QMenu(parent)
180 , m_extraActionsSeparator(nullptr)
181{
182 m_cancelAction = new QAction(i18n("C&ancel") + QLatin1Char('\t') + QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText), this);
183 m_cancelAction->setIcon(QIcon::fromTheme(QStringLiteral("process-stop")));
184
185 m_lastSeparator = new QAction(this);
186 m_lastSeparator->setSeparator(true);
187}
188
189DropMenu::~DropMenu()
190{
191}
192
193void DropMenu::addExtraActions(const QList<QAction *> &appActions, const QList<QAction *> &pluginActions)
194{
195 removeAction(m_lastSeparator);
196 removeAction(m_cancelAction);
197
198 removeAction(m_extraActionsSeparator);
199 for (QAction *action : std::as_const(m_appActions)) {
200 removeAction(action);
201 }
202 for (QAction *action : std::as_const(m_pluginActions)) {
203 removeAction(action);
204 }
205
206 m_appActions = appActions;
207 m_pluginActions = pluginActions;
208
209 if (!m_appActions.isEmpty() || !m_pluginActions.isEmpty()) {
210 QAction *firstExtraAction = m_appActions.value(0, m_pluginActions.value(0, nullptr));
211 if (firstExtraAction && !firstExtraAction->isSeparator()) {
212 if (!m_extraActionsSeparator) {
213 m_extraActionsSeparator = new QAction(this);
214 m_extraActionsSeparator->setSeparator(true);
215 }
216 addAction(m_extraActionsSeparator);
217 }
218 addActions(appActions);
219 addActions(pluginActions);
220 }
221
222 addAction(m_lastSeparator);
223 addAction(m_cancelAction);
224}
225
226DropJob::DropJob(DropJobPrivate &dd)
227 : Job(dd)
228{
229 Q_D(DropJob);
230
231 QTimer::singleShot(0, this, [d]() {
232 d->slotStart();
233 });
234}
235
236DropJob::~DropJob()
237{
238}
239
240void DropJobPrivate::slotStart()
241{
242 Q_Q(DropJob);
243
244 if (m_hasArkFormat) {
245 QDBusMessage message = QDBusMessage::createMethodCall(m_remoteArkDBusClient,
246 m_remoteArkDBusPath,
247 QStringLiteral("org.kde.ark.DndExtract"),
248 QStringLiteral("extractSelectedFilesTo"));
250 const auto pending = QDBusConnection::sessionBus().asyncCall(message);
251 auto watcher = std::make_shared<QDBusPendingCallWatcher>(pending);
252 QObject::connect(watcher.get(), &QDBusPendingCallWatcher::finished, q, [this, watcher] {
253 Q_Q(DropJob);
254
255 if (watcher->isError()) {
256 q->setError(KIO::ERR_UNKNOWN);
257 }
258 q->emitResult();
259 });
260
261 return;
262 }
263
264 if (!m_urls.isEmpty()) {
265 if (destIsDirectory()) {
266 handleCopyToDirectory();
267 } else { // local file
268 const QString destFile = m_destUrl.toLocalFile();
269 if (KDesktopFile::isDesktopFile(destFile)) {
270 handleDropToDesktopFile();
271 } else if (QFileInfo(destFile).isExecutable()) {
272 handleDropToExecutable();
273 } else {
274 // should not happen, if KDirModel::flags is correct
275 q->setError(KIO::ERR_ACCESS_DENIED);
276 q->emitResult();
277 }
278 }
279 } else if (m_mimeData) {
280 // Dropping raw data
281 KIO::PasteJob *job = KIO::PasteJobPrivate::newJob(m_mimeData, m_destUrl, KIO::HideProgressInfo, false /*not clipboard*/);
283 q->addSubjob(job);
284 }
285}
286
287void DropJobPrivate::fillPopupMenu(KIO::DropMenu *popup)
288{
289 Q_Q(DropJob);
290
291 // Check what the source can do
292 // TODO: Determining the MIME type of the source URLs is difficult for remote URLs,
293 // we would need to KIO::stat each URL in turn, asynchronously....
294 KFileItemList fileItems;
295 fileItems.reserve(m_urls.size());
296 for (const QUrl &url : m_urls) {
297 fileItems.append(KFileItem(url));
298 }
299 const KFileItemListProperties itemProps(fileItems);
300
301 Q_EMIT q->popupMenuAboutToShow(itemProps);
302
303 const bool sReading = itemProps.supportsReading();
304 const bool sDeleting = itemProps.supportsDeleting();
305 const bool sMoving = itemProps.supportsMoving();
306
307 const int separatorLength = QCoreApplication::translate("QShortcut", "+").size();
309 seq.chop(separatorLength); // chop superfluous '+'
310 QAction *popupMoveAction = new QAction(i18n("&Move Here") + QLatin1Char('\t') + seq, popup);
311 popupMoveAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))));
312 popupMoveAction->setData(QVariant::fromValue(Qt::MoveAction));
314 seq.chop(separatorLength);
315 QAction *popupCopyAction = new QAction(i18n("&Copy Here") + QLatin1Char('\t') + seq, popup);
316 popupCopyAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
317 popupCopyAction->setData(QVariant::fromValue(Qt::CopyAction));
319 seq.chop(separatorLength);
320 QAction *popupLinkAction = new QAction(i18n("&Link Here") + QLatin1Char('\t') + seq, popup);
321 popupLinkAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-link")));
322 popupLinkAction->setData(QVariant::fromValue(Qt::LinkAction));
323
324 if (sMoving || (sReading && sDeleting)) {
325 const bool equalDestination = std::all_of(m_urls.cbegin(), m_urls.cend(), [this](const QUrl &src) {
326 return m_destUrl.matches(src.adjusted(QUrl::RemoveFilename), QUrl::StripTrailingSlash);
327 });
328
329 if (!equalDestination) {
330 popup->addAction(popupMoveAction);
331 }
332 }
333
334 if (sReading) {
335 popup->addAction(popupCopyAction);
336 }
337
338 popup->addAction(popupLinkAction);
339
340 addPluginActions(popup, itemProps);
341}
342
343void DropJobPrivate::addPluginActions(KIO::DropMenu *popup, const KFileItemListProperties &itemProps)
344{
345 const QList<KPluginMetaData> plugin_offers = KPluginMetaData::findPlugins(QStringLiteral("kf6/kio_dnd"));
346 for (const KPluginMetaData &data : plugin_offers) {
347 if (auto plugin = KPluginFactory::instantiatePlugin<KIO::DndPopupMenuPlugin>(data).plugin) {
348 const auto actions = plugin->setup(itemProps, m_destUrl);
349 for (auto action : actions) {
350 action->setParent(popup);
351 }
352 m_pluginActions += actions;
353 }
354 }
355
356 popup->addExtraActions(m_appActions, m_pluginActions);
357}
358
360{
361 Q_D(DropJob);
362
363 d->m_appActions = actions;
364
365 for (KIO::DropMenu *menu : std::as_const(d->m_menus)) {
366 menu->addExtraActions(d->m_appActions, d->m_pluginActions);
367 }
368}
369
370void DropJob::showMenu(const QPoint &p, QAction *atAction)
371{
372 Q_D(DropJob);
373
374 if (!(d->m_dropjobFlags & KIO::ShowMenuManually)) {
375 return;
376 }
377
378 for (KIO::DropMenu *menu : std::as_const(d->m_menus)) {
379 menu->popup(p, atAction);
380 }
381}
382
383void DropJobPrivate::slotTriggered(QAction *action)
384{
385 Q_Q(DropJob);
386 if (m_appActions.contains(action) || m_pluginActions.contains(action)) {
387 q->emitResult();
388 return;
389 }
390 const QVariant data = action->data();
391 if (!data.canConvert<Qt::DropAction>()) {
392 q->setError(KIO::ERR_USER_CANCELED);
393 q->emitResult();
394 return;
395 }
396 m_dropAction = data.value<Qt::DropAction>();
397 doCopyToDirectory();
398}
399
400void DropJobPrivate::slotAboutToHide()
401{
402 Q_Q(DropJob);
403 // QMenu emits aboutToHide before triggered.
404 // So we need to give the menu time in case it needs to emit triggered.
405 // If it does, the cleanup will be done by slotTriggered.
406 QTimer::singleShot(0, q, [=, this]() {
407 if (!m_triggered) {
408 q->setError(KIO::ERR_USER_CANCELED);
409 q->emitResult();
410 }
411 });
412}
413
414void DropJobPrivate::handleCopyToDirectory()
415{
416 Q_Q(DropJob);
417
418 // Process m_dropAction as set by Qt at the time of the drop event
419 if (!KProtocolManager::supportsWriting(m_destUrl)) {
420 slotDropActionDetermined(KIO::ERR_CANNOT_WRITE);
421 return;
422 }
423
424 if (!m_destItem.isNull() && !m_destItem.isWritable() && (m_flags & KIO::NoPrivilegeExecution)) {
425 slotDropActionDetermined(KIO::ERR_WRITE_ACCESS_DENIED);
426 return;
427 }
428
429 bool allItemsAreFromTrash = true;
430 bool containsTrashRoot = false;
431 for (const QUrl &url : m_urls) {
432 const bool local = url.isLocalFile();
433 if (!local /*optimization*/ && url.scheme() == QLatin1String("trash")) {
434 if (url.path().isEmpty() || url.path() == QLatin1String("/")) {
435 containsTrashRoot = true;
436 }
437 } else {
438 allItemsAreFromTrash = false;
439 }
440 if (url.matches(m_destUrl, QUrl::StripTrailingSlash)) {
441 slotDropActionDetermined(KIO::ERR_DROP_ON_ITSELF);
442 return;
443 }
444 }
445
446 const bool trashing = m_destUrl.scheme() == QLatin1String("trash");
447 if (trashing) {
448 if (allItemsAreFromTrash) {
449 qCDebug(KIO_WIDGETS) << "Dropping items from trash to trash";
450 slotDropActionDetermined(KIO::ERR_DROP_ON_ITSELF);
451 return;
452 }
453 m_dropAction = Qt::MoveAction;
454
455 auto *askUserInterface = KIO::delegateExtension<AskUserActionInterface *>(q);
456
457 // No UI Delegate set for this job, or a delegate that doesn't implement
458 // AskUserActionInterface, then just proceed with the job without asking.
459 // This is useful for non-interactive usage, (which doesn't actually apply
460 // here as a DropJob is always interactive), but this is useful for unittests,
461 // which are typically non-interactive.
462 if (!askUserInterface) {
463 slotDropActionDetermined(KJob::NoError);
464 return;
465 }
466
467 QObject::connect(askUserInterface, &KIO::AskUserActionInterface::askUserDeleteResult, q, [this](bool allowDelete) {
468 if (allowDelete) {
469 slotDropActionDetermined(KJob::NoError);
470 } else {
471 slotDropActionDetermined(KIO::ERR_USER_CANCELED);
472 }
473 });
474
476 return;
477 }
478
479 // If we can't determine the action below, we use ERR::UNKNOWN as we need to ask
480 // the user via a popup menu.
481 int err = KIO::ERR_UNKNOWN;
482 const bool implicitCopy = m_destUrl.scheme() == QLatin1String("stash");
483 if (implicitCopy) {
484 m_dropAction = Qt::CopyAction;
485 err = KJob::NoError; // Ok
486 } else if (containsTrashRoot) {
487 // Dropping a link to the trash: don't move the full contents, just make a link (#319660)
488 m_dropAction = Qt::LinkAction;
489 err = KJob::NoError; // Ok
490 } else if (allItemsAreFromTrash) {
491 // No point in asking copy/move/link when using dragging from the trash, just move the file out.
492 m_dropAction = Qt::MoveAction;
493 err = KJob::NoError; // Ok
494 } else if (m_keyboardModifiers & (Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier)) {
495 // Qt determined m_dropAction from the modifiers already
496 err = KJob::NoError; // Ok
497 }
498 slotDropActionDetermined(err);
499}
500
501void DropJobPrivate::slotDropActionDetermined(int error)
502{
503 Q_Q(DropJob);
504
505 if (error == KJob::NoError) {
506 doCopyToDirectory();
507 return;
508 }
509
510 // There was an error, handle it
511 if (error == KIO::ERR_UNKNOWN) {
512 auto *window = KJobWidgets::window(q);
513 KIO::DropMenu *menu = new KIO::DropMenu(window);
515
516 // If the user clicks outside the menu, it will be destroyed without emitting the triggered signal.
517 QObject::connect(menu, &QMenu::aboutToHide, q, [this]() {
518 slotAboutToHide();
519 });
520
521 fillPopupMenu(menu);
522 QObject::connect(menu, &QMenu::triggered, q, [this](QAction *action) {
523 m_triggered = true;
524 slotTriggered(action);
525 });
526
527 if (!(m_dropjobFlags & KIO::ShowMenuManually)) {
528 menu->popup(window ? window->mapToGlobal(m_relativePos) : QCursor::pos());
529 }
530 m_menus.insert(menu);
531 QObject::connect(menu, &QObject::destroyed, q, [this, menu]() {
532 m_menus.remove(menu);
533 });
534 } else {
535 q->setError(error);
536 q->emitResult();
537 }
538}
539
540void DropJobPrivate::doCopyToDirectory()
541{
542 Q_Q(DropJob);
543 KIO::CopyJob *job = nullptr;
544 switch (m_dropAction) {
545 case Qt::MoveAction:
546 job = KIO::move(m_urls, m_destUrl, m_flags);
547 KIO::FileUndoManager::self()->recordJob(m_destUrl.scheme() == QLatin1String("trash") ? KIO::FileUndoManager::Trash : KIO::FileUndoManager::Move,
548 m_urls,
549 m_destUrl,
550 job);
551 break;
552 case Qt::CopyAction:
553 job = KIO::copy(m_urls, m_destUrl, m_flags);
555 break;
556 case Qt::LinkAction:
557 job = KIO::link(m_urls, m_destUrl, m_flags);
559 break;
560 default:
561 qCWarning(KIO_WIDGETS) << "Unknown drop action" << int(m_dropAction);
562 q->setError(KIO::ERR_UNSUPPORTED_ACTION);
563 q->emitResult();
564 return;
565 }
566 Q_ASSERT(job);
567 job->setParentJob(q);
568 job->setMetaData(m_metaData);
569 QObject::connect(job, &KIO::CopyJob::copyingDone, q, [q](KIO::Job *, const QUrl &, const QUrl &to) {
570 Q_EMIT q->itemCreated(to);
571 });
572 QObject::connect(job, &KIO::CopyJob::copyingLinkDone, q, [q](KIO::Job *, const QUrl &, const QString &, const QUrl &to) {
573 Q_EMIT q->itemCreated(to);
574 });
575 q->addSubjob(job);
576
577 Q_EMIT q->copyJobStarted(job);
578}
579
580void DropJobPrivate::handleDropToDesktopFile()
581{
582 Q_Q(DropJob);
583 const QString urlKey = QStringLiteral("URL");
584 const QString destFile = m_destUrl.toLocalFile();
585 const KDesktopFile desktopFile(destFile);
586 const KConfigGroup desktopGroup = desktopFile.desktopGroup();
587 if (desktopFile.hasApplicationType()) {
588 // Drop to application -> start app with urls as argument
589 KService::Ptr service(new KService(destFile));
590 // Can't use setParentJob() because ApplicationLauncherJob isn't a KIO::Job,
591 // instead pass q as parent so that KIO::delegateExtension() can find a delegate
593 job->setUrls(m_urls);
594 QObject::connect(job, &KJob::result, q, [=]() {
595 if (job->error()) {
596 q->setError(KIO::ERR_CANNOT_LAUNCH_PROCESS);
597 q->setErrorText(destFile);
598 }
599 q->emitResult();
600 });
601 job->start();
602 } else if (desktopFile.hasLinkType() && desktopGroup.hasKey(urlKey)) {
603 // Drop to link -> adjust destination directory
604 m_destUrl = QUrl::fromUserInput(desktopGroup.readPathEntry(urlKey, QString()));
605 handleCopyToDirectory();
606 } else {
607 if (desktopFile.hasDeviceType()) {
608 qCWarning(KIO_WIDGETS) << "Not re-implemented; please email kde-frameworks-devel@kde.org if you need this.";
609 // take code from libkonq's old konq_operations.cpp
610 // for now, fallback
611 }
612 // Some other kind of .desktop file (service, servicetype...)
613 q->setError(KIO::ERR_UNSUPPORTED_ACTION);
614 q->emitResult();
615 }
616}
617
618void DropJobPrivate::handleDropToExecutable()
619{
620 Q_Q(DropJob);
621 // Launch executable for each of the files
622 QStringList args;
623 args.reserve(m_urls.size());
624 for (const QUrl &url : std::as_const(m_urls)) {
625 args << url.toLocalFile(); // assume local files
626 }
627 QProcess::startDetached(m_destUrl.toLocalFile(), args);
628 q->emitResult();
629}
630
631void DropJob::slotResult(KJob *job)
632{
633 if (job->error()) {
634 KIO::Job::slotResult(job); // will set the error and emit result(this)
635 return;
636 }
637 removeSubjob(job);
638 emitResult();
639}
640
641DropJob *KIO::drop(const QDropEvent *dropEvent, const QUrl &destUrl, JobFlags flags)
642{
643 return DropJobPrivate::newJob(dropEvent, destUrl, KIO::DropJobDefaultFlags, flags);
644}
645
646DropJob *KIO::drop(const QDropEvent *dropEvent, const QUrl &destUrl, DropJobFlags dropjobFlags, JobFlags flags)
647{
648 return DropJobPrivate::newJob(dropEvent, destUrl, dropjobFlags, flags);
649}
650
651#include "dropjob.moc"
652#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:359
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:370
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:641
@ 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 Tue Mar 26 2024 11:18:52 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.