]> cloud.milkyroute.net Git - dolphin.git/blob - src/global.cpp
Improve copying and moving items between panels
[dolphin.git] / src / global.cpp
1 /*
2 * SPDX-FileCopyrightText: 2015 Ashish Bansal <bansal.ashish096@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "global.h"
8
9 #include "dolphin_generalsettings.h"
10 #include "dolphindebug.h"
11 #include "dolphinmainwindowinterface.h"
12 #include "views/viewproperties.h"
13
14 #include <KConfigWatcher>
15 #include <KDialogJobUiDelegate>
16 #include <KIO/ApplicationLauncherJob>
17 #include <KService>
18 #include <KWindowSystem>
19 #ifdef HAVE_KACTIVITIES
20 #include <KActivities/Consumer>
21 #endif
22
23 #include <QApplication>
24
25 QList<QUrl> Dolphin::validateUris(const QStringList &uriList)
26 {
27 const QString currentDir = QDir::currentPath();
28 QList<QUrl> urls;
29 for (const QString &str : uriList) {
30 const QUrl url = QUrl::fromUserInput(str, currentDir, QUrl::AssumeLocalFile);
31 if (url.isValid()) {
32 urls.append(url);
33 } else {
34 qCWarning(DolphinDebug) << "Invalid URL: " << str;
35 }
36 }
37 return urls;
38 }
39
40 QUrl Dolphin::homeUrl()
41 {
42 return QUrl::fromUserInput(GeneralSettings::homeUrl(), QString(), QUrl::AssumeLocalFile);
43 }
44
45 void Dolphin::openNewWindow(const QList<QUrl> &urls, QWidget *window, const OpenNewWindowFlags &flags)
46 {
47 QString command = QStringLiteral("dolphin --new-window");
48
49 if (flags.testFlag(OpenNewWindowFlag::Select)) {
50 command.append(QLatin1String(" --select"));
51 }
52
53 if (!urls.isEmpty()) {
54 command.append(QLatin1String(" %U"));
55 }
56 KService::Ptr service(new KService(QApplication::applicationDisplayName(), command, QApplication::windowIcon().name()));
57 auto *job = new KIO::ApplicationLauncherJob(service, window);
58 job->setUrls(urls);
59 job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, window));
60 job->start();
61 }
62
63 bool Dolphin::attachToExistingInstance(const QList<QUrl> &inputUrls,
64 bool openFiles,
65 bool splitView,
66 const QString &preferredService,
67 const QString &activationToken)
68 {
69 bool attached = false;
70
71 if (inputUrls.isEmpty()) {
72 return false;
73 }
74
75 auto dolphinInterfaces = dolphinGuiInstances(preferredService);
76 if (dolphinInterfaces.isEmpty()) {
77 return false;
78 }
79
80 int activeWindowIndex = -1;
81 for (const auto &interface : qAsConst(dolphinInterfaces)) {
82 ++activeWindowIndex;
83
84 auto isActiveWindowReply = interface.first->isActiveWindow();
85 isActiveWindowReply.waitForFinished();
86 if (!isActiveWindowReply.isError() && isActiveWindowReply.value()) {
87 break;
88 }
89 }
90
91 // check to see if any instances already have any of the given URLs or their parents open
92 QList<QUrl> newWindowURLs;
93 for (const QUrl &url : inputUrls) {
94 bool urlFound = false;
95 const QString urlString = url.toString();
96
97 // looping through the windows starting from the active one
98 int i = activeWindowIndex;
99 do {
100 auto &interface = dolphinInterfaces[i];
101
102 auto isUrlOpenReply = openFiles ? interface.first->isItemVisibleInAnyView(urlString) : interface.first->isUrlOpen(urlString);
103 isUrlOpenReply.waitForFinished();
104 if (!isUrlOpenReply.isError() && isUrlOpenReply.value()) {
105 interface.second.append(urlString);
106 urlFound = true;
107 break;
108 }
109
110 i = (i + 1) % dolphinInterfaces.size();
111 } while (i != activeWindowIndex);
112
113 if (!urlFound) {
114 if (GeneralSettings::openExternallyCalledFolderInNewTab()) {
115 dolphinInterfaces[activeWindowIndex].second.append(urlString);
116 } else {
117 newWindowURLs.append(url);
118 }
119 }
120 }
121
122 for (const auto &interface : qAsConst(dolphinInterfaces)) {
123 if (interface.second.isEmpty()) {
124 continue;
125 }
126 auto reply = openFiles ? interface.first->openFiles(interface.second, splitView) : interface.first->openDirectories(interface.second, splitView);
127 reply.waitForFinished();
128 if (!reply.isError()) {
129 interface.first->activateWindow(activationToken);
130 attached = true;
131 }
132 }
133 if (attached && !newWindowURLs.isEmpty()) {
134 if (openFiles) {
135 openNewWindow(newWindowURLs, nullptr, Dolphin::OpenNewWindowFlag::Select);
136 } else {
137 openNewWindow(newWindowURLs);
138 }
139 }
140
141 return attached;
142 }
143
144 QVector<QPair<QSharedPointer<OrgKdeDolphinMainWindowInterface>, QStringList>> Dolphin::dolphinGuiInstances(const QString &preferredService)
145 {
146 #ifdef HAVE_KACTIVITIES
147 static std::once_flag one_consumer;
148 static KActivities::Consumer *consumer;
149 std::call_once(one_consumer, []() {
150 consumer = new KActivities::Consumer();
151 // ensures the consumer is ready for query
152 QEventLoop loop;
153 QObject::connect(consumer, &KActivities::Consumer::serviceStatusChanged, &loop, &QEventLoop::quit);
154 loop.exec();
155 });
156 #endif
157
158 QVector<QPair<QSharedPointer<OrgKdeDolphinMainWindowInterface>, QStringList>> dolphinInterfaces;
159 const auto tryAppendInterface = [&dolphinInterfaces](const QString &service) {
160 // Check if instance can handle our URLs
161 QSharedPointer<OrgKdeDolphinMainWindowInterface> interface(
162 new OrgKdeDolphinMainWindowInterface(service, QStringLiteral("/dolphin/Dolphin_1"), QDBusConnection::sessionBus()));
163 if (interface->isValid() && !interface->lastError().isValid()) {
164 #ifdef HAVE_KACTIVITIES
165 const auto currentActivity = consumer->currentActivity();
166 if (currentActivity.isEmpty() || currentActivity == QStringLiteral("00000000-0000-0000-0000-000000000000")
167 || interface->isOnActivity(consumer->currentActivity()))
168 #endif
169 if (interface->isOnCurrentDesktop()) {
170 dolphinInterfaces.append(qMakePair(interface, QStringList()));
171 }
172 }
173 };
174
175 if (!preferredService.isEmpty()) {
176 tryAppendInterface(preferredService);
177 }
178
179 // Look for dolphin instances among all available dbus services.
180 QDBusConnectionInterface *sessionInterface = QDBusConnection::sessionBus().interface();
181 const QStringList dbusServices = sessionInterface ? sessionInterface->registeredServiceNames().value() : QStringList();
182 // Don't match the service without trailing "-" (unique instance)
183 const QString pattern = QStringLiteral("org.kde.dolphin-");
184 // Don't match the pid without leading "-"
185 const QString myPid = QLatin1Char('-') + QString::number(QCoreApplication::applicationPid());
186 for (const QString &service : dbusServices) {
187 if (service.startsWith(pattern) && !service.endsWith(myPid)) {
188 tryAppendInterface(service);
189 }
190 }
191
192 return dolphinInterfaces;
193 }
194
195 QPair<QString, Qt::SortOrder> Dolphin::sortOrderForUrl(QUrl &url)
196 {
197 ViewProperties globalProps(url);
198 return QPair<QString, Qt::SortOrder>(globalProps.sortRole(), globalProps.sortOrder());
199 }
200
201 double GlobalConfig::animationDurationFactor()
202 {
203 if (s_animationDurationFactor >= 0.0) {
204 return s_animationDurationFactor;
205 }
206 // This is the first time this method is called.
207 auto kdeGlobalsConfig = KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("KDE"));
208 updateAnimationDurationFactor(kdeGlobalsConfig, {"AnimationDurationFactor"});
209
210 KConfigWatcher::Ptr configWatcher = KConfigWatcher::create(KSharedConfig::openConfig());
211 connect(configWatcher.data(), &KConfigWatcher::configChanged, &GlobalConfig::updateAnimationDurationFactor);
212 return s_animationDurationFactor;
213 }
214
215 void GlobalConfig::updateAnimationDurationFactor(const KConfigGroup &group, const QByteArrayList &names)
216 {
217 if (group.name() == QLatin1String("KDE") && names.contains(QByteArrayLiteral("AnimationDurationFactor"))) {
218 s_animationDurationFactor = std::max(0.0, group.readEntry("AnimationDurationFactor", 1.0));
219 }
220 }
221
222 double GlobalConfig::s_animationDurationFactor = -1.0;