From bc3701305df979cb462492945bc35cddd8c21ef7 Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Sat, 20 Dec 2014 23:47:06 +0100 Subject: [PATCH] Moved translation support into MUtilities library + make clean-up of temporary files work again + various minor fixes. --- MUtilities_VS2013.vcxproj | 5 + MUtilities_VS2013.vcxproj.filters | 6 + include/MUtils/Startup.h | 5 +- include/MUtils/Translation.h | 56 ++++++++ src/DLLMain.cpp | 4 +- src/DirLocker.h | 24 +++- src/ErrorHandler_Win32.cpp | 2 - src/GUI_Win32.cpp | 16 +-- src/Global.cpp | 25 +++- src/OSSupport_Win32.cpp | 2 - src/Startup.cpp | 38 +++--- src/Terminal_Win32.cpp | 4 +- src/Translation.cpp | 205 ++++++++++++++++++++++++++++++ src/Version.cpp | 8 +- 14 files changed, 350 insertions(+), 50 deletions(-) create mode 100644 include/MUtils/Translation.h create mode 100644 src/Translation.cpp diff --git a/MUtilities_VS2013.vcxproj b/MUtilities_VS2013.vcxproj index b8a2f87..b651360 100644 --- a/MUtilities_VS2013.vcxproj +++ b/MUtilities_VS2013.vcxproj @@ -33,6 +33,7 @@ + @@ -50,6 +51,7 @@ + @@ -149,6 +151,9 @@ NoExtensions $(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(SolutionDir)\..\Prerequisites\VisualLeakDetector\include;%(AdditionalIncludeDirectories) true + Disabled + Default + ProgramDatabase Windows diff --git a/MUtilities_VS2013.vcxproj.filters b/MUtilities_VS2013.vcxproj.filters index 3778c5d..05c2d70 100644 --- a/MUtilities_VS2013.vcxproj.filters +++ b/MUtilities_VS2013.vcxproj.filters @@ -87,6 +87,9 @@ Source Files + + Source Files + @@ -149,6 +152,9 @@ Public Headers + + Public Headers + diff --git a/include/MUtils/Startup.h b/include/MUtils/Startup.h index 0a30ba5..ad7699c 100644 --- a/include/MUtils/Startup.h +++ b/include/MUtils/Startup.h @@ -24,6 +24,9 @@ //MUtils #include +//Forward Declarations +class QApplication; + /////////////////////////////////////////////////////////////////////////////// namespace MUtils @@ -37,7 +40,7 @@ namespace MUtils MUTILS_API int startup(int &argc, char **argv, main_function_t *const entry_point, const bool &debugConsole); //Initialize Qt - MUTILS_API bool init_qt(int &argc, char **argv, const QString &appName); + MUTILS_API QApplication *create_qt(int &argc, char **argv, const QString &appName); } } diff --git a/include/MUtils/Translation.h b/include/MUtils/Translation.h new file mode 100644 index 0000000..67fe8a5 --- /dev/null +++ b/include/MUtils/Translation.h @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// MuldeR's Utilities for Qt +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// http://www.gnu.org/licenses/lgpl-2.1.txt +////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +//MUtils +#include + +//Qt +#include + +/////////////////////////////////////////////////////////////////////////////// + +namespace MUtils +{ + namespace Translation + { + //Register new translation + MUTILS_API bool insert(const QString &langId, const QString &qmFile, const QString &langName, const quint32 &systemId, const quint32 &country); + + //Enumerate translations + MUTILS_API int enumerate(QStringList &list); + + //Get translation info + MUTILS_API QString get_name (const QString &langId); + MUTILS_API quint32 get_sysid (const QString &langId); + MUTILS_API quint32 get_country(const QString &langId); + + //Install translator + MUTILS_API bool install_translator(const QString &langId); + MUTILS_API bool install_translator_from_file(const QString &qmFile); + + //Constant + MUTILS_API extern const char *const DEFAULT_LANGID; + } +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/src/DLLMain.cpp b/src/DLLMain.cpp index 7c94ca8..71f9ec2 100644 --- a/src/DLLMain.cpp +++ b/src/DLLMain.cpp @@ -31,11 +31,11 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: + case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: break; - } + }; return TRUE; } diff --git a/src/DirLocker.h b/src/DirLocker.h index f4a683f..ceb94f5 100644 --- a/src/DirLocker.h +++ b/src/DirLocker.h @@ -56,16 +56,16 @@ namespace MUtils : m_dirPath(dirPath) { + bool okay = false; + const QByteArray testData = QByteArray(TEST_DATA); if(m_dirPath.isEmpty()) { throw DirLockException("Path must not be empty!"); } - const QByteArray testData = QByteArray(TEST_DATA); - bool okay = false; for(int i = 0; i < 32; i++) { m_lockFile.reset(new QFile(QString("%1/~%2.lck").arg(m_dirPath, MUtils::rand_str()))); - if(m_lockFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) + if(m_lockFile->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Unbuffered)) { if(m_lockFile->write(testData) >= testData.size()) { @@ -83,20 +83,34 @@ namespace MUtils ~DirLock(void) { + bool okay = false; if(!m_lockFile.isNull()) { - m_lockFile->remove(); + for(int i = 0; i < 8; i++) + { + if(m_lockFile->remove()) + { + break; + } + OS::sleep_ms(1); + } } for(int i = 0; i < 8; i++) { if(MUtils::remove_directory(m_dirPath)) { + okay = true; break; } + OS::sleep_ms(1); + } + if(!okay) + { + OS::system_message_wrn(L"Directory Lock", L"Warning: Not all temporary files could be removed!"); } } - inline const QString &path(void) const + inline const QString &getPath(void) const { return m_dirPath; } diff --git a/src/ErrorHandler_Win32.cpp b/src/ErrorHandler_Win32.cpp index cdbb2e4..76208ef 100644 --- a/src/ErrorHandler_Win32.cpp +++ b/src/ErrorHandler_Win32.cpp @@ -19,8 +19,6 @@ // http://www.gnu.org/licenses/lgpl-2.1.txt ////////////////////////////////////////////////////////////////////////////////// -#pragma once - //MUtils #include #include diff --git a/src/GUI_Win32.cpp b/src/GUI_Win32.cpp index 66bf78b..591a9cd 100644 --- a/src/GUI_Win32.cpp +++ b/src/GUI_Win32.cpp @@ -46,7 +46,7 @@ static QReadWriteLock g_themes_lock; static bool g_themes_initialized = false; static bool g_themes_enabled = false; -typedef int (WINAPI *IsAppThemedFunction)(void); +typedef int (WINAPI IsAppThemedFunction)(void); bool MUtils::GUI::themes_enabled(void) { @@ -68,18 +68,16 @@ bool MUtils::GUI::themes_enabled(void) const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version(); if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP) { - IsAppThemedFunction IsAppThemedPtr = NULL; QLibrary uxTheme("UxTheme.dll"); if(uxTheme.load()) { - IsAppThemedPtr = (IsAppThemedFunction) uxTheme.resolve("IsAppThemed"); - } - if(IsAppThemedPtr) - { - g_themes_enabled = IsAppThemedPtr(); - if(!g_themes_enabled) + if(IsAppThemedFunction *const IsAppThemedPtr = (IsAppThemedFunction*) uxTheme.resolve("IsAppThemed")) { - qWarning("Theme support is disabled for this process!"); + g_themes_enabled = IsAppThemedPtr(); + if(!g_themes_enabled) + { + qWarning("Theme support is disabled for this process!"); + } } } } diff --git a/src/Global.cpp b/src/Global.cpp index 96d60e2..6c4be19 100644 --- a/src/Global.cpp +++ b/src/Global.cpp @@ -43,7 +43,9 @@ #include //VLD +#ifdef _MSC_VER #include +#endif /////////////////////////////////////////////////////////////////////////////// // Random Support @@ -112,7 +114,7 @@ QString MUtils::rand_str(const bool &bLong) /////////////////////////////////////////////////////////////////////////////// static QScopedPointer g_temp_folder_file; -static QReadWriteLock g_temp_folder_lock; +static QReadWriteLock g_temp_folder_lock; static QString try_create_subfolder(const QString &baseDir, const QString &postfix) { @@ -150,6 +152,17 @@ static MUtils::Internal::DirLock *try_init_temp_folder(const QString &baseDir) return NULL; } +static void temp_folder_cleaup(void) +{ + QWriteLocker writeLock(&g_temp_folder_lock); + + //Clean the directory + while(!g_temp_folder_file.isNull()) + { + g_temp_folder_file.reset(NULL); + } +} + const QString &MUtils::temp_folder(void) { QReadLocker readLock(&g_temp_folder_lock); @@ -157,7 +170,7 @@ const QString &MUtils::temp_folder(void) //Already initialized? if(!g_temp_folder_file.isNull()) { - return g_temp_folder_file->path(); + return g_temp_folder_file->getPath(); } //Obtain the write lock to initilaize @@ -167,14 +180,15 @@ const QString &MUtils::temp_folder(void) //Still uninitilaized? if(!g_temp_folder_file.isNull()) { - return g_temp_folder_file->path(); + return g_temp_folder_file->getPath(); } //Try the %TMP% or %TEMP% directory first if(MUtils::Internal::DirLock *lockFile = try_init_temp_folder(QDir::tempPath())) { g_temp_folder_file.reset(lockFile); - return lockFile->path(); + atexit(temp_folder_cleaup); + return lockFile->getPath(); } qWarning("%%TEMP%% directory not found -> trying fallback mode now!"); @@ -190,7 +204,8 @@ const QString &MUtils::temp_folder(void) if(MUtils::Internal::DirLock *lockFile = try_init_temp_folder(tempRoot)) { g_temp_folder_file.reset(lockFile); - return lockFile->path(); + atexit(temp_folder_cleaup); + return lockFile->getPath(); } } } diff --git a/src/OSSupport_Win32.cpp b/src/OSSupport_Win32.cpp index a875e3d..f47590d 100644 --- a/src/OSSupport_Win32.cpp +++ b/src/OSSupport_Win32.cpp @@ -19,8 +19,6 @@ // http://www.gnu.org/licenses/lgpl-2.1.txt ////////////////////////////////////////////////////////////////////////////////// -#pragma once - //Win32 API #define WIN32_LEAN_AND_MEAN 1 #include diff --git a/src/Startup.cpp b/src/Startup.cpp index e06c464..50e7015 100644 --- a/src/Startup.cpp +++ b/src/Startup.cpp @@ -125,20 +125,19 @@ int MUtils::Startup::startup(int &argc, char **argv, main_function_t *const entr // QT INITIALIZATION /////////////////////////////////////////////////////////////////////////////// -static QMutex g_qt_lock; -static QScopedPointer g_application; - +static QMutex g_init_lock; static const char *const g_imageformats[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", "svg", NULL}; -bool MUtils::Startup::init_qt(int &argc, char **argv, const QString &appName) +QApplication *MUtils::Startup::create_qt(int &argc, char **argv, const QString &appName) { - QMutexLocker lock(&g_qt_lock); + QMutexLocker lock(&g_init_lock); const QStringList &arguments = MUtils::OS::arguments(); //Don't initialized again, if done already - if(!g_application.isNull()) + if(QApplication::instance() != NULL) { - return true; + qWarning("Qt is already initialized!"); + return NULL; } //Extract executable name from argv[] array @@ -205,7 +204,7 @@ bool MUtils::Startup::init_qt(int &argc, char **argv, const QString &appName) if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive)) { qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData()); - return false; + return NULL; } } @@ -219,17 +218,17 @@ bool MUtils::Startup::init_qt(int &argc, char **argv, const QString &appName) QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); //Create Qt application instance - g_application.reset(new QApplication(argc, argv)); + QApplication *application = new QApplication(argc, argv); //Load plugins from application directory QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath()); qDebug("Library Path:\n%s\n", MUTILS_UTF8(QApplication::libraryPaths().first())); //Set application properties - g_application->setApplicationName(appName); - g_application->setOrganizationName("LoRd_MuldeR"); - g_application->setOrganizationDomain("mulder.at.gg"); - g_application->setEventFilter(qt_event_filter); + application->setApplicationName(appName); + application->setOrganizationName("LoRd_MuldeR"); + application->setOrganizationDomain("mulder.at.gg"); + application->setEventFilter(qt_event_filter); //Check for supported image formats QList supportedFormats = QImageReader::supportedImageFormats(); @@ -238,7 +237,8 @@ bool MUtils::Startup::init_qt(int &argc, char **argv, const QString &appName) if(!supportedFormats.contains(g_imageformats[i])) { qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_imageformats[i]); - return false; + MUTILS_DELETE(application); + return NULL; } } @@ -254,9 +254,9 @@ bool MUtils::Startup::init_qt(int &argc, char **argv, const QString &appName) if(!qFuzzyCompare(fontScaleFactor, 1.0)) { qWarning("Application font scale factor set to: %.3f\n", fontScaleFactor); - QFont appFont = g_application->font(); + QFont appFont = application->font(); appFont.setPointSizeF(appFont.pointSizeF() * fontScaleFactor); - g_application->setFont(appFont); + application->setFont(appFont); } //Check for process elevation @@ -267,12 +267,14 @@ bool MUtils::Startup::init_qt(int &argc, char **argv, const QString &appName) messageBox.addButton("Ignore", QMessageBox::NoRole); if(messageBox.exec() == 0) { + MUTILS_DELETE(application); return NULL; } } - //Successful - return g_application.data(); + //Qt created successfully + return application; } /////////////////////////////////////////////////////////////////////////////// + diff --git a/src/Terminal_Win32.cpp b/src/Terminal_Win32.cpp index f46ab57..9f1b404 100644 --- a/src/Terminal_Win32.cpp +++ b/src/Terminal_Win32.cpp @@ -25,7 +25,6 @@ #define WIN32_LEAN_AND_MEAN 1 #include - //Internal #include #include @@ -162,7 +161,7 @@ void MUtils::Terminal::setup(int &argc, char **argv, const bool forceEnabled) g_terminal_attached = true; } } - + if(g_terminal_attached) { //------------------------------------------------------------------- @@ -184,6 +183,7 @@ void MUtils::Terminal::setup(int &argc, char **argv, const bool forceEnabled) *stderr = *hfStdErr; g_filebufStdErr.reset(new std::filebuf(hfStdErr)); std::cerr.rdbuf(g_filebufStdErr.data()); + std::cerr.rdbuf(new std::filebuf(hfStdErr)); } const HWND hwndConsole = GetConsoleWindow(); diff --git a/src/Translation.cpp b/src/Translation.cpp new file mode 100644 index 0000000..a1b20ee --- /dev/null +++ b/src/Translation.cpp @@ -0,0 +1,205 @@ +/////////////////////////////////////////////////////////////////////////////// +// MuldeR's Utilities for Qt +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +// http://www.gnu.org/licenses/lgpl-2.1.txt +////////////////////////////////////////////////////////////////////////////////// + +//MUtils +#include + +//Qt +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////////// +// TYPES +////////////////////////////////////////////////////////////////////////////////// + +typedef QPair translation_info_t; +typedef QPair translation_data_t; + +typedef QPair translation_entry_t; +typedef QMap translation_store_t; + +#define MAKE_ENTRY(NAME,PATH,SYSID,CNTRY) \ + qMakePair(qMakePair((NAME),(PATH)),qMakePair((SYSID),(CNTRY))) + +////////////////////////////////////////////////////////////////////////////////// +// TRANSLATIONS STORE +////////////////////////////////////////////////////////////////////////////////// + +static QReadWriteLock g_translation_lock; +static QScopedPointer g_translation_data; +static QScopedPointer g_translation_inst; + +////////////////////////////////////////////////////////////////////////////////// +// CONSTANT +////////////////////////////////////////////////////////////////////////////////// + +namespace MUtils +{ + namespace Translation + { + const char *const DEFAULT_LANGID = "en"; + } +} + +////////////////////////////////////////////////////////////////////////////////// +// REGISTER TRANSLATION +////////////////////////////////////////////////////////////////////////////////// + +bool MUtils::Translation::insert(const QString &langId, const QString &qmFile, const QString &langName, const quint32 &systemId, const quint32 &country) +{ + QWriteLocker writeLockTranslations(&g_translation_lock); + + const QString key = langId.simplified().toLower(); + if(key.isEmpty() || qmFile.isEmpty() || langName.isEmpty() || (systemId < 1)) + { + return false; + } + + if(g_translation_data.isNull()) + { + g_translation_data.reset(new translation_store_t()); + } + + if(g_translation_data->contains(key)) + { + qWarning("Translation store already contains entry for '%s', going to replace!", MUTILS_UTF8(key)); + } + + g_translation_data->insert(key, MAKE_ENTRY(langName, qmFile, systemId, country)); + return true; +} + +////////////////////////////////////////////////////////////////////////////////// +// GET TRANSLATION INFO +////////////////////////////////////////////////////////////////////////////////// + +int MUtils::Translation::enumerate(QStringList &list) +{ + QReadLocker readLockTranslations(&g_translation_lock); + + if(g_translation_data.isNull()) + { + list.clear(); + return -1; + } + + list.swap(g_translation_data->keys()); + return list.count(); +} + +QString MUtils::Translation::get_name(const QString &langId) +{ + QReadLocker readLockTranslations(&g_translation_lock); + + const QString key = langId.simplified().toLower(); + if(key.isEmpty() || g_translation_data.isNull() || (!g_translation_data->contains(key))) + { + return QString(); + } + + return (*g_translation_data)[key].first.first; +} + +quint32 MUtils::Translation::get_sysid(const QString &langId) +{ + QReadLocker readLockTranslations(&g_translation_lock); + + const QString key = langId.simplified().toLower(); + if(key.isEmpty() || g_translation_data.isNull() || (!g_translation_data->contains(key))) + { + return 0; + } + + return (*g_translation_data)[key].second.first; +} + +quint32 MUtils::Translation::get_country(const QString &langId) +{ + QReadLocker readLockTranslations(&g_translation_lock); + const QString key = langId.simplified().toLower(); + if(key.isEmpty() || g_translation_data.isNull() || (!g_translation_data->contains(key))) + { + return 0; + } + + return (*g_translation_data)[key].second.second; +} + +////////////////////////////////////////////////////////////////////////////////// +// INSTALL TRANSLATION +////////////////////////////////////////////////////////////////////////////////// + +bool MUtils::Translation::install_translator(const QString &langId) +{ + QReadLocker readLockTranslations(&g_translation_lock); + + const QString key = langId.simplified().toLower(); + if(key.isEmpty() || g_translation_data.isNull() || (!g_translation_data->contains(key))) + { + return false; + } + + const QString qmFile = (*g_translation_data)[key].first.second; + readLockTranslations.unlock(); + return install_translator_from_file(qmFile); +} + +bool MUtils::Translation::install_translator_from_file(const QString &qmFile) +{ + QWriteLocker writeLock(&g_translation_lock); + + if(g_translation_inst.isNull()) + { + g_translation_inst.reset(new QTranslator()); + } + + if(qmFile.isEmpty()) + { + QApplication::removeTranslator(g_translation_inst.data()); + return true; + } + + const QFileInfo qmFileInfo(qmFile); + if(!(qmFileInfo.exists() && qmFileInfo.isFile())) + { + qWarning("Translation file not found:\n\"%s\"", MUTILS_UTF8(qmFile)); + return false; + } + + const QString qmPath = QFileInfo(qmFile).canonicalFilePath(); + if(!qmPath.isEmpty()) + { + QApplication::removeTranslator(g_translation_inst.data()); + if(g_translation_inst->load(qmPath)) + { + QApplication::installTranslator(g_translation_inst.data()); + return true; + } + } + + qWarning("Failed to load translation:\n\"%s\"", MUTILS_UTF8(qmFile)); + return false; +} diff --git a/src/Version.cpp b/src/Version.cpp index 5c3d9d8..d31a933 100644 --- a/src/Version.cpp +++ b/src/Version.cpp @@ -19,14 +19,14 @@ // http://www.gnu.org/licenses/lgpl-2.1.txt ////////////////////////////////////////////////////////////////////////////////// -#define MUTILS_INC_CONFIG 1 - +//MUtils #include - -//Internal #include #include #include + +//Internal +#define MUTILS_INC_CONFIG 1 #include "Config.h" ///////////////////////////////////////////////////////////////////////////////