src/model.cpp

changeset 200
ca23936b455b
parent 173
8a3047468994
child 204
52e10e8d88cc
--- a/src/model.cpp	Wed May 25 20:36:34 2022 +0300
+++ b/src/model.cpp	Mon Jun 06 22:01:22 2022 +0300
@@ -16,254 +16,169 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <QBrush>
-#include <QFile>
-#include <QFileInfo>
-#include <QFont>
-#include <QSaveFile>
 #include "model.h"
-#include "modeleditor.h"
-#include "documentmanager.h"
 
-/**
- * @brief Constructs a model
- * @param parent QObject parent to pass forward
- */
+QString modelElementToString(const ModelElement &element)
+{
+	return std::visit(overloaded{
+		[](const Colored<SubfileReference>& ref) {
+			return QStringLiteral("1 %1 %2 %3")
+				.arg(ref.color.index)
+				.arg(transformToString(ref.transformation))
+				.arg(ref.name);
+		},
+		[](const Colored<LineSegment>& seg) {
+			return QStringLiteral("2 %1 %2 %3")
+				.arg(seg.color.index)
+				.arg(vertexToString(seg.p1))
+				.arg(vertexToString(seg.p2));
+		},
+		[](const Colored<Triangle>& triangle) {
+			return QStringLiteral("3 %1 %2 %3 %4")
+				.arg(triangle.color.index)
+				.arg(vertexToString(triangle.p1))
+				.arg(vertexToString(triangle.p2))
+				.arg(vertexToString(triangle.p3));
+		},
+		[](const Colored<Quadrilateral>& quad) {
+			return QStringLiteral("4 %1 %2 %3 %4 %5")
+				.arg(quad.color.index)
+				.arg(vertexToString(quad.p1))
+				.arg(vertexToString(quad.p2))
+				.arg(vertexToString(quad.p3))
+				.arg(vertexToString(quad.p4));
+		},
+		[](const Colored<ConditionalEdge>& cedge) {
+			return QStringLiteral("5 %1 %2 %3 %4 %5")
+				.arg(cedge.color.index)
+				.arg(vertexToString(cedge.p1))
+				.arg(vertexToString(cedge.p2))
+				.arg(vertexToString(cedge.c1))
+				.arg(vertexToString(cedge.c2));
+		},
+		[](const Comment& comment) {
+			return "0 " + comment.text;
+		},
+		[](const Empty&) {
+			return QStringLiteral("");
+		},
+		[](const ParseError& parseError) {
+			return parseError.code;
+		},
+	}, element);
+}
+
 Model::Model(QObject *parent) :
 	QAbstractListModel{parent}
 {
 }
 
-/**
- * @returns the amount of elements in the model
- */
-int Model::size() const
+Model::~Model()
+{
+}
+
+ModelId Model::append(const ModelElement &value)
 {
-	return static_cast<int>(this->body.size());
+	const int position = static_cast<int>(this->body.size());
+	const ModelId id = this->runningId;
+	this->runningId.value += 1;
+	Q_EMIT this->beginInsertRows({}, position, position);
+	this->body.push_back({value, id});
+	this->positions[id] = position;
+	Q_EMIT this->endInsertRows();
+	return id;
+}
+
+const ModelElement &Model::at(int position) const
+{
+	return this->body[position].data;
 }
 
-/**
- * @brief Looks up the object ID at the specified index. If out of bounds, returns NULL_ID.
- * @param index Index of object to look up
- * @return object ID
- */
-ldraw::id_t Model::at(int index) const
+ModelId Model::idAt(int position) const
+{
+	return this->body[position].id;
+}
+
+void Model::assignAt(int position, const ModelElement &element)
 {
-	if (index >= 0 and index < this->size())
-	{
-		return this->body[index]->id;
-	}
-	else
-	{
-		return ldraw::NULL_ID;
+	this->body[position].data = element;
+	const QModelIndex index = this->index(position);
+	Q_EMIT this->dataChanged(index, index);
+}
+
+std::optional<int> Model::find(ModelId id) const
+{
+	return pointerToOptional(findInMap(this->positions, id));
+}
+
+void Model::remove(int index)
+{
+	if (index >= 0 and index < this->size()) {
+		Q_EMIT this->beginRemoveRows({}, index, index);
+		this->body.erase(this->body.begin() + index);
+		Q_EMIT this->endRemoveRows();
 	}
 }
 
-/**
- * @brief @overload QAbstractListModel::rowCount
- * @return size
- */
-int Model::rowCount(const QModelIndex&) const
+int Model::rowCount(const QModelIndex &) const
 {
 	return this->size();
 }
 
-/**
- * @brief @overload QAbstractListModel::data
- * @param index
- * @param role
- * @return QVariant
- */
-QVariant Model::data(const QModelIndex& index, int role) const
+QVariant Model::data(const QModelIndex &index, int role) const
 {
-	const ldraw::Object* object = (*this)[index.row()];
+	const int i = index.row();
 	switch(role)
 	{
+	/*
 	case Qt::DecorationRole:
 		return QPixmap{object->iconName()}.scaledToHeight(24);
+	*/
 	case Qt::DisplayRole:
-		return object->textRepresentation();
+		return modelElementToString(this->body[i].data);
+	/*
 	case Qt::ForegroundRole:
 		return object->textRepresentationForeground();
 	case Qt::BackgroundRole:
 		return object->textRepresentationBackground();
 	case Qt::FontRole:
 		return object->textRepresentationFont();
+	*/
 	default:
 		return {};
 	}
 }
 
-/**
- * @brief Finds the position of the specified object in the model
- * @param id Object id to look for
- * @return model index
- */
-QModelIndex Model::find(ldraw::id_t id) const
+const ModelElement &Model::operator[](int index) const
+{
+	return this->body[index].data;
+}
+
+int Model::size() const
 {
-	if (this->needObjectsByIdRebuild)
-	{
-		this->objectsById.clear();
-		for (std::size_t i = 0; i < this->body.size(); ++i)
-		{
-			this->objectsById[this->body[i]->id] = i;
-		}
-		this->needObjectsByIdRebuild = false;
-	}
-	const auto it = this->objectsById.find(id);
-	if (it != this->objectsById.end())
-	{
-		return this->index(it->second);
-	}
-	else
-	{
-		return {};
+	return this->body.size();
+}
+
+void save(const Model &model, QIODevice *device)
+{
+	QTextStream out{device};
+	for (int i = 0; i < model.size(); ++i) {
+		out << modelElementToString(model[i]) << "\r\n";
 	}
 }
 
 /**
- * @brief Gets an object id by position in the model
- * @param index Position of the object in the model
- * @return id
- */
-ldraw::id_t Model::idAt(const QModelIndex& index) const
-{
-	return (*this)[index.row()]->id;
-}
-
-#if 0
-/**
  * @brief Sets the path to the model
  * @param path New path to use
  */
-void Model::setPath(const QString &path)
+void updateHeaderNameField(Model& model, const QString &name)
 {
-	this->storedPath = path;
-	this->header.name = QFileInfo{path}.fileName();
 	// Update the "Name: 1234.dat" comment
-	if (this->body.size() >= 2)
-	{
-		const ldraw::id_t id = this->body[1]->id;
-		if (this->isA<ldraw::MetaCommand>(id))
-		{
-			const QString& textBody = this->body[1]->getProperty<ldraw::Property::Text>();
-			if (textBody.startsWith("Name: "))
-			{
-				auto editor = this->edit();
-				editor.setObjectProperty<ldraw::Property::Text>(id, "Name: " + this->header.name);
+	if (model.size() >= 2) {
+		if (const Comment* nameObject = std::get_if<Comment>(&model[1])) {
+			if (nameObject->text.startsWith("Name: ")) {
+				model[1] = Comment{"Name: " + name};
 			}
 		}
 	}
 }
-#endif
-
-/**
- * @brief Adds the given object into the model.
- * @param object r-value reference to the object
- */
-ldraw::id_t Model::append(ModelObjectPointer&& object)
-{
-	const int position = static_cast<int>(this->body.size());
-	Q_EMIT this->beginInsertRows({}, position, position);
-	this->body.push_back(std::move(object));
-	Q_EMIT this->endInsertRows();
-	const ldraw::id_t id = this->body.back()->id;
-	this->objectsById[id] = this->body.size() - 1;
-	return id;
-}
-
-/**
- * @brief Removes the object at the specified position
- * @param position
- */
-void Model::remove(int position)
-{
-	if (position >= 0 and position < signed_cast(this->body.size()))
-	{
-		Q_EMIT this->beginRemoveRows({}, position, position);
-		this->body.erase(std::begin(this->body) + position);
-		this->needObjectsByIdRebuild = true;
-		Q_EMIT this->endRemoveRows();
-	}
-}
-
-void Model::emitDataChangedSignal(int position)
-{
-	Q_EMIT this->dataChanged(this->index(position), this->index(position));
-}
-
-/**
- * @brief Gets the object pointer at the specified position
- * @param index Position of the object
- * @returns object pointer
- */
-ldraw::Object* Model::operator[](int index)
-{
-	if (index >= 0 and index < this->size())
-	{
-		return this->body[index].get();
-	}
-	else
-	{
-		throw std::out_of_range{"index out of range"};
-	}
-}
-
-/**
- * @brief Gets the object pointer at the specified position
- * @param index Position of the object
- * @returns object pointer
- */
-const ldraw::Object* Model::operator[](int index) const
-{
-	if (index >= 0 and index < this->size())
-	{
-		return this->body[index].get();
-	}
-	else
-	{
-		throw std::out_of_range{"index out of range"};
-	}
-}
-
-/**
- * @brief Gets an object pointer by id. Used by the editing context to actually modify objects.
- * @param id
- * @return object pointer
- */
-ldraw::Object* Model::findObjectById(const ldraw::id_t id)
-{
-	const QModelIndex index = this->find(id);
-	if (index.isValid())
-	{
-		return (*this)[index.row()];
-	}
-	else
-	{
-		return nullptr;
-	}
-}
-
-const ldraw::Object* Model::findObjectById(const ldraw::id_t id) const
-{
-	const QModelIndex index = this->find(id);
-	if (index.isValid())
-	{
-		return (*this)[index.row()];
-	}
-	else
-	{
-		return nullptr;
-	}
-}
-
-/**
- * @brief Attempts the save the model
- */
-void save(const Model &model, QIODevice *device)
-{
-	QTextStream out{device};
-	applyToModel<ldraw::Object>(model, [&](const ldraw::Object* object) {
-		out << object->toLDrawCode() << "\r\n";
-	});
-}

mercurial