diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/list_item.cpp | 4 | ||||
-rw-r--r-- | src/list_item.h | 2 | ||||
-rw-r--r-- | src/mainwindow.cpp | 25 | ||||
-rw-r--r-- | src/mainwindow.h | 5 | ||||
-rw-r--r-- | src/widgets/status_info.cpp | 82 | ||||
-rw-r--r-- | src/widgets/status_info.h | 56 | ||||
-rw-r--r-- | src/widgets/status_info.ui | 44 |
8 files changed, 203 insertions, 18 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 15486f5..8aa19f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,9 @@ set(PROJECT_SOURCES src/settingsdialog.ui src/settings_interface.cpp src/settings_interface.h + src/widgets/status_info.cpp + src/widgets/status_info.h + src/widgets/status_info.ui src/archive/base_archive.cpp src/archive/base_archive.h src/archive/mastodon.cpp diff --git a/src/list_item.cpp b/src/list_item.cpp index deead65..b4e7e84 100644 --- a/src/list_item.cpp +++ b/src/list_item.cpp @@ -50,6 +50,10 @@ StatusType StatusListItem::get_status_type() { return status_type; } +APActivity* StatusListItem::get_activity() { + return data_archive->get_activity(status_index, {status_type}); +} + const QString StatusListItem::get_info_html(int text_zone_width, QLocale* locale) { APActivity* activity = data_archive->get_activity(status_index, {status_type}); QString html = activity->get_html_render({text_zone_width, locale}); diff --git a/src/list_item.h b/src/list_item.h index d730551..22debe7 100644 --- a/src/list_item.h +++ b/src/list_item.h @@ -1,6 +1,7 @@ #pragma once #include <QListWidgetItem> +#include "src/activitypub/apactivity.h" #include "src/archive/base_archive.h" #include "types.h" @@ -13,6 +14,7 @@ public: StatusListItem(const QString &text, StatusType status_type, bool has_attachement, Archive* data_archive, QListWidget *parent = nullptr, int index = 0); int get_status_index(); StatusType get_status_type(); + APActivity* get_activity(); const QString get_info_html(int text_zone_width, QLocale* locale); private: diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4ab0bb2..8f72f23 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -21,6 +21,8 @@ MainWindow::MainWindow(QWidget *parent) , ui(new Ui::MainWindow) { ui->setupUi(this); + status_info_widget = new StatusInfoWidget(this); + ui->gridLayout->addWidget(status_info_widget, 1, 1); connect(ui->buttonCopy, &QPushButton::clicked, ui->actionCopy_status, &QAction::trigger); connect(ui->buttonRandom, &QPushButton::clicked, ui->actionRandom_status, &QAction::trigger); connect(ui->buttonSearch, &QPushButton::clicked, ui->actionFind, &QAction::trigger); @@ -85,22 +87,13 @@ void MainWindow::on_actionAbout_triggered(bool checked) { QMessageBox::information(this, "title", "text"); } -std::variant<QString, Archive::InitError> start_listWidget_itemActivated(StatusListItem* status, int text_zone_width, QLocale* locale) { - return (QString)status->get_info_html(text_zone_width, locale); -} - void MainWindow::on_listWidget_itemActivated(QListWidgetItem *item) { StatusListItem* status = dynamic_cast<StatusListItem*>(item); if (status != nullptr) { - const QFuture<std::variant<QString, Archive::InitError>> status_info = QtConcurrent::run(start_listWidget_itemActivated, status, ui->statusInfoText->width(), &locale_context); - archive_thread_watcher.setFuture(status_info); + status_info_widget->show_list_item(status); } } -void MainWindow::finish_listWidget_itemActivated(const QString& status_info) { - ui->statusInfoText->setHtml(status_info); -} - void MainWindow::on_actionRandom_status_triggered(bool checked) { if (data_archive == nullptr) return; // No archive open, avoids crashing @@ -291,12 +284,10 @@ void MainWindow::archive_thread_watcher_done() { std::variant<QString, Archive::InitError> result = archive_thread_watcher.result(); // For MainWindow::on_listWidget_itemActivated - if (const QString* status_info = std::get_if<QString>(&result)) { - finish_listWidget_itemActivated(*status_info); - } else - // For MainWindow::open_file - if (const Archive::InitError* parse_error = std::get_if<Archive::InitError>(&result)) { - finish_open_file(*parse_error); - } else + if (std::get_if<Archive::InitError>(&result)) { + // For MainWindow::open_file + if (const Archive::InitError* parse_error = std::get_if<Archive::InitError>(&result)) + finish_open_file(*parse_error); + } else if (not std::get_if<QString>(&result)) qDebug() << "What, the variant is weird"; } diff --git a/src/mainwindow.h b/src/mainwindow.h index 24bc970..22f5b29 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -7,7 +7,9 @@ #include <variant> #include "archive/base_archive.h" +#include "src/list_item.h" #include "src/settingsdialog.h" +#include "src/widgets/status_info.h" #include "types.h" #include "command_line.h" #include "finddialog.h" @@ -63,12 +65,13 @@ private: void open_file(const QString &filename); void archive_thread_watcher_done(); - void finish_listWidget_itemActivated(const QString& status_info); + std::variant<QString, Archive::InitError> start_listWidget_itemActivated(StatusListItem* status); void finish_open_file(const Archive::InitError& parse_error); void settingsDialog_done(int result); FindDialog* find_dialog = nullptr; SettingsDialog* settings_dialog = nullptr; + StatusInfoWidget* status_info_widget = nullptr; QString open_file_filename; diff --git a/src/widgets/status_info.cpp b/src/widgets/status_info.cpp new file mode 100644 index 0000000..847aec4 --- /dev/null +++ b/src/widgets/status_info.cpp @@ -0,0 +1,82 @@ +#include "status_info.h" +#include "src/list_item.h" +#include <QTimer> +#include <QDebug> +#include <QCloseEvent> + +StatusInfoWidget::StatusInfoWidget(QWidget* parent) + : QWidget(parent), ui(new Ui::StatusInfo) +{ + ui->setupUi(this); + + worker.moveToThread(&worker_thread); + connect(this, &StatusInfoWidget::do_process_item, &worker, &StatusInfoWidgetWorker::process_item, Qt::QueuedConnection); + connect(this, &StatusInfoWidget::do_process_activity, &worker, &StatusInfoWidgetWorker::process_activity, Qt::QueuedConnection); + connect(&worker, &StatusInfoWidgetWorker::itemProcessed, this, &StatusInfoWidget::postProcess, Qt::QueuedConnection); + worker_thread.start(); + + worker.set_text_zone_width(ui->statusInfoText->width()); +} + +StatusInfoWidget::~StatusInfoWidget() { + worker_thread.quit(); + worker_thread.wait(); + + delete displayed_activity; + delete ui; +} + +void StatusInfoWidget::resizeEvent(QResizeEvent* event) { + // TODO: probably create a template, define or inline function for this + static QTimer* differed_resize = new QTimer(this); + if (static bool timer_init_done = false; not timer_init_done) { + differed_resize->setTimerType(Qt::CoarseTimer); + differed_resize->setSingleShot(true); + differed_resize->setInterval(150); + connect(differed_resize, &QTimer::timeout, this, [=]() { + worker.set_text_zone_width(ui->statusInfoText->width()); + if (displayed_activity) + emit do_process_activity(displayed_activity); + }); + } + differed_resize->start(); + QWidget::resizeEvent(event); +} + +void StatusInfoWidget::show_list_item(StatusListItem* new_item) { + qDebug() << "got item" << new_item << "old is" << displayed_item << displayed_activity; + if (new_item != displayed_item) { + delete displayed_activity; displayed_activity = nullptr; + displayed_item = new_item; + emit do_process_item(new_item); + } +} + +// Update the GUI with the displayed Activity. +// Has to be done on the GUI thread, no other way in Qt +void StatusInfoWidget::postProcess(const QString &html, APActivity* activity) { + // Make sure to not delete the displayed_activity if we are reprocessing it after a resize event, else you get a crash that requires nasty debugging (don't ask how i found out ;) + if (activity != displayed_activity) { + // We are doing "double" deletion of old displayed_activity but sometimes that's important when really scrubbing the search results bar very quickly (we sometimes do reach that code and it hopefully helps against memory leaks) + if (displayed_activity) + delete displayed_activity; + displayed_activity = activity; + } + ui->statusInfoText->setHtml(html); +} + +/* + * ---------------- + * Worker functions. Ran on non-main, non-GUI, thread + * ---------------- + */ + +void StatusInfoWidgetWorker::process_item(StatusListItem* item) { + APActivity* activity = item->get_activity(); + process_activity(activity); +} + +void StatusInfoWidgetWorker::process_activity(APActivity* activity) { + QString html = activity->get_html_render(render_info); + emit itemProcessed(html, activity); +} diff --git a/src/widgets/status_info.h b/src/widgets/status_info.h new file mode 100644 index 0000000..988f930 --- /dev/null +++ b/src/widgets/status_info.h @@ -0,0 +1,56 @@ +#pragma once +#include <QWidget> +#include <QLocale> +#include <QThread> +#include "./ui_status_info.h" +#include "src/activitypub/apactivity.h" +#include "src/activitypub/apbase.h" +#include "src/list_item.h" + +class StatusInfoWidgetWorker : public QObject { + Q_OBJECT + +public slots: + void process_item(StatusListItem* item); + void process_activity(APActivity* activity); + void set_text_zone_width(int width) {render_info.text_zone_width = width;} + +signals: + void itemProcessed(const QString &html, APActivity* activity = nullptr); + +private: + QLocale locale_context; + HtmlRenderDetails render_info = {0, &locale_context}; +}; + +QT_BEGIN_NAMESPACE +namespace Ui { class StatusInfo; } +QT_END_NAMESPACE + +class StatusInfoWidget : public QWidget { + Q_OBJECT + +public: + StatusInfoWidget(QWidget *parent = nullptr); + ~StatusInfoWidget(); + + void resizeEvent(QResizeEvent* event); + +public slots: + void show_list_item(StatusListItem* status); // Call from GUI thread + void postProcess(const QString &html, APActivity* activity); + +signals: + // These signals are called privetely by StatusInfoWidget + void do_process_item(StatusListItem* item); + void do_process_activity(APActivity* activity); + +private: + Ui::StatusInfo* ui; + QThread worker_thread; + StatusInfoWidgetWorker worker; + + // Used for determining if we are dealing with a new list item or not + StatusListItem* displayed_item = nullptr; + APActivity* displayed_activity = nullptr; +}; diff --git a/src/widgets/status_info.ui b/src/widgets/status_info.ui new file mode 100644 index 0000000..b8b2586 --- /dev/null +++ b/src/widgets/status_info.ui @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>StatusInfo</class> + <widget class="QWidget" name="StatusInfo"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QTextEdit" name="statusInfoText"> + <property name="cursor" stdset="0"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="undoRedoEnabled"> + <bool>false</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="html"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Select Status to display from list.</span></p></body></html></string> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextBrowserInteraction</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> |