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>
25#include <QStandardPaths>
29#include <c++utilities/conversion/stringbuilder.h>
37inline void initResources()
39 Q_INIT_RESOURCE(qtutilsicons);
42inline void cleanupResources()
44 Q_CLEANUP_RESOURCE(qtutilsicons);
78namespace TranslationFiles {
83static QList<QTranslator *> translators;
96static QString relativeBase()
98 static const auto relativeBase = [] {
99 auto appDir = QCoreApplication::applicationDirPath();
100 if (appDir.isEmpty()) {
101 appDir = QStringLiteral(
".");
145 const auto debugTranslations = qEnvironmentVariableIntValue(
"QT_DEBUG_TRANSLATIONS");
146 const auto relBase = relativeBase();
147 for (
const auto &repoName : repositoryNames) {
148 auto *
const qtTranslator =
new QTranslator(QCoreApplication::instance());
149 const auto fileName = QString(repoName % QChar(
'_') % localeName);
156 || qtTranslator->load(fileName,
158#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
159 QLibraryInfo::location(QLibraryInfo::TranslationsPath)
161 QLibraryInfo::path(QLibraryInfo::TranslationsPath)
165 || qtTranslator->load(fileName, path = relBase + QStringLiteral(
"/../share/qt/translations"))
167 || qtTranslator->load(fileName, path = QStringLiteral(
":/translations"))) {
168 QCoreApplication::installTranslator(qtTranslator);
169 translators.append(qtTranslator);
170 if (debugTranslations) {
171 cerr <<
"Loading translation file for Qt repository \"" << repoName.toLocal8Bit().data() <<
"\" and the locale \""
172 << localeName.toLocal8Bit().data() <<
"\" from \"" << path.toLocal8Bit().data() <<
"\"." << endl;
176 if (localeName.startsWith(QLatin1String(
"en"))) {
180#if defined(Q_OS_ANDROID)
181 qDebug() <<
"Unable to load translation file for Qt repository: " << repoName << localeName;
183 cerr <<
"Unable to load translation file for Qt repository \"" << repoName.toLocal8Bit().data() <<
"\" and locale "
184 << localeName.toLocal8Bit().data() <<
"." << endl;
215 const auto defaultLocale(QLocale().name());
216 if (defaultLocale != QLatin1String(
"en_US")) {
222static void logTranslationEvent(
223 const char *event,
const QString &configName,
const QString &applicationName,
const QString &localeName,
const QString &path = QString())
225#if defined(Q_OS_ANDROID)
226 qDebug() << CppUtilities::argsToString(event,
" translation file for: ").data() << applicationName << localeName;
227 if (!configName.isEmpty()) {
228 qDebug() <<
"config: " << configName;
230 if (!path.isEmpty()) {
231 qDebug() <<
"path: " << path;
234 cerr <<
event <<
" translation file for \"" << applicationName.toLocal8Bit().data() <<
"\"";
235 if (!configName.isEmpty()) {
236 cerr <<
" (config \"" << configName.toLocal8Bit().data() <<
"\")";
238 cerr <<
" and locale \"" << localeName.toLocal8Bit().data() <<
'\"';
239 if (!path.isEmpty()) {
240 cerr <<
" from \"" << path.toLocal8Bit().data() <<
'\"';
270 auto *
const appTranslator =
new QTranslator(QCoreApplication::instance());
271 const auto fileName = QString(applicationName % QChar(
'_') % localeName);
272 const auto directoryName = configName.isEmpty() ? applicationName : QString(applicationName % QChar(
'-') % configName);
273 const auto relBase = relativeBase();
275 if (
auto path = QString();
280 || appTranslator->load(fileName, path = relBase)
283 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/../") % applicationName)
284 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/../../") % applicationName)
287 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/translations"))
289 || appTranslator->load(fileName, path = relBase % QStringLiteral(
"/../share/") % directoryName % QStringLiteral(
"/translations"))
290 || appTranslator->load(fileName, path = QStringLiteral(APP_INSTALL_PREFIX
"/share/") % directoryName % QStringLiteral(
"/translations"))
292 || appTranslator->load(fileName, path = QStringLiteral(
":/translations"))) {
293 QCoreApplication::installTranslator(appTranslator);
294 translators.append(appTranslator);
295 if (qEnvironmentVariableIntValue(
"QT_DEBUG_TRANSLATIONS")) {
296 logTranslationEvent(
"Loading", configName, applicationName, localeName, path);
299 delete appTranslator;
300 if (localeName.startsWith(QLatin1String(
"en"))) {
304 logTranslationEvent(
"Unable to load", configName, applicationName, localeName);
316 for (
const QString &applicationName : applicationNames) {
330 for (
const QString &applicationName : applicationNames) {
340 for (
auto *
const translator : translators) {
341 QCoreApplication::removeTranslator(translator);
353namespace ApplicationInstances {
355#if defined(QT_UTILITIES_GUI_QTWIDGETS)
361 return qobject_cast<QApplication *>(QCoreApplication::instance()) !=
nullptr;
365#if defined(QT_UTILITIES_GUI_QTWIDGETS) || defined(QT_UTILITIES_GUI_QTQUICK)
371 return qobject_cast<QGuiApplication *>(QCoreApplication::instance()) !=
nullptr;
380 return qobject_cast<QCoreApplication *>(QCoreApplication::instance()) !=
nullptr;
396#if defined(Q_OS_WINDOWS) && (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
397 if (
const auto qtVersion = QLibraryInfo::version();
398 qtVersion >= QVersionNumber(6, 4, 0) && qtVersion < QVersionNumber(6, 5, 0) && !qEnvironmentVariableIsSet(
"QT_QPA_PLATFORM")) {
399 qputenv(
"QT_QPA_PLATFORM",
"windows:darkmode=1");
404#ifdef QT_FEATURE_fontdialog
405 if (!qEnvironmentVariableIsSet(
"FONTCONFIG_PATH") && QDir(QStringLiteral(
"/etc/fonts")).exists()) {
406 qputenv(
"FONTCONFIG_PATH",
"/etc/fonts");
411#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
412 if (!QCoreApplication::instance()) {
413 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling,
true);
415 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps,
true);
431std::unique_ptr<QSettings>
getSettings(
const QString &organization,
const QString &application)
433 auto settings = std::unique_ptr<QSettings>();
434 const auto portableFileName
435 = application.isEmpty() ? organization + QStringLiteral(
".ini") : organization % QChar(
'/') % application % QStringLiteral(
".ini");
436 if (
const auto portableFileWorkingDir = QFile(portableFileName); portableFileWorkingDir.exists()) {
437 settings = std::make_unique<QSettings>(portableFileWorkingDir.fileName(), QSettings::IniFormat);
438 }
else if (
const auto portableFileNextToApp = QFile(QCoreApplication::applicationDirPath() % QChar(
'/') % portableFileName);
439 portableFileNextToApp.exists()) {
440 settings = std::make_unique<QSettings>(portableFileNextToApp.fileName(), QSettings::IniFormat);
442 settings = std::make_unique<QSettings>(QSettings::IniFormat, QSettings::UserScope, organization, application);
444 if (organization != QCoreApplication::organizationName() || application != QCoreApplication::applicationName()) {
446 = QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName())
448 QFile::rename(oldConfig, settings->fileName()) || QFile::remove(oldConfig);
461 if (!qEnvironmentVariableIntValue(
"QT_DEBUG_SETTINGS")) {
465 if (error.isEmpty()) {
466 std::cerr <<
"Loaded/synced settings from " << settings.fileName().toStdString() <<
'\n';
468 std::cerr <<
"Unable to load settings: " << error.toStdString() <<
'\n';
478 if (!qEnvironmentVariableIntValue(
"QT_DEBUG_SETTINGS")) {
482 if (error.isEmpty()) {
483 std::cerr <<
"Saved/synced settings to " << settings.fileName().toStdString() <<
'\n';
485 std::cerr <<
"Unable to save settings: " << error.toStdString() <<
'\n';
494 auto errorMessage = QString();
495 switch (settings.status()) {
496 case QSettings::NoError:
498 case QSettings::AccessError:
499 errorMessage = QCoreApplication::translate(
"QtUtilities",
"unable to access file");
501 case QSettings::FormatError:
502 errorMessage = QCoreApplication::translate(
"QtUtilities",
"file has invalid format");
505 errorMessage = QCoreApplication::translate(
"QtUtilities",
"unknown error");
507 return QCoreApplication::translate(
"QtUtilities",
"Unable to sync settings from \"%1\": %2").arg(settings.fileName(), errorMessage);
517 const auto cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation);
518 for (
const auto &cachePath : cachePaths) {
519 const auto cacheDir = QDir(cachePath);
520 const auto subdirs = cacheDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
521 for (
const auto &subdir : subdirs) {
522 if (subdir.startsWith(QLatin1String(
"qtpipelinecache"))) {
523 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.