Changeset View
Standalone View
runners/recentdocuments/recentdocuments.cpp
Show All 17 Lines | |||||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | #include "recentdocuments.h" | 20 | #include "recentdocuments.h" | ||
21 | 21 | | |||
22 | #include <QAction> | 22 | #include <QAction> | ||
23 | #include <QDir> | 23 | #include <QDir> | ||
24 | #include <QMimeData> | 24 | #include <QMimeData> | ||
25 | 25 | | |||
26 | #include <KDesktopFile> | | |||
27 | #include <KConfigGroup> | | |||
28 | #include <KDirWatch> | | |||
29 | #include <KRun> | 26 | #include <KRun> | ||
30 | #include <KRecentDocument> | | |||
31 | #include <KLocalizedString> | 27 | #include <KLocalizedString> | ||
32 | #include <KIO/OpenFileManagerWindowJob> | 28 | #include <KIO/OpenFileManagerWindowJob> | ||
29 | #include <KIO/Job> | ||||
30 | | ||||
31 | #include <KActivities/Stats/ResultModel> | ||||
32 | #include <KActivities/Stats/Terms> | ||||
33 | #include <KActivities/Stats/Query> | ||||
34 | | ||||
35 | using namespace KActivities::Stats; | ||||
36 | using namespace KActivities::Stats::Terms; | ||||
33 | 37 | | |||
34 | K_EXPORT_PLASMA_RUNNER(recentdocuments, RecentDocuments) | 38 | K_EXPORT_PLASMA_RUNNER(recentdocuments, RecentDocuments) | ||
35 | 39 | | |||
36 | static const QString s_openParentDirId = QStringLiteral("openParentDir"); | 40 | static const QString s_openParentDirId = QStringLiteral("openParentDir"); | ||
37 | 41 | | |||
38 | RecentDocuments::RecentDocuments(QObject *parent, const QVariantList& args) | 42 | RecentDocuments::RecentDocuments(QObject *parent, const QVariantList& args) | ||
39 | : Plasma::AbstractRunner(parent, args) | 43 | : Plasma::AbstractRunner(parent, args) | ||
40 | { | 44 | { | ||
41 | Q_UNUSED(args); | 45 | Q_UNUSED(args); | ||
42 | setObjectName( QStringLiteral("Recent Documents" )); | 46 | setObjectName( QStringLiteral("Recent Documents" )); | ||
43 | loadRecentDocuments(); | 47 | | ||
44 | // listen for changes to the list of recent documents | | |||
45 | KDirWatch *recentDocWatch = new KDirWatch(this); | | |||
46 | recentDocWatch->addDir(KRecentDocument::recentDocumentDirectory(), KDirWatch::WatchFiles); | | |||
47 | connect(recentDocWatch, &KDirWatch::created, this, &RecentDocuments::loadRecentDocuments); | | |||
48 | connect(recentDocWatch, &KDirWatch::deleted, this, &RecentDocuments::loadRecentDocuments); | | |||
49 | connect(recentDocWatch, &KDirWatch::dirty, this, &RecentDocuments::loadRecentDocuments); | | |||
50 | addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Looks for documents recently used with names matching :q:."))); | 48 | addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Looks for documents recently used with names matching :q:."))); | ||
51 | 49 | | |||
52 | addAction(s_openParentDirId, QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("Open Containing Folder")); | 50 | addAction(s_openParentDirId, QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("Open Containing Folder")); | ||
53 | } | 51 | } | ||
54 | 52 | | |||
55 | RecentDocuments::~RecentDocuments() | 53 | RecentDocuments::~RecentDocuments() | ||
56 | { | 54 | { | ||
57 | } | 55 | } | ||
58 | 56 | | |||
59 | void RecentDocuments::loadRecentDocuments() | | |||
60 | { | | |||
61 | m_recentdocuments = KRecentDocument::recentDocuments(); | | |||
62 | } | | |||
63 | | ||||
64 | | ||||
65 | void RecentDocuments::match(Plasma::RunnerContext &context) | 57 | void RecentDocuments::match(Plasma::RunnerContext &context) | ||
66 | { | 58 | { | ||
67 | if (m_recentdocuments.isEmpty()) { | 59 | if (!context.isValid()) { | ||
68 | return; | 60 | return; | ||
69 | } | 61 | } | ||
70 | 62 | | |||
71 | const QString term = context.query(); | 63 | const QString term = context.query(); | ||
72 | if (term.length() < 3) { | | |||
73 | return; | | |||
74 | } | | |||
75 | | ||||
76 | const QString homePath = QDir::homePath(); | | |||
77 | 64 | | |||
78 | // avoid duplicates | 65 | auto query = UsedResources | ||
79 | QSet<QUrl> knownUrls; | 66 | | Activity::current() | ||
67 | | Order::RecentlyUsedFirst | ||||
68 | | Agent::any() | ||||
69 | | Url("/*/" + term + "*") | ||||
meven: Request for now is limited, it will need some work in KActivityStats to be more clever | |||||
70 | | Limit(30); | ||||
80 | 71 | | |||
81 | for (const QString &document : qAsConst(m_recentdocuments)) { | 72 | const auto result = new ResultModel(query); | ||
82 | if (!context.isValid()) { | | |||
83 | return; | | |||
84 | } | | |||
85 | 73 | | |||
86 | if (document.contains(term, Qt::CaseInsensitive)) { | 74 | for (int i = 0; i < result->rowCount(); i++) { | ||
87 | KDesktopFile config(document); | 75 | const auto index = result->index(i, 0); | ||
88 | 76 | | |||
89 | const QUrl url = QUrl(config.readUrl()); | 77 | const auto url = QUrl::fromUserInput(result->data(index, ResultModel::ResourceRole).toString()); | ||
90 | if (knownUrls.contains(url)) { | 78 | const auto name = result->data(index, ResultModel::TitleRole).toString(); | ||
Do we really want QUrl::fromUserInput here? This thing typically assumes web addresses. Maybe pass AssumeLocalFile? But I recal that doing a file system access every time checking for existance.. probably not a big deal in this instance since it's in a thread broulik: Do we really want `QUrl::fromUserInput` here? This thing typically assumes web addresses. Maybe… | |||||
It is needed for QString coming from KActivitiesStats, they can be "/home/meven/doc.txt" or "file://" or "application://" or "http://". meven: It is needed for QString coming from KActivitiesStats, they can be "/home/meven/doc.txt" or… | |||||
meven: Well workingdirectory can be empty in fact. | |||||
91 | continue; | | |||
92 | } | | |||
93 | | ||||
94 | knownUrls.insert(url); | | |||
95 | 79 | | |||
96 | Plasma::QueryMatch match(this); | 80 | Plasma::QueryMatch match(this); | ||
81 | | ||||
82 | auto relevance = 0.5; | ||||
83 | match.setType(Plasma::QueryMatch::PossibleMatch); | ||||
84 | if (url.fileName() == term) { | ||||
85 | relevance = 1.0; | ||||
86 | match.setType(Plasma::QueryMatch::ExactMatch); | ||||
87 | } else if(url.fileName().startsWith(term)) { | ||||
broulik: Coding style | |||||
88 | relevance = 0.9; | ||||
97 | match.setType(Plasma::QueryMatch::PossibleMatch); | 89 | match.setType(Plasma::QueryMatch::PossibleMatch); | ||
98 | match.setRelevance(1.0); | | |||
99 | match.setIconName(config.readIcon()); | | |||
100 | match.setData(url); | | |||
101 | match.setText(config.readName()); | | |||
102 | | ||||
103 | QUrl folderUrl = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); | | |||
104 | if (folderUrl.isLocalFile()) { | | |||
105 | QString folderPath = folderUrl.toLocalFile(); | | |||
106 | if (folderPath.startsWith(homePath)) { | | |||
107 | folderPath.replace(0, homePath.length(), QStringLiteral("~")); | | |||
108 | } | | |||
109 | match.setSubtext(folderPath); | | |||
110 | } else { | | |||
111 | match.setSubtext(folderUrl.toDisplayString()); | | |||
112 | } | 90 | } | ||
91 | match.setIconName(KIO::iconNameForUrl(url)); | ||||
92 | match.setRelevance(relevance); | ||||
93 | match.setData(QVariant(url)); | ||||
94 | match.setText(name); | ||||
113 | 95 | | |||
114 | context.addMatch(match); | 96 | const QString homePath = QDir::homePath(); | ||
97 | QString destUrlString = url.adjusted(QUrl::RemoveFilename).path(); | ||||
98 | if (destUrlString.startsWith(homePath)) { | ||||
alex: You could use KShell:: tildeCollapse here :-) | |||||
Indeed, the irony is that I created KShell::titdeCollapes, but this diff is older than KF that introduced it... meven: Indeed, the irony is that I created `KShell::titdeCollapes`, but this diff is older than KF… | |||||
99 | destUrlString = QLatin1String("~") + destUrlString.mid(homePath.length()); | ||||
115 | } | 100 | } | ||
101 | match.setSubtext(destUrlString); | ||||
102 | | ||||
103 | context.addMatch(match); | ||||
116 | } | 104 | } | ||
117 | } | 105 | } | ||
118 | 106 | | |||
119 | void RecentDocuments::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) | 107 | void RecentDocuments::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) | ||
120 | { | 108 | { | ||
121 | Q_UNUSED(context) | 109 | Q_UNUSED(context) | ||
122 | 110 | | |||
123 | const QString url = match.data().toString(); | 111 | const QUrl url = match.data().toUrl(); | ||
124 | 112 | | |||
125 | if (match.selectedAction() && match.selectedAction() == action(s_openParentDirId)) { | 113 | if (match.selectedAction() == action(s_openParentDirId)) { | ||
126 | KIO::highlightInFileManager({QUrl(url)}); | 114 | KIO::highlightInFileManager({url}); | ||
127 | return; | 115 | return; | ||
128 | } | 116 | } | ||
129 | 117 | | |||
130 | new KRun(QUrl(url), nullptr); | 118 | new KRun(url, nullptr); | ||
131 | } | 119 | } | ||
132 | 120 | | |||
133 | QList<QAction *> RecentDocuments::actionsForMatch(const Plasma::QueryMatch &match) | 121 | QList<QAction *> RecentDocuments::actionsForMatch(const Plasma::QueryMatch &match) | ||
134 | { | 122 | { | ||
135 | Q_UNUSED(match) | 123 | Q_UNUSED(match) | ||
136 | 124 | | |||
137 | QList<QAction *> actions; | 125 | QList<QAction *> actions; | ||
138 | 126 | | |||
139 | if (QUrl(match.data().toString()).isLocalFile()) { | 127 | const QUrl url = match.data().toUrl(); | ||
128 | | ||||
129 | if (url.isLocalFile() && !QFileInfo(url.toLocalFile()).isDir()) { | ||||
Why not for dirs? If you have a recent docs on a defunct network share it would block now broulik: Why not for dirs? If you have a recent docs on a defunct network share it would block now | |||||
140 | actions << action(s_openParentDirId); | 130 | actions << action(s_openParentDirId); | ||
141 | } | 131 | } | ||
142 | 132 | | |||
143 | return actions; | 133 | return actions; | ||
144 | } | 134 | } | ||
145 | 135 | | |||
146 | QMimeData * RecentDocuments::mimeDataForMatch(const Plasma::QueryMatch& match) | 136 | QMimeData * RecentDocuments::mimeDataForMatch(const Plasma::QueryMatch& match) | ||
147 | { | 137 | { | ||
148 | QMimeData *result = new QMimeData(); | 138 | QMimeData *result = new QMimeData(); | ||
149 | result->setText(match.data().toString()); | 139 | result->setUrls({match.data().toUrl()}); | ||
150 | return result; | 140 | return result; | ||
151 | } | 141 | } | ||
152 | 142 | | |||
153 | #include "recentdocuments.moc" | 143 | #include "recentdocuments.moc" |
Request for now is limited, it will need some work in KActivityStats to be more clever