Replace item view with a text editor

Sun, 03 Jul 2022 23:54:22 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Sun, 03 Jul 2022 23:54:22 +0300
changeset 328
3ea38fd469ca
parent 327
2aa15daa0216
child 329
6d75fa09cc0c

Replace item view with a text editor

src/documentmanager.cpp 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
src/model.h file | annotate | diff | comparison | revisions
src/parser.cpp file | annotate | diff | comparison | revisions
src/parser.h file | annotate | diff | comparison | revisions
--- a/src/documentmanager.cpp	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/documentmanager.cpp	Sun Jul 03 23:54:22 2022 +0300
@@ -121,7 +121,7 @@
 	file.open(QFile::ReadOnly | QFile::Text);
 	std::unique_ptr<Model> newModel = std::make_unique<Model>(nullptr);
 	QTextStream textStream{&file};
-	Parser parser{file};
+	Parser parser{textStream};
 	parser.parseBody(*newModel);
 	std::optional<ModelId> result;
 	if (file.error() == QFile::NoError)
@@ -195,7 +195,8 @@
 		QSaveFile file{info->path};
 		file.setDirectWriteFallback(true);
 		if (file.open(QSaveFile::WriteOnly)) {
-			::save(*info->model.get(), &file);
+			QTextStream stream{&file};
+			::save(*info->model.get(), &stream);
 			const bool commitSucceeded = file.commit();
 			if (not commitSucceeded) {
 				errors << QObject::tr("Could not save: %1").arg(file.errorString());
--- a/src/main.cpp	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/main.cpp	Sun Jul 03 23:54:22 2022 +0300
@@ -21,6 +21,7 @@
 #include "src/ui/objecteditor.h"
 #include "src/version.h"
 #include "src/widgets/colorselectdialog.h"
+#include "src/parser.h"
 #include <GL/glew.h>
 
 static const QDir LOCALE_DIR {":/locale"};
@@ -48,10 +49,11 @@
 public:
 	ModelData(QObject* parent) : QObject {parent} {}
 	std::unique_ptr<PartRenderer> canvas;
-	std::unique_ptr<QItemSelectionModel> itemSelectionModel;
 	std::unique_ptr<EditTools> tools;
 	std::unique_ptr<AxesLayer> axesLayer;
 	std::unique_ptr<GridLayer> gridLayer;
+	std::unique_ptr<QTextDocument> textbuffer;
+	std::unique_ptr<QTextCursor> textcursor;
 	Model* model;
 };
 
@@ -401,13 +403,13 @@
 
 static QSet<ElementId> resolveIdsFromSelection(const ModelData* data)
 {
-	const auto selection = data->itemSelectionModel->selection();
+//	const auto selection = data->itemSelectionModel->selection();
 	QSet<ElementId> selectedIndexes;
-	for (const QModelIndex& qindex : selection.indexes()) {
+/*	for (const QModelIndex& qindex : selection.indexes()) {
 		const std::size_t row = unsigned_cast(qindex.row());
 		selectedIndexes.insert(data->model->idAt(row));
 	}
-	return selectedIndexes;
+*/	return selectedIndexes;
 }
 
 int main(int argc, char *argv[])
@@ -427,6 +429,11 @@
 	MessageLog messageLog;
 	Signal settingsChanged;
 	ui.setupUi(&mainWindow);
+	QFont monospace{"Monospace"};
+	monospace.setStyleHint(QFont::TypeWriter);
+	monospace.setPointSize(10);
+	monospace.setFixedPitch(true);
+	ui.modelEdit->setFont(monospace);
 	ToolWidgets toolWidgets{
 		.circleToolOptions = new CircleToolOptionsWidget{&mainWindow},
 		.objectEditor = new ObjectEditor{&mainWindow},
@@ -462,6 +469,7 @@
 	const auto executeAction = [&](
 		Model* model, const ModelAction& action
 	) {
+		/*
 		std::visit(overloaded{
 			[model](const AppendToModel& action){
 				model->append(action.newElement);
@@ -473,6 +481,7 @@
 				model->assignAt(action.position, action.newElement);
 			},
 		}, action);
+		*/
 	};
 	const auto restoreSettings = [&]{
 		recentlyOpenedFiles = setting<Setting::RecentFiles>();
@@ -502,8 +511,6 @@
 			ModelData* data = new ModelData(&documents);
 			data->tools = std::make_unique<EditTools>();
 			data->canvas = std::make_unique<PartRenderer>(model, &documents, colorTable);
-			data->itemSelectionModel = std::make_unique<QItemSelectionModel>();
-			data->itemSelectionModel->setModel(model);
 			data->axesLayer = std::make_unique<AxesLayer>();
 			constexpr glm::mat4 XZ = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}};
 			data->gridLayer = std::make_unique<GridLayer>();
@@ -514,31 +521,18 @@
 			data->canvas->setLayerEnabled(data->axesLayer.get(), setting<Setting::DrawAxes>());
 			data->canvas->addRenderLayer(data->gridLayer.get());
 			data->canvas->addRenderLayer(data->tools.get());
+			QString modeltext;
+			QTextStream stream{&modeltext};
+			::save(*model, &stream);
+			data->textbuffer = std::make_unique<QTextDocument>();
+			data->textbuffer->setPlainText(modeltext);
+			data->textbuffer->setDocumentLayout(new QPlainTextDocumentLayout(data->textbuffer.get()));
+			data->textcursor = std::make_unique<QTextCursor>(data->textbuffer.get());
 			documents.setModelPayload(modelId, data);
 			QObject::connect(
 				data->tools.get(),
 				&EditTools::modelAction,
 				std::bind(executeAction, model, std::placeholders::_1));
-			QObject::connect(
-				data->itemSelectionModel.get(),
-				&QItemSelectionModel::selectionChanged,
-				[modelId, &documents, &toolWidgets]{
-				ModelData* data = findModelData(&documents, modelId);
-				if (data != nullptr) {
-					data->canvas->setSelection(resolveIdsFromSelection(data));
-					/*
-					if (indices.size() == 1) {
-						opt<std::size_t> index = data->model->find(*indices.begin());
-						if (index.has_value()) {
-							toolWidgets.objectEditor->setObject((*data->model)[*index]);
-						}
-					}
-					else {
-						toolWidgets.objectEditor->reset();
-					}
-					*/
-				}
-			});
 			data->canvas->setRenderPreferences(renderPreferences);
 			QObject::connect(
 				data->tools.get(),
@@ -546,6 +540,7 @@
 				[&](const QString& newStatusText) {
 					mainWindow.statusBar()->showMessage(newStatusText);
 				});
+#if 0
 			QObject::connect(
 				data->tools.get(),
 				&EditTools::select,
@@ -553,7 +548,7 @@
 					ModelData* data = findModelData(&documents, modelId);
 					if (data != nullptr) {
 						if (not retain) {
-							data->itemSelectionModel->clear();
+							data->textcursor->clearSelection();
 						}
 						for (const ElementId id : indices) {
 							opt<int> index = data->model->find(id);
@@ -564,6 +559,7 @@
 						}
 					}
 				});
+#endif
 			QObject::connect(&settingsChanged, &Signal::triggered, [modelId, &documents]{
 				ModelData* data = findModelData(&documents, modelId);
 				if (data != nullptr) {
@@ -675,15 +671,6 @@
 			}
 		}
 	});
