From ff8e353290c0b443c0ec68ee3fc4e137a7025f27 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Sun, 23 Jul 2017 03:45:40 +0200 Subject: Add proxy log window Both GTK and QT log windows will scroll down to the last row whenever a new row is appended. --- src/gui_qt.cc | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) (limited to 'src/gui_qt.cc') diff --git a/src/gui_qt.cc b/src/gui_qt.cc index 7aa52d3..cc2ad0d 100644 --- a/src/gui_qt.cc +++ b/src/gui_qt.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ #include "gui_main.hh" #include "gui_menu.hh" #include "gui_statusbar.hh" +#include "gui_textwnd.hh" #include "looper.hh" #include "observers.hh" @@ -1098,6 +1100,181 @@ private: bool applied_; }; +class OptionalCloseWidget : public QWidget { +public: + class Delegate { + public: + virtual ~Delegate() {} + + virtual bool about_to_close() = 0; + + protected: + Delegate() {} + }; + + OptionalCloseWidget(QWidget* parent, Delegate* delegate) + : QWidget(parent), delegate_(delegate) { + } + +protected: + void closeEvent(QCloseEvent* event) override { + if (!delegate_->about_to_close()) { + event->ignore(); + return; + } + this->QWidget::closeEvent(event); + } + +private: + Delegate* const delegate_; +}; + +class QtGuiTextWindow : public virtual GuiTextWindow, public QtGuiWindow, + public virtual OptionalCloseWidget::Delegate, + public virtual HtmlAttributedText::Listener { +public: + QtGuiTextWindow(std::string const& title, uint32_t width, uint32_t height, + AttributedText const* text) + : title_(title), width_(width), height_(height), + text_(static_cast(text)), + widget_(nullptr), view_(nullptr) { + } + + ~QtGuiTextWindow() override { + } + + void set_text(AttributedText const* text) override { + if (!text) { + assert(false); + if (text_own_) text_own_->reset(); + return; + } + disconnect_buffer(); + text_ = static_cast(text); + connect_buffer(); + text_own_.reset(); + } + + void set_text(std::unique_ptr&& text) override { + if (!text) { + assert(false); + if (text_own_) text_own_->reset(); + return; + } + disconnect_buffer(); + text_ = static_cast(text.get()); + connect_buffer(); + text_own_.swap(text); + } + + AttributedText const* text() const override { + return text_; + } + + void add_listener(GuiTextWindow::Listener* listener) override { + observers_.insert(listener); + } + + void remove_listener(GuiTextWindow::Listener* listener) override { + observers_.erase(listener); + } + + void set_title(std::string const& title) override { + title_ = title; + QtGuiWindow::set_title(title); + } + + QWidget* widget() const override { + return widget_.get(); + } + + void* impl() const override { + return QtGuiWindow::impl(); + } + + bool showWidget() override { + show(); + return true; + } + + void show(GuiWindow* UNUSED(parent)) override { + if (widget_) { + focus(); + return; + } + show(); + } + + void focus() override { + if (!widget_) { + assert(false); + show(); + return; + } + widget_->raise(); + widget_->activateWindow(); + } + +private: + void show() { + widget_.reset(new OptionalCloseWidget(nullptr, this)); + widget_->setWindowTitle(QString::fromStdString(title_)); + layout_.reset(new SizeHintLayout(widget_.get(), QSize(width_, height_))); + view_ = new QTextEdit(); + view_->setReadOnly(true); + connect_buffer(); + if (text_) view_->setHtml(QString::fromStdString(text_->html())); + widget_->layout()->addWidget(view_); + widget_->show(); + } + + bool about_to_close() override { + disconnect_buffer(); + auto view = view_; + view_ = nullptr; + auto widget = widget_.release(); + auto it = observers_.notify(); + while (it.has_next()) { + if (!it.next()->about_to_close(this)) { + widget_.reset(widget); + view_ = view; + connect_buffer(); + return false; + } + } + return true; + } + + void changed(HtmlAttributedText* text) override { + assert(text == text_); + if (view_) { + view_->setHtml(QString::fromStdString(text->html())); + view_->moveCursor(QTextCursor::End); + view_->ensureCursorVisible(); + } + } + + void connect_buffer() { + if (!text_ || !view_) return; + const_cast(text_)->add_listener(this); + } + + void disconnect_buffer() { + if (!text_ || !view_) return; + const_cast(text_)->remove_listener(this); + } + + std::string title_; + uint32_t width_; + uint32_t height_; + HtmlAttributedText const* text_; + std::unique_ptr text_own_; + Observers observers_; + std::unique_ptr layout_; + std::unique_ptr widget_; + QTextEdit* view_; +}; + bool QtGuiMain::run(int argc, char** argv) { QApplication app(argc, argv); app.setStyleSheet("QStatusBar::item { border: 0px }"); @@ -1322,3 +1499,10 @@ Looper* GuiMain::createLooper() { AttributedText* AttributedText::create() { return HtmlAttributedText::create(); } + +// static +GuiTextWindow* GuiTextWindow::create(std::string const& title, + uint32_t width, uint32_t height, + AttributedText const* text) { + return new QtGuiTextWindow(title, width, height, text); +} -- cgit v1.2.3-70-g09d2