diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,10 @@ ) +find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS + KIO + I18n +) add_library ( KF5ActivitiesStats SHARED @@ -148,4 +152,5 @@ DESTINATION ${ECM_MKSPECS_INSTALL_DIR} ) +add_subdirectory( ioslave ) diff --git a/src/ioslave/CMakeLists.txt b/src/ioslave/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/ioslave/CMakeLists.txt @@ -0,0 +1,12 @@ +add_definitions(-DTRANSLATION_DOMAIN=\"kio5_recentdocumentsactivities\") + +add_library(recentdocumentsactivities MODULE recentdocumentsactivities.cpp) +target_link_libraries(recentdocumentsactivities + KF5::KIOCore + KF5::I18n + KF5::Activities + KF5::ActivitiesStats) +set_target_properties(recentdocumentsactivities PROPERTIES OUTPUT_NAME "recentdocumentsactivities") +install(TARGETS recentdocumentsactivities DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kio) + +install( FILES recentdocumentsactivities.protocol DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) diff --git a/src/ioslave/recentdocumentsactivities.h b/src/ioslave/recentdocumentsactivities.h new file mode 100644 --- /dev/null +++ b/src/ioslave/recentdocumentsactivities.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Méven Car + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +#ifndef RECENTDOCUMENTACTIVITIES_H +#define RECENTDOCUMENTACTIVITIES_H + +#include +#include + +class RecentDocumentActivities : public KIO::ForwardingSlaveBase +{ +public: + RecentDocumentActivities(const QByteArray &pool, const QByteArray &app); + ~RecentDocumentActivities() override; + +protected: + bool rewriteUrl(const QUrl &url, QUrl &newUrl) override; + void listDir(const QUrl &url) override; + //void prepareUDSEntry(KIO::UDSEntry &entry, bool listing = false) const override; + void stat(const QUrl& url) override; + void mimetype(const QUrl& url) override; +}; + +#endif diff --git a/src/ioslave/recentdocumentsactivities.cpp b/src/ioslave/recentdocumentsactivities.cpp new file mode 100644 --- /dev/null +++ b/src/ioslave/recentdocumentsactivities.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2019 Méven Car + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +#include "recentdocumentsactivities.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include + +#include +#include +#include + +namespace KAStats = KActivities::Stats; + +using namespace KAStats; +using namespace KAStats::Terms; + +extern "C" int Q_DECL_EXPORT kdemain(int argc, char **argv) +{ + // necessary to use other kio slaves + QCoreApplication app(argc, argv); + app.setApplicationName(QStringLiteral("kio_recentdocumentsactivities")); + if (argc != 4) { + fprintf(stderr, "Usage: kio_recentdocumentsactivities protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + // start the slave + RecentDocumentActivities slave(argv[2], argv[3]); + slave.dispatchLoop(); + return 0; +} + +bool isRootUrl(const QUrl &url) +{ + const QString path = url.adjusted(QUrl::StripTrailingSlash).path(); + return (path.isEmpty() || path == QLatin1String("/")); +} + + +RecentDocumentActivities::RecentDocumentActivities(const QByteArray& pool, const QByteArray& app): + ForwardingSlaveBase("recentdocumentsactivities", pool, app) +{} + +RecentDocumentActivities::~RecentDocumentActivities() +{} + + +bool RecentDocumentActivities::rewriteUrl(const QUrl& url, QUrl& newUrl) +{ + Q_UNUSED(url) + Q_UNUSED(newUrl); + return false; +} + +void RecentDocumentActivities::listDir(const QUrl& url) +{ + if (!isRootUrl(url)) { + error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); + return; + } + + auto query = UsedResources + | RecentlyUsedFirst + | Agent::any() + | Activity::current() + | Url::file() + | Limit(30); + + // Parse url query parameter + auto urlQuery = QUrlQuery(url); + + // handles type aka mimetype + if (urlQuery.hasQueryItem(QStringLiteral("type"))) { + auto typeValue = urlQuery.queryItemValue(QStringLiteral("type")); + if (typeValue.contains(QLatin1Char(','))) { + // multiple mimetypes were passed + query = query | Type(typeValue.split(QLatin1Char(','))); + } else { + query = query | Type(typeValue); + } + } + + auto model = new ResultModel(query); + + KIO::UDSEntryList udslist; + udslist.reserve(model->rowCount()); + + for(int r = 0; r < model->rowCount(); ++r) { + QModelIndex index = model->index(r, 0); + QString resource = model->data(index, ResultModel::ResourceRole).toString(); + + // the query only returns files and folders + QUrl resourceUrl = QUrl::fromLocalFile(resource); + + KIO::UDSEntry uds; + KIO::StatJob* job = KIO::stat(resourceUrl, KIO::HideProgressInfo); + + // we do not want to wait for the event loop to delete the job + QScopedPointer sp(job); + job->setAutoDelete(false); + if (job->exec()) { + uds = job->statResult(); + } + uds.fastInsert(KIO::UDSEntry::UDS_URL, resourceUrl.toString()); + + udslist << uds; + } + + listEntries(udslist); + finished(); +} + +void RecentDocumentActivities::stat(const QUrl& url) +{ + if (isRootUrl(url)) { + // + // stat the root path + // + + QString dirName = i18n("Recent Documents"); + KIO::UDSEntry uds; + uds.reserve(5); + uds.fastInsert(KIO::UDSEntry::UDS_NAME, dirName); + uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, dirName); + uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_TYPE, dirName); + uds.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1("document-open-recent")); + uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1("inode/directory")); + + statEntry(uds); + finished(); + } + else { + error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); + finished(); + } +} + +void RecentDocumentActivities::mimetype(const QUrl& url) +{ + // the root url is always a folder + if (isRootUrl(url)) { + mimeType(QString::fromLatin1("inode/directory")); + finished(); + } + // results are forwarded + else { + ForwardingSlaveBase::mimetype(url); + } +} diff --git a/src/ioslave/recentdocumentsactivities.protocol b/src/ioslave/recentdocumentsactivities.protocol new file mode 100644 --- /dev/null +++ b/src/ioslave/recentdocumentsactivities.protocol @@ -0,0 +1,14 @@ +[Protocol] +X-DocPath=kioslave5/recentdocumentsactivities/index.html +exec=kf5/kio/recentdocumentsactivities +protocol=recentdocumentsactivities +Icon=document-open-recent +input=none +output=filesystem +listing=Name,Type,Size,Date,AccessDate,Access,Owner,Group,Link +reading=true +opening=true +writing=true +deleting=true +maxInstances=1 +Class=:local