From 4f4da7f114ef4b643afdba711aa5331e082bec91 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sat, 10 Jun 2023 02:50:19 +0300 Subject: [PATCH] Revert qt_sinks changes and color support, since they are not thread safe --- include/spdlog/sinks/qt_sinks.h | 194 +++++--------------------------- 1 file changed, 26 insertions(+), 168 deletions(-) diff --git a/include/spdlog/sinks/qt_sinks.h b/include/spdlog/sinks/qt_sinks.h index 7714043d..d61c6bec 100644 --- a/include/spdlog/sinks/qt_sinks.h +++ b/include/spdlog/sinks/qt_sinks.h @@ -4,16 +4,12 @@ #pragma once // -// Custom sink for QPlainTextEdit or QTextEdit and its children(QTextBrowser...etc) -// Building and using requires Qt library. -// Recommended: Use the `qt_color_sink` to get nice coloring per level -// For example -// auto edit = new QTextEdit(); -// setCentralWidget(edit); -// auto logger = spdlog::qt_color_logger_mt("my_logger", my_edit_widget); +// Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... +// etc) Building and using requires Qt library. // -// Warning: those sinks won't be notified if the target widget is destroyed. -// Use a permanent QObject or make sure the sink is not used after the widget is gone. +// Warning: the qt_sink won't be notified if the target widget is destroyed. +// If the widget's lifetime can be shorter than the logger's one, you should provide some permanent QObject, +// and then use a standard signal/slot. // #include "spdlog/common.h" @@ -21,32 +17,22 @@ #include "spdlog/details/synchronous_factory.h" #include "spdlog/sinks/base_sink.h" -#include - -#include #include #include -#include +// +// qt_sink class +// namespace spdlog { namespace sinks { template class qt_sink : public base_sink { public: - // qt object is the object that receives the log messages (e.g QPlainTextEdit or QTextEdit) - // meta_method_name is the name of the slot to be called on the qt_object for every log message (e.g "append(QString)"). - qt_sink(QObject *qt_object, const std::string &meta_method_name) + qt_sink(QObject *qt_object, const std::string &meta_method) { - // store the meta method object for later usage qt_object_ = qt_object; - auto *metaobject = qt_object_->metaObject(); - auto methodIndex = metaobject->indexOfMethod(meta_method_name.c_str()); - if (methodIndex == -1) - { - throw_spdlog_ex("qt_sink: qt_object does not have meta_method " + meta_method_name); - } - meta_method_ = metaobject->method(methodIndex); + meta_method_ = meta_method; } ~qt_sink() @@ -60,180 +46,52 @@ protected: memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); string_view_t str = string_view_t(formatted.data(), formatted.size()); - auto payload = QString::fromUtf8(str.data(), static_cast(str.size())).trimmed(); - meta_method_.invoke(qt_object_, Qt::AutoConnection, Q_ARG(QString, payload)); + QMetaObject::invokeMethod(qt_object_, meta_method_.c_str(), Qt::AutoConnection, + Q_ARG(QString, QString::fromUtf8(str.data(), static_cast(str.size())).trimmed())); } void flush_() override {} private: QObject *qt_object_ = nullptr; - QMetaMethod meta_method_; -}; - -// QT color sink to QTextEdit. -// Color location is determined by the sink log pattern like in the rest of spdlog sinks. -// Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). -// Note: Only ascii (latin1) is supported by this sink. -template -class qt_color_sink : public base_sink -{ -public: - qt_color_sink(QTextEdit *qt_text_edit) - : qt_text_edit_(qt_text_edit) - { - if (!qt_text_edit_) - { - throw_spdlog_ex("qt_color_text_sink: text_edit is null"); - } - // set color for each log level - default_color_ = qt_text_edit_->currentCharFormat(); - QTextCharFormat format; - // trace - format.setForeground(Qt::gray); - colors_.at(level::trace) = format; - // debug - format.setForeground(Qt::cyan); - colors_.at(level::debug) = format; - // info - format.setForeground(Qt::green); - colors_.at(level::info) = format; - // warn - format.setForeground(Qt::yellow); - colors_.at(level::warn) = format; - // err - format.setForeground(Qt::red); - colors_.at(level::err) = format; - // critical - format.setForeground(Qt::white); - format.setBackground(Qt::red); - colors_.at(level::critical) = format; - } - - ~qt_color_sink() - { - flush_(); - } - - void set_default_color(QTextCharFormat format) - { - std::lock_guard lock(base_sink::mutex_); - default_color_ = format; - } - - void set_level_color(level::level_enum color_level, QTextCharFormat format) - { - std::lock_guard lock(base_sink::mutex_); - colors_.at(static_cast(color_level)) = format; - } - - QTextCharFormat &get_level_color(level::level_enum color_level) - { - std::lock_guard lock(base_sink::mutex_); - return colors_.at(static_cast(color_level)); - } - - QTextCharFormat &get_default_color() - { - std::lock_guard lock(base_sink::mutex_); - return default_color_; - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - string_view_t str = string_view_t(formatted.data(), formatted.size()); - - // apply the color to the color range in the formatted message. - auto payload = QString::fromLatin1(str.data(), static_cast(str.size())); - if (msg.color_range_end > msg.color_range_start) - { - QTextCursor cursor(qt_text_edit_->document()); - cursor.movePosition(QTextCursor::End); - - // insert the text before the color range - cursor.setCharFormat(default_color_); - cursor.insertText(payload.left(msg.color_range_start)); - - // insert the colorized text - auto color = colors_.at(static_cast(msg.level)); - cursor.setCharFormat(color); - cursor.insertText(payload.mid(msg.color_range_start, msg.color_range_end - msg.color_range_start)); - - // insert the text after the color range with default format - cursor.setCharFormat(default_color_); - cursor.insertText(payload.mid(msg.color_range_end)); - } - else // no color range - { - qt_text_edit_->append(payload.trimmed()); - } - } - - void flush_() override {} - QTextEdit *qt_text_edit_; - QTextCharFormat default_color_; - std::array colors_; + std::string meta_method_; }; #include "spdlog/details/null_mutex.h" #include using qt_sink_mt = qt_sink; using qt_sink_st = qt_sink; -using qt_color_sink_mt = qt_color_sink; -using qt_color_sink_st = qt_color_sink; } // namespace sinks // // Factory functions // +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") +{ + return Factory::template create(logger_name, qt_object, meta_method); +} -// create logger using QTextEdit object template inline std::shared_ptr qt_logger_mt( - const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append(QString)") + const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") { return Factory::template create(logger_name, qt_object, meta_method); } template inline std::shared_ptr qt_logger_st( - const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append(QString)") + const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") { return Factory::template create(logger_name, qt_object, meta_method); } -// create logger using QPlainTextEdit object -template -inline std::shared_ptr qt_logger_mt( - const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText(QString)") -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -template -inline std::shared_ptr qt_logger_st( - const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText(QString)") -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -// create color qt logger using QTextEdit object -template -inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_object) -{ - return Factory::template create(logger_name, qt_object); -} - -template -inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_object) -{ - return Factory::template create(logger_name, qt_object); -} - -// create logger with other QObject object template inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) {