diff --git a/src/filewidgets/kfileplacesitem.cpp b/src/filewidgets/kfileplacesitem.cpp --- a/src/filewidgets/kfileplacesitem.cpp +++ b/src/filewidgets/kfileplacesitem.cpp @@ -121,6 +121,9 @@ case KFilePlacesModel::RemovableDevicesType: m_groupName = i18nc("@item", "Removable Devices"); break; + case KFilePlacesModel::TagsType: + m_groupName = i18nc("@item", "Tags"); + break; default: Q_UNREACHABLE(); break; @@ -162,6 +165,10 @@ return KFilePlacesModel::DevicesType; } + if (protocol == QLatin1String("tags")) { + return KFilePlacesModel::TagsType; + } + if (protocol == QLatin1String("remote") || KProtocolInfo::protocolClass(protocol) != QLatin1String(":local")) { return KFilePlacesModel::RemoteType; diff --git a/src/filewidgets/kfileplacesitem_p.h b/src/filewidgets/kfileplacesitem_p.h --- a/src/filewidgets/kfileplacesitem_p.h +++ b/src/filewidgets/kfileplacesitem_p.h @@ -51,7 +51,8 @@ RecentlySavedType, SearchForType, DevicesType, - RemovableDevicesType + RemovableDevicesType, + TagsType }; KFilePlacesItem(KBookmarkManager *manager, diff --git a/src/filewidgets/kfileplacesmodel.h b/src/filewidgets/kfileplacesmodel.h --- a/src/filewidgets/kfileplacesmodel.h +++ b/src/filewidgets/kfileplacesmodel.h @@ -62,7 +62,8 @@ SearchForType, DevicesType, RemovableDevicesType, - UnknownType + UnknownType, + TagsType }; explicit KFilePlacesModel(QObject *parent = nullptr); diff --git a/src/filewidgets/kfileplacesmodel.cpp b/src/filewidgets/kfileplacesmodel.cpp --- a/src/filewidgets/kfileplacesmodel.cpp +++ b/src/filewidgets/kfileplacesmodel.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -76,6 +77,8 @@ return QStringLiteral("GroupState-Devices-IsHidden"); case KFilePlacesModel::RemovableDevicesType: return QStringLiteral("GroupState-RemovableDevices-IsHidden"); + case KFilePlacesModel::TagsType: + return QStringLiteral("GroupState-Tags-IsHidden"); default: Q_UNREACHABLE(); } @@ -173,8 +176,35 @@ Private(KFilePlacesModel *self) : q(self), bookmarkManager(nullptr), - fileIndexingEnabled(isFileIndexingEnabled()) + fileIndexingEnabled(isFileIndexingEnabled()), + tags(), + tagsLister(new KCoreDirLister()) { + if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) { + connect(tagsLister, &KCoreDirLister::itemsAdded, q, [this](const QUrl& directoryUrl, const KFileItemList& items) { + + Q_UNUSED(directoryUrl); + const int maxTags = 8; + + if (tags.isEmpty()) { + KFilePlacesItem::createSystemBookmark(bookmarkManager, + QStringLiteral("All tags"), I18N_NOOP2("KFile System Bookmarks", "All tags"), + QUrl(tagsUrlBase), QStringLiteral("tag")); + } + + for (const KFileItem &item: items) { + const QString name = item.name(); + + if (!tags.contains(name) && tags.size() < maxTags) { + tags.append(name); + KFilePlacesItem::createSystemBookmark(bookmarkManager,name, name, QUrl(item.url()), QStringLiteral("tag")); + + } + } + _k_reloadBookmarks(); + }); + tagsLister->openUrl(QUrl(tagsUrlBase), KCoreDirLister::OpenUrlFlag::Reload); + } } ~Private() @@ -200,6 +230,10 @@ QList loadBookmarkList(); int findNearestPosition(int source, int target); + QList tags; + const QString tagsUrlBase = QStringLiteral("tags:/"); + KCoreDirLister* tagsLister; + void _k_initDeviceList(); void _k_deviceAdded(const QString &udi); void _k_deviceRemoved(const QString &udi); @@ -279,6 +313,7 @@ setDefaultMetadataItemForGroup(RemoteType); setDefaultMetadataItemForGroup(DevicesType); setDefaultMetadataItemForGroup(RemovableDevicesType); + setDefaultMetadataItemForGroup(TagsType); // Force bookmarks to be saved. If on open/save dialog and the bookmarks are not saved, QFile::exists // will always return false, which opening/closing all the time the open/save dialog would case the @@ -1062,7 +1097,7 @@ if (isGroupHidden(type) == hidden) return; - d->bookmarkManager->root().setMetaDataItem(stateNameForGroupType(type), (hidden ? QStringLiteral("true") : QStringLiteral("false"))); + d->bookmarkManager->root().setMetaDataItem(stateNameForGroupType(type), (hidden ? QStringLiteral("true") : QStringLiteral("false"))); d->reloadAndSignal(); emit groupHiddenChanged(type, hidden); } diff --git a/src/panels/places/placesitem.h b/src/panels/places/placesitem.h --- a/src/panels/places/placesitem.h +++ b/src/panels/places/placesitem.h @@ -45,7 +45,8 @@ PlacesType, SearchForType, RecentlySavedType, - DevicesType + DevicesType, + TagsType }; explicit PlacesItem(const KBookmark& bookmark, PlacesItem* parent = 0); diff --git a/src/panels/places/placesitem.cpp b/src/panels/places/placesitem.cpp --- a/src/panels/places/placesitem.cpp +++ b/src/panels/places/placesitem.cpp @@ -145,6 +145,7 @@ switch (type) { case RecentlySavedType: setIcon(QStringLiteral("chronometer")); break; case SearchForType: setIcon(QStringLiteral("system-search")); break; + case TagsType: setIcon(QStringLiteral("tag")); break; case PlacesType: default: setIcon(QStringLiteral("folder")); } @@ -156,6 +157,7 @@ case RecentlySavedType: setGroup(i18nc("@item", "Recently Saved")); break; case SearchForType: setGroup(i18nc("@item", "Search For")); break; case DevicesType: setGroup(i18nc("@item", "Devices")); break; + case TagsType: setGroup(i18nc("@item", "Tags")); break; default: Q_ASSERT(false); break; } @@ -171,6 +173,7 @@ { if (udi().isEmpty()) { const QString protocol = url().scheme(); + if (protocol == QLatin1String("timeline")) { return RecentlySavedType; } @@ -183,6 +186,10 @@ return DevicesType; } + if (protocol == QLatin1String("tags")) { + return TagsType; + } + return PlacesType; } diff --git a/src/panels/places/placesitemmodel.h b/src/panels/places/placesitemmodel.h --- a/src/panels/places/placesitemmodel.h +++ b/src/panels/places/placesitemmodel.h @@ -30,6 +30,7 @@ #include #include #include +#include class KBookmark; class KBookmarkManager; @@ -145,6 +146,7 @@ void slotStorageTeardownDone(Solid::ErrorType error, const QVariant& errorData); void slotStorageSetupDone(Solid::ErrorType error, const QVariant& errorData, const QString& udi); void hideItem(); + void addTag(const QUrl& directoryUrl, const KFileItemList& items); /** * Updates the bookmarks from the model corresponding to the changed @@ -284,6 +286,10 @@ QTimer* m_updateBookmarksTimer; QHash m_storageSetupInProgress; + + QList m_tags; + const QString m_tagsUrlBase = QStringLiteral("tags:/"); + KCoreDirLister* m_dirLister; }; #endif diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -78,7 +79,8 @@ m_bookmarkedItems(), m_hiddenItemToRemove(-1), m_updateBookmarksTimer(0), - m_storageSetupInProgress() + m_storageSetupInProgress(), + m_tags() { #ifdef HAVE_BALOO Baloo::IndexerConfig config; @@ -86,9 +88,16 @@ #endif const QString file = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/user-places.xbel"; m_bookmarkManager = KBookmarkManager::managerForExternalFile(file); + m_dirLister = new KCoreDirLister(); createSystemBookmarks(); initializeAvailableDevices(); + + if (KProtocolInfo::isKnownProtocol(QStringLiteral("tags"))) { + connect(m_dirLister, &KCoreDirLister::itemsAdded, this, &PlacesItemModel::addTag); + m_dirLister->openUrl(QUrl(m_tagsUrlBase)); + } + loadBookmarks(); const int syncBookmarksTimeout = 100; @@ -106,6 +115,7 @@ { qDeleteAll(m_bookmarkedItems); m_bookmarkedItems.clear(); + delete m_dirLister; } PlacesItem* PlacesItemModel::createPlacesItem(const QString& text, @@ -550,7 +560,7 @@ m_availableDevices << udi; const KBookmark bookmark = PlacesItem::createDeviceBookmark(m_bookmarkManager, udi); - appendItem(new PlacesItem(bookmark)); + appendItemToGroup(new PlacesItem(bookmark)); } void PlacesItemModel::slotDeviceRemoved(const QString& udi) @@ -661,7 +671,7 @@ PlacesItem* item = new PlacesItem(newBookmark); if (item->isHidden() && !m_hiddenItemsShown) { m_bookmarkedItems.append(item); - } else { + } else if (!(item->groupType() == PlacesItem::TagsType)) { appendItemToGroup(item); } } @@ -680,6 +690,10 @@ item = placesItem(modelIndex); } + if (item->groupType() == PlacesItem::TagsType){ + continue; + } + bool hasBeenRemoved = true; const KBookmark oldBookmark = item->bookmark(); KBookmark newBookmark = root.first(); @@ -756,6 +770,7 @@ case PlacesItem::PlacesType: placesItems.append(item); break; case PlacesItem::RecentlySavedType: recentlySavedItems.append(item); break; case PlacesItem::SearchForType: searchForItems.append(item); break; + case PlacesItem::TagsType: break; case PlacesItem::DevicesType: default: Q_ASSERT(false); break; } @@ -775,6 +790,7 @@ case PlacesItem::PlacesType: placesItems.append(item); break; case PlacesItem::RecentlySavedType: recentlySavedItems.append(item); break; case PlacesItem::SearchForType: searchForItems.append(item); break; + case PlacesItem::TagsType: break; case PlacesItem::DevicesType: default: Q_ASSERT(false); break; } @@ -1167,6 +1183,32 @@ return query.toSearchUrl(); } + +void PlacesItemModel::addTag(const QUrl& directoryUrl, const KFileItemList& items) +{ + Q_UNUSED(directoryUrl); + const int maxTags = 8; + + if (m_tags.isEmpty()) { + PlacesItem* allTagsItem = createSystemPlacesItem(SystemBookmarkData(QUrl(m_tagsUrlBase), + QStringLiteral("tag"), + I18N_NOOP2("KFile System Bookmarks", "All tags"))); + appendItemToGroup(allTagsItem); + } + + for (const KFileItem &item: items) { + const QString name = item.name(); + + if (!m_tags.contains(name) && m_tags.size() < maxTags) { + m_tags.append(name); + PlacesItem* placesItem = createSystemPlacesItem(SystemBookmarkData(QUrl(item.url()), + QStringLiteral("tag"), + name)); + appendItemToGroup(placesItem); + } + } +} + #endif #ifdef PLACESITEMMODEL_DEBUG diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -321,7 +321,7 @@ const PlacesItem* destItem = m_model->placesItem(index); const PlacesItem::GroupType group = destItem->groupType(); - if (group == PlacesItem::SearchForType || group == PlacesItem::RecentlySavedType) { + if (group == PlacesItem::SearchForType || group == PlacesItem::RecentlySavedType || group == PlacesItem::TagsType) { return; }