3#include "resources/config.h"
13#include <QStringBuilder>
15#if defined(QT_UTILITIES_GUI_QTWIDGETS)
16#include <QApplication>
17#elif defined(QT_UTILITIES_GUI_QTQUICK)
18#include <QGuiApplication>
20#include <QCoreApplication>
24#include <QStandardPaths>
32inline void initResources()
34 Q_INIT_RESOURCE(qtutilsicons);
37inline void cleanupResources()
39 Q_CLEANUP_RESOURCE(qtutilsicons);
73namespace TranslationFiles {
78static QList<QTranslator *> translators;
91static QString relativeBase()
93 static const auto relativeBase = [] {
94 auto appDir = QCoreApplication::applicationDirPath();
95 if (appDir.isEmpty()) {
96 appDir = QStringLiteral(
".");
140 const auto debugTranslations = qEnvironmentVariableIntValue(
"QT_DEBUG_TRANSLATIONS");
141 const auto relBase = relativeBase();
142 for (
const auto &repoName : repositoryNames) {
143 auto *
const qtTranslator =
new QTranslator(QCoreApplication::instance());
144 const auto fileName = QString(repoName % QChar(
'_') % localeName);
148 || qtTranslator->load(fileName,
150#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
151 QLibraryInfo::location(QLibraryInfo::TranslationsPath)
153 QLibraryInfo::path(QLibraryInfo::TranslationsPath)
156 || qtTranslator->load(fileName, path = relBase + QStringLiteral(
"/../share/qt/translations"))
157 || qtTranslator->load(fileName, path = QStringLiteral(
":/translations"))) {
158 QCoreApplication::installTranslator(qtTranslator);
159 translators.append(qtTranslator);
160 if (debugTranslations) {
161 cerr <<
"Loading translation file for Qt repository \"" << repoName.toLocal8Bit().data() <<
"\" and the locale \""
162 << localeName.toLocal8Bit().data() <<
"\" from \"" << path.toLocal8Bit().data() <<
"\"." << endl;
166 if (localeName.startsWith(QLatin1String(
"en"))) {
170 cerr <<
"Unable to load translation file for Qt repository \"" << repoName.toLocal8Bit().data() <<
"\" and locale "
171 << localeName.toLocal8Bit().data() <<
"." << endl;
200 const auto defaultLocale(QLocale().name());
201 if (defaultLocale != QLatin1String(
"en_US")) {
207static void logTranslationEvent(
208 const char *event,
const QString &configName,
const QString &applicationName,
const QString &localeName,
const QString &path = QString())
210 cerr <<
event <<
" translation file for \"" << applicationName.toLocal8Bit().data() <<
"\"";
211 if (!configName.isEmpty()) {
212 cerr <<
" (config \"" << configName.toLocal8Bit().data() <<
"\")";
214 cerr <<
" and locale \"" << localeName.toLocal8Bit().data() <<
'\"';
215 if (!path.isEmpty()) {
216 cerr <<
" from \"" << path.toLocal8Bit().data() <<
'\"';
244 auto *
const appTranslator =
new QTranslator(QCoreApplication::instance());
245 const auto fileName = QString(applicationName % QChar(
'_') % localeName);
246 const auto directoryName = configName.isEmpty() ? applicationName : QString(applicationName % QChar(
'-') % configName);
247 const auto relBase = relativeBase();
250 || appTranslator->load(fileName, path = relBase) || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/../") % directoryName)
251 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/../../") % directoryName)
252 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/translations"))
253 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/../share/") % directoryName % QStringLiteral(
"/translations"))
254 || appTranslator->load(fileName, path = QStringLiteral(APP_INSTALL_PREFIX
"/share/") % directoryName % QStringLiteral(
"/translations"))
255 || appTranslator->load(fileName, path = QStringLiteral(
":/translations"))) {
256 QCoreApplication::installTranslator(appTranslator);
257 translators.append(appTranslator);
258 if (qEnvironmentVariableIntValue(
"QT_DEBUG_TRANSLATIONS")) {
259 logTranslationEvent(
"Loading", configName, applicationName, localeName, path);
262 delete appTranslator;
263 if (localeName.startsWith(QLatin1String(
"en"))) {
267 logTranslationEvent(
"Unable to load", configName, applicationName, localeName);
278 for (
const QString &applicationName : applicationNames) {
291 for (
const QString &applicationName : applicationNames) {
301 for (
auto *
const translator : translators) {
302 QCoreApplication::removeTranslator(translator);
314namespace ApplicationInstances {
316#if defined(QT_UTILITIES_GUI_QTWIDGETS)
322 return qobject_cast<QApplication *>(QCoreApplication::instance()) !=
nullptr;
326#if defined(QT_UTILITIES_GUI_QTWIDGETS) || defined(QT_UTILITIES_GUI_QTQUICK)
332 return qobject_cast<QGuiApplication *>(QCoreApplication::instance()) !=
nullptr;
341 return qobject_cast<QCoreApplication *>(QCoreApplication::instance()) !=
nullptr;
357#if defined(Q_OS_WINDOWS) && (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
358 if (
const auto qtVersion = QLibraryInfo::version();
359 qtVersion >= QVersionNumber(6, 4, 0) && qtVersion < QVersionNumber(6, 5, 0) && !qEnvironmentVariableIsSet(
"QT_QPA_PLATFORM")) {
360 qputenv(
"QT_QPA_PLATFORM",
"windows:darkmode=1");
365#ifdef QT_FEATURE_fontdialog
366 if (!qEnvironmentVariableIsSet(
"FONTCONFIG_PATH") && QDir(QStringLiteral(
"/etc/fonts")).exists()) {
367 qputenv(
"FONTCONFIG_PATH",
"/etc/fonts");
372#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
373 if (!QCoreApplication::instance()) {
374 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling,
true);
376 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps,
true);
392std::unique_ptr<QSettings>
getSettings(
const QString &organization,
const QString &application)
394 auto settings = std::unique_ptr<QSettings>();
395 const auto portableFileName
396 = application.isEmpty() ? organization + QStringLiteral(
".ini") : organization % QChar(
'/') % application % QStringLiteral(
".ini");
397 if (
const auto portableFileWorkingDir = QFile(portableFileName); portableFileWorkingDir.exists()) {
398 settings = std::make_unique<QSettings>(portableFileWorkingDir.fileName(), QSettings::IniFormat);
399 }
else if (
const auto portableFileNextToApp = QFile(QCoreApplication::applicationDirPath() % QChar(
'/') % portableFileName);
400 portableFileNextToApp.exists()) {
401 settings = std::make_unique<QSettings>(portableFileNextToApp.fileName(), QSettings::IniFormat);
403 settings = std::make_unique<QSettings>(QSettings::IniFormat, QSettings::UserScope, organization, application);
405 if (organization != QCoreApplication::organizationName() || application != QCoreApplication::applicationName()) {
407 = QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName())
409 QFile::rename(oldConfig, settings->fileName()) || QFile::remove(oldConfig);
422 if (!qEnvironmentVariableIntValue(
"QT_DEBUG_SETTINGS")) {
426 if (error.isEmpty()) {
427 std::cerr <<
"Loaded/synced settings from " << settings.fileName().toStdString() <<
'\n';
429 std::cerr <<
"Unable to load settings: " << error.toStdString() <<
'\n';
439 if (!qEnvironmentVariableIntValue(
"QT_DEBUG_SETTINGS")) {
443 if (error.isEmpty()) {
444 std::cerr <<
"Saved/synced settings to " << settings.fileName().toStdString() <<
'\n';
446 std::cerr <<
"Unable to save settings: " << error.toStdString() <<
'\n';
455 auto errorMessage = QString();
456 switch (settings.status()) {
457 case QSettings::NoError:
459 case QSettings::AccessError:
460 errorMessage = QCoreApplication::translate(
"QtUtilities",
"unable to access file");
462 case QSettings::FormatError:
463 errorMessage = QCoreApplication::translate(
"QtUtilities",
"file has invalid format");
466 errorMessage = QCoreApplication::translate(
"QtUtilities",
"unknown error");
468 return QCoreApplication::translate(
"QtUtilities",
"Unable to sync settings from \"%1\": %2").arg(settings.fileName(), errorMessage);
478 const auto cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation);
479 for (
const auto &cachePath : cachePaths) {
480 const auto cacheDir = QDir(cachePath);
481 const auto subdirs = cacheDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
482 for (
const auto &subdir : subdirs) {
483 if (subdir.startsWith(QLatin1String(
"qtpipelinecache"))) {
484 QFile::remove(cachePath % QChar(
'/') % subdir % QStringLiteral(
"/qqpc_opengl"));
QT_UTILITIES_EXPORT bool hasCoreApp()
Returns whether a QCoreApplication has been instantiated yet.
Functions for using the resources provided by this library.
QT_UTILITIES_EXPORT void init()
Initiates the resources used and provided by this library.
QT_UTILITIES_EXPORT void cleanup()
Frees the resources used and provided by this library.
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.
QT_UTILITIES_EXPORT void loadSettingsWithLogging(QSettings &settings)
Loads settings and logs a corresponding message if the env variable QT_DEBUG_SETTINGS is set.
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 deletePipelineCacheIfNeeded()
Deletes the Qt Quick pipeline cache on platforms where this is needed to workaround issues with the c...
QT_UTILITIES_EXPORT void setupCommonQtApplicationAttributes()
Sets Qt application attributes which are commonly used within my Qt applications.
QT_UTILITIES_EXPORT void saveSettingsWithLogging(QSettings &settings)
Saves settings and logs a corresponding message if the env variable QT_DEBUG_SETTINGS is set.
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.