diff --git a/autotests/kfileplacesmodeltest.cpp b/autotests/kfileplacesmodeltest.cpp --- a/autotests/kfileplacesmodeltest.cpp +++ b/autotests/kfileplacesmodeltest.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -96,6 +97,7 @@ QMap m_interfacesMap; QTemporaryDir m_tmpHome; + bool m_hasRecentlyUsedKio; }; static QString bookmarksFile() @@ -128,6 +130,8 @@ qputenv("SOLID_FAKEHW", QFile::encodeName(fakeHw)); m_places = new KFilePlacesModel(); m_places2 = new KFilePlacesModel(); + + m_hasRecentlyUsedKio = KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused")); } void KFilePlacesModelTest::cleanupTestCase() @@ -195,9 +199,10 @@ void KFilePlacesModelTest::testInitialState() { - QCOMPARE(m_places->rowCount(), 3); // when the xbel file is empty, KFilePlacesModel fills it with 3 default items + QCOMPARE(m_places->rowCount(), m_hasRecentlyUsedKio ? 4 : 3); // when the xbel file is empty, KFilePlacesModel fills it with 3 default items + // 4 when ioslave recentlyused:/ is installed QCoreApplication::processEvents(); // Devices have a delayed loading - QCOMPARE(m_places->rowCount(), 8); + QCOMPARE(m_places->rowCount(), m_hasRecentlyUsedKio ? 9 : 8); } static const QStringList initialListOfPlaces() @@ -210,6 +215,15 @@ return QStringList() << QStringLiteral("remote:/") << QStringLiteral("/media/nfs"); } +static const QStringList initialListOfRecent() +{ + auto list = QStringList(); + if (KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) { + list << QStringLiteral("recentlyused:/"); + } + return list; +} + static const QStringList initialListOfDevices() { return QStringList() << QStringLiteral("/foreign"); @@ -224,6 +238,7 @@ { return QStringList() << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); } @@ -395,6 +410,7 @@ QStringList urls; urls << QStringLiteral("trash:/") << QDir::homePath() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); @@ -416,6 +432,7 @@ urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -452,6 +469,7 @@ QStringList urls; urls << QStringLiteral("trash:/") << QDir::homePath() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -474,6 +492,7 @@ urls.clear(); urls << QDir::homePath() << QStringLiteral("trash:/") << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -510,6 +529,7 @@ QStringList urls; urls << initialListOfPlaces() << QStringLiteral("/home/foo") << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -531,6 +551,7 @@ urls.clear(); urls << QDir::homePath() << QStringLiteral("/home/foo") << QStringLiteral("trash:/") << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -550,6 +571,7 @@ urls.clear(); urls << QDir::homePath() << QStringLiteral("/mnt/foo") << QStringLiteral("trash:/") << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -567,13 +589,14 @@ urls.clear(); urls << QDir::homePath() << QStringLiteral("/mnt/foo") << QStringLiteral("trash:/") << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 0); QCOMPARE(spy_removed.count(), 0); - QCOMPARE(spy_changed.count(), 9); + QCOMPARE(spy_changed.count(), m_hasRecentlyUsedKio ? 10 : 9); args = spy_changed[2]; QCOMPARE(args.at(0).toModelIndex(), m_places->index(2, 0)); QCOMPARE(args.at(1).toModelIndex(), m_places->index(2, 0)); @@ -584,6 +607,7 @@ urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -599,6 +623,7 @@ urls.clear(); urls << QDir::homePath() << QStringLiteral("/home/foo") << QStringLiteral("trash:/") << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); @@ -623,29 +648,31 @@ QStringList urls; urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/floppy0") << QStringLiteral("/media/cdrom"); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 0); QCOMPARE(spy_removed.count(), 1); args = spy_removed.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 6); - QCOMPARE(args.at(2).toInt(), 6); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 6); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 6); fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 1); args = spy_inserted.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 6); - QCOMPARE(args.at(2).toInt(), 6); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 6); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 6); QCOMPARE(spy_removed.count(), 0); // Move the device in the list, and check that it memorizes the position across plug/unplug @@ -655,7 +682,8 @@ KBookmark before_floppy; KBookmark device = root.first(); // The device we'll move is the 6th bookmark - for (int i = 0; i < 5; i++) { + int stop = m_hasRecentlyUsedKio ? 6 : 5; + for (int i = 0; i < stop; i++) { if (i == 2) { // store item before to be able to move it back to original position device = before_floppy = root.next(device); @@ -670,73 +698,77 @@ urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/floppy0") << QStringLiteral("/media/cdrom"); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 1); args = spy_inserted.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 6); - QCOMPARE(args.at(2).toInt(), 6); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 6); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 6); QCOMPARE(spy_removed.count(), 1); args = spy_removed.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 5); - QCOMPARE(args.at(2).toInt(), 5); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 6 : 5); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 6 : 5); fakeManager()->call(QStringLiteral("unplug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/floppy0") << QStringLiteral("/media/cdrom"); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 0); QCOMPARE(spy_removed.count(), 1); args = spy_removed.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 5); - QCOMPARE(args.at(2).toInt(), 5); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 6 : 5); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 6 : 5); fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096"); urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/floppy0") << QStringLiteral("/media/cdrom"); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 1); args = spy_inserted.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 5); - QCOMPARE(args.at(2).toInt(), 5); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 6 : 5); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 6 : 5); QCOMPARE(spy_removed.count(), 0); - KBookmark sixth = root.first(); - for (int i = 0; i < 5; i++) { - sixth = root.next(sixth); + KBookmark seventh = root.first(); + for (int i = 0; i < stop; i++) { + seventh = root.next(seventh); } - root.moveBookmark(device, sixth); + root.moveBookmark(device, seventh); bookmarkManager->emitChanged(root); urls.clear(); urls << initialListOfPlaces() << initialListOfShared() + << initialListOfRecent() << initialListOfDevices() << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); QCOMPARE(spy_inserted.count(), 1); args = spy_inserted.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 6); - QCOMPARE(args.at(2).toInt(), 6); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 7 : 6); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 7 : 6); QCOMPARE(spy_removed.count(), 1); args = spy_removed.takeFirst(); QCOMPARE(args.at(0).toModelIndex(), QModelIndex()); - QCOMPARE(args.at(1).toInt(), 5); - QCOMPARE(args.at(2).toInt(), 5); + QCOMPARE(args.at(1).toInt(), m_hasRecentlyUsedKio ? 6 : 5); + QCOMPARE(args.at(2).toInt(), m_hasRecentlyUsedKio ? 6 : 5); } void KFilePlacesModelTest::testDeviceSetupTeardown() @@ -748,15 +780,15 @@ QCOMPARE(spy_changed.count(), 1); args = spy_changed.takeFirst(); - QCOMPARE(args.at(0).toModelIndex().row(), 6); - QCOMPARE(args.at(1).toModelIndex().row(), 6); + QCOMPARE(args.at(0).toModelIndex().row(), m_hasRecentlyUsedKio ? 7 : 6); + QCOMPARE(args.at(1).toModelIndex().row(), m_hasRecentlyUsedKio ? 7 : 6); fakeDevice(QStringLiteral("/org/kde/solid/fakehw/volume_part1_size_993284096/StorageAccess"))->call(QStringLiteral("setup")); QCOMPARE(spy_changed.count(), 1); args = spy_changed.takeFirst(); - QCOMPARE(args.at(0).toModelIndex().row(), 6); - QCOMPARE(args.at(1).toModelIndex().row(), 6); + QCOMPARE(args.at(0).toModelIndex().row(), m_hasRecentlyUsedKio ? 7 : 6); + QCOMPARE(args.at(1).toModelIndex().row(), m_hasRecentlyUsedKio ? 7 : 6); } void KFilePlacesModelTest::testEnableBaloo() @@ -811,7 +843,9 @@ QStringList urls; urls << QDir::homePath() << QStringLiteral("trash:/") // places << QStringLiteral("remote:/") << QStringLiteral("/media/nfs") - << url.toString() << QStringLiteral("/foreign") + << url.toString() + << initialListOfRecent() + << QStringLiteral("/foreign") << QStringLiteral("/media/floppy0") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/cdrom"); CHECK_PLACES_URLS(urls); @@ -929,19 +963,25 @@ QTest::addColumn("expectedIconName"); // places - QTest::newRow("Places - Home") << m_places->index(0, 0) + int idx = 0; + QTest::newRow("Places - Home") << m_places->index(idx++, 0) << QStringLiteral("user-home"); - QTest::newRow("Places - Trash") << m_places->index(1, 0) + QTest::newRow("Places - Trash") << m_places->index(idx++, 0) << QStringLiteral("user-trash"); - QTest::newRow("Remote - Network") << m_places->index(2, 0) + + QTest::newRow("Remote - Network") << m_places->index(idx++, 0) << QStringLiteral("folder-network"); - QTest::newRow("Devices - Nfs") << m_places->index(3, 0) + QTest::newRow("Devices - Nfs") << m_places->index(idx++, 0) << QStringLiteral("hwinfo"); - QTest::newRow("Devices - foreign") << m_places->index(4, 0) + if (m_hasRecentlyUsedKio) { + QTest::newRow("Recently Used") << m_places->index(idx++, 0) + << QStringLiteral("document-open-recent"); + } + QTest::newRow("Devices - foreign") << m_places->index(idx++, 0) << QStringLiteral("blockdevice"); - QTest::newRow("Devices - Floppy") << m_places->index(5, 0) + QTest::newRow("Devices - Floppy") << m_places->index(idx++, 0) << QStringLiteral("blockdevice"); - QTest::newRow("Devices - cdrom") << m_places->index(6, 0) + QTest::newRow("Devices - cdrom") << m_places->index(idx++, 0) << QStringLiteral("blockdevice"); } @@ -1040,7 +1080,11 @@ QCOMPARE(m_places->hiddenCount(), 0); QStringList urls; - urls << initialListOfPlaces() << initialListOfShared() << initialListOfDevices() << initialListOfRemovableDevices(); + urls << initialListOfPlaces() + << initialListOfShared() + << initialListOfRecent() + << initialListOfDevices() + << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); QVector indexesHidden; @@ -1107,7 +1151,11 @@ QCOMPARE(m_places->hiddenCount(), 0); QStringList urls; - urls << initialListOfPlaces() << initialListOfShared() << initialListOfDevices() << initialListOfRemovableDevices(); + urls << initialListOfPlaces() + << initialListOfShared() + << initialListOfRecent() + << initialListOfDevices() + << initialListOfRemovableDevices(); CHECK_PLACES_URLS(urls); QModelIndex firstIndexHidden = m_places->index(0,0); @@ -1145,7 +1193,7 @@ QVERIFY(m_places->groupIndexes(KFilePlacesModel::UnknownType).isEmpty()); QVERIFY(m_places->isGroupHidden(KFilePlacesModel::PlacesType)); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::PlacesType).count(), initialListOfPlaces().count()); - QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RecentlySavedType).count(), 0); + QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RecentlySavedType).count(), m_hasRecentlyUsedKio ? 1 : 0); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::SearchForType).count(), 0); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::DevicesType).count(), initialListOfDevices().count()); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RemovableDevicesType).count(), initialListOfRemovableDevices().count()); @@ -1157,7 +1205,7 @@ // Make sure that hidden place group doesn't change model QVERIFY(!m_places->isGroupHidden(KFilePlacesModel::PlacesType)); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::PlacesType).count(), initialListOfPlaces().count()); - QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RecentlySavedType).count(), 0); + QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RecentlySavedType).count(), m_hasRecentlyUsedKio ? 1 : 0); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::SearchForType).count(), 0); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::DevicesType).count(), initialListOfDevices().count()); QCOMPARE(m_places->groupIndexes(KFilePlacesModel::RemovableDevicesType).count(), initialListOfRemovableDevices().count()); diff --git a/autotests/kfileplacesviewtest.cpp b/autotests/kfileplacesviewtest.cpp --- a/autotests/kfileplacesviewtest.cpp +++ b/autotests/kfileplacesviewtest.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -78,17 +79,21 @@ const QDate currentDate = QDate::currentDate(); const QDate yesterdayDate = currentDate.addDays(-1); - QTest::newRow("Today") << 3 << QStringLiteral("timeline:/today"); - QTest::newRow("Yesterday") << 4 << QString("timeline:/%1-%2/%1-%2-%3") + int idx = 3; + if (KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) { + QTest::newRow("Recently Used") << idx++ << QStringLiteral("recentlyused:/"); + } + QTest::newRow("Today") << idx++ << QStringLiteral("timeline:/today"); + QTest::newRow("Yesterday") << idx++ << QString("timeline:/%1-%2/%1-%2-%3") .arg(yesterdayDate.year()) .arg(yesterdayDate.month(), 2, 10, QChar('0')) .arg(yesterdayDate.day(), 2, 10, QChar('0')); // search - QTest::newRow("Documents") << 5 << QStringLiteral("baloosearch:/documents"); - QTest::newRow("Images") << 6 << QStringLiteral("baloosearch:/images"); - QTest::newRow("Audio Files") << 7 << QStringLiteral("baloosearch:/audio"); - QTest::newRow("Videos") << 8 << QStringLiteral("baloosearch:/videos"); + QTest::newRow("Documents") << idx++ << QStringLiteral("baloosearch:/documents"); + QTest::newRow("Images") << idx++ << QStringLiteral("baloosearch:/images"); + QTest::newRow("Audio Files") << idx++ << QStringLiteral("baloosearch:/audio"); + QTest::newRow("Videos") << idx++ << QStringLiteral("baloosearch:/videos"); } void KFilePlacesViewTest::testUrlChanged() diff --git a/src/filewidgets/kfileplacesitem.cpp b/src/filewidgets/kfileplacesitem.cpp --- a/src/filewidgets/kfileplacesitem.cpp +++ b/src/filewidgets/kfileplacesitem.cpp @@ -110,7 +110,7 @@ m_groupName = i18nc("@item", "Remote"); break; case KFilePlacesModel::RecentlySavedType: - m_groupName = i18nc("@item", "Recently Saved"); + m_groupName = i18nc("@item", "Recent"); break; case KFilePlacesModel::SearchForType: m_groupName = i18nc("@item", "Search For"); @@ -151,7 +151,8 @@ { if (!isDevice()) { const QString protocol = bookmark().url().scheme(); - if (protocol == QLatin1String("timeline")) { + if (protocol == QLatin1String("timeline") || + protocol == QLatin1String("recentlyused")) { return KFilePlacesModel::RecentlySavedType; } diff --git a/src/filewidgets/kfileplacesmodel.h b/src/filewidgets/kfileplacesmodel.h --- a/src/filewidgets/kfileplacesmodel.h +++ b/src/filewidgets/kfileplacesmodel.h @@ -90,6 +90,8 @@ bool isDevice(const QModelIndex &index) const; Solid::Device deviceForIndex(const QModelIndex &index) const; KBookmark bookmarkForIndex(const QModelIndex &index) const; + /// @since 5.62 + KBookmark bookmarkForUrl(const QUrl &searchUrl); /// @since 5.42 GroupType groupType(const QModelIndex &index) const; QModelIndexList groupIndexes(const GroupType type) const; diff --git a/src/filewidgets/kfileplacesmodel.cpp b/src/filewidgets/kfileplacesmodel.cpp --- a/src/filewidgets/kfileplacesmodel.cpp +++ b/src/filewidgets/kfileplacesmodel.cpp @@ -248,6 +248,19 @@ bool isBalooUrl(const QUrl &url) const; }; +KBookmark KFilePlacesModel::bookmarkForUrl(const QUrl &searchUrl) +{ + KBookmarkGroup root = d->bookmarkManager->root(); + KBookmark current = root.first(); + while (!current.isNull()) { + if (current.url() == searchUrl) { + return current; + } + current = root.next(current); + } + return KBookmark(); +} + KFilePlacesModel::KFilePlacesModel(const QString &alternativeApplicationName, QObject *parent) : QAbstractItemModel(parent), d(new Private(this)) { @@ -317,16 +330,37 @@ d->bookmarkManager->saveAs(file); } + // Add a Recently Used entry if available (it comes from kio-extras) + if (KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused")) && + root.metaDataItem(QStringLiteral("withRecentlyUsed")) != QLatin1String("true")) { + + root.setMetaDataItem(QStringLiteral("withRecentlyUsed"), QStringLiteral("true")); + + KBookmark recentlyusedBookmark = KFilePlacesItem::createSystemBookmark(d->bookmarkManager, + QStringLiteral("Recently Used"), I18N_NOOP2("KFile System Bookmarks", "Recently Used"), + QUrl(QStringLiteral("recentlyused:/")), QStringLiteral("document-open-recent-symbolic")); + + setDefaultMetadataItemForGroup(RecentlySavedType); + + // Move The recently used below the trash, making it the first element in the Recent group + KBookmark trashBookmark = bookmarkForUrl(QUrl("trash:/")); + if (!trashBookmark.isNull()) { + root.moveBookmark(recentlyusedBookmark, trashBookmark); + } + + d->bookmarkManager->save(); + } + // if baloo is enabled, add new urls even if the bookmark file is not empty if (d->fileIndexingEnabled && root.metaDataItem(QStringLiteral("withBaloo")) != QLatin1String("true")) { root.setMetaDataItem(QStringLiteral("withBaloo"), QStringLiteral("true")); KFilePlacesItem::createSystemBookmark(d->bookmarkManager, - QStringLiteral("Today"), I18N_NOOP2("KFile System Bookmarks", "Today"), + QStringLiteral("Modified Today"), I18N_NOOP2("KFile System Bookmarks", "Today"), QUrl(QStringLiteral("timeline:/today")), QStringLiteral("go-jump-today")); KFilePlacesItem::createSystemBookmark(d->bookmarkManager, - QStringLiteral("Yesterday"), I18N_NOOP2("KFile System Bookmarks", "Yesterday"), + QStringLiteral("Modified Yesterday"), I18N_NOOP2("KFile System Bookmarks", "Yesterday"), QUrl(QStringLiteral("timeline:/yesterday")), QStringLiteral("view-calendar-day")); KFilePlacesItem::createSystemBookmark(d->bookmarkManager, QStringLiteral("Documents"), I18N_NOOP2("KFile System Bookmarks", "Documents"),