File indexing completed on 2024-06-16 04:40:27

0001 /*
0002  *   SPDX-FileCopyrightText: 2012-2016 Ivan Cukic <ivan.cukic@kde.org>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "FileItemLinkingPluginActionLoader.h"
0008 
0009 #include <KFileItemListProperties>
0010 #include <utils/d_ptr_implementation.h>
0011 #include <utils/qsqlquery_iterator.h>
0012 
0013 #include <QCursor>
0014 #include <QDBusPendingCall>
0015 #include <QDebug>
0016 #include <QFileInfo>
0017 #include <QMenu>
0018 #include <QSqlDatabase>
0019 #include <QSqlDriver>
0020 #include <QSqlError>
0021 #include <QSqlField>
0022 #include <QSqlQuery>
0023 #include <QStandardPaths>
0024 
0025 #include <KLocalizedString>
0026 #include <KPluginFactory>
0027 
0028 #include "common/dbus/common.h"
0029 
0030 FileItemLinkingPluginActionLoader *FileItemLinkingPluginActionLoader::create(const KFileItemListProperties &items)
0031 {
0032     auto l = new FileItemLinkingPluginActionLoader(items);
0033     connect(l, &QThread::finished, l, &QObject::deleteLater);
0034     return l;
0035 }
0036 
0037 FileItemLinkingPluginActionLoader::FileItemLinkingPluginActionLoader(const KFileItemListProperties &items)
0038     : items(items)
0039 {
0040 }
0041 
0042 void FileItemLinkingPluginActionLoader::run()
0043 {
0044     ActionList actions;
0045 
0046     const auto activitiesList = activities.activities();
0047     const auto itemsSize = items.urlList().size();
0048 
0049     if (itemsSize >= 10) {
0050         // we are not going to check for this large number of files
0051         actions << createAction(QString(), true, i18n("Link to the current activity"), "list-add");
0052         actions << createAction(QString(), false, i18n("Unlink from the current activity"), "list-remove");
0053 
0054         actions << createSeparator(i18n("Link to:"));
0055         for (const auto &activity : activitiesList) {
0056             actions << createAction(activity, true);
0057         }
0058 
0059         actions << createSeparator(i18n("Unlink from:"));
0060         for (const auto &activity : activitiesList) {
0061             actions << createAction(activity, false);
0062         }
0063 
0064     } else {
0065         const QString connectionName = QStringLiteral("kactivities_db_resources_") + QString::number((quintptr)this);
0066 
0067         {
0068             auto database = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), connectionName);
0069 
0070             database.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
0071                                      + QStringLiteral("/kactivitymanagerd/resources/database"));
0072 
0073             if (database.open()) {
0074                 static const auto queryString = QStringLiteral(
0075                     "SELECT usedActivity, COUNT(targettedResource) "
0076                     "FROM ResourceLink "
0077                     "WHERE targettedResource IN (%1) "
0078                     "AND initiatingAgent = \":global\" "
0079                     "AND usedActivity != \":global\" "
0080                     "GROUP BY usedActivity");
0081 
0082                 QStringList escapedFiles;
0083                 QSqlField field;
0084                 field.setType(QVariant::String);
0085 
0086                 const auto urlList = items.urlList();
0087                 for (const auto &item : urlList) {
0088                     field.setValue(QFileInfo(item.toLocalFile()).canonicalFilePath());
0089                     escapedFiles << database.driver()->formatValue(field);
0090                 }
0091 
0092                 QSqlQuery query(queryString.arg(escapedFiles.join(",")), database);
0093 
0094                 QStringList activitiesForLinking;
0095                 QStringList activitiesForUnlinking;
0096 
0097                 for (const auto &result : query) {
0098                     const auto linkedFileCount = result[1].toInt();
0099                     const auto activity = result[0].toString();
0100                     if (linkedFileCount < itemsSize) {
0101                         activitiesForLinking << activity;
0102                     }
0103 
0104                     if (linkedFileCount > 0) {
0105                         activitiesForUnlinking << activity;
0106                     }
0107                 }
0108 
0109                 if (activitiesForLinking.contains(activities.currentActivity()) || !activitiesForUnlinking.contains(activities.currentActivity())) {
0110                     actions << createAction(QString(), true, i18n("Link to the current activity"), "list-add");
0111                 }
0112                 if (activitiesForUnlinking.contains(activities.currentActivity())) {
0113                     actions << createAction(QString(), false, i18n("Unlink from the current activity"), "list-remove");
0114                 }
0115 
0116                 actions << createSeparator(i18n("Link to:"));
0117                 for (const auto &activity : activitiesList) {
0118                     if (activitiesForLinking.contains(activity) || !activitiesForUnlinking.contains(activity)) {
0119                         actions << createAction(activity, true);
0120                     }
0121                 }
0122 
0123                 actions << createSeparator(i18n("Unlink from:"));
0124                 for (const auto &activity : activitiesList) {
0125                     if (activitiesForUnlinking.contains(activity)) {
0126                         actions << createAction(activity, false);
0127                     }
0128                 }
0129 
0130                 database.close();
0131             }
0132         }
0133 
0134         QSqlDatabase::removeDatabase(connectionName);
0135     }
0136 
0137     Q_EMIT result(actions);
0138 }
0139 
0140 Action FileItemLinkingPluginActionLoader::createAction(const QString &activity, bool link, const QString &title, const QString &icon) const
0141 {
0142     Action action = {};
0143     action.link = link;
0144 
0145     if (title.isEmpty()) {
0146         KActivities::Info activityInfo(activity);
0147         action.title = activityInfo.name();
0148         action.icon = activityInfo.icon().isEmpty() ? "activities" : activityInfo.icon();
0149 
0150     } else {
0151         action.title = title;
0152     }
0153 
0154     if (!icon.isEmpty()) {
0155         action.icon = icon;
0156     }
0157 
0158     action.activity = activity.isEmpty() ? activities.currentActivity() : activity;
0159 
0160     return action;
0161 }
0162 
0163 Action FileItemLinkingPluginActionLoader::createSeparator(const QString &title) const
0164 {
0165     Action action = {};
0166     action.icon = "-";
0167     action.title = title;
0168     return action;
0169 }
0170 
0171 #include "moc_FileItemLinkingPluginActionLoader.cpp"