File indexing completed on 2024-05-12 17:07:08
0001 /* 0002 This file is part of the KDE Baloo Project 0003 SPDX-FileCopyrightText: 2014 Vishesh Handa <me@vhanda.in> 0004 SPDX-FileCopyrightText: 2019 Tomaz Canabrava <tcanabrava@kde.org> 0005 SPDX-FileCopyrightText: 2020 Benjamin Port <benjamin.port@enioka.com> 0006 0007 SPDX-License-Identifier: LGPL-2.1-or-later 0008 0009 */ 0010 0011 #include "filteredfoldermodel.h" 0012 0013 #include <QIcon> 0014 0015 #include <KLocalizedString> 0016 #include <QDir> 0017 #include <QStringList> 0018 #include <QTimer> 0019 #include <QUrl> 0020 0021 #include "baloo/baloosettings.h" 0022 0023 namespace 0024 { 0025 QString normalizeTrailingSlashes(QString &&input) 0026 { 0027 if (!input.endsWith('/')) 0028 return input + QLatin1Char('/'); 0029 return input; 0030 } 0031 0032 QStringList addTrailingSlashes(QStringList &&list) 0033 { 0034 for (QString &str : list) { 0035 str = normalizeTrailingSlashes(std::move(str)); 0036 } 0037 return list; 0038 } 0039 0040 QString makeHomePretty(const QString &url) 0041 { 0042 if (url.startsWith(QDir::homePath())) 0043 return QString(url).replace(0, QDir::homePath().length(), QStringLiteral("~")); 0044 return url; 0045 } 0046 } 0047 0048 FilteredFolderModel::FilteredFolderModel(BalooSettings *settings, QObject *parent) 0049 : QAbstractListModel(parent) 0050 , m_settings(settings) 0051 { 0052 } 0053 0054 void FilteredFolderModel::updateDirectoryList() 0055 { 0056 beginResetModel(); 0057 0058 const QStringList runtimeExcluded = m_runtimeConfig.excludeFolders(); 0059 0060 QStringList settingsIncluded = addTrailingSlashes(m_settings->folders()); 0061 QStringList settingsExcluded = addTrailingSlashes(m_settings->excludedFolders()); 0062 0063 const QString homePath = normalizeTrailingSlashes(QDir::homePath()); 0064 0065 auto folderListEntry = [&homePath](const QString &url, bool include, bool fromConfig) { 0066 QString displayName = url; 0067 if (displayName.size() > 1) { 0068 displayName.chop(1); 0069 } 0070 if (displayName.startsWith(homePath)) { 0071 displayName.replace(0, homePath.length(), QStringLiteral("~/")); 0072 } 0073 0074 QString icon = QStringLiteral("folder"); 0075 if (url == homePath) { 0076 icon = QStringLiteral("user-home"); 0077 } else if (!fromConfig) { 0078 icon = QStringLiteral("drive-harddisk"); 0079 } 0080 0081 return FolderInfo{url, displayName, icon, include, fromConfig}; 0082 }; 0083 m_folderList.clear(); 0084 0085 for (const QString &folder : settingsIncluded) { 0086 m_folderList.append(folderListEntry(folder, true, true)); 0087 } 0088 for (const QString &folder : settingsExcluded) { 0089 m_folderList.append(folderListEntry(folder, false, true)); 0090 } 0091 0092 // Add any automatically excluded mounts to the list 0093 for (const QString &folder : runtimeExcluded) { 0094 if (settingsIncluded.contains(folder) || settingsExcluded.contains(folder)) { 0095 // Do not add any duplicates 0096 continue; 0097 } 0098 if (m_deletedSettings.contains(folder)) { 0099 // Skip entries deleted from the config 0100 continue; 0101 } 0102 m_folderList.append(folderListEntry(folder, false, false)); 0103 } 0104 0105 std::sort(m_folderList.begin(), m_folderList.end(), [](const FolderInfo &a, const FolderInfo &b) { 0106 return a.url < b.url; 0107 }); 0108 0109 endResetModel(); 0110 } 0111 0112 QVariant FilteredFolderModel::data(const QModelIndex &idx, int role) const 0113 { 0114 if (!idx.isValid() || idx.row() >= m_folderList.size()) { 0115 return {}; 0116 } 0117 0118 const auto entry = m_folderList.at(idx.row()); 0119 switch (role) { 0120 case Qt::DisplayRole: 0121 return entry.displayName; 0122 case Qt::WhatsThisRole: 0123 return entry.url; 0124 case Qt::DecorationRole: 0125 return entry.icon; 0126 case Qt::ToolTipRole: 0127 return makeHomePretty(entry.url); 0128 case Url: 0129 return entry.url; 0130 case Folder: 0131 return entry.displayName; 0132 case EnableIndex: 0133 return entry.enableIndex; 0134 case Deletable: 0135 return entry.isFromConfig && entry.url != normalizeTrailingSlashes(QDir::homePath()); 0136 default: 0137 return {}; 0138 } 0139 } 0140 0141 bool FilteredFolderModel::setData(const QModelIndex &idx, const QVariant &value, int role) 0142 { 0143 if (!idx.isValid() || idx.row() >= m_folderList.size()) { 0144 return false; 0145 } 0146 FolderInfo &entry = m_folderList[idx.row()]; 0147 if (role == EnableIndex) { 0148 entry.enableIndex = value.toBool(); 0149 syncFolderConfig(entry); 0150 Q_EMIT dataChanged(idx, idx); 0151 return true; 0152 } 0153 return false; 0154 } 0155 0156 int FilteredFolderModel::rowCount(const QModelIndex &parent) const 0157 { 0158 Q_UNUSED(parent); 0159 return m_folderList.count(); 0160 } 0161 0162 void FilteredFolderModel::addFolder(const QString &url, const bool included = false) 0163 { 0164 QString nUrl = normalizeTrailingSlashes(QUrl(url).toLocalFile()); 0165 0166 auto it = std::find_if(m_folderList.begin(), m_folderList.end(), [nUrl](const FolderInfo &folder) { 0167 return folder.url == nUrl; 0168 }); 0169 if (it != m_folderList.end() && (*it).isFromConfig) { 0170 return; 0171 } 0172 if (included) { 0173 auto included = addTrailingSlashes(m_settings->folders()); 0174 included.append(nUrl); 0175 std::sort(std::begin(included), std::end(included)); 0176 m_settings->setFolders(included); 0177 } else { 0178 auto excluded = addTrailingSlashes(m_settings->excludedFolders()); 0179 excluded.append(nUrl); 0180 std::sort(std::begin(excluded), std::end(excluded)); 0181 m_settings->setExcludedFolders(excluded); 0182 } 0183 m_deletedSettings.removeAll(nUrl); 0184 } 0185 0186 void FilteredFolderModel::removeFolder(int row) 0187 { 0188 auto entry = m_folderList.at(row); 0189 if (!entry.isFromConfig) { 0190 return; 0191 } 0192 if (!entry.enableIndex) { 0193 auto excluded = addTrailingSlashes(m_settings->excludedFolders()); 0194 excluded.removeAll(entry.url); 0195 std::sort(std::begin(excluded), std::end(excluded)); 0196 m_settings->setExcludedFolders(excluded); 0197 } else { 0198 auto included = addTrailingSlashes(m_settings->folders()); 0199 included.removeAll(entry.url); 0200 std::sort(std::begin(included), std::end(included)); 0201 m_settings->setFolders(included); 0202 } 0203 m_deletedSettings.append(entry.url); 0204 } 0205 0206 void FilteredFolderModel::syncFolderConfig(const FolderInfo &entry) 0207 { 0208 auto excluded = addTrailingSlashes(m_settings->excludedFolders()); 0209 auto included = addTrailingSlashes(m_settings->folders()); 0210 if (entry.enableIndex) { 0211 included.append(entry.url); 0212 std::sort(std::begin(included), std::end(included)); 0213 if (excluded.removeAll(entry.url)) { 0214 std::sort(std::begin(excluded), std::end(excluded)); 0215 m_settings->setExcludedFolders(excluded); 0216 } 0217 m_settings->setFolders(included); 0218 } else { 0219 excluded.append(entry.url); 0220 std::sort(std::begin(excluded), std::end(excluded)); 0221 if (included.removeAll(entry.url)) { 0222 std::sort(std::begin(included), std::end(included)); 0223 m_settings->setFolders(included); 0224 } 0225 m_settings->setExcludedFolders(excluded); 0226 } 0227 } 0228 0229 QHash<int, QByteArray> FilteredFolderModel::roleNames() const 0230 { 0231 return {{Url, "url"}, // 0232 {Folder, "folder"}, 0233 {EnableIndex, "enableIndex"}, 0234 {Deletable, "deletable"}, 0235 {Qt::DecorationRole, "decoration"}}; 0236 }