1 /*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2013 Dawit Alemayehu <adawit@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8 #include "../pathhelpers_p.h"
9 #include "clipboardupdater_p.h"
10 #include "copyjob.h"
11 #include "deletejob.h"
12 #include "jobclasses.h"
13 #include <KUrlMimeData>
14
15 #include <QClipboard>
16 #include <QGuiApplication>
17 #include <QMimeData>
18
19 using namespace KIO;
20
overwriteUrlsInClipboard(KJob * job)21 static void overwriteUrlsInClipboard(KJob *job)
22 {
23 CopyJob *copyJob = qobject_cast<CopyJob *>(job);
24 FileCopyJob *fileCopyJob = qobject_cast<FileCopyJob *>(job);
25
26 if (!copyJob && !fileCopyJob) {
27 return;
28 }
29
30 QList<QUrl> newUrls;
31
32 if (copyJob) {
33 const auto srcUrls = copyJob->srcUrls();
34 newUrls.reserve(srcUrls.size());
35 for (const QUrl &url : srcUrls) {
36 QUrl dUrl = copyJob->destUrl().adjusted(QUrl::StripTrailingSlash);
37 dUrl.setPath(concatPaths(dUrl.path(), url.fileName()));
38 newUrls.append(dUrl);
39 }
40 } else if (fileCopyJob) {
41 newUrls << fileCopyJob->destUrl();
42 }
43
44 QMimeData *mime = new QMimeData();
45 mime->setUrls(newUrls);
46 QGuiApplication::clipboard()->setMimeData(mime);
47 }
48
updateUrlsInClipboard(KJob * job)49 static void updateUrlsInClipboard(KJob *job)
50 {
51 CopyJob *copyJob = qobject_cast<CopyJob *>(job);
52 FileCopyJob *fileCopyJob = qobject_cast<FileCopyJob *>(job);
53
54 if (!copyJob && !fileCopyJob) {
55 return;
56 }
57
58 QClipboard *clipboard = QGuiApplication::clipboard();
59 auto mimeData = clipboard->mimeData();
60 if (!mimeData) {
61 return;
62 }
63
64 QList<QUrl> clipboardUrls = KUrlMimeData::urlsFromMimeData(mimeData);
65 bool update = false;
66
67 if (copyJob) {
68 const QList<QUrl> urls = copyJob->srcUrls();
69 for (const QUrl &url : urls) {
70 const int index = clipboardUrls.indexOf(url);
71 if (index > -1) {
72 QUrl dUrl = copyJob->destUrl().adjusted(QUrl::StripTrailingSlash);
73 dUrl.setPath(concatPaths(dUrl.path(), url.fileName()));
74 clipboardUrls.replace(index, dUrl);
75 update = true;
76 }
77 }
78 } else if (fileCopyJob) {
79 const int index = clipboardUrls.indexOf(fileCopyJob->srcUrl());
80 if (index > -1) {
81 clipboardUrls.replace(index, fileCopyJob->destUrl());
82 update = true;
83 }
84 }
85
86 if (update) {
87 QMimeData *mime = new QMimeData();
88 mime->setUrls(clipboardUrls);
89 clipboard->setMimeData(mime);
90 }
91 }
92
removeUrlsFromClipboard(KJob * job)93 static void removeUrlsFromClipboard(KJob *job)
94 {
95 SimpleJob *simpleJob = qobject_cast<SimpleJob *>(job);
96 DeleteJob *deleteJob = qobject_cast<DeleteJob *>(job);
97
98 if (!simpleJob && !deleteJob) {
99 return;
100 }
101
102 QList<QUrl> deletedUrls;
103 if (simpleJob) {
104 deletedUrls << simpleJob->url();
105 } else if (deleteJob) {
106 deletedUrls << deleteJob->urls();
107 }
108
109 if (deletedUrls.isEmpty()) {
110 return;
111 }
112
113 QClipboard *clipboard = QGuiApplication::clipboard();
114 auto mimeData = clipboard->mimeData();
115 if (!mimeData) {
116 return;
117 }
118
119 QList<QUrl> clipboardUrls = KUrlMimeData::urlsFromMimeData(mimeData);
120 quint32 removedCount = 0;
121
122 for (const QUrl &url : std::as_const(deletedUrls)) {
123 removedCount += clipboardUrls.removeAll(url);
124 }
125
126 if (removedCount > 0) {
127 QMimeData *mime = new QMimeData();
128 if (!clipboardUrls.isEmpty()) {
129 mime->setUrls(clipboardUrls);
130 }
131 clipboard->setMimeData(mime);
132 }
133 }
134
slotResult(KJob * job)135 void ClipboardUpdater::slotResult(KJob *job)
136 {
137 if (job->error()) {
138 return;
139 }
140
141 switch (m_mode) {
142 case JobUiDelegateExtension::UpdateContent:
143 updateUrlsInClipboard(job);
144 break;
145 case JobUiDelegateExtension::OverwriteContent:
146 overwriteUrlsInClipboard(job);
147 break;
148 case JobUiDelegateExtension::RemoveContent:
149 removeUrlsFromClipboard(job);
150 break;
151 }
152 }
153
setMode(JobUiDelegateExtension::ClipboardUpdaterMode mode)154 void ClipboardUpdater::setMode(JobUiDelegateExtension::ClipboardUpdaterMode mode)
155 {
156 m_mode = mode;
157 }
158
update(const QUrl & srcUrl,const QUrl & destUrl)159 void ClipboardUpdater::update(const QUrl &srcUrl, const QUrl &destUrl)
160 {
161 QClipboard *clipboard = QGuiApplication::clipboard();
162 auto mimeData = clipboard->mimeData();
163 if (mimeData && mimeData->hasUrls()) {
164 QList<QUrl> clipboardUrls = KUrlMimeData::urlsFromMimeData(clipboard->mimeData());
165 const int index = clipboardUrls.indexOf(srcUrl);
166 if (index > -1) {
167 clipboardUrls.replace(index, destUrl);
168 QMimeData *mime = new QMimeData();
169 mime->setUrls(clipboardUrls);
170 clipboard->setMimeData(mime);
171 }
172 }
173 }
174
ClipboardUpdater(Job * job,JobUiDelegateExtension::ClipboardUpdaterMode mode)175 ClipboardUpdater::ClipboardUpdater(Job *job, JobUiDelegateExtension::ClipboardUpdaterMode mode)
176 : QObject(job)
177 , m_mode(mode)
178 {
179 Q_ASSERT(job);
180 connect(job, &KJob::result, this, &ClipboardUpdater::slotResult);
181 }
182