File indexing completed on 2024-04-28 04:44:39
0001 // Copyright 2018-2020 Camilo Higuita <milo.h@aol.com> 0002 // Copyright 2018-2020 Nitrux Latinoamericana S.C. 0003 // 0004 // SPDX-License-Identifier: GPL-3.0-or-later 0005 0006 #include "index.h" 0007 0008 #if (defined Q_OS_LINUX || defined Q_OS_FREEBSD) && !defined Q_OS_ANDROID 0009 #include <KTerminalLauncherJob> 0010 #include <KWindowConfig> 0011 #endif 0012 0013 #include <QGuiApplication> 0014 #include <QQuickWindow> 0015 #include <QQmlApplicationEngine> 0016 0017 #include <QDebug> 0018 #include <QFileInfo> 0019 0020 #include <QProcess> 0021 0022 #include <MauiKit3/Core/fmh.h> 0023 #include <MauiKit3/FileBrowsing/fmstatic.h> 0024 0025 #if (defined Q_OS_LINUX || defined Q_OS_FREEBSD) && !defined Q_OS_ANDROID 0026 #include "indexinterface.h" 0027 #include "indexadaptor.h" 0028 0029 QVector<QPair<QSharedPointer<OrgKdeIndexActionsInterface>, QStringList>> IndexInstance::appInstances(const QString& preferredService) 0030 { 0031 QVector<QPair<QSharedPointer<OrgKdeIndexActionsInterface>, QStringList>> dolphinInterfaces; 0032 0033 if (!preferredService.isEmpty()) 0034 { 0035 QSharedPointer<OrgKdeIndexActionsInterface> preferredInterface( 0036 new OrgKdeIndexActionsInterface(preferredService, 0037 QStringLiteral("/Actions"), 0038 QDBusConnection::sessionBus())); 0039 0040 qDebug() << "IS PREFRFRED INTERFACE VALID?" << preferredInterface->isValid() << preferredInterface->lastError().message(); 0041 if (preferredInterface->isValid() && !preferredInterface->lastError().isValid()) { 0042 dolphinInterfaces.append(qMakePair(preferredInterface, QStringList())); 0043 } 0044 } 0045 0046 // Look for dolphin instances among all available dbus services. 0047 QDBusConnectionInterface *sessionInterface = QDBusConnection::sessionBus().interface(); 0048 const QStringList dbusServices = sessionInterface ? sessionInterface->registeredServiceNames().value() : QStringList(); 0049 // Don't match the service without trailing "-" (unique instance) 0050 const QString pattern = QStringLiteral("org.kde.index-"); 0051 0052 // Don't match the pid without leading "-" 0053 const QString myPid = QLatin1Char('-') + QString::number(QCoreApplication::applicationPid()); 0054 0055 for (const QString& service : dbusServices) 0056 { 0057 if (service.startsWith(pattern) && !service.endsWith(myPid)) 0058 { 0059 qDebug() << "EXISTING INTANCES" << service; 0060 0061 // Check if instance can handle our URLs 0062 QSharedPointer<OrgKdeIndexActionsInterface> interface( 0063 new OrgKdeIndexActionsInterface(service, 0064 QStringLiteral("/Actions"), 0065 QDBusConnection::sessionBus())); 0066 if (interface->isValid() && !interface->lastError().isValid()) 0067 { 0068 dolphinInterfaces.append(qMakePair(interface, QStringList())); 0069 } 0070 } 0071 } 0072 0073 return dolphinInterfaces; 0074 } 0075 0076 bool IndexInstance::attachToExistingInstance(const QList<QUrl>& inputUrls, bool openFiles, bool splitView, const QString& preferredService) 0077 { 0078 bool attached = false; 0079 0080 if (inputUrls.isEmpty()) 0081 { 0082 return false; 0083 } 0084 0085 auto dolphinInterfaces = appInstances(preferredService); 0086 if (dolphinInterfaces.isEmpty()) 0087 { 0088 return false; 0089 } 0090 0091 QStringList newUrls; 0092 0093 // check to see if any instances already have any of the given URLs open 0094 const auto urls = QUrl::toStringList(inputUrls); 0095 for (const QString& url : urls) 0096 { 0097 bool urlFound = false; 0098 0099 for (auto& interface: dolphinInterfaces) 0100 { 0101 auto isUrlOpenReply = interface.first->isUrlOpen(url); 0102 isUrlOpenReply.waitForFinished(); 0103 0104 if (!isUrlOpenReply.isError() && isUrlOpenReply.value()) 0105 { 0106 interface.second.append(url); 0107 urlFound = true; 0108 break; 0109 } 0110 } 0111 0112 if (!urlFound) 0113 { 0114 newUrls.append(url); 0115 } 0116 } 0117 0118 for (const auto& interface: qAsConst(dolphinInterfaces)) 0119 { 0120 auto reply = openFiles ? interface.first->openFiles(newUrls, splitView) : interface.first->openDirectories(newUrls, splitView); 0121 reply.waitForFinished(); 0122 0123 if (!reply.isError()) 0124 { 0125 interface.first->activateWindow(); 0126 attached = true; 0127 break; 0128 } 0129 } 0130 0131 return attached; 0132 } 0133 0134 0135 bool IndexInstance::registerService() 0136 { 0137 QDBusConnectionInterface *iface = QDBusConnection::sessionBus().interface(); 0138 0139 auto registration = iface->registerService(QStringLiteral("org.kde.index-%1").arg(QCoreApplication::applicationPid()), 0140 QDBusConnectionInterface::ReplaceExistingService, 0141 QDBusConnectionInterface::DontAllowReplacement); 0142 0143 if (!registration.isValid()) 0144 { 0145 qWarning("2 Failed to register D-Bus service \"%s\" on session bus: \"%s\"", 0146 qPrintable("org.kde.index"), 0147 qPrintable(registration.error().message())); 0148 return false; 0149 } 0150 0151 return true; 0152 } 0153 0154 #endif 0155 0156 Index::Index(QObject *parent) 0157 : QObject(parent) 0158 { 0159 #if (defined Q_OS_LINUX || defined Q_OS_FREEBSD) && !defined Q_OS_ANDROID 0160 new ActionsAdaptor(this); 0161 if(!QDBusConnection::sessionBus().registerObject(QStringLiteral("/Actions"), this)) 0162 { 0163 qDebug() << "FAILED TO REGISTER BACKGROUND DBUS OBJECT"; 0164 return; 0165 } 0166 #endif 0167 } 0168 0169 void Index::openDirectories(const QStringList &dirs, bool splitView) 0170 { 0171 openPaths(dirs); 0172 } 0173 0174 void Index::openFiles(const QStringList &files, bool splitView) 0175 { 0176 openPaths(files); 0177 } 0178 0179 void Index::activateWindow() 0180 { 0181 if(m_qmlObject) 0182 { 0183 auto window = qobject_cast<QQuickWindow *>(m_qmlObject); 0184 if (window) 0185 { 0186 qDebug() << "Trying to raise wndow"; 0187 window->raise(); 0188 window->requestActivate(); 0189 } 0190 } 0191 } 0192 0193 bool Index::isUrlOpen(const QString &url) 0194 { 0195 bool value = false; 0196 0197 QMetaObject::invokeMethod(m_qmlObject, "isUrlOpen", 0198 Q_RETURN_ARG(bool, value), 0199 Q_ARG(QString, url)); 0200 0201 return value; 0202 } 0203 0204 void Index::pasteIntoFolder() 0205 { 0206 0207 } 0208 0209 void Index::changeUrl(const QUrl &url) 0210 { 0211 0212 } 0213 0214 void Index::slotTerminalDirectoryChanged(const QUrl &url) 0215 { 0216 0217 } 0218 0219 void Index::quit() 0220 { 0221 QCoreApplication::quit(); 0222 } 0223 0224 void Index::openNewTab(const QUrl &url) 0225 { 0226 0227 } 0228 0229 void Index::openNewTabAndActivate(const QUrl &url) 0230 { 0231 0232 } 0233 0234 void Index::openNewWindow(const QUrl &url) 0235 { 0236 QProcess process; 0237 process.setProgram("index"); 0238 process.setArguments({"-n", url.toString()}); 0239 process.startDetached(); 0240 } 0241 0242 /* to be called to launch index with opening different paths */ 0243 void Index::openPaths(const QStringList &paths) 0244 { 0245 QStringList urls = std::accumulate(paths.constBegin(), paths.constEnd(), QStringList(), [](QStringList &list, const QString &path) -> QStringList { 0246 const auto url = QUrl::fromUserInput(path); 0247 if (url.isLocalFile()) 0248 { 0249 if (FMStatic::isDir(url)) 0250 { 0251 list << url.toString(); 0252 } 0253 else 0254 { 0255 list << FMStatic::fileDir(url).toString(); 0256 } 0257 } 0258 0259 return list; 0260 }); 0261 0262 if(m_qmlObject) 0263 QMetaObject::invokeMethod(m_qmlObject, "openDirs", 0264 Q_ARG(QVariant, urls)); 0265 } 0266 0267 void Index::setQmlObject(QObject *object) 0268 { 0269 m_qmlObject = object; 0270 } 0271 0272 void Index::openTerminal(const QUrl &url) 0273 { 0274 #if (defined Q_OS_LINUX || defined Q_OS_FREEBSD) && !defined Q_OS_ANDROID 0275 0276 auto job = new KTerminalLauncherJob(QString()); 0277 job->setWorkingDirectory(url.toLocalFile()); 0278 job->start(); 0279 0280 #else 0281 Q_UNUSED(url) 0282 #endif 0283 } 0284 0285 QVariantList Index::quickPaths() 0286 { 0287 FMH::MODEL_LIST paths; 0288 0289 paths << FMH::MODEL {{FMH::MODEL_KEY::PATH, "overview:///"}, {FMH::MODEL_KEY::ICON, "folder-recent"}, {FMH::MODEL_KEY::LABEL, "Overview"}, {FMH::MODEL_KEY::TYPE, "Quick"}}; 0290 0291 paths << FMH::MODEL {{FMH::MODEL_KEY::PATH, FMStatic::PATHTYPE_URI[FMStatic::PATHTYPE_KEY::TAGS_PATH] + "fav"}, {FMH::MODEL_KEY::ICON, "love"}, {FMH::MODEL_KEY::LABEL, "Favorite"}, {FMH::MODEL_KEY::TYPE, "Quick"}}; 0292 0293 paths << FMH::MODEL {{FMH::MODEL_KEY::PATH, "tags:///"}, {FMH::MODEL_KEY::ICON, "tag"}, {FMH::MODEL_KEY::LABEL, "Tags"}, {FMH::MODEL_KEY::TYPE, "Quick"}}; 0294 0295 paths << FMStatic::getDefaultPaths(); 0296 0297 0298 return FMH::toMapList(paths); 0299 } 0300 0301 QUrl Index::cameraPath() 0302 { 0303 const static auto paths = QStringList{FMStatic::HomePath + "/DCIM/Camera", FMStatic::HomePath + "/Camera"}; 0304 0305 for (const auto &path : paths) { 0306 if (FMH::fileExists(path)) 0307 return QUrl(path); 0308 } 0309 0310 return QUrl(); 0311 } 0312 0313 QUrl Index::screenshotsPath() 0314 { 0315 const static auto paths = QStringList{FMStatic::HomePath + "/DCIM/Screenshots", FMStatic::HomePath + "/Screenshots"}; 0316 0317 for (const auto &path : paths) { 0318 if (FMH::fileExists(path)) 0319 return QUrl(path); 0320 } 0321 0322 return QUrl(); 0323 }