11#include "kio_tags_debug.h"
15#include <KLocalizedString>
19#include <QCoreApplication>
21#include <QRegularExpression>
24#include "taglistjob.h"
25#include "../common/udstools.h"
32class KIOPluginForMetaData :
public QObject
35 Q_PLUGIN_METADATA(IID
"org.kde.kio.worker.tags" FILE
"tags.json")
39 :
KIO::ForwardingWorkerBase(
"tags", pool_socket, app_socket)
43TagsProtocol::~TagsProtocol()
47KIO::WorkerResult TagsProtocol::listDir(
const QUrl& url)
49 ParseResult result = parseUrl(url);
51 switch(result.urlType) {
54 qCWarning(KIO_TAGS) << result.decodedUrl <<
"list() invalid url";
63KIO::WorkerResult TagsProtocol::stat(
const QUrl& url)
65 ParseResult result = parseUrl(url);
67 switch(result.urlType) {
69 qCWarning(KIO_TAGS) << result.decodedUrl <<
"stat() invalid url";
72 return ForwardingWorkerBase::stat(result.fileUrl);
74 for (
const KIO::UDSEntry& entry : std::as_const(result.pathUDSResults)) {
85KIO::WorkerResult TagsProtocol::copy(
const QUrl& src,
const QUrl& dest,
int permissions,
KIO::JobFlags flags)
87 Q_UNUSED(permissions);
90 ParseResult srcResult = parseUrl(src);
91 ParseResult dstResult = parseUrl(dest, QList<ParseFlags>() << ChopLastSection << LazyValidation);
93 if (srcResult.urlType == InvalidUrl) {
94 qCWarning(KIO_TAGS) << srcResult.decodedUrl <<
"copy() invalid src url";
96 }
else if (dstResult.urlType == InvalidUrl) {
97 qCWarning(KIO_TAGS) << dstResult.decodedUrl <<
"copy() invalid dest url";
101 auto rewriteTags = [] (KFileMetaData::UserMetaData& md,
const QString& newTag) {
102 qCDebug(KIO_TAGS) << md.filePath() <<
"adding tag" << newTag;
103 QStringList tags = md.tags();
108 if (srcResult.metaData.tags().contains(dstResult.tag)) {
109 qCWarning(KIO_TAGS) << srcResult.fileUrl.toLocalFile() <<
"file already has tag" << dstResult.tag;
110 infoMessage(
i18n(
"File %1 already has tag %2", srcResult.fileUrl.toLocalFile(), dstResult.tag));
111 }
else if (dstResult.urlType == TagUrl) {
112 rewriteTags(srcResult.metaData, dstResult.tag);
118KIO::WorkerResult TagsProtocol::get(
const QUrl& url)
120 ParseResult result = parseUrl(url);
122 switch(result.urlType) {
124 qCWarning(KIO_TAGS) << result.decodedUrl <<
"get() invalid url";
127 return ForwardingWorkerBase::get(result.fileUrl);
135KIO::WorkerResult TagsProtocol::rename(
const QUrl& src,
const QUrl& dest,
KIO::JobFlags flags)
139 ParseResult srcResult = parseUrl(src);
140 ParseResult dstResult;
142 if (srcResult.urlType == FileUrl) {
143 dstResult = parseUrl(dest, QList<ParseFlags>() << ChopLastSection);
144 }
else if (srcResult.urlType == TagUrl) {
145 dstResult = parseUrl(dest, QList<ParseFlags>() << LazyValidation);
148 if (srcResult.urlType == InvalidUrl) {
149 qCWarning(KIO_TAGS) << srcResult.decodedUrl <<
"rename() invalid src url";
151 }
else if (dstResult.urlType == InvalidUrl) {
152 qCWarning(KIO_TAGS) << dstResult.decodedUrl <<
"rename() invalid dest url";
156 auto rewriteTags = [] (KFileMetaData::UserMetaData& md,
const QString& oldTag,
const QString& newTag) {
157 qCDebug(KIO_TAGS) << md.filePath() <<
"swapping tag" << oldTag <<
"with" << newTag;
158 QStringList tags = md.tags();
164 if (srcResult.metaData.tags().contains(dstResult.tag)) {
165 qCWarning(KIO_TAGS) << srcResult.fileUrl.toLocalFile() <<
"file already has tag" << dstResult.tag;
166 infoMessage(
i18n(
"File %1 already has tag %2", srcResult.fileUrl.toLocalFile(), dstResult.tag));
167 }
else if (srcResult.urlType == FileUrl) {
168 rewriteTags(srcResult.metaData, srcResult.tag, dstResult.tag);
169 }
else if (srcResult.urlType == TagUrl) {
170 ResultIterator it = srcResult.query.exec();
172 KFileMetaData::UserMetaData md(it.filePath());
173 if (it.filePath() == srcResult.fileUrl.toLocalFile()) {
174 rewriteTags(md, srcResult.tag, dstResult.tag);
175 }
else if (srcResult.fileUrl.isEmpty()) {
176 const auto tags = md.tags();
177 for (
const QString& tag : tags) {
178 if (tag == srcResult.tag || (tag.startsWith(srcResult.tag + QLatin1Char(
'/')))) {
179 QString newTag = tag;
181 rewriteTags(md, tag, newTag);
191KIO::WorkerResult TagsProtocol::del(
const QUrl& url,
bool isfile)
195 ParseResult result = parseUrl(url);
197 auto rewriteTags = [] (KFileMetaData::UserMetaData& md,
const QString& tag) {
198 qCDebug(KIO_TAGS) << md.filePath() <<
"removing tag" << tag;
199 QStringList tags = md.tags();
204 switch(result.urlType) {
206 qCWarning(KIO_TAGS) << result.decodedUrl <<
"del() invalid url";
210 ResultIterator it = result.query.exec();
212 KFileMetaData::UserMetaData md(it.filePath());
213 if (it.filePath() == result.fileUrl.toLocalFile()) {
214 rewriteTags(md, result.tag);
215 }
else if (result.fileUrl.isEmpty()) {
216 const auto tags = md.tags();
217 for (
const QString &tag : tags) {
218 if ((tag == result.tag) || (tag.startsWith(result.tag + QLatin1Char(
'/'),
Qt::CaseInsensitive))) {
219 rewriteTags(md, tag);
229KIO::WorkerResult TagsProtocol::mimetype(
const QUrl& url)
231 ParseResult result = parseUrl(url);
233 switch(result.urlType) {
235 qCWarning(KIO_TAGS) << result.decodedUrl <<
"mimetype() invalid url";
238 return ForwardingWorkerBase::mimetype(result.fileUrl);
240 mimeType(QStringLiteral(
"inode/directory"));
246KIO::WorkerResult TagsProtocol::mkdir(
const QUrl& url,
int permissions)
248 Q_UNUSED(permissions);
250 ParseResult result = parseUrl(url, QList<ParseFlags>() << LazyValidation);
252 switch(result.urlType) {
255 qCWarning(KIO_TAGS) << result.decodedUrl <<
"mkdir() invalid url";
258 m_unassignedTags << result.tag;
264bool TagsProtocol::rewriteUrl(
const QUrl& url, QUrl& newURL)
272TagsProtocol::ParseResult TagsProtocol::parseUrl(
const QUrl& url,
const QList<ParseFlags> &flags)
274 TagsProtocol::ParseResult result;
277 if ((url.
scheme() == QLatin1String(
"tags")) && result.decodedUrl.
length()>6 && result.decodedUrl.
at(6) == QLatin1Char(
'/')) {
278 result.urlType = InvalidUrl;
282 auto createUDSEntryForTag = [] (
const QString& tagSection,
const QString& tag) {
297 if (tagSection == tag) {
298 displayType =
i18nc(
"This is a noun",
"Tag");
303 else if (!tag.isEmpty()) {
304 displayType =
i18nc(
"This is a noun",
"Tag Fragment");
305 if (tagSection == QStringLiteral(
"..")) {
307 }
else if (tagSection == QStringLiteral(
".")) {
316 displayType =
i18n(
"All Tags");
326 TagListJob* tagJob =
new TagListJob();
327 if (!tagJob->
exec()) {
328 qCWarning(KIO_TAGS) <<
"tag fetch failed:" << tagJob->
errorString();
333 result.urlType = FileUrl;
334 result.fileUrl = url;
335 result.metaData = KFileMetaData::UserMetaData(url.
toLocalFile());
336 }
else if (url.
scheme() == QLatin1String(
"tags")) {
337 bool validTag = flags.
contains(LazyValidation);
340 result.tag = result.decodedUrl;
343 while (result.tag.
startsWith(QLatin1Char(
'/'))) {
353 QRegularExpression regexp(QStringLiteral(
"\\s\\((\\d+)\\)$"));
354 QRegularExpressionMatch regMatch = regexp.match(fileName);
362 q.
setSearchString(QStringLiteral(
"tag=\"%1\" AND filename=\"%2\"").arg(tag, fileName));
363 ResultIterator it = q.exec();
368 result.metaData = KFileMetaData::UserMetaData(it.filePath());
381 validTag = validTag || result.tag.
isEmpty();
385 QString
query = result.tag;
387 query.
replace(QLatin1Char(
' '), QStringLiteral(
" AND tag:"));
388 query.
replace(QLatin1Char(
'/'), QStringLiteral(
" AND tag:"));
391 qCDebug(KIO_TAGS) << result.decodedUrl <<
"url query:" <<
query;
395 int index = result.tag.
count(QLatin1Char(
'/')) + (result.tag.
isEmpty() ? 0 : 1);
396 QStringList tagPaths;
398 const QStringList tags = QStringList() << tagJob->tags() << m_unassignedTags;
399 for (
const QString& tag : tags) {
403 result.pathUDSResults << createUDSEntryForTag(tagSection, tag);
404 tagPaths << tagSection;
411 if (validTag && result.fileUrl.
isEmpty()) {
412 result.urlType = TagUrl;
413 }
else if (validTag && !result.fileUrl.
isEmpty()) {
414 result.urlType = FileUrl;
418 if (result.urlType == FileUrl) {
421 result.pathUDSResults << createUDSEntryForTag(QStringLiteral(
"."), result.tag);
428 result.pathUDSResults << createUDSEntryForTag(QStringLiteral(
".."), result.tag);
434 ResultIterator it = q.exec();
435 QList<QString> resultNames;
439 KIO::UDSEntry uds = udsf.createUdsEntry(it.filePath());
440 if (uds.
count() == 0) {
453 result.pathUDSResults << uds;
461 Q_DECL_EXPORT
int kdemain(
int argc,
char** argv)
463 QCoreApplication app(argc, argv);
464 app.setApplicationName(QStringLiteral(
"kio_tags"));
465 Baloo::TagsProtocol worker(argv[2], argv[3]);
466 worker.dispatchLoop();
471#include "kio_tags.moc"
472#include "moc_kio_tags.cpp"
void setSearchString(const QString &str)
Set some text which should be used to search for Items.
void fastInsert(uint field, const QString &value)
QString stringValue(uint field) const
void replace(uint field, const QString &value)
void statEntry(const UDSEntry &_entry)
void infoMessage(const QString &msg)
void listEntries(const UDSEntryList &_entry)
void mimeType(const QString &_type)
static WorkerResult pass()
static WorkerResult fail(int _error=KIO::ERR_UNKNOWN, const QString &_errorString=QString())
virtual QString errorString() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
Implements storage for docIds without any associated data Instantiated for:
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
QFlags< JobFlag > JobFlags
QString cleanPath(const QString &path)
void append(QList< T > &&value)
bool contains(const AT &value) const const
qsizetype count() const const
void prepend(parameter_type value)
qsizetype removeAll(const AT &t)
void replace(qsizetype i, parameter_type value)
QString captured(QStringView name) const const
bool hasMatch() const const
qsizetype count() const const
const QChar at(qsizetype position) const const
bool isEmpty() const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QByteArray toUtf8() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString fileName(ComponentFormattingOptions options) const const
QUrl fromLocalFile(const QString &localFile)
QString fromPercentEncoding(const QByteArray &input)
bool isEmpty() const const
bool isLocalFile() const const
QString scheme() const const
QString toLocalFile() const const
QString toString(FormattingOptions options) const const