From b5f0e15e5ec68314b57ab9579d6796f49422a8fd Mon Sep 17 00:00:00 2001 From: Uyanide Date: Thu, 7 Aug 2025 02:05:34 +0200 Subject: [PATCH] refactor: better logger --- CMakeLists.txt | 2 +- src/images_carousel.cpp | 10 +++- src/logger.cpp | 106 ++++++++++++++++++++++++++++++++++++++++ src/logger.h | 77 +++++++++++++---------------- src/main.cpp | 5 +- 5 files changed, 150 insertions(+), 50 deletions(-) create mode 100644 src/logger.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a96c12..1ca1207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) ${PROJECT_SOURCES} src/images_carousel.h src/images_carousel.cpp src/designer/images_carousel.ui src/config.h src/config.cpp - src/logger.h + src/logger.h src/logger.cpp src/loading_indicator.h src/loading_indicator.cpp src/designer/loading_indicator.ui ) # Define target properties for Android with Qt 6 as: diff --git a/src/images_carousel.cpp b/src/images_carousel.cpp index 889ccbe..ab0ffaf 100644 --- a/src/images_carousel.cpp +++ b/src/images_carousel.cpp @@ -1,7 +1,7 @@ /* * @Author: Uyanide pywang0608@foxmail.com * @Date: 2025-08-05 01:22:53 - * @LastEditTime: 2025-08-07 00:50:11 + * @LastEditTime: 2025-08-07 02:01:23 * @Description: Animated carousel widget for displaying and selecting images. */ #include "images_carousel.h" @@ -172,6 +172,7 @@ void ImageLoader::run() { ImageData::ImageData(const QString& p, const int initWidth, const int initHeight) : file(p) { if (!image.load(p)) { warn(QString("Failed to load image from path: %1").arg(p)); + return; } // resize in "cover" mode const QSize targetSize(initWidth, initHeight); @@ -290,7 +291,12 @@ ImageItem::ImageItem(const ImageData* data, m_itemSize(itemWidth, itemHeight), m_itemFocusSize(itemFocusWidth, itemFocusHeight) { setScaledContents(true); - setPixmap(QPixmap::fromImage(data->image)); + if (data->image.isNull()) { + setText(":("); + setAlignment(Qt::AlignCenter); + } else { + setPixmap(QPixmap::fromImage(data->image)); + } setFixedSize(itemWidth, itemHeight); } diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..3e8da8e --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,106 @@ +/* + * @Author: Uyanide pywang0608@foxmail.com + * @Date: 2025-08-07 01:12:37 + * @LastEditTime: 2025-08-07 01:55:56 + * @Description: Implementation of logger. + */ +#include "logger.h" + +#include + +#include +#include +#include +#include +#include + +#ifdef GENERAL_LOGGER_DISABLED +#define ENSURE_ENABLED return; +#else +#define ENSURE_ENABLED +static QTextStream s_logStream(stderr); +#endif + +Logger* Logger::instance(FILE* stream) { + static Logger* logger{}; + if (!logger) { + if (!stream) { + stream = stderr; // Default to stderr if no stream provided + } + logger = new Logger(stream); + } + return logger; +} + +Logger::Logger(FILE* stream, QObject* parent) + : QObject(parent), m_stream(stream), m_logStream(stream) { + connect(this, + &Logger::logSig, + this, + &Logger::_log, + Qt::QueuedConnection); +} + +void Logger::_log( + const QString& msg, + const QString& levelString, + const QString& levelColorString, + const QString& textColorString, + const GeneralLogger::LogIndent indent) { + ENSURE_ENABLED + + s_logStream << levelColorString << levelString << ' '; + for (qint32 i = 0; i < indent; i++) s_logStream << " "; + s_logStream << textColorString << msg << (textColorString.isEmpty() ? "\n" : "\033[0m\n"); + s_logStream.flush(); +} + +bool Logger::isColored() { + const auto stream = Logger::instance()->m_stream; + if (!isatty(fileno(stream))) { + return false; + } + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString term = env.value("TERM"); + if (term.isEmpty() || term == "dumb") { + return false; + } + return true; +} + +void GeneralLogger::info( + const QString& msg, + const GeneralLogger::LogIndent indent) { + ENSURE_ENABLED + constexpr const char* colorInfoMsg[]{"\033[32m", "\033[0m", "\033[0m"}; + const auto color = Logger::isColored(); + emit Logger::instance() -> logSig(msg, + "[INFO]", + color ? "\033[92m" : "", + color ? colorInfoMsg[indent] : "", + indent); +} + +void GeneralLogger::warn( + const QString& msg, + const GeneralLogger::LogIndent indent) { + ENSURE_ENABLED + const auto color = Logger::isColored(); + emit Logger::instance() -> logSig(msg, + "[WARN]", + color ? "\033[93m" : "", + color ? "\033[33m" : "", + indent); +} + +void GeneralLogger::error( + const QString& msg, + const GeneralLogger::LogIndent indent) { + ENSURE_ENABLED + const auto color = Logger::isColored(); + emit Logger::instance() -> logSig(msg, + "[ERROR]", + color ? "\033[91m" : "", + color ? "\033[31m" : "", + indent); +} \ No newline at end of file diff --git a/src/logger.h b/src/logger.h index 8feb998..fdd39d8 100644 --- a/src/logger.h +++ b/src/logger.h @@ -1,71 +1,62 @@ /* * @Author: Uyanide pywang0608@foxmail.com * @Date: 2025-08-05 10:43:31 - * @LastEditTime: 2025-08-05 17:25:18 - * @Description: A simple logger for general use. - * g_logStream must be defined somewhere else in the project. + * @LastEditTime: 2025-08-07 01:55:42 + * @Description: A simple thread-safe logger for general use. */ #ifndef GENERAL_LOGGER_H #define GENERAL_LOGGER_H +#include #include #include namespace GeneralLogger { -inline constexpr const char* colorInfoMsg[]{"\033[32m", "\033[0m", "\033[0m"}; - enum LogIndent : qint32 { GENERAL = 0, STEP = 1, DETAIL = 2, }; -#ifdef GENERAL_LOGGER_DISABLED -#define ENSURE_ENABLED return; -#else -#define ENSURE_ENABLED -extern QTextStream g_logStream; -#endif +void info(const QString& msg, + const LogIndent indent = GENERAL); -inline void -info(const QString& msg, - const LogIndent indent = GENERAL, - const bool color = true) { - ENSURE_ENABLED +void warn(const QString& msg, + const LogIndent indent = GENERAL); - g_logStream << (color ? "\033[92m" : "") << "[INFO] "; - for (qint32 i = 0; i < indent; i++) g_logStream << " "; - g_logStream << (color ? colorInfoMsg[indent] : "") << msg << (color ? "\033[0m\n" : "\n"); - g_logStream.flush(); -} +void error(const QString& msg, + const LogIndent indent = GENERAL); +} // namespace GeneralLogger -inline void -warn(const QString& msg, - const LogIndent indent = GENERAL, - const bool color = true) { - ENSURE_ENABLED +class Logger : public QObject { + Q_OBJECT - g_logStream << (color ? "\033[93m" : "") << "[WARN] "; - for (uint32_t i = 0; i < indent; i++) g_logStream << " "; - g_logStream << (color ? "\033[33m" : "") << msg << (color ? "\033[0m\n" : "\n"); - g_logStream.flush(); -} + public: + static Logger* instance(FILE* stream = nullptr); -inline void -error(const QString& msg, - const LogIndent indent = GENERAL, - const bool color = true) { - ENSURE_ENABLED + static bool isColored(); - g_logStream << (color ? "\033[91m" : "") << "[ERROR] "; - for (uint32_t i = 0; i < indent; i++) g_logStream << " "; - g_logStream << (color ? "\033[31m" : "") << msg << (color ? "\033[0m\n" : "\n"); - g_logStream.flush(); -} + private: + explicit Logger(FILE* stream, QObject* parent = nullptr); -#undef ENSURE_ENABLED + private slots: + void _log(const QString& msg, + const QString& levelString, + const QString& levelColorString, + const QString& textColorString, + const GeneralLogger::LogIndent indent); -}; // namespace GeneralLogger + private: + FILE* m_stream; + QTextStream m_logStream; + + signals: + void logSig(const QString& msg, + const QString& levelString, + const QString& levelColorString, + const QString& textColorString, + const GeneralLogger::LogIndent indent); +}; #endif // GENERAL_LOGGER_H diff --git a/src/main.cpp b/src/main.cpp index 6570c8e..1366e16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ /* * @Author: Uyanide pywang0608@foxmail.com * @Date: 2025-08-05 00:37:58 - * @LastEditTime: 2025-08-05 19:42:07 + * @LastEditTime: 2025-08-07 01:49:07 * @Description: Entry point. */ #include @@ -12,11 +12,8 @@ #include #include "config.h" -#include "logger.h" #include "main_window.h" -QTextStream GeneralLogger::g_logStream(stderr); - static QString getConfigDir() { auto configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); if (configDir.isEmpty()) {