-	QObject::connect(ui.actionDelete, &QAction::triggered, [&]{
-		if (Model* model = currentModelBody(&ui, &documents)) {
-			std::vector<int> selectedRows = rows(ui.modelListView->selectionModel()->selectedRows());
-			std::sort(selectedRows.begin(), selectedRows.end(), std::greater<int>{});
-			for (int row : selectedRows) {
-				executeAction(model, DeleteFromModel{.position = unsigned_cast(row)});
-			}
-		}
-	});
 	QObject::connect(ui.actionDrawAxes, &QAction::triggered, [&](bool drawAxes){
 		renderPreferences.drawAxes = drawAxes;
 		saveSettings();
@@ -725,10 +712,8 @@
 		if (modelSubWindow != nullptr) {
 			if (ModelData* data = documents.findPayload<ModelData>(modelSubWindow->modelId)) {
 				checkEditingModeAction(data->tools->currentEditingMode());
-				if (data->itemSelectionModel != nullptr) {
-					ui.modelListView->setModel(data->model);
-					ui.modelListView->setSelectionModel(data->itemSelectionModel.get());
-				}
+				ui.modelEdit->setDocument(data->textbuffer.get());
+				ui.modelEdit->setTextCursor(*data->textcursor);
 			}
 		}
 		else {
@@ -781,18 +766,17 @@
 		}
 	);
 	QObject::connect(
-		ui.actionCopy,
-		&QAction::triggered,
+		ui.modelEdit,
+		&QPlainTextEdit::textChanged,
 		[&]{
-			if (Model* model = currentModelBody(&ui, &documents)) {
-				std::vector<int> selectedRows = rows(ui.modelListView->selectionModel()->selectedRows());
-				QString text;
-				for (int row : selectedRows) {
-					const std::size_t i = static_cast<std::size_t>(row);
-					text += modelElementToString((*model)[i]);
-					text += QStringLiteral("\r\n");
-				}
-				app.clipboard()->setText(text);
+			if (ModelData* data = currentModelData(&ui, &documents)) {
+				Model* const model = data->model;
+				model->clear();
+				QString text = ui.modelEdit->toPlainText();
+				QTextStream stream{&text};
+				Parser parser(stream);
+				parser.parseBody(*data->model);
+				data->canvas->update();
 			}
 		});
 	mainWindow.tabifyDockWidget(ui.messageLogDock, ui.toolOptionsDock);
--- a/src/mainwindow.ui	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/mainwindow.ui	Sun Jul 03 23:54:22 2022 +0300
@@ -217,29 +217,7 @@
    <widget class="QWidget" name="dockWidgetContents_3">
     <layout class="QVBoxLayout" name="verticalLayout_4">
      <item>
-      <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="verticalScrollMode">
-        <enum>QAbstractItemView::ScrollPerPixel</enum>
-       </property>
-       <property name="horizontalScrollMode">
-        <enum>QAbstractItemView::ScrollPerPixel</enum>
-       </property>
-       <property name="wordWrap">
-        <bool>true</bool>
-       </property>
-       <property name="selectionRectVisible">
-        <bool>true</bool>
-       </property>
-      </widget>
+      <widget class="QPlainTextEdit" name="modelEdit"/>
      </item>
     </layout>
    </widget>
@@ -609,21 +587,5 @@
     </hint>
    </hints>
   </connection>
-  <connection>
-   <sender>actionSelectAll</sender>
-   <signal>triggered()</signal>
-   <receiver>modelListView</receiver>
-   <slot>selectAll()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>-1</x>
-     <y>-1</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>589</x>
-     <y>216</y>
-    </hint>
-   </hints>
-  </connection>
  </connections>
 </ui>
--- a/src/model.cpp	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/model.cpp	Sun Jul 03 23:54:22 2022 +0300
@@ -274,11 +274,17 @@
 	return this->body.size();
 }
 
-void save(const Model &model, QIODevice *device)
+void Model::clear()
 {
-	QTextStream out{device};
+	this->beginResetModel();
+	this->body.clear();
+	this->endResetModel();
+}
+
+void save(const Model &model, QTextStream* stream)
+{
 	for (std::size_t i = 0; i < model.size(); ++i) {
-		out << modelElementToString(model[i]) << "\r\n";
+		(*stream) << modelElementToString(model[i]) << "\r\n";
 	}
 }
 
--- a/src/model.h	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/model.h	Sun Jul 03 23:54:22 2022 +0300
@@ -228,6 +228,7 @@
 	QVariant data(const QModelIndex& index, int role) const override;
 	const ModelElement& operator[](std::size_t index) const;
 	std::size_t size() const;
+	void clear();
 	auto operator[](const std::size_t index) {
 		struct {
 			Model& model;
@@ -247,7 +248,7 @@
 	}
 };
 
-void save(const Model& model, QIODevice *device);
+void save(const Model& model, QTextStream* stream);
 void updateHeaderNameField(Model& model, const QString &name);
 
 template<typename T>
--- a/src/parser.cpp	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/parser.cpp	Sun Jul 03 23:54:22 2022 +0300
@@ -30,16 +30,16 @@
 /*
  * Constructs an LDraw parser
  */
-Parser::Parser(QIODevice& device, QObject* parent) :
+Parser::Parser(QTextStream& stream, QObject* parent) :
 	QObject {parent},
-	device {device} {}
+	stream {stream} {}
 
 /*
  * Reads a single line from the device.
  */
 QString Parser::readLine()
 {
-	return QString::fromUtf8(this->device.readLine()).trimmed();
+	return this->stream.readLine().trimmed();
 }
 
 /**
@@ -49,7 +49,7 @@
 void Parser::parseBody(Model& model)
 {
 	bool invertNext = false;
-	while (not this->device.atEnd())
+	while (not this->stream.atEnd())
 	{
 		// Some LDraw parts such as 53588.dat can contain "BFC  INVERTNEXT" with multiple inner whitespaces.
 		// So we need to pass the string through QString::simplified to catch these cases.
--- a/src/parser.h	Sun Jul 03 22:32:50 2022 +0300
+++ b/src/parser.h	Sun Jul 03 23:54:22 2022 +0300
@@ -24,11 +24,11 @@
 {
 	Q_OBJECT
 public:
-	Parser(QIODevice& device, QObject* parent = nullptr);
+	Parser(QTextStream& stream, QObject* parent = nullptr);
 	void parseBody(Model &model);
 private:
 	QString readLine();
-	QIODevice& device;
+	QTextStream& stream;
 };
 
 ModelElement parseLDrawLine(QString line);

mercurial