File indexing completed on 2025-12-17 10:29:02
0001
0002
0003
0004 #pragma once
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include "spdlog/common.h"
0016 #include "spdlog/details/log_msg.h"
0017 #include "spdlog/details/synchronous_factory.h"
0018 #include "spdlog/sinks/base_sink.h"
0019 #include <array>
0020
0021 #include <QPlainTextEdit>
0022 #include <QTextEdit>
0023
0024
0025
0026
0027 namespace spdlog {
0028 namespace sinks {
0029 template <typename Mutex>
0030 class qt_sink : public base_sink<Mutex> {
0031 public:
0032 qt_sink(QObject *qt_object, std::string meta_method)
0033 : qt_object_(qt_object),
0034 meta_method_(std::move(meta_method)) {
0035 if (!qt_object_) {
0036 throw_spdlog_ex("qt_sink: qt_object is null");
0037 }
0038 }
0039
0040 ~qt_sink() { flush_(); }
0041
0042 protected:
0043 void sink_it_(const details::log_msg &msg) override {
0044 memory_buf_t formatted;
0045 base_sink<Mutex>::formatter_->format(msg, formatted);
0046 const string_view_t str = string_view_t(formatted.data(), formatted.size());
0047 QMetaObject::invokeMethod(
0048 qt_object_, meta_method_.c_str(), Qt::AutoConnection,
0049 Q_ARG(QString, QString::fromUtf8(str.data(), static_cast<int>(str.size())).trimmed()));
0050 }
0051
0052 void flush_() override {}
0053
0054 private:
0055 QObject *qt_object_ = nullptr;
0056 std::string meta_method_;
0057 };
0058
0059
0060
0061
0062
0063
0064
0065 template <typename Mutex>
0066 class qt_color_sink : public base_sink<Mutex> {
0067 public:
0068 qt_color_sink(QTextEdit *qt_text_edit,
0069 int max_lines,
0070 bool dark_colors = false,
0071 bool is_utf8 = false)
0072 : qt_text_edit_(qt_text_edit),
0073 max_lines_(max_lines),
0074 is_utf8_(is_utf8) {
0075 if (!qt_text_edit_) {
0076 throw_spdlog_ex("qt_color_text_sink: text_edit is null");
0077 }
0078
0079 default_color_ = qt_text_edit_->currentCharFormat();
0080
0081 QTextCharFormat format;
0082
0083 format.setForeground(dark_colors ? Qt::darkGray : Qt::gray);
0084 colors_.at(level::trace) = format;
0085
0086 format.setForeground(dark_colors ? Qt::darkCyan : Qt::cyan);
0087 colors_.at(level::debug) = format;
0088
0089 format.setForeground(dark_colors ? Qt::darkGreen : Qt::green);
0090 colors_.at(level::info) = format;
0091
0092 format.setForeground(dark_colors ? Qt::darkYellow : Qt::yellow);
0093 colors_.at(level::warn) = format;
0094
0095 format.setForeground(Qt::red);
0096 colors_.at(level::err) = format;
0097
0098 format.setForeground(Qt::white);
0099 format.setBackground(Qt::red);
0100 colors_.at(level::critical) = format;
0101 }
0102
0103 ~qt_color_sink() { flush_(); }
0104
0105 void set_default_color(QTextCharFormat format) {
0106
0107 default_color_ = format;
0108 }
0109
0110 void set_level_color(level::level_enum color_level, QTextCharFormat format) {
0111
0112 colors_.at(static_cast<size_t>(color_level)) = format;
0113 }
0114
0115 QTextCharFormat &get_level_color(level::level_enum color_level) {
0116 std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
0117 return colors_.at(static_cast<size_t>(color_level));
0118 }
0119
0120 QTextCharFormat &get_default_color() {
0121 std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
0122 return default_color_;
0123 }
0124
0125 protected:
0126 struct invoke_params {
0127 invoke_params(int max_lines,
0128 QTextEdit *q_text_edit,
0129 QString payload,
0130 QTextCharFormat default_color,
0131 QTextCharFormat level_color,
0132 int color_range_start,
0133 int color_range_end)
0134 : max_lines(max_lines),
0135 q_text_edit(q_text_edit),
0136 payload(std::move(payload)),
0137 default_color(default_color),
0138 level_color(level_color),
0139 color_range_start(color_range_start),
0140 color_range_end(color_range_end) {}
0141 int max_lines;
0142 QTextEdit *q_text_edit;
0143 QString payload;
0144 QTextCharFormat default_color;
0145 QTextCharFormat level_color;
0146 int color_range_start;
0147 int color_range_end;
0148 };
0149
0150 void sink_it_(const details::log_msg &msg) override {
0151 memory_buf_t formatted;
0152 base_sink<Mutex>::formatter_->format(msg, formatted);
0153
0154 const string_view_t str = string_view_t(formatted.data(), formatted.size());
0155
0156 QString payload;
0157 int color_range_start = static_cast<int>(msg.color_range_start);
0158 int color_range_end = static_cast<int>(msg.color_range_end);
0159 if (is_utf8_) {
0160 payload = QString::fromUtf8(str.data(), static_cast<int>(str.size()));
0161
0162 if (msg.color_range_start < msg.color_range_end) {
0163 color_range_start = QString::fromUtf8(str.data(), msg.color_range_start).size();
0164 color_range_end = QString::fromUtf8(str.data(), msg.color_range_end).size();
0165 }
0166 } else {
0167 payload = QString::fromLatin1(str.data(), static_cast<int>(str.size()));
0168 }
0169
0170 invoke_params params{max_lines_,
0171 qt_text_edit_,
0172 std::move(payload),
0173 default_color_,
0174 colors_.at(msg.level),
0175 color_range_start,
0176 color_range_end};
0177
0178 QMetaObject::invokeMethod(
0179 qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection);
0180 }
0181
0182 void flush_() override {}
0183
0184
0185
0186
0187
0188 static void invoke_method_(invoke_params params) {
0189 auto *document = params.q_text_edit->document();
0190 QTextCursor cursor(document);
0191
0192
0193 while (document->blockCount() > params.max_lines) {
0194 cursor.select(QTextCursor::BlockUnderCursor);
0195 cursor.removeSelectedText();
0196 cursor.deleteChar();
0197 }
0198
0199 cursor.movePosition(QTextCursor::End);
0200 cursor.setCharFormat(params.default_color);
0201
0202
0203 if (params.color_range_end <= params.color_range_start) {
0204 cursor.insertText(params.payload);
0205 return;
0206 }
0207
0208
0209 cursor.insertText(params.payload.left(params.color_range_start));
0210
0211
0212 cursor.setCharFormat(params.level_color);
0213 cursor.insertText(params.payload.mid(params.color_range_start,
0214 params.color_range_end - params.color_range_start));
0215
0216
0217 cursor.setCharFormat(params.default_color);
0218 cursor.insertText(params.payload.mid(params.color_range_end));
0219 }
0220
0221 QTextEdit *qt_text_edit_;
0222 int max_lines_;
0223 bool is_utf8_;
0224 QTextCharFormat default_color_;
0225 std::array<QTextCharFormat, level::n_levels> colors_;
0226 };
0227
0228 #include "spdlog/details/null_mutex.h"
0229 #include <mutex>
0230
0231 using qt_sink_mt = qt_sink<std::mutex>;
0232 using qt_sink_st = qt_sink<details::null_mutex>;
0233 using qt_color_sink_mt = qt_color_sink<std::mutex>;
0234 using qt_color_sink_st = qt_color_sink<details::null_mutex>;
0235 }
0236
0237
0238
0239
0240
0241
0242 template <typename Factory = spdlog::synchronous_factory>
0243 inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name,
0244 QTextEdit *qt_object,
0245 const std::string &meta_method = "append") {
0246 return Factory::template create<sinks::qt_sink_mt>(logger_name, qt_object, meta_method);
0247 }
0248
0249 template <typename Factory = spdlog::synchronous_factory>
0250 inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name,
0251 QTextEdit *qt_object,
0252 const std::string &meta_method = "append") {
0253 return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
0254 }
0255
0256
0257 template <typename Factory = spdlog::synchronous_factory>
0258 inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name,
0259 QPlainTextEdit *qt_object,
0260 const std::string &meta_method = "appendPlainText") {
0261 return Factory::template create<sinks::qt_sink_mt>(logger_name, qt_object, meta_method);
0262 }
0263
0264 template <typename Factory = spdlog::synchronous_factory>
0265 inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name,
0266 QPlainTextEdit *qt_object,
0267 const std::string &meta_method = "appendPlainText") {
0268 return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
0269 }
0270
0271 template <typename Factory = spdlog::synchronous_factory>
0272 inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name,
0273 QObject *qt_object,
0274 const std::string &meta_method) {
0275 return Factory::template create<sinks::qt_sink_mt>(logger_name, qt_object, meta_method);
0276 }
0277
0278 template <typename Factory = spdlog::synchronous_factory>
0279 inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name,
0280 QObject *qt_object,
0281 const std::string &meta_method) {
0282 return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
0283 }
0284
0285
0286 template <typename Factory = spdlog::synchronous_factory>
0287 inline std::shared_ptr<logger> qt_color_logger_mt(const std::string &logger_name,
0288 QTextEdit *qt_text_edit,
0289 int max_lines,
0290 bool is_utf8 = false) {
0291 return Factory::template create<sinks::qt_color_sink_mt>(logger_name, qt_text_edit, max_lines,
0292 false, is_utf8);
0293 }
0294
0295 template <typename Factory = spdlog::synchronous_factory>
0296 inline std::shared_ptr<logger> qt_color_logger_st(const std::string &logger_name,
0297 QTextEdit *qt_text_edit,
0298 int max_lines,
0299 bool is_utf8 = false) {
0300 return Factory::template create<sinks::qt_color_sink_st>(logger_name, qt_text_edit, max_lines,
0301 false, is_utf8);
0302 }
0303
0304 }