7#include <QtCore/qdebug.h>
8#include <QtCore/qdir.h>
9#include <QtCore/qfileinfo.h>
10#include <QtCore/qset.h>
11#include <QtCore/qtextstream.h>
12#if QT_CONFIG(settings)
13#include <QtCore/qsettings.h>
15#include <QtCore/qstandardpaths.h>
17using namespace Qt::StringLiterals;
19void QQmlToolingSettings::addOption(
const QString &name,
const QVariant &defaultValue)
21 if (defaultValue.isValid()) {
22 m_values[name] = defaultValue;
26QQmlToolingSettings::QQmlToolingSettings(
const QString &toolName)
27 : m_searcher(u".%1.ini"_s.arg(toolName), u"%1.ini"_s.arg(toolName))
31QQmlToolingSettings::SearchResult QQmlToolingSettings::read(
const QString &settingsFilePath)
33#if QT_CONFIG(settings)
34 Q_ASSERT(QFileInfo::exists(settingsFilePath));
36 if (m_currentSettingsPath == settingsFilePath)
37 return { SearchResult::ResultType::Found, settingsFilePath };
39 QSettings settings(settingsFilePath, QSettings::IniFormat);
40 for (
const QString &key : settings.allKeys())
41 m_values[key] = settings.value(key).toString();
43 m_currentSettingsPath = settingsFilePath;
44 return { SearchResult::ResultType::Found, settingsFilePath };
46 Q_UNUSED(settingsFilePath);
47 return SearchResult();
51bool QQmlToolingSettings::writeDefaults()
const
53#if QT_CONFIG(settings)
54 const QString path = QFileInfo(m_searcher.localSettingsFile()).absoluteFilePath();
56 QSettings settings(path, QSettings::IniFormat);
57 for (
auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) {
58 settings.setValue(it.key(), it.value().isNull() ? QString() : it.value());
63 if (settings.status() != QSettings::NoError) {
64 qWarning() <<
"Failed to write default settings to" << path
65 <<
"Error:" << settings.status();
69 qInfo() <<
"Wrote default settings to" << path;
76QQmlToolingSettings::SearchResult
77QQmlToolingSettings::Searcher::searchCurrentDirInCache(
const QString &dirPath)
79 const auto it = m_seenDirectories.constFind(dirPath);
80 return it != m_seenDirectories.constEnd()
81 ? SearchResult{ SearchResult::ResultType::Found, *it }
82 : SearchResult{ SearchResult::ResultType::NotFound, {} };
90 const QString iniFile = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, local);
91 if (!iniFile.isEmpty())
95 return QStandardPaths::locate(QStandardPaths::GenericConfigLocation, global);
98QQmlToolingSettings::SearchResult
99QQmlToolingSettings::Searcher::searchDefaultLocation(
const QSet<QString> *visitedDirs)
101 QString iniFile = findIniFile(m_localSettingsFile, m_globalSettingsFile);
104 for (
const QString &dir : *visitedDirs)
105 m_seenDirectories[dir] = iniFile;
107 const SearchResult::ResultType found = iniFile.isEmpty()
108 ? SearchResult::ResultType::NotFound
109 : SearchResult::ResultType::Found;
110 return SearchResult { found, std::move(iniFile) };
113QQmlToolingSettings::SearchResult
114QQmlToolingSettings::Searcher::searchDirectoryHierarchy(
115 QSet<QString> *visitedDirs,
const QString &path)
117 const QFileInfo fileInfo(path);
118 QDir dir(fileInfo.isDir() ? path : fileInfo.dir());
120 while (dir.exists() && dir.isReadable()) {
121 const QString dirPath = dir.absolutePath();
128 if (
const SearchResult result = searchCurrentDirInCache(dirPath); result.isValid())
131 visitedDirs->insert(dirPath);
135 if (QString ini = dir.absoluteFilePath(m_localSettingsFile); QFileInfo::exists(ini)) {
136 for (
const QString &visitedDir : std::as_const(*visitedDirs))
137 m_seenDirectories[visitedDir] = ini;
139 return { SearchResult::ResultType::Found, std::move(ini) };
146 return SearchResult();
149QQmlToolingSettings::SearchResult QQmlToolingSettings::Searcher::search(
const QString &path)
151 QSet<QString> visitedDirs;
154 if (
const SearchResult result = searchDirectoryHierarchy(&visitedDirs, path); result.isValid())
159 if (
const SearchResult result = searchDefaultLocation(&visitedDirs); result.isValid())
162 return SearchResult();
165QQmlToolingSettings::SearchResult QQmlToolingSettings::search(
166 const QString &path,
const SearchOptions &options)
168 const auto maybeReport = qScopeGuard([&]() {
170 reportConfigForFiles({ path });
174 if (!options.settingsFileName.isEmpty()) {
175 QFileInfo fileInfo(options.settingsFileName);
176 return fileInfo.exists() ? read(fileInfo.absoluteFilePath()) : SearchResult();
179 if (
const SearchResult result = m_searcher.search(path); result.isValid())
180 return read(result.iniFilePath);
182 return SearchResult();
185QVariant QQmlToolingSettings::value(
const QString &name)
const
187 return m_values.value(name);
190bool QQmlToolingSettings::isSet(
const QString &name)
const
192 if (!m_values.contains(name))
195 QVariant variant = m_values[name];
198 return !(variant.canConvert(QMetaType(QMetaType::QString)) && variant.toString().isEmpty());
201bool QQmlToolingSettings::reportConfigForFiles(
const QStringList &files)
203 constexpr int maxAllowedFileLength = 255;
204 constexpr int minAllowedFileLength = 40;
205 bool headerPrinted =
false;
206 auto lengthForFile = [maxAllowedFileLength](
const QString &file) {
207 return std::min(
int(file.length()), maxAllowedFileLength);
211 std::accumulate(files.begin(), files.end(), 0, [&](
int acc,
const QString &file) {
212 return std::max(acc, lengthForFile(file));
215 if (maxFileLength < minAllowedFileLength)
216 maxFileLength = minAllowedFileLength;
218 for (
const auto &file : files) {
219 if (file.isEmpty()) {
220 qWarning().noquote() <<
"Error: Could not find file" << file;
224 QString displayFile = file;
225 if (displayFile.length() > maxAllowedFileLength) {
226 displayFile = u"..." + displayFile.right(maxAllowedFileLength - 3);
229 const auto result = search(file);
231 if (!headerPrinted) {
233 QStringLiteral(
"%1 | %2").arg(
"File", -maxFileLength).arg(
"Settings File");
234 qWarning().noquote() << header;
235 qWarning().noquote() << QString(header.length(), u'-');
236 headerPrinted =
true;
239 QStringLiteral(
"%1 | %2").arg(displayFile, -maxFileLength).arg(result.iniFilePath);
240 qWarning().noquote() << line;