Made message log a model

Mon, 20 Jun 2022 18:40:22 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Mon, 20 Jun 2022 18:40:22 +0300
changeset 236
1fa0e1de9f0a
parent 235
7ef03c2b46ab
child 237
10a6298f636f

Made message log a model

src/main.cpp file | annotate | diff | comparison | revisions
src/mainwindow.ui file | annotate | diff | comparison | revisions
src/messagelog.cpp file | annotate | diff | comparison | revisions
src/messagelog.h file | annotate | diff | comparison | revisions
--- a/src/main.cpp	Mon Jun 20 17:27:30 2022 +0300
+++ b/src/main.cpp	Mon Jun 20 18:40:22 2022 +0300
@@ -15,6 +15,7 @@
 #include "widgets/colorselectdialog.h"
 #include "settings.h"
 #include "ui/circletooloptionswidget.h"
+#include "messagelog.h"
 
 static const QDir LOCALE_DIR {":/locale"};
 
@@ -342,6 +343,7 @@
 	return result;
 }
 
+#include <QScrollBar>
 int main(int argc, char *argv[])
 {
 	doQtRegistrations();
@@ -355,6 +357,7 @@
 	QStringList recentlyOpenedFiles;
 	ColorTable colorTable;
 	gl::RenderPreferences renderPreferences;
+	MessageLog messageLog;
 	ui.setupUi(&mainWindow);
 	const uiutilities::KeySequenceMap defaultKeyboardShortcuts =
 		uiutilities::makeKeySequenceMap(uiutilities::collectActions(&mainWindow));
@@ -413,22 +416,6 @@
 		saveSettings();
 		updateRecentlyOpenedDocumentsMenu();
 	};
-	const auto logMessage = [&ui](const Message& message){
-		QString messagetext = message.time.toString(QObject::tr("[hh:mm:ss]"));
-		switch(message.type) {
-		case Message::Info:
-			messagetext += QObject::tr(" [INFO] ");
-			break;
-		case Message::Warning:
-			messagetext += QObject::tr(" [WARN] ");
-			break;
-		case Message::Error:
-			messagetext += QObject::tr(" [ERR!] ");
-			break;
-		}
-		messagetext += message.text;
-		ui.messageLog->append(messagetext);
-	};
 	const auto openModelForEditing = [&](const ModelId modelId){
 		Model* model = documents.getModelById(modelId);
 		if (model != nullptr) {
@@ -641,8 +628,18 @@
 			}
 		}
 	});
+	ui.messageLog->setModel(&messageLog);
 	QObject::connect(ui.actionAboutQt, &QAction::triggered, &app, &QApplication::aboutQt);
-	QObject::connect(&documents, &DocumentManager::message, logMessage);
+	QObject::connect(&documents, &DocumentManager::message, &messageLog, &MessageLog::addMessage);
+	QObject::connect(&messageLog, &MessageLog::rowsAboutToBeInserted, [&]{
+		const auto bar = ui.messageLog->verticalScrollBar();
+		ui.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum());
+	});
+	QObject::connect(&messageLog, &MessageLog::rowsInserted, [&]{
+		if (ui.messageLog->property("shouldAutoScroll").toBool()) {
+			ui.messageLog->scrollToBottom();
+		}
+	});
 	mainWindow.setWindowTitle(title());
 	mainWindow.restoreGeometry(setting<Setting::MainWindowGeometry>());
 	restoreSettings();
--- a/src/mainwindow.ui	Mon Jun 20 17:27:30 2022 +0300
+++ b/src/mainwindow.ui	Mon Jun 20 18:40:22 2022 +0300
@@ -16,6 +16,9 @@
   <property name="dockNestingEnabled">
    <bool>true</bool>
   </property>
+  <property name="dockOptions">
+   <set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks</set>
+  </property>
   <widget class="QWidget" name="centralwidget">
    <layout class="QVBoxLayout" name="verticalLayout_3">
     <item>
@@ -160,6 +163,9 @@
    </attribute>
   </widget>
   <widget class="QDockWidget" name="dockWidget_2">
+   <property name="features">
+    <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
+   </property>
    <property name="windowTitle">
     <string>Tool options</string>
    </property>
@@ -175,6 +181,9 @@
    </widget>
   </widget>
   <widget class="QDockWidget" name="dockWidget_3">
+   <property name="features">
+    <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
+   </property>
    <property name="windowTitle">
     <string>Model body</string>
    </property>
@@ -206,6 +215,9 @@
    </widget>
   </widget>
   <widget class="QDockWidget" name="dockWidget">
+   <property name="features">
+    <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
+   </property>
    <property name="windowTitle">
     <string>Message log</string>
    </property>
@@ -215,10 +227,25 @@
    <widget class="QWidget" name="dockWidgetContents">
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
-      <widget class="QTextEdit" name="messageLog">
-       <property name="readOnly">
+      <widget class="QTableView" name="messageLog">
+       <property name="alternatingRowColors">
         <bool>true</bool>
        </property>
+       <property name="verticalScrollMode">
+        <enum>QAbstractItemView::ScrollPerPixel</enum>
+       </property>
+       <property name="gridStyle">
+        <enum>Qt::DotLine</enum>
+       </property>
+       <attribute name="horizontalHeaderDefaultSectionSize">
+        <number>150</number>
+       </attribute>
+       <attribute name="horizontalHeaderStretchLastSection">
+        <bool>true</bool>
+       </attribute>
+       <attribute name="verticalHeaderVisible">
+        <bool>false</bool>
+       </attribute>
       </widget>
      </item>
     </layout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/messagelog.cpp	Mon Jun 20 18:40:22 2022 +0300
@@ -0,0 +1,77 @@
+#include <QColor>
+#include "messagelog.h"
+
+MessageLog::MessageLog(QObject *parent) :
+	QAbstractTableModel{parent}
+{
+	
+}
+
+void MessageLog::addMessage(const Message& message)
+{
+	this->beginInsertRows({}, this->messages.size(), this->messages.size());
+	this->messages.push_back(message);
+	this->endInsertRows();
+}
+
+QVariant MessageLog::headerData(int section, Qt::Orientation orientation, int role) const
+{
+	if (orientation != Qt::Horizontal or role != Qt::DisplayRole) {
+		return {};
+	}
+	else {
+		switch (static_cast<Column>(section)) {
+		case TimeColumn:
+			return tr("Time");
+		case MessageColumn:
+			return tr("Message");
+		}
+		return {};
+	}
+}
+
+int MessageLog::rowCount(const QModelIndex&) const
+{
+	return signed_cast(this->messages.size());
+}
+
+int MessageLog::columnCount(const QModelIndex&) const
+{
+	return NUM_COLUMNS;
+}
+
+QVariant MessageLog::data(const QModelIndex& index, int role) const
+{
+	const std::size_t row = unsigned_cast(index.row());
+	if (false
+		or row >= this->messages.size()
+		or index.column() < 0
+		or index.column() >= NUM_COLUMNS
+	) {
+		return {};
+	}
+	else {
+		const Message& message = this->messages[row];
+		switch (role) {
+		case Qt::DisplayRole:
+			switch (static_cast<Column>(index.column())) {
+			case TimeColumn:
+				return message.time.toString(tr("hh:mm:ss"));
+			case MessageColumn:
+				return message.text;
+			}
+			break;
+		case Qt::BackgroundRole:
+			switch(message.type) {
+			case Message::Info:
+				return {};
+			case Message::Warning:
+				return QColor{Qt::yellow};
+			case Message::Error:
+				return QColor{Qt::red};
+			}
+			break;
+		}
+		return {};
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/messagelog.h	Mon Jun 20 18:40:22 2022 +0300
@@ -0,0 +1,23 @@
+#include <QAbstractTableModel>
+#include "basics.h"
+
+class MessageLog final : public QAbstractTableModel
+{
+	Q_OBJECT
+	std::vector<Message> messages;
+public:
+	enum Column {
+		TimeColumn,
+		MessageColumn,
+	};
+	static constexpr int NUM_COLUMNS = int(MessageColumn) + 1;
+	explicit MessageLog(QObject *parent = nullptr);
+	Q_SLOT void addMessage(const Message& message);
+
+	// QAbstractItemModel interface
+public:
+	QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+	int rowCount(const QModelIndex& parent) const override;
+	int columnCount(const QModelIndex& parent) const override;
+	QVariant data(const QModelIndex& index, int role) const override;
+};

mercurial