diff --git a/include/spdlog/sinks/qt_sinks.h b/include/spdlog/sinks/qt_sinks.h index 1a40638d..f801ac34 100644 --- a/include/spdlog/sinks/qt_sinks.h +++ b/include/spdlog/sinks/qt_sinks.h @@ -30,13 +30,14 @@ template class qt_sink : public base_sink { public: - qt_sink(QObject *qt_object, std::string meta_method): qt_object_(qt_object), meta_method_(std::move(meta_method)) + qt_sink(QObject *qt_object, std::string meta_method) + : qt_object_(qt_object) + , meta_method_(std::move(meta_method)) { if (!qt_object_) { throw_spdlog_ex("qt_sink: qt_object is null"); } - } ~qt_sink() @@ -66,166 +67,162 @@ private: // Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). // max_lines is the maximum number of lines that the sink will hold before removing the oldest lines. // Note: Only ascii (latin1) is supported by this sink. - template - class qt_color_sink : public base_sink +template +class qt_color_sink : public base_sink +{ +public: + qt_color_sink(QTextEdit *qt_text_edit, int max_lines) + : qt_text_edit_(qt_text_edit) + , max_lines_(max_lines) { - public: - qt_color_sink(QTextEdit *qt_text_edit, int max_lines) - : qt_text_edit_(qt_text_edit), max_lines_(max_lines) + if (!qt_text_edit_) { - if (!qt_text_edit_) - { - throw_spdlog_ex("qt_color_text_sink: text_edit is null"); - } - - default_color_ = qt_text_edit_->currentCharFormat(); - // set colors - 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; + throw_spdlog_ex("qt_color_text_sink: text_edit is null"); } - ~qt_color_sink() - { - flush_(); - } + default_color_ = qt_text_edit_->currentCharFormat(); + // set colors + 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; + } - void set_default_color(QTextCharFormat format) - { - // std::lock_guard lock(base_sink::mutex_); - default_color_ = format; - } + ~qt_color_sink() + { + flush_(); + } - 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; - } + void set_default_color(QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + default_color_ = format; + } - QTextCharFormat &get_level_color(level::level_enum color_level) - { - std::lock_guard lock(base_sink::mutex_); - return colors_.at(static_cast(color_level)); - } + 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_default_color() - { - std::lock_guard lock(base_sink::mutex_); - return default_color_; - } + QTextCharFormat &get_level_color(level::level_enum color_level) + { + std::lock_guard lock(base_sink::mutex_); + return colors_.at(static_cast(color_level)); + } - protected: - struct invoke_params - { - invoke_params(int max_lines, QTextEdit *q_text_edit, QString payload, QTextCharFormat default_color, - QTextCharFormat level_color, int color_range_start, int color_range_end) - : max_lines(max_lines), - q_text_edit(q_text_edit), - payload(std::move(payload)), - default_color(default_color), - level_color(level_color), - color_range_start(color_range_start), - color_range_end(color_range_end) - { - } - int max_lines; - QTextEdit *q_text_edit; - QString payload; - QTextCharFormat default_color; - QTextCharFormat level_color; - int color_range_start; - int color_range_end; - }; + QTextCharFormat &get_default_color() + { + std::lock_guard lock(base_sink::mutex_); + return default_color_; + } - void sink_it_(const details::log_msg &msg) override - { - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - - const 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())); - - invoke_params params { - max_lines_, // max lines - qt_text_edit_, // text edit to append to - std::move(payload), // text to append - default_color_, // default color - colors_.at(msg.level), // color to apply - static_cast(msg.color_range_start), // color range start - static_cast(msg.color_range_end)}; // color range end - - QMetaObject::invokeMethod( - qt_text_edit_, - [params]() {invoke_method_(params);}, - Qt::AutoConnection); - - } - - void flush_() override {} - - // Add colored text to the text edit widget. This method is invoked in the GUI thread. - // It is a static method to ensure that it is handled correctly even if the sink is destroyed prematurely - // before it is invoked. - - static void invoke_method_(invoke_params params) - { - auto *document = params.q_text_edit->document(); - QTextCursor cursor(document); - - // remove first blocks if number of blocks exceeds max_lines - while(document->blockCount() > params.max_lines) - { - cursor.select(QTextCursor::BlockUnderCursor); - cursor.removeSelectedText(); - cursor.deleteChar(); // delete the newline after the block - } - - cursor.movePosition(QTextCursor::End); - cursor.setCharFormat(params.default_color); - - // if color range not specified or not not valid, just append the text with default color - if(params.color_range_end <= params.color_range_start) - { - cursor.insertText(params.payload); - return; - } - - // insert the text before the color range - cursor.insertText(params.payload.left(params.color_range_start)); - - // insert the colorized text - cursor.setCharFormat(params.level_color); - cursor.insertText(params.payload.mid(params.color_range_start, params.color_range_end - params.color_range_start)); - - // insert the text after the color range with default format - cursor.setCharFormat(params.default_color); - cursor.insertText(params.payload.mid(params.color_range_end)); - } - - QTextEdit *qt_text_edit_; - int max_lines_; - QTextCharFormat default_color_; - std::array colors_; +protected: + struct invoke_params + { + invoke_params(int max_lines, QTextEdit *q_text_edit, QString payload, QTextCharFormat default_color, QTextCharFormat level_color, + int color_range_start, int color_range_end) + : max_lines(max_lines) + , q_text_edit(q_text_edit) + , payload(std::move(payload)) + , default_color(default_color) + , level_color(level_color) + , color_range_start(color_range_start) + , color_range_end(color_range_end) + {} + int max_lines; + QTextEdit *q_text_edit; + QString payload; + QTextCharFormat default_color; + QTextCharFormat level_color; + int color_range_start; + int color_range_end; }; + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + + const 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())); + + invoke_params params{max_lines_, // max lines + qt_text_edit_, // text edit to append to + std::move(payload), // text to append + default_color_, // default color + colors_.at(msg.level), // color to apply + static_cast(msg.color_range_start), // color range start + static_cast(msg.color_range_end)}; // color range end + + QMetaObject::invokeMethod( + qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection); + } + + void flush_() override {} + + // Add colored text to the text edit widget. This method is invoked in the GUI thread. + // It is a static method to ensure that it is handled correctly even if the sink is destroyed prematurely + // before it is invoked. + + static void invoke_method_(invoke_params params) + { + auto *document = params.q_text_edit->document(); + QTextCursor cursor(document); + + // remove first blocks if number of blocks exceeds max_lines + while (document->blockCount() > params.max_lines) + { + cursor.select(QTextCursor::BlockUnderCursor); + cursor.removeSelectedText(); + cursor.deleteChar(); // delete the newline after the block + } + + cursor.movePosition(QTextCursor::End); + cursor.setCharFormat(params.default_color); + + // if color range not specified or not not valid, just append the text with default color + if (params.color_range_end <= params.color_range_start) + { + cursor.insertText(params.payload); + return; + } + + // insert the text before the color range + cursor.insertText(params.payload.left(params.color_range_start)); + + // insert the colorized text + cursor.setCharFormat(params.level_color); + cursor.insertText(params.payload.mid(params.color_range_start, params.color_range_end - params.color_range_start)); + + // insert the text after the color range with default format + cursor.setCharFormat(params.default_color); + cursor.insertText(params.payload.mid(params.color_range_end)); + } + + QTextEdit *qt_text_edit_; + int max_lines_; + QTextCharFormat default_color_; + std::array colors_; +}; + #include "spdlog/details/null_mutex.h" #include @@ -283,13 +280,13 @@ inline std::shared_ptr qt_logger_st(const std::string &logger_name, QObj template inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) { - return Factory::template create(logger_name, qt_text_edit, max_lines); + return Factory::template create(logger_name, qt_text_edit, max_lines); } template inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) { - return Factory::template create(logger_name, qt_text_edit, max_lines); + return Factory::template create(logger_name, qt_text_edit, max_lines); } } // namespace spdlog