Mercurial > hg > svcore
changeset 1704:452b48b29c2d single-point
Associate a label with each recent files entry, as well as the identifier (filename)
author | Chris Cannam |
---|---|
date | Mon, 13 May 2019 15:43:23 +0100 |
parents | b17fb3a4560c |
children | 28f9ff7864c6 |
files | base/RecentFiles.cpp base/RecentFiles.h |
diffstat | 2 files changed, 156 insertions(+), 67 deletions(-) [+] |
line wrap: on
line diff
--- a/base/RecentFiles.cpp Thu May 09 16:01:04 2019 +0100 +++ b/base/RecentFiles.cpp Mon May 13 15:43:23 2019 +0100 @@ -20,6 +20,7 @@ #include <QFileInfo> #include <QSettings> #include <QRegExp> +#include <QMutexLocker> RecentFiles::RecentFiles(QString settingsGroup, int maxCount) : m_settingsGroup(settingsGroup), @@ -36,16 +37,26 @@ void RecentFiles::read() { - m_names.clear(); + // Private method - called only from constructor - no mutex lock required + + m_entries.clear(); QSettings settings; settings.beginGroup(m_settingsGroup); for (int i = 0; i < 100; ++i) { - QString key = QString("recent-%1").arg(i); - QString name = settings.value(key, "").toString(); - if (name == "") break; - if (i < m_maxCount) m_names.push_back(name); - else settings.setValue(key, ""); + + QString idKey = QString("recent-%1").arg(i); + QString identifier = settings.value(idKey, "").toString(); + if (identifier == "") break; + + QString labelKey = QString("recent-%1-label").arg(i); + QString label = settings.value(labelKey, "").toString(); + + if (i < m_maxCount) m_entries.push_back({ identifier, label }); + else { + settings.setValue(idKey, ""); + settings.setValue(labelKey, ""); + } } settings.endGroup(); @@ -54,14 +65,22 @@ void RecentFiles::write() { + // Private method - must be serialised at call site + QSettings settings; settings.beginGroup(m_settingsGroup); for (int i = 0; i < m_maxCount; ++i) { - QString key = QString("recent-%1").arg(i); - QString name = ""; - if (i < (int)m_names.size()) name = m_names[i]; - settings.setValue(key, name); + QString idKey = QString("recent-%1").arg(i); + QString labelKey = QString("recent-%1-label").arg(i); + QString identifier; + QString label; + if (in_range_for(m_entries, i)) { + identifier = m_entries[i].first; + label = m_entries[i].second; + } + settings.setValue(idKey, identifier); + settings.setValue(labelKey, label); } settings.endGroup(); @@ -70,67 +89,92 @@ void RecentFiles::truncateAndWrite() { - while (int(m_names.size()) > m_maxCount) { - m_names.pop_back(); + // Private method - must be serialised at call site + + while (int(m_entries.size()) > m_maxCount) { + m_entries.pop_back(); } write(); } std::vector<QString> -RecentFiles::getRecent() const +RecentFiles::getRecentIdentifiers() const { - std::vector<QString> names; + QMutexLocker locker(&m_mutex); + + std::vector<QString> identifiers; for (int i = 0; i < m_maxCount; ++i) { - if (i < (int)m_names.size()) { - names.push_back(m_names[i]); + if (i < (int)m_entries.size()) { + identifiers.push_back(m_entries[i].first); } } - return names; + + return identifiers; +} + +std::vector<std::pair<QString, QString>> +RecentFiles::getRecentEntries() const +{ + QMutexLocker locker(&m_mutex); + + std::vector<std::pair<QString, QString>> entries; + for (int i = 0; i < m_maxCount; ++i) { + if (i < (int)m_entries.size()) { + entries.push_back(m_entries[i]); + } + } + + return entries; } void -RecentFiles::add(QString name) +RecentFiles::add(QString identifier, QString label) { - bool have = false; - for (int i = 0; i < int(m_names.size()); ++i) { - if (m_names[i] == name) { - have = true; - break; + { + QMutexLocker locker(&m_mutex); + + bool have = false; + for (int i = 0; i < int(m_entries.size()); ++i) { + if (m_entries[i].first == identifier) { + have = true; + break; + } } + + if (!have) { + m_entries.push_front({ identifier, label }); + } else { + std::deque<std::pair<QString, QString>> newEntries; + newEntries.push_back({ identifier, label }); + for (int i = 0; in_range_for(m_entries, i); ++i) { + if (m_entries[i].first == identifier) continue; + newEntries.push_back(m_entries[i]); + } + m_entries = newEntries; + } + + truncateAndWrite(); } - if (!have) { - m_names.push_front(name); - } else { - std::deque<QString> newnames; - newnames.push_back(name); - for (int i = 0; i < int(m_names.size()); ++i) { - if (m_names[i] == name) continue; - newnames.push_back(m_names[i]); - } - m_names = newnames; - } - - truncateAndWrite(); emit recentChanged(); } void -RecentFiles::addFile(QString name) +RecentFiles::addFile(QString filepath, QString label) { static QRegExp schemeRE("^[a-zA-Z]{2,5}://"); static QRegExp tempRE("[\\/][Tt]e?mp[\\/]"); - if (schemeRE.indexIn(name) == 0) { - add(name); + if (schemeRE.indexIn(filepath) == 0) { + add(filepath, label); } else { - QString absPath = QFileInfo(name).absoluteFilePath(); + QString absPath = QFileInfo(filepath).absoluteFilePath(); if (tempRE.indexIn(absPath) != -1) { Preferences *prefs = Preferences::getInstance(); if (prefs && !prefs->getOmitTempsFromRecentFiles()) { - add(absPath); + add(absPath, label); } } else { - add(absPath); + add(absPath, label); } } }
--- a/base/RecentFiles.h Thu May 09 16:01:04 2019 +0100 +++ b/base/RecentFiles.h Mon May 13 15:43:23 2019 +0100 @@ -18,15 +18,21 @@ #include <QObject> #include <QString> +#include <QMutex> #include <vector> #include <deque> /** - * RecentFiles manages a list of the names of recently-used objects, - * saving and restoring that list via QSettings. The names do not - * actually have to refer to files. + * RecentFiles manages a list of recently-used identifier strings, + * saving and restoring that list via QSettings. The identifiers do + * not actually have to refer to files. + * + * Each entry must have a non-empty identifier, which is typically a + * filename, path, URI, or internal id, and may optionally also have a + * label, which is typically a user-visible convenience. + * + * RecentFiles is thread-safe - all access is serialised. */ - class RecentFiles : public QObject { Q_OBJECT @@ -35,42 +41,81 @@ /** * Construct a RecentFiles object that saves and restores in the * given QSettings group and truncates when the given count of - * strings is reached. + * identifiers is reached. */ - RecentFiles(QString settingsGroup = "RecentFiles", int maxCount = 10); + RecentFiles(QString settingsGroup = "RecentFiles", + int maxCount = 10); virtual ~RecentFiles(); - QString getSettingsGroup() const { return m_settingsGroup; } - - int getMaxCount() const { return m_maxCount; } - - std::vector<QString> getRecent() const; + /** + * Return the settingsGroup as passed to the constructor. + */ + QString getSettingsGroup() const { + return m_settingsGroup; + } /** - * Add a name that should be treated as a literal string. + * Return the maxCount as passed to the constructor. */ - void add(QString name); + int getMaxCount() const { + return m_maxCount; + } + + /** + * Return the list of recent identifiers, without labels. + */ + std::vector<QString> getRecentIdentifiers() const; + + /** + * Return the list of recent identifiers, without labels. This is + * an alias for getRecentIdentifiers included for backward + * compatibility. + */ + std::vector<QString> getRecent() const { + return getRecentIdentifiers(); + } + + /** + * Return the list of recent identifiers, with labels. Each + * returned entry is a pair of identifier and label in that order. + */ + std::vector<std::pair<QString, QString>> getRecentEntries() const; /** - * Add a name that is known to be either a file path or a URL. If - * it looks like a URL, add it literally; otherwise treat it as a - * file path and canonicalise it appropriately. Also takes into - * account the user preference for whether to include temporary - * files in the recent files menu: the file will not be added if - * the preference is set and the file appears to be a temporary - * one. + * Add a literal identifier, optionally with a label. + * + * If the identifier already exists in the recent entries list, it + * is moved to the front of the list and its label is replaced + * with the given one. */ - void addFile(QString name); + void add(QString identifier, QString label = ""); + + /** + * Add a name that is known to be either a file path or a URL, + * optionally with a label. If it looks like a URL, add it + * literally; otherwise treat it as a file path and canonicalise + * it appropriately. Also take into account the user preference + * for whether to include temporary files in the recent files + * menu: the file will not be added if the preference is set and + * the file appears to be a temporary one. + * + * If the identifier derived from the file path already exists in + * the recent entries list, it is moved to the front of the list + * and its label is replaced with the given one. + */ + void addFile(QString filepath, QString label = ""); signals: void recentChanged(); -protected: - QString m_settingsGroup; - int m_maxCount; +private: + mutable QMutex m_mutex; - std::deque<QString> m_names; + const QString m_settingsGroup; + const int m_maxCount; + + std::deque<std::pair<QString, QString>> m_entries; // identifier, label void read(); void write();