Refactor Locator filter settings saving

Unify setting saving. Do not write settings that stay at the default, so
defaults could change and take effect.

For this we explicitly differentiate between default and user settings.
Make QJsonDocument the basis for saving settings, because QDataStream
cannot really handle structured data where parts could be missing.

Write locator settings to a different settings group, so we do not
destroy reading older settings from older Qt Creator versions.

Task-number: QTCREATORBUG-24762
Change-Id: I5909e2d79313f6fc26159bb644fdfb43781b6c38
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Eike Ziller
2021-01-26 16:31:12 +01:00
parent b47a80c5ce
commit cb96b91dd4
37 changed files with 398 additions and 201 deletions

View File

@@ -40,7 +40,7 @@ BookmarkFilter::BookmarkFilter(BookmarkManager *manager)
setId("Bookmarks");
setDisplayName(tr("Bookmarks"));
setPriority(Medium);
setShortcutString("b");
setDefaultShortcutString("b");
}
void BookmarkFilter::prepareSearch(const QString &entry)

View File

@@ -56,9 +56,9 @@ ClangCurrentDocumentFilter::ClangCurrentDocumentFilter()
{
setId(CppTools::Constants::CURRENT_DOCUMENT_FILTER_ID);
setDisplayName(CppTools::Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME);
setShortcutString(QString(QLatin1Char('.')));
setDefaultShortcutString(".");
setPriority(High);
setIncludedByDefault(false);
setDefaultIncludedByDefault(false);
Core::EditorManager *editorManager = Core::EditorManager::instance();
connect(editorManager, &Core::EditorManager::currentEditorChanged,

View File

@@ -49,8 +49,8 @@ public:
{
setId(id);
setDisplayName(displayName);
setShortcutString(shortCut);
setIncludedByDefault(includedByDefault);
setDefaultShortcutString(shortCut);
setDefaultIncludedByDefault(includedByDefault);
}
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,

View File

@@ -121,7 +121,7 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter()
{
setId("Build CMake target");
setDisplayName(tr("Build CMake target"));
setShortcutString("cm");
setDefaultShortcutString("cm");
setPriority(High);
}
@@ -170,7 +170,7 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter()
{
setId("Open CMake target definition");
setDisplayName(tr("Open CMake target"));
setShortcutString("cmo");
setDefaultShortcutString("cmo");
setPriority(Medium);
}

View File

@@ -57,7 +57,7 @@ CommandLocator::CommandLocator(Id id,
{
setId(id);
setDisplayName(displayName);
setShortcutString(shortCutString);
setDefaultShortcutString(shortCutString);
}
CommandLocator::~CommandLocator()

View File

@@ -33,6 +33,8 @@
#include <utils/filesearch.h>
#include <QFileDialog>
#include <QJsonArray>
#include <QJsonObject>
using namespace Utils;
@@ -44,32 +46,70 @@ namespace Core {
\internal
*/
DirectoryFilter::DirectoryFilter(Id id)
: m_filters({"*.h", "*.cpp", "*.ui", "*.qrc"}),
m_exclusionFilters({"*/.git/*", "*/.cvs/*", "*/.svn/*"})
const char kDisplayNameKey[] = "displayName";
const char kDirectoriesKey[] = "directories";
const char kFiltersKey[] = "filters";
const char kFilesKey[] = "files";
const char kExclusionFiltersKey[] = "exclusionFilters";
const QStringList kFiltersDefault = {"*.h", "*.cpp", "*.ui", "*.qrc"};
const QStringList kExclusionFiltersDefault = {"*/.git/*", "*/.cvs/*", "*/.svn/*"};
static QString defaultDisplayName()
{
setId(id);
setIncludedByDefault(true);
setDisplayName(tr("Generic Directory Filter"));
return DirectoryFilter::tr("Generic Directory Filter");
}
QByteArray DirectoryFilter::saveState() const
DirectoryFilter::DirectoryFilter(Id id)
: m_filters(kFiltersDefault)
, m_exclusionFilters(kExclusionFiltersDefault)
{
setId(id);
setDefaultIncludedByDefault(true);
setDisplayName(defaultDisplayName());
}
void DirectoryFilter::saveState(QJsonObject &object) const
{
QMutexLocker locker(&m_lock); // m_files is modified in other thread
if (displayName() != defaultDisplayName())
object.insert(kDisplayNameKey, displayName());
if (!m_directories.isEmpty())
object.insert(kDirectoriesKey, QJsonArray::fromStringList(m_directories));
if (m_filters != kFiltersDefault)
object.insert(kFiltersKey, QJsonArray::fromStringList(m_filters));
if (!m_files.isEmpty())
object.insert(kFilesKey,
QJsonArray::fromStringList(
Utils::transform(m_files, &Utils::FilePath::toString)));
if (m_exclusionFilters != kExclusionFiltersDefault)
object.insert(kExclusionFiltersKey, QJsonArray::fromStringList(m_exclusionFilters));
}
static QStringList toStringList(const QJsonArray &array)
{
return Utils::transform(array.toVariantList(), &QVariant::toString);
}
void DirectoryFilter::restoreState(const QJsonObject &object)
{
QMutexLocker locker(&m_lock);
QByteArray value;
QDataStream out(&value, QIODevice::WriteOnly);
out << displayName();
out << m_directories;
out << m_filters;
out << shortcutString();
out << isIncludedByDefault();
out << Utils::transform(m_files, &Utils::FilePath::toString);
out << m_exclusionFilters;
return value;
setDisplayName(object.value(kDisplayNameKey).toString(defaultDisplayName()));
m_directories = toStringList(object.value(kDirectoriesKey).toArray());
m_filters = toStringList(
object.value(kFiltersKey).toArray(QJsonArray::fromStringList(kFiltersDefault)));
m_files = Utils::transform(toStringList(object.value(kFilesKey).toArray()),
&FilePath::fromString);
m_exclusionFilters = toStringList(
object.value(kExclusionFiltersKey)
.toArray(QJsonArray::fromStringList(kExclusionFiltersDefault)));
}
void DirectoryFilter::restoreState(const QByteArray &state)
{
if (isOldSetting(state)) {
// TODO read old settings, remove some time after Qt Creator 4.15
QMutexLocker locker(&m_lock);
QString name;
@@ -99,6 +139,9 @@ void DirectoryFilter::restoreState(const QByteArray &state)
locker.unlock();
updateFileIterator();
} else {
ILocatorFilter::restoreState(state);
}
}
bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)

View File

@@ -47,7 +47,6 @@ class CORE_EXPORT DirectoryFilter : public BaseFileFilter
public:
DirectoryFilter(Utils::Id id);
QByteArray saveState() const override;
void restoreState(const QByteArray &state) override;
bool openConfigDialog(QWidget *parent, bool &needsRefresh) override;
void refresh(QFutureInterface<void> &future) override;
@@ -60,7 +59,9 @@ public:
void setFilters(const QStringList &filters);
void setExclusionFilters(const QStringList &exclusionFilters);
using ILocatorFilter::setDisplayName;
protected:
void saveState(QJsonObject &object) const final;
void restoreState(const QJsonObject &object) final;
private:
void handleAddDirectory();

View File

@@ -38,9 +38,9 @@ ExecuteFilter::ExecuteFilter()
{
setId("Execute custom commands");
setDisplayName(tr("Execute Custom Commands"));
setShortcutString("!");
setDefaultShortcutString("!");
setPriority(High);
setIncludedByDefault(false);
setDefaultIncludedByDefault(false);
m_process = new Utils::QtcProcess(this);
m_process->setEnvironment(Utils::Environment::systemEnvironment());

View File

@@ -37,7 +37,7 @@ ExternalToolsFilter::ExternalToolsFilter()
{
setId("Run external tool");
setDisplayName(tr("Run External Tool"));
setShortcutString("x");
setDefaultShortcutString("x");
setPriority(Medium);
}

View File

@@ -38,6 +38,7 @@
#include <utils/fileutils.h>
#include <QDir>
#include <QJsonObject>
#include <QPushButton>
#include <QRegularExpression>
@@ -65,8 +66,8 @@ FileSystemFilter::FileSystemFilter()
{
setId("Files in file system");
setDisplayName(tr("Files in File System"));
setShortcutString("f");
setIncludedByDefault(false);
setDefaultShortcutString("f");
setDefaultIncludedByDefault(false);
}
void FileSystemFilter::prepareSearch(const QString &entry)
@@ -235,18 +236,23 @@ bool FileSystemFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
return false;
}
QByteArray FileSystemFilter::saveState() const
const char kIncludeHiddenKey[] = "includeHidden";
void FileSystemFilter::saveState(QJsonObject &object) const
{
QByteArray value;
QDataStream out(&value, QIODevice::WriteOnly);
out << m_includeHidden;
out << shortcutString();
out << isIncludedByDefault();
return value;
if (m_includeHidden != kIncludeHiddenDefault)
object.insert(kIncludeHiddenKey, m_includeHidden);
}
void FileSystemFilter::restoreState(const QJsonObject &object)
{
m_currentIncludeHidden = object.value(kIncludeHiddenKey).toBool(kIncludeHiddenDefault);
}
void FileSystemFilter::restoreState(const QByteArray &state)
{
if (isOldSetting(state)) {
// TODO read old settings, remove some time after Qt Creator 4.15
QDataStream in(state);
in >> m_includeHidden;
@@ -259,4 +265,7 @@ void FileSystemFilter::restoreState(const QByteArray &state)
setShortcutString(shortcut);
setIncludedByDefault(defaultFilter);
}
} else {
ILocatorFilter::restoreState(state);
}
}

View File

@@ -47,16 +47,20 @@ public:
const QString &entry) override;
void accept(LocatorFilterEntry selection,
QString *newText, int *selectionStart, int *selectionLength) const override;
QByteArray saveState() const override;
void restoreState(const QByteArray &state) override;
bool openConfigDialog(QWidget *parent, bool &needsRefresh) override;
void refresh(QFutureInterface<void> &) override {}
protected:
void saveState(QJsonObject &object) const final;
void restoreState(const QJsonObject &object) final;
private:
static MatchLevel matchLevelFor(const QRegularExpressionMatch &match, const QString &matchText);
bool m_includeHidden = true;
bool m_currentIncludeHidden = true;
static const bool kIncludeHiddenDefault = true;
bool m_includeHidden = kIncludeHiddenDefault;
bool m_currentIncludeHidden = kIncludeHiddenDefault;
QString m_currentDocumentDirectory;
};

View File

@@ -33,6 +33,8 @@
#include <QCoreApplication>
#include <QDialog>
#include <QDialogButtonBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLabel>
#include <QLineEdit>
#include <QRegularExpression>
@@ -117,32 +119,55 @@ void ILocatorFilter::prepareSearch(const QString &entry)
}
/*!
Sets the \a shortcut string that can be used to explicitly choose this
filter in the locator input field. Call from the constructor of subclasses
to set the default setting.
Sets the default \a shortcut string that can be used to explicitly choose
this filter in the locator input field. Call for example from the
constructor of subclasses.
\sa shortcutString()
*/
void ILocatorFilter::setDefaultShortcutString(const QString &shortcut)
{
m_defaultShortcut = shortcut;
m_shortcut = shortcut;
}
/*!
Sets the current shortcut string of the filter to \a shortcut. Use
setDefaultShortcutString() if you want to set the default shortcut string
instead.
\sa setDefaultShortcutString()
*/
void ILocatorFilter::setShortcutString(const QString &shortcut)
{
m_shortcut = shortcut;
}
const char kShortcutStringKey[] = "shortcut";
const char kIncludedByDefaultKey[] = "includeByDefault";
/*!
Returns data that can be used to restore the settings for this filter
(for example at startup).
By default, adds the base settings (shortcut string, included by default)
with a data stream.
and calls saveState() with a JSON object where subclasses should write
their custom settings.
\sa restoreState()
*/
QByteArray ILocatorFilter::saveState() const
{
QByteArray value;
QDataStream out(&value, QIODevice::WriteOnly);
out << shortcutString();
out << isIncludedByDefault();
return value;
QJsonObject obj;
if (shortcutString() != m_defaultShortcut)
obj.insert(kShortcutStringKey, shortcutString());
if (isIncludedByDefault() != m_defaultIncludedByDefault)
obj.insert(kIncludedByDefaultKey, isIncludedByDefault());
saveState(obj);
if (obj.isEmpty())
return {};
QJsonDocument doc;
doc.setObject(obj);
return doc.toJson(QJsonDocument::Compact);
}
/*!
@@ -153,15 +178,22 @@ QByteArray ILocatorFilter::saveState() const
*/
void ILocatorFilter::restoreState(const QByteArray &state)
{
QString shortcut;
bool defaultFilter;
QJsonDocument doc = QJsonDocument::fromJson(state);
if (state.isEmpty() || doc.isObject()) {
const QJsonObject obj = doc.object();
setShortcutString(obj.value(kShortcutStringKey).toString(m_defaultShortcut));
setIncludedByDefault(obj.value(kIncludedByDefaultKey).toBool(m_defaultIncludedByDefault));
restoreState(obj);
} else {
// TODO read old settings, remove some time after Qt Creator 4.15
m_shortcut = m_defaultShortcut;
m_includedByDefault = m_defaultIncludedByDefault;
// TODO this reads legacy settings from Qt Creator < 4.15
QDataStream in(state);
in >> shortcut;
in >> defaultFilter;
setShortcutString(shortcut);
setIncludedByDefault(defaultFilter);
in >> m_shortcut;
in >> m_includedByDefault;
}
}
/*!
@@ -281,13 +313,26 @@ bool ILocatorFilter::isIncludedByDefault() const
}
/*!
Sets whether using the shortcut string is required to use this filter
to \a includedByDefault.
Sets the default setting for whether using the shortcut string is required
to use this filter to \a includedByDefault.
Call from the constructor of subclasses to change the default.
Call for example from the constructor of subclasses.
\sa isIncludedByDefault()
*/
void ILocatorFilter::setDefaultIncludedByDefault(bool includedByDefault)
{
m_defaultIncludedByDefault = includedByDefault;
m_includedByDefault = includedByDefault;
}
/*!
Sets whether using the shortcut string is required to use this filter to
\a includedByDefault. Use setDefaultIncludedByDefault() if you want to
set the default value instead.
\sa setDefaultIncludedByDefault()
*/
void ILocatorFilter::setIncludedByDefault(bool includedByDefault)
{
m_includedByDefault = includedByDefault;
@@ -402,7 +447,8 @@ void ILocatorFilter::setPriority(Priority priority)
}
/*!
Sets the translated display name of this filter to \a displayString.
Sets the translated display name of this filter to \a
displayString.
Subclasses must set the display name in their constructor.
@@ -474,6 +520,44 @@ bool ILocatorFilter::openConfigDialog(QWidget *parent, QWidget *additionalWidget
return accepted;
}
/*!
Saves the filter settings and state to the JSON \a object.
The default implementation does nothing.
Implementations should write key-value pairs to the \a object for their
custom settings that changed from the default. Default values should
never be saved.
*/
void ILocatorFilter::saveState(QJsonObject &object) const
{
Q_UNUSED(object)
}
/*!
Reads the filter settings and state from the JSON \a object
The default implementation does nothing.
Implementations should read their custom settings from the \a object,
resetting any missing setting to its default value.
*/
void ILocatorFilter::restoreState(const QJsonObject &object)
{
Q_UNUSED(object)
}
/*!
Returns if \a state must be restored via pre-4.15 settings reading.
*/
bool ILocatorFilter::isOldSetting(const QByteArray &state)
{
if (state.isEmpty())
return false;
const QJsonDocument doc = QJsonDocument::fromJson(state);
return !doc.isObject();
}
/*!
\fn QList<Core::LocatorFilterEntry> Core::ILocatorFilter::matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)

View File

@@ -125,10 +125,12 @@ public:
Utils::Id actionId() const;
QString displayName() const;
void setDisplayName(const QString &displayString);
Priority priority() const;
QString shortcutString() const;
void setDefaultShortcutString(const QString &shortcut);
void setShortcutString(const QString &shortcut);
virtual void prepareSearch(const QString &entry);
@@ -147,6 +149,7 @@ public:
bool isConfigurable() const;
bool isIncludedByDefault() const;
void setDefaultIncludedByDefault(bool includedByDefault);
void setIncludedByDefault(bool includedByDefault);
bool isHidden() const;
@@ -172,16 +175,22 @@ protected:
void setHidden(bool hidden);
void setId(Utils::Id id);
void setPriority(Priority priority);
void setDisplayName(const QString &displayString);
void setConfigurable(bool configurable);
bool openConfigDialog(QWidget *parent, QWidget *additionalWidget);
virtual void saveState(QJsonObject &object) const;
virtual void restoreState(const QJsonObject &object);
static bool isOldSetting(const QByteArray &state);
private:
Utils::Id m_id;
QString m_shortcut;
Priority m_priority = Medium;
QString m_displayName;
bool m_includedByDefault = false;
QString m_defaultShortcut;
bool m_defaultIncludedByDefault = false;
bool m_includedByDefault = m_defaultIncludedByDefault;
bool m_hidden = false;
bool m_enabled = true;
bool m_isConfigurable = true;

View File

@@ -38,8 +38,8 @@ JavaScriptFilter::JavaScriptFilter()
{
setId("JavaScriptFilter");
setDisplayName(tr("Evaluate JavaScript"));
setIncludedByDefault(false);
setShortcutString("=");
setDefaultIncludedByDefault(false);
setDefaultShortcutString("=");
m_abortTimer.setSingleShot(true);
m_abortTimer.setInterval(1000);
connect(&m_abortTimer, &QTimer::timeout, this, [this] {

View File

@@ -92,7 +92,7 @@ public:
LocatorData::LocatorData()
{
m_urlFilter.setShortcutString("r");
m_urlFilter.setDefaultShortcutString("r");
m_urlFilter.addDefaultUrl("https://www.bing.com/search?q=%1");
m_urlFilter.addDefaultUrl("https://www.google.com/search?q=%1");
m_urlFilter.addDefaultUrl("https://search.yahoo.com/search?p=%1");
@@ -101,7 +101,7 @@ LocatorData::LocatorData()
"http://en.cppreference.com/mwiki/index.php?title=Special%3ASearch&search=%1");
m_urlFilter.addDefaultUrl("https://en.wikipedia.org/w/index.php?search=%1");
m_bugFilter.setShortcutString("bug");
m_bugFilter.setDefaultShortcutString("bug");
m_bugFilter.addDefaultUrl("https://bugreports.qt.io/secure/QuickSearch.jspa?searchString=%1");
}
@@ -172,7 +172,11 @@ bool Locator::delayedInitialize()
void Locator::loadSettings()
{
SettingsDatabase *settings = ICore::settingsDatabase();
settings->beginGroup("QuickOpen");
// check if we have to read old settings
// TOOD remove a few versions after 4.15
const QString settingsGroup = settings->contains("Locator") ? QString("Locator")
: QString("QuickOpen");
settings->beginGroup(settingsGroup);
m_refreshTimer.setInterval(settings->value("RefreshInterval", 60).toInt() * 60000);
for (ILocatorFilter *filter : qAsConst(m_filters)) {
@@ -297,12 +301,14 @@ void Locator::saveSettings() const
SettingsDatabase *s = ICore::settingsDatabase();
s->beginTransaction();
s->beginGroup("QuickOpen");
s->beginGroup("Locator");
s->remove(QString());
s->setValue("RefreshInterval", refreshInterval());
for (ILocatorFilter *filter : m_filters) {
if (!m_customFilters.contains(filter))
s->setValue(filter->id().toString(), filter->saveState());
if (!m_customFilters.contains(filter)) {
const QByteArray state = filter->saveState();
s->setValueWithDefault(filter->id().toString(), state);
}
}
s->beginGroup("CustomFilters");
int i = 0;
@@ -311,7 +317,8 @@ void Locator::saveSettings() const
Constants::CUSTOM_DIRECTORY_FILTER_BASEID)
? kDirectoryFilterPrefix
: kUrlFilterPrefix;
s->setValue(prefix + QString::number(i), filter->saveState());
const QByteArray state = filter->saveState();
s->setValueWithDefault(prefix + QString::number(i), state);
++i;
}
s->endGroup();

View File

@@ -41,7 +41,7 @@ LocatorFiltersFilter::LocatorFiltersFilter():
{
setId("FiltersFilter");
setDisplayName(tr("Available filters"));
setIncludedByDefault(true);
setDefaultIncludedByDefault(true);
setHidden(true);
setPriority(Highest);
setConfigurable(false);

View File

@@ -42,9 +42,9 @@ OpenDocumentsFilter::OpenDocumentsFilter()
{
setId("Open documents");
setDisplayName(tr("Open Documents"));
setShortcutString("o");
setDefaultShortcutString("o");
setPriority(High);
setIncludedByDefault(true);
setDefaultIncludedByDefault(true);
connect(DocumentModel::model(), &QAbstractItemModel::dataChanged,
this, &OpenDocumentsFilter::refreshInternally);

View File

@@ -205,11 +205,6 @@ static QString defaultCaseSensitiveArguments()
return "-l 10000 -r \"%{Query:Regex}\"";
}
const char kShortcutStringDefault[] = "md";
const bool kIncludedByDefaultDefault = false;
const char kShortcutStringKey[] = "shortcut";
const char kIncludedByDefaultKey[] = "includeByDefault";
const char kCommandKey[] = "command";
const char kArgumentsKey[] = "arguments";
const char kCaseSensitiveKey[] = "caseSensitive";
@@ -244,6 +239,8 @@ static MacroExpander *createMacroExpander(const QString &query)
SpotlightLocatorFilter::SpotlightLocatorFilter()
{
setId("SpotlightFileNamesLocatorFilter");
setDefaultShortcutString("md");
setDefaultIncludedByDefault(false);
setDisplayName(tr("File Name Index"));
setConfigurable(true);
reset();
@@ -305,45 +302,25 @@ bool SpotlightLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefres
return accepted;
}
QByteArray SpotlightLocatorFilter::saveState() const
void SpotlightLocatorFilter::saveState(QJsonObject &obj) const
{
QJsonObject obj;
if (shortcutString() != kShortcutStringDefault)
obj.insert(kShortcutStringKey, shortcutString());
if (isIncludedByDefault() != kIncludedByDefaultDefault)
obj.insert(kIncludedByDefaultKey, isIncludedByDefault());
if (m_command != defaultCommand())
obj.insert(kCommandKey, m_command);
if (m_arguments != defaultArguments())
obj.insert(kArgumentsKey, m_arguments);
if (m_caseSensitiveArguments != defaultCaseSensitiveArguments())
obj.insert(kCaseSensitiveKey, m_caseSensitiveArguments);
QJsonDocument doc;
doc.setObject(obj);
return doc.toJson(QJsonDocument::Compact);
}
void SpotlightLocatorFilter::restoreState(const QByteArray &state)
void SpotlightLocatorFilter::restoreState(const QJsonObject &obj)
{
QJsonDocument doc = QJsonDocument::fromJson(state);
if (doc.isNull() || !doc.isObject()) {
reset();
ILocatorFilter::restoreState(state); // legacy settings from Qt Creator < 4.15
} else {
const QJsonObject obj = doc.object();
setShortcutString(obj.value(kShortcutStringKey).toString(kShortcutStringDefault));
setIncludedByDefault(obj.value(kIncludedByDefaultKey).toBool(kIncludedByDefaultDefault));
m_command = obj.value(kCommandKey).toString(defaultCommand());
m_arguments = obj.value(kArgumentsKey).toString(defaultArguments());
m_caseSensitiveArguments = obj.value(kCaseSensitiveKey)
.toString(defaultCaseSensitiveArguments());
}
m_caseSensitiveArguments = obj.value(kCaseSensitiveKey).toString(defaultCaseSensitiveArguments());
}
void SpotlightLocatorFilter::reset()
{
setShortcutString(kShortcutStringDefault);
setIncludedByDefault(kIncludedByDefaultDefault);
m_command = defaultCommand();
m_arguments = defaultArguments();
m_caseSensitiveArguments = defaultCaseSensitiveArguments();

View File

@@ -44,8 +44,9 @@ public:
using ILocatorFilter::openConfigDialog;
bool openConfigDialog(QWidget *parent, bool &needsRefresh) final;
QByteArray saveState() const final;
void restoreState(const QByteArray &state) final;
protected:
void saveState(QJsonObject &obj) const final;
void restoreState(const QJsonObject &obj) final;
private:
void reset();

View File

@@ -25,9 +25,12 @@
#include "urllocatorfilter.h"
#include <utils/algorithm.h>
#include <utils/stringutils.h>
#include <QDesktopServices>
#include <QJsonArray>
#include <QJsonObject>
#include <QMutexLocker>
#include <QUrl>
@@ -136,8 +139,9 @@ UrlLocatorFilter::UrlLocatorFilter(Id id)
UrlLocatorFilter::UrlLocatorFilter(const QString &displayName, Id id)
{
setId(id);
m_defaultDisplayName = displayName;
setDisplayName(displayName);
setIncludedByDefault(false);
setDefaultIncludedByDefault(false);
}
UrlLocatorFilter::~UrlLocatorFilter() = default;
@@ -177,19 +181,30 @@ void UrlLocatorFilter::refresh(QFutureInterface<void> &future)
// Nothing to refresh
}
QByteArray UrlLocatorFilter::saveState() const
const char kDisplayNameKey[] = "displayName";
const char kRemoteUrlsKey[] = "remoteUrls";
void UrlLocatorFilter::saveState(QJsonObject &object) const
{
QByteArray value;
QDataStream out(&value, QIODevice::WriteOnly);
out << m_remoteUrls.join('^');
out << shortcutString();
out << isIncludedByDefault();
out << displayName();
return value;
if (displayName() != m_defaultDisplayName)
object.insert(kDisplayNameKey, displayName());
if (m_remoteUrls != m_defaultUrls)
object.insert(kRemoteUrlsKey, QJsonArray::fromStringList(m_remoteUrls));
}
void UrlLocatorFilter::restoreState(const QJsonObject &object)
{
setDisplayName(object.value(kDisplayNameKey).toString(m_defaultDisplayName));
m_remoteUrls = Utils::transform(object.value(kRemoteUrlsKey)
.toArray(QJsonArray::fromStringList(m_defaultUrls))
.toVariantList(),
&QVariant::toString);
}
void UrlLocatorFilter::restoreState(const QByteArray &state)
{
if (isOldSetting(state)) {
// TODO read old settings, remove some time after Qt Creator 4.15
QDataStream in(state);
QString value;
@@ -209,6 +224,9 @@ void UrlLocatorFilter::restoreState(const QByteArray &state)
in >> name;
setDisplayName(name);
}
} else {
ILocatorFilter::restoreState(state);
}
}
bool UrlLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
@@ -232,6 +250,7 @@ bool UrlLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
void UrlLocatorFilter::addDefaultUrl(const QString &urlTemplate)
{
m_remoteUrls.append(urlTemplate);
m_defaultUrls.append(urlTemplate);
}
QStringList UrlLocatorFilter::remoteUrls() const

View File

@@ -49,7 +49,6 @@ public:
void accept(Core::LocatorFilterEntry selection,
QString *newText, int *selectionStart, int *selectionLength) const override;
void refresh(QFutureInterface<void> &future) override;
QByteArray saveState() const override;
void restoreState(const QByteArray &state) override;
bool openConfigDialog(QWidget *parent, bool &needsRefresh) override;
@@ -59,9 +58,13 @@ public:
void setIsCustomFilter(bool value);
bool isCustomFilter() const;
using ILocatorFilter::setDisplayName;
protected:
void saveState(QJsonObject &object) const final;
void restoreState(const QJsonObject &object) final;
private:
QString m_defaultDisplayName;
QStringList m_defaultUrls;
QStringList m_remoteUrls;
bool m_isCustomFilter = false;
mutable QMutex m_mutex;

View File

@@ -54,7 +54,7 @@ MenuBarFilter::MenuBarFilter()
{
setId("Actions from the menu");
setDisplayName(tr("Actions from the Menu"));
setShortcutString("t");
setDefaultShortcutString("t");
connect(ICore::instance(), &ICore::contextAboutToChange, this, [this] {
if (LocatorManager::locatorHasFocus())
updateEnabledActionCache();

View File

@@ -195,7 +195,21 @@ QVariant SettingsDatabase::value(const QString &key, const QVariant &defaultValu
bool SettingsDatabase::contains(const QString &key) const
{
return d->m_settings.contains(d->effectiveKey(key));
// check exact key
// this already caches the value
if (value(key).isValid())
return true;
// check for group
if (d->m_db.isOpen()) {
const QString glob = d->effectiveKey(key) + "/?*";
QSqlQuery query(d->m_db);
query.prepare(
QLatin1String("SELECT value FROM settings WHERE key GLOB '%1' LIMIT 1").arg(glob));
query.exec();
if (query.next())
return true;
}
return false;
}
void SettingsDatabase::remove(const QString &key)

View File

@@ -44,6 +44,12 @@ public:
void setValue(const QString &key, const QVariant &value);
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
template<typename T>
void setValueWithDefault(const QString &key, const T &val, const T &defaultValue);
template<typename T>
void setValueWithDefault(const QString &key, const T &val);
bool contains(const QString &key) const;
void remove(const QString &key);
@@ -61,4 +67,22 @@ private:
Internal::SettingsDatabasePrivate *d;
};
template<typename T>
void SettingsDatabase::setValueWithDefault(const QString &key, const T &val, const T &defaultValue)
{
if (val == defaultValue)
remove(key);
else
setValue(key, QVariant::fromValue(val));
}
template<typename T>
void SettingsDatabase::setValueWithDefault(const QString &key, const T &val)
{
if (val == T())
remove(key);
else
setValue(key, QVariant::fromValue(val));
}
} // namespace Core

View File

@@ -35,8 +35,8 @@ CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData)
{
setId(Constants::CLASSES_FILTER_ID);
setDisplayName(Constants::CLASSES_FILTER_DISPLAY_NAME);
setShortcutString(QLatin1String("c"));
setIncludedByDefault(false);
setDefaultShortcutString("c");
setDefaultIncludedByDefault(false);
}
CppClassesFilter::~CppClassesFilter() = default;

View File

@@ -42,9 +42,9 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppTools::CppModelManager *ma
{
setId(Constants::CURRENT_DOCUMENT_FILTER_ID);
setDisplayName(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME);
setShortcutString(".");
setDefaultShortcutString(".");
setPriority(High);
setIncludedByDefault(false);
setDefaultIncludedByDefault(false);
search.setSymbolsToSearchFor(SymbolSearcher::Declarations |
SymbolSearcher::Enums |

View File

@@ -37,8 +37,8 @@ CppFunctionsFilter::CppFunctionsFilter(CppLocatorData *locatorData)
{
setId(Constants::FUNCTIONS_FILTER_ID);
setDisplayName(Constants::FUNCTIONS_FILTER_DISPLAY_NAME);
setShortcutString("m");
setIncludedByDefault(false);
setDefaultShortcutString("m");
setDefaultIncludedByDefault(false);
}
CppFunctionsFilter::~CppFunctionsFilter() = default;

View File

@@ -121,8 +121,8 @@ CppIncludesFilter::CppIncludesFilter()
{
setId(Constants::INCLUDES_FILTER_ID);
setDisplayName(Constants::INCLUDES_FILTER_DISPLAY_NAME);
setShortcutString("ai");
setIncludedByDefault(true);
setDefaultShortcutString("ai");
setDefaultIncludedByDefault(true);
setPriority(ILocatorFilter::Low);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged,

View File

@@ -43,8 +43,8 @@ CppLocatorFilter::CppLocatorFilter(CppLocatorData *locatorData)
{
setId(Constants::LOCATOR_FILTER_ID);
setDisplayName(Constants::LOCATOR_FILTER_DISPLAY_NAME);
setShortcutString(":");
setIncludedByDefault(false);
setDefaultShortcutString(":");
setDefaultIncludedByDefault(false);
}
CppLocatorFilter::~CppLocatorFilter() = default;

View File

@@ -62,8 +62,8 @@ HelpIndexFilter::HelpIndexFilter()
{
setId("HelpIndexFilter");
setDisplayName(tr("Help Index"));
setIncludedByDefault(false);
setShortcutString("?");
setDefaultIncludedByDefault(false);
setDefaultShortcutString("?");
m_icon = Utils::Icons::BOOKMARK.icon();
connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::setupFinished,

View File

@@ -47,8 +47,8 @@ DocumentLocatorFilter::DocumentLocatorFilter()
{
setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID);
setDisplayName(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME);
setShortcutString(".");
setIncludedByDefault(false);
setDefaultShortcutString(".");
setDefaultIncludedByDefault(false);
setPriority(ILocatorFilter::Low);
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
this, &DocumentLocatorFilter::updateCurrentClient);
@@ -208,8 +208,8 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector<SymbolKind> &filter
{
setId(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_ID);
setDisplayName(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DISPLAY_NAME);
setShortcutString(":");
setIncludedByDefault(false);
setDefaultShortcutString(":");
setDefaultIncludedByDefault(false);
setPriority(ILocatorFilter::Low);
}
@@ -298,7 +298,7 @@ WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter()
{
setId(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_ID);
setDisplayName(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME);
setShortcutString("c");
setDefaultShortcutString("c");
}
WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter()
@@ -306,7 +306,7 @@ WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter()
{
setId(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID);
setDisplayName(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME);
setShortcutString("m");
setDefaultShortcutString("m");
}
} // namespace LanguageClient

View File

@@ -42,7 +42,7 @@ MacroLocatorFilter::MacroLocatorFilter()
{
setId("Macros");
setDisplayName(tr("Text Editing Macros"));
setShortcutString("rm");
setDefaultShortcutString("rm");
}
MacroLocatorFilter::~MacroLocatorFilter() = default;

View File

@@ -40,8 +40,8 @@ AllProjectsFilter::AllProjectsFilter()
{
setId("Files in any project");
setDisplayName(tr("Files in Any Project"));
setShortcutString(QString(QLatin1Char('a')));
setIncludedByDefault(true);
setDefaultShortcutString("a");
setDefaultIncludedByDefault(true);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged,
this, &AllProjectsFilter::markFilesAsOutOfDate);

View File

@@ -35,12 +35,13 @@ using namespace Core;
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
CurrentProjectFilter::CurrentProjectFilter() : BaseFileFilter()
CurrentProjectFilter::CurrentProjectFilter()
: BaseFileFilter()
{
setId("Files in current project");
setDisplayName(tr("Files in Current Project"));
setShortcutString(QString(QLatin1Char('p')));
setIncludedByDefault(false);
setDefaultShortcutString("p");
setDefaultIncludedByDefault(false);
connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged,
this, &CurrentProjectFilter::currentProjectChanged);

View File

@@ -2798,8 +2798,9 @@ ProjectExplorerPluginPrivate::ProjectExplorerPluginPrivate()
: m_allProjectDirectoriesFilter("Files in All Project Directories")
{
m_allProjectDirectoriesFilter.setDisplayName(m_allProjectDirectoriesFilter.id().toString());
m_allProjectDirectoriesFilter.setShortcutString("a"); // shared with "Files in Any Project"
m_allProjectDirectoriesFilter.setIncludedByDefault(false); // but not included in default
// shared with "Files in Any Project":
m_allProjectDirectoriesFilter.setDefaultShortcutString("a");
m_allProjectDirectoriesFilter.setDefaultIncludedByDefault(false); // but not included in default
m_allProjectDirectoriesFilter.setFilters({});
m_allProjectDirectoriesFilter.setIsCustomFilter(false);
}

View File

@@ -44,8 +44,8 @@ FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent)
{
setId("Functions");
setDisplayName(tr("QML Functions"));
setShortcutString("m");
setIncludedByDefault(false);
setDefaultShortcutString("m");
setDefaultIncludedByDefault(false);
}
FunctionFilter::~FunctionFilter() = default;

View File

@@ -49,8 +49,8 @@ LineNumberFilter::LineNumberFilter(QObject *parent)
setId("Line in current document");
setDisplayName(tr("Line in Current Document"));
setPriority(High);
setShortcutString("l");
setIncludedByDefault(true);
setDefaultShortcutString("l");
setDefaultIncludedByDefault(true);
}
void LineNumberFilter::prepareSearch(const QString &entry)