Qt Utilities 6.14.4
Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models
Loading...
Searching...
No Matches
resources.cpp
Go to the documentation of this file.
1#include "./resources.h"
2
3#include "resources/config.h"
4
5#include <QDir>
6#include <QFile>
7#include <QFont>
8#include <QIcon>
9#include <QLibraryInfo>
10#include <QLocale>
11#include <QSettings>
12#include <QString>
13#include <QStringBuilder>
14#include <QTranslator>
15#if defined(QT_UTILITIES_GUI_QTWIDGETS)
16#include <QApplication>
17#elif defined(QT_UTILITIES_GUI_QTQUICK)
18#include <QGuiApplication>
19#else
20#include <QCoreApplication>
21#endif
22
23#include <iostream>
24
25using namespace std;
26
28inline void initResources()
29{
30 Q_INIT_RESOURCE(qtutilsicons);
31}
32
33inline void cleanupResources()
34{
35 Q_CLEANUP_RESOURCE(qtutilsicons);
36}
38
39namespace QtUtilities {
40
45namespace QtUtilitiesResources {
46
51void init()
52{
53 initResources();
54}
55
60void cleanup()
61{
62 cleanupResources();
63}
64} // namespace QtUtilitiesResources
65
69namespace TranslationFiles {
70
74static QList<QTranslator *> translators;
75
81{
82 static QString path;
83 return path;
84}
85
100void loadQtTranslationFile(std::initializer_list<QString> repositoryNames)
101{
102 loadQtTranslationFile(repositoryNames, QLocale().name());
103}
104
120void loadQtTranslationFile(initializer_list<QString> repositoryNames, const QString &localeName)
121{
122 const auto debugTranslations = qEnvironmentVariableIsSet("QT_DEBUG_TRANSLATIONS");
123 for (const auto &repoName : repositoryNames) {
124 auto *const qtTranslator = new QTranslator(QCoreApplication::instance());
125 const auto fileName = QString(repoName % QChar('_') % localeName);
126
127 QString path;
128 if ((!additionalTranslationFilePath().isEmpty() && qtTranslator->load(fileName, path = additionalTranslationFilePath()))
129 || qtTranslator->load(fileName,
130 path =
131#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
132 QLibraryInfo::location(QLibraryInfo::TranslationsPath)
133#else
134 QLibraryInfo::path(QLibraryInfo::TranslationsPath)
135#endif
136 )
137 || qtTranslator->load(fileName, path = QStringLiteral("../share/qt/translations"))
138 || qtTranslator->load(fileName, path = QStringLiteral(":/translations"))) {
139 QCoreApplication::installTranslator(qtTranslator);
140 translators.append(qtTranslator);
141 if (debugTranslations) {
142 cerr << "Loading translation file for Qt repository \"" << repoName.toLocal8Bit().data() << "\" and the locale \""
143 << localeName.toLocal8Bit().data() << "\" from \"" << path.toLocal8Bit().data() << "\"." << endl;
144 }
145 } else {
146 delete qtTranslator;
147 if (localeName.startsWith(QLatin1String("en"))) {
148 // the translation file is probably just empty (English is built-in and usually only used for plural forms)
149 continue;
150 }
151 cerr << "Unable to load translation file for Qt repository \"" << repoName.toLocal8Bit().data() << "\" and locale "
152 << localeName.toLocal8Bit().data() << "." << endl;
153 }
154 }
155}
156
176void loadApplicationTranslationFile(const QString &configName, const QString &applicationName)
177{
178 // load English translation files as fallback
179 loadApplicationTranslationFile(configName, applicationName, QStringLiteral("en_US"));
180 // load translation files for current locale
181 const auto defaultLocale(QLocale().name());
182 if (defaultLocale != QLatin1String("en_US")) {
183 loadApplicationTranslationFile(configName, applicationName, defaultLocale);
184 }
185}
186
188void logTranslationEvent(
189 const char *event, const QString &configName, const QString &applicationName, const QString &localeName, const QString &path = QString())
190{
191 cerr << event << " translation file for \"" << applicationName.toLocal8Bit().data() << "\"";
192 if (!configName.isEmpty()) {
193 cerr << " (config \"" << configName.toLocal8Bit().data() << "\")";
194 }
195 cerr << " and locale \"" << localeName.toLocal8Bit().data() << '\"';
196 if (!path.isEmpty()) {
197 cerr << " from \"" << path.toLocal8Bit().data() << '\"';
198 }
199 cerr << '.' << endl;
200}
202
223void loadApplicationTranslationFile(const QString &configName, const QString &applicationName, const QString &localeName)
224{
225 auto *const appTranslator = new QTranslator(QCoreApplication::instance());
226 const auto fileName = QString(applicationName % QChar('_') % localeName);
227 const auto directoryName = configName.isEmpty() ? applicationName : QString(applicationName % QChar('-') % configName);
228
229 QString path;
230 if ((!additionalTranslationFilePath().isEmpty() && appTranslator->load(fileName, path = additionalTranslationFilePath()))
231 || appTranslator->load(fileName, path = QStringLiteral(".")) || appTranslator->load(fileName, path = QStringLiteral("../") % directoryName)
232 || appTranslator->load(fileName, path = QStringLiteral("../../") % directoryName)
233 || appTranslator->load(fileName, path = QStringLiteral("./translations"))
234 || appTranslator->load(fileName, path = QStringLiteral("../share/") % directoryName % QStringLiteral("/translations"))
235 || appTranslator->load(fileName, path = QStringLiteral(APP_INSTALL_PREFIX "/share/") % directoryName % QStringLiteral("/translations"))
236 || appTranslator->load(fileName, path = QStringLiteral(":/translations"))) {
237 QCoreApplication::installTranslator(appTranslator);
238 translators.append(appTranslator);
239 if (qEnvironmentVariableIsSet("QT_DEBUG_TRANSLATIONS")) {
240 logTranslationEvent("Loading", configName, applicationName, localeName, path);
241 }
242 } else {
243 delete appTranslator;
244 if (localeName.startsWith(QLatin1String("en"))) {
245 // the translation file is probably just empty (English is built-in and usually only used for plural forms)
246 return;
247 }
248 logTranslationEvent("Unable to load", configName, applicationName, localeName);
249 }
250}
251
257void loadApplicationTranslationFile(const QString &configName, const std::initializer_list<QString> &applicationNames)
258{
259 for (const QString &applicationName : applicationNames) {
260 loadApplicationTranslationFile(configName, applicationName);
261 }
262}
263
270void loadApplicationTranslationFile(const QString &configName, const std::initializer_list<QString> &applicationNames, const QString &localeName)
271{
272 for (const QString &applicationName : applicationNames) {
273 loadApplicationTranslationFile(configName, applicationName, localeName);
274 }
275}
276
281{
282 for (auto *const translator : translators) {
283 QCoreApplication::removeTranslator(translator);
284 }
285 translators.clear();
286}
287
288} // namespace TranslationFiles
289
295namespace ApplicationInstances {
296
297#if defined(QT_UTILITIES_GUI_QTWIDGETS)
301bool hasWidgetsApp()
302{
303 return qobject_cast<QApplication *>(QCoreApplication::instance()) != nullptr;
304}
305#endif
306
307#if defined(QT_UTILITIES_GUI_QTWIDGETS) || defined(QT_UTILITIES_GUI_QTQUICK)
311bool hasGuiApp()
312{
313 return qobject_cast<QGuiApplication *>(QCoreApplication::instance()) != nullptr;
314}
315#endif
316
321{
322 return qobject_cast<QCoreApplication *>(QCoreApplication::instance()) != nullptr;
323}
324} // namespace ApplicationInstances
325
333{
334 // enable dark window frame on Windows if the configured color palette is dark
335 // - supported as of Qt 6.4; no longer required as of Qt 6.5
336 // - see https://bugreports.qt.io/browse/QTBUG-72028?focusedCommentId=677819#comment-677819
337 // and https://www.qt.io/blog/dark-mode-on-windows-11-with-qt-6.5
338#if defined(Q_OS_WINDOWS) && (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
339 if (const auto qtVersion = QLibraryInfo::version();
340 qtVersion >= QVersionNumber(6, 4, 0) && qtVersion < QVersionNumber(6, 5, 0) && !qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) {
341 qputenv("QT_QPA_PLATFORM", "windows:darkmode=1");
342 }
343#endif
344
345 // ensure FONTCONFIG_PATH is set (mainly required for static GNU/Linux builds)
346#ifdef QT_FEATURE_fontdialog
347 if (!qEnvironmentVariableIsSet("FONTCONFIG_PATH") && QDir(QStringLiteral("/etc/fonts")).exists()) {
348 qputenv("FONTCONFIG_PATH", "/etc/fonts");
349 }
350#endif
351
352 // enable settings for High-DPI scaling
353#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
354 if (!QCoreApplication::instance()) {
355 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
356 }
357 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
358#endif
359}
360
373std::unique_ptr<QSettings> getSettings(const QString &organization, const QString &application)
374{
375 auto settings = std::unique_ptr<QSettings>();
376 const auto portableFileName
377 = application.isEmpty() ? organization + QStringLiteral(".ini") : organization % QChar('/') % application % QStringLiteral(".ini");
378 if (const auto portableFileWorkingDir = QFile(portableFileName); portableFileWorkingDir.exists()) {
379 settings = std::make_unique<QSettings>(portableFileWorkingDir.fileName(), QSettings::IniFormat);
380 } else if (const auto portableFileNextToApp = QFile(QCoreApplication::applicationDirPath() % QChar('/') % portableFileName);
381 portableFileNextToApp.exists()) {
382 settings = std::make_unique<QSettings>(portableFileNextToApp.fileName(), QSettings::IniFormat);
383 } else {
384 settings = std::make_unique<QSettings>(QSettings::IniFormat, QSettings::UserScope, organization, application);
385 // move config created by older versions to new location
386 if (organization != QCoreApplication::organizationName() || application != QCoreApplication::applicationName()) {
387 const auto oldConfig
388 = QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName())
389 .fileName();
390 QFile::rename(oldConfig, settings->fileName()) || QFile::remove(oldConfig);
391 }
392 }
393 settings->sync();
394 return settings;
395}
396
400QString errorMessageForSettings(const QSettings &settings)
401{
402 auto errorMessage = QString();
403 switch (settings.status()) {
404 case QSettings::NoError:
405 return QString();
406 case QSettings::AccessError:
407 errorMessage = QCoreApplication::translate("QtUtilities", "unable to access file");
408 break;
409 case QSettings::FormatError:
410 errorMessage = QCoreApplication::translate("QtUtilities", "file has invalid format");
411 break;
412 default:
413 errorMessage = QCoreApplication::translate("QtUtilities", "unknown error");
414 }
415 return QCoreApplication::translate("QtUtilities", "Unable to sync settings from \"%1\": %2").arg(settings.fileName(), errorMessage);
416}
417
418// namespace ApplicationInstances
419
420} // namespace QtUtilities
QT_UTILITIES_EXPORT bool hasCoreApp()
Returns whether a QCoreApplication has been instantiated yet.
QT_UTILITIES_EXPORT void init()
Initiates the resources used and provided by this library.
Definition resources.cpp:51
QT_UTILITIES_EXPORT void cleanup()
Frees the resources used and provided by this library.
Definition resources.cpp:60
QT_UTILITIES_EXPORT void loadQtTranslationFile(std::initializer_list< QString > repositoryNames)
Loads and installs the appropriate Qt translation file for the current locale.
QT_UTILITIES_EXPORT void clearTranslationFiles()
Clears all translation files previously loaded via the load-functions in this namespace.
QT_UTILITIES_EXPORT void loadApplicationTranslationFile(const QString &configName, const QString &applicationName)
Loads and installs the appropriate application translation file for the current locale.
QT_UTILITIES_EXPORT QString & additionalTranslationFilePath()
Allows to set an additional search path for translation files.
Definition resources.cpp:80
QT_UTILITIES_EXPORT std::unique_ptr< QSettings > getSettings(const QString &organization, const QString &application=QString())
Returns the settings object for the specified organization and application.
QT_UTILITIES_EXPORT void setupCommonQtApplicationAttributes()
Sets Qt application attributes which are commonly used within my Qt applications.
QT_UTILITIES_EXPORT QString errorMessageForSettings(const QSettings &settings)
Returns an error message for the specified settings or an empty string if there's no error.