Concentrate model editing into one coroutine inside main()

Wed, 08 Jun 2022 19:33:00 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 08 Jun 2022 19:33:00 +0300
changeset 204
52e10e8d88cc
parent 203
1909a0123c72
child 205
1a4342d80de7

Concentrate model editing into one coroutine inside main()

src/document.cpp file | annotate | diff | comparison | revisions
src/document.h file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/mainwindow.ui file | annotate | diff | comparison | revisions
src/model.cpp file | annotate | diff | comparison | revisions
--- a/src/document.cpp	Tue Jun 07 21:35:29 2022 +0300
+++ b/src/document.cpp	Wed Jun 08 19:33:00 2022 +0300
@@ -32,7 +32,6 @@
 	colorTable{colorTable},
 	canvas{new Canvas{model, this, documents, colorTable, this}},
 	model{model},
-	documents{documents},
 	vertexMap{model}
 {
 	this->setMouseTracking(true);
@@ -183,31 +182,40 @@
 		switch (this->drawState.polygon.size())
 		{
 		case 2:
-			this->model->append(Colored<LineSegment>{
-				LineSegment{
-					.p1 = this->drawState.polygon[0],
-					.p2 = this->drawState.polygon[1],
-				},
-				ldraw::EDGE_COLOR});
+			Q_EMIT this->modelAction(AppendToModel{
+				.newElement = Colored<LineSegment>{
+					LineSegment{
+						.p1 = this->drawState.polygon[0],
+						.p2 = this->drawState.polygon[1],
+					},
+					ldraw::EDGE_COLOR,
+				}
+			});
 			break;
 		case 3:
-			this->model->append(Colored<Triangle>{
-				Triangle{
-					.p1 = this->drawState.polygon[0],
-					.p2 = this->drawState.polygon[1],
-					.p3 = this->drawState.polygon[2],
-				},
-				ldraw::MAIN_COLOR});
+			Q_EMIT this->modelAction(AppendToModel{
+				.newElement = Colored<Triangle>{
+					Triangle{
+						.p1 = this->drawState.polygon[0],
+						.p2 = this->drawState.polygon[1],
+						.p3 = this->drawState.polygon[2],
+					},
+					ldraw::MAIN_COLOR,
+				}
+			});
 			break;
 		case 4:
-			this->model->append(Colored<Quadrilateral>{
-				Quadrilateral{
-					.p1 = this->drawState.polygon[0],
-					.p2 = this->drawState.polygon[1],
-					.p3 = this->drawState.polygon[2],
-					.p4 = this->drawState.polygon[3],
-				},
-				ldraw::MAIN_COLOR});
+			Q_EMIT this->modelAction(AppendToModel{
+				.newElement = Colored<Quadrilateral>{
+					Quadrilateral{
+						.p1 = this->drawState.polygon[0],
+						.p2 = this->drawState.polygon[1],
+						.p3 = this->drawState.polygon[2],
+						.p4 = this->drawState.polygon[3],
+					},
+					ldraw::MAIN_COLOR,
+				}
+			});
 			break;
 		}
 	}
--- a/src/document.h	Tue Jun 07 21:35:29 2022 +0300
+++ b/src/document.h	Wed Jun 08 19:33:00 2022 +0300
@@ -24,6 +24,20 @@
 #include "model.h"
 #include "vertexmap.h"
 
+struct AppendToModel
+{
+	ModelElement newElement;
+};
+
+struct DeleteFromModel
+{
+	int position;
+};
+
+using ModelAction = std::variant<AppendToModel, DeleteFromModel>;
+
+Q_DECLARE_METATYPE(ModelAction)
+
 class EditorTabWidget : public QWidget
 {
 	Q_OBJECT
@@ -46,9 +60,9 @@
 Q_SIGNALS:
 	void newStatusText(const QString& newStatusText);
 	void splitterChanged();
+	void modelAction(const ModelAction& action);
 private:
 	void closeShape();
 	DrawState drawState;
-	DocumentManager* const documents;
 	VertexMap vertexMap;
 };
--- a/src/main.cpp	Tue Jun 07 21:35:29 2022 +0300
+++ b/src/main.cpp	Wed Jun 08 19:33:00 2022 +0300
@@ -263,6 +263,22 @@
 	}
 }
 
+constexpr bool sortModelIndexesByRow(const QModelIndex& a, const QModelIndex& b)
+{
+	return a.row() < b.row();
+}
+
+std::vector<int> rows(const QModelIndexList& indexList)
+{
+	std::vector<int> result;
+	result.reserve(indexList.size());
+	for (const QModelIndex& index : indexList)
+	{
+		result.push_back(index.row());
+	}
+	return result;
+}
+
 int main(int argc, char *argv[])
 {
 	doQtRegistrations();
@@ -303,6 +319,18 @@
 			);
 		}
 	};
+	static constexpr auto executeAction = [&](
+		Model* model, const ModelAction& action
+	) {
+		std::visit(overloaded{
+			[model](const AppendToModel& action){
+				model->append(action.newElement);
+			},
+			[model](const DeleteFromModel& action){
+				model->remove(action.position);
+			},
+		}, action);
+	};
 	const auto restoreSettings = [&]{
 		recentlyOpenedFiles = settings.recentFiles();
 		documentSplitterState = settings.mainSplitterState();
@@ -329,6 +357,10 @@
 	const auto openModelForEditing = [&](const ModelId modelId){
 		Model* model = documents.getModelById(modelId);
 		EditorTabWidget* document = new EditorTabWidget{model, &documents, colorTable};
+		QObject::connect(
+			document,
+			&EditorTabWidget::modelAction,
+			std::bind(executeAction, model, std::placeholders::_1));
 		QItemSelectionModel* selectionModel = new QItemSelectionModel{model};
 		itemSelectionModels[model] = selectionModel;
 		QObject::connect(selectionModel, &QItemSelectionModel::selectionChanged,
@@ -447,6 +479,16 @@
 			}
 		}
 	});
+	QObject::connect(ui.actionDelete, &QAction::triggered, [&]{
+		EditorTabWidget* tab = currentTabWidget(&ui);
+		if (tab != nullptr) {
+			std::vector<int> selectedRows = rows(ui.modelListView->selectionModel()->selectedRows());
+			std::sort(selectedRows.begin(), selectedRows.end(), std::greater<int>{});
+			for (int row : selectedRows) {
+				executeAction(tab->model, DeleteFromModel{.position = row});
+			}
+		}
+	});
 	QObject::connect(ui.actionDrawAxes, &QAction::triggered, [&](bool drawAxes){
 		renderPreferences.drawAxes = drawAxes;
 		saveSettings();
@@ -477,14 +519,16 @@
 		});
 	}
 	QObject::connect(ui.mdiArea, &QMdiArea::subWindowActivated,
-	[&](QMdiSubWindow* subWindow){
-		EditorTabWidget* tab = qobject_cast<EditorTabWidget*>(subWindow->widget());
-		if (tab != nullptr) {
-			checkEditingModeAction(tab->currentEditingMode());
-			QItemSelectionModel* selectionModel = itemSelectionModels.value(tab->model);
-			if (selectionModel != nullptr) {
-				ui.modelListView->setModel(tab->model);
-				ui.modelListView->setSelectionModel(selectionModel);
+	[&](QMdiSubWindow* subWindow) {
+		if (subWindow != nullptr) {
+			EditorTabWidget* tab = qobject_cast<EditorTabWidget*>(subWindow->widget());
+			if (tab != nullptr) {
+				checkEditingModeAction(tab->currentEditingMode());
+				QItemSelectionModel* selectionModel = itemSelectionModels.value(tab->model);
+				if (selectionModel != nullptr) {
+					ui.modelListView->setModel(tab->model);
+					ui.modelListView->setSelectionModel(selectionModel);
+				}
 			}
 		}
 	});
--- a/src/mainwindow.ui	Tue Jun 07 21:35:29 2022 +0300
+++ b/src/mainwindow.ui	Wed Jun 08 19:33:00 2022 +0300
@@ -39,7 +39,7 @@
      <x>0</x>
      <y>0</y>
      <width>800</width>
-     <height>22</height>
+     <height>28</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -172,7 +172,23 @@
    <widget class="QWidget" name="dockWidgetContents_3">
     <layout class="QVBoxLayout" name="verticalLayout_4">
      <item>
-      <widget class="QListView" name="modelListView"/>
+      <widget class="QListView" name="modelListView">
+       <property name="alternatingRowColors">
+        <bool>true</bool>
+       </property>
+       <property name="selectionMode">
+        <enum>QAbstractItemView::ExtendedSelection</enum>
+       </property>
+       <property name="selectionBehavior">
+        <enum>QAbstractItemView::SelectRows</enum>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+       <property name="selectionRectVisible">
+        <bool>true</bool>
+       </property>
+      </widget>
      </item>
     </layout>
    </widget>
--- a/src/model.cpp	Tue Jun 07 21:35:29 2022 +0300
+++ b/src/model.cpp	Wed Jun 08 19:33:00 2022 +0300
@@ -111,11 +111,24 @@
 	return pointerToOptional(findInMap(this->positions, id));
 }
 
+template<typename K, typename V>
+void removeFromMap(std::map<K, V>& map, const K& key)
+{
+	const auto it = map.find(key);
+	if (it != map.end()) {
+		map.erase(it);
+	}
+}
+
 void Model::remove(int index)
 {
 	if (index >= 0 and index < this->size()) {
 		Q_EMIT this->beginRemoveRows({}, index, index);
+		removeFromMap(this->positions, this->body[index].id);
 		this->body.erase(this->body.begin() + index);
+		for (int i = index; i < this->size(); ++i) {
+			this->positions[this->body[i].id] = i;
+		}
 		Q_EMIT this->endRemoveRows();
 	}
 }

mercurial