Sun, 05 Mar 2017 16:47:52 +0200
Moved LDObject lifetime management from Model to ResourceVector. This is a large refactor that removes some hacks from the Model class.
--- a/src/documentloader.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/documentloader.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -55,7 +55,7 @@ return m_isOnForeground; } -const QVector<LDObject*>& DocumentLoader::objects() const +const ResourceVector<LDObject>& DocumentLoader::objects() const { return _model->objects(); }
--- a/src/documentloader.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/documentloader.h Sun Mar 05 16:47:52 2017 +0200 @@ -37,7 +37,7 @@ bool hasAborted(); bool isDone() const; bool isOnForeground() const; - const QVector<LDObject*>& objects() const; + const ResourceVector<LDObject>& objects() const; int progress() const; void read (QIODevice* fp); Q_SLOT void start();
--- a/src/glcompiler.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/glcompiler.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -71,9 +71,9 @@ HierarchyElement (renderer), m_renderer (renderer) { - connect(renderer->model(), SIGNAL(objectAdded(LDObject*)), this, SLOT(compileObject(LDObject*))); + connect(renderer->model(), SIGNAL(objectAdded(LDObject*, int)), this, SLOT(compileObject(LDObject*))); connect(renderer->model(), SIGNAL(objectModified(LDObject*)), this, SLOT(compileObject(LDObject*))); - connect(renderer->model(), SIGNAL(aboutToRemoveObject(LDObject*)), this, SLOT(forgetObject(LDObject*)), Qt::DirectConnection); + connect(renderer->model(), SIGNAL(aboutToRemoveObject(LDObject*, int)), this, SLOT(forgetObject(LDObject*)), Qt::DirectConnection); connect(renderer, SIGNAL(objectHighlightingChanged(LDObject*)), this, SLOT(compileObject(LDObject*))); connect(m_window, SIGNAL(gridChanged()), this, SLOT(recompile()));
--- a/src/glrenderer.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/glrenderer.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -71,7 +71,7 @@ m_toolTipTimer->setSingleShot (true); setAcceptDrops (true); connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (showCameraIconTooltip())); - connect(model, SIGNAL(aboutToRemoveObject(LDObject*)), this, SLOT(removeObject(LDObject*))); + connect(model, SIGNAL(aboutToRemoveObject(LDObject*, int)), this, SLOT(removeObject(LDObject*))); resetAllAngles(); m_needZoomToFit = true;
--- a/src/lddocument.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/lddocument.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -33,7 +33,12 @@ m_history (new EditHistory (this)), m_savePosition(-1), m_tabIndex(-1), - m_manager (parent) {} + m_manager (parent) +{ + connect(this, SIGNAL(objectAdded(LDObject*, int)), this, SLOT(handleNewObject(LDObject*, int))); + connect(this, SIGNAL(objectsSwapped(LDObject*, LDObject*)), this, SLOT(handleObjectSwap(LDObject*, LDObject*))); + connect(this, SIGNAL(aboutToRemoveObject(LDObject*, int)), this, SLOT(handleObjectRemoval(LDObject*, int))); +} LDDocument::~LDDocument() { @@ -293,15 +298,14 @@ // ============================================================================= // -void LDDocument::insertObject (int pos, LDObject* obj) +void LDDocument::handleNewObject(LDObject* object, int position) { - Model::insertObject(pos, obj); - history()->add(new AddHistoryEntry {pos, obj}); - connect(obj, SIGNAL(codeChanged(QString,QString)), this, SLOT(objectChanged(QString,QString))); + history()->add(new AddHistoryEntry {position, object}); + connect(object, SIGNAL(codeChanged(QString,QString)), this, SLOT(objectChanged(QString,QString))); #ifdef DEBUG if (not isFrozen()) - print("Inserted object #%1 (%2) at %3\n", obj->id(), obj->typeName(), pos); + print("Inserted object #%1 (%2) at %3\n", object->id(), object->typeName(), position); #endif } @@ -313,10 +317,8 @@ emit objectModified(object); } -LDObject* LDDocument::withdrawAt(int position) +void LDDocument::handleObjectRemoval(LDObject* object, int position) { - LDObject* object = getObject(position); - if (not isFrozen() and not m_isBeingDestroyed) { history()->add(new DelHistoryEntry {position, object}); @@ -324,7 +326,6 @@ } m_selection.remove(object); - return Model::withdrawAt(position); } // ============================================================================= @@ -487,17 +488,9 @@ // ============================================================================= // -bool LDDocument::swapObjects (LDObject* one, LDObject* other) +void LDDocument::handleObjectSwap(LDObject* one, LDObject* other) { - if (Model::swapObjects(one, other)) - { - addToHistory(new SwapHistoryEntry {one->id(), other->id()}); - return true; - } - else - { - return false; - } + addToHistory(new SwapHistoryEntry {one->id(), other->id()}); } // =============================================================================
--- a/src/lddocument.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/lddocument.h Sun Mar 05 16:47:52 2017 +0200 @@ -62,7 +62,6 @@ void inlineContents(Model& model, bool deep, bool renderinline); QList<LDPolygon> inlinePolygons(); const QSet<Vertex>& inlineVertices(); - void insertObject (int pos, LDObject* obj); bool isFrozen() const; bool isSafeToClose(); QString name() const; @@ -81,7 +80,6 @@ void setName (QString value); void setSavePosition (long value); void setTabIndex (int value); - bool swapObjects (LDObject* one, LDObject* other); int tabIndex() const; void undo(); void vertexChanged (const Vertex& a, const Vertex& b); @@ -91,9 +89,6 @@ public slots: void objectChanged(QString before, QString after); -protected: - LDObject* withdrawAt(int position); - private: QString m_name; QString m_fullPath; @@ -111,6 +106,10 @@ QSet<Vertex> m_vertices; QSet<LDObject*> m_selection; DocumentManager* m_manager; + + Q_SLOT void handleNewObject(LDObject* object, int position); + Q_SLOT void handleObjectSwap(LDObject* one, LDObject* other); + Q_SLOT void handleObjectRemoval(LDObject* object, int position); }; // Parses a string line containing an LDraw object and returns the object parsed.
--- a/src/ldobjectiterator.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/ldobjectiterator.h Sun Mar 05 16:47:52 2017 +0200 @@ -31,7 +31,7 @@ seekTillValid(); } - LDObjectIterator (const QVector<LDObject*>& objs) : + LDObjectIterator (const ResourceVector<LDObject>& objs) : m_list (objs), m_i (-1) { @@ -111,7 +111,7 @@ } private: - const QVector<LDObject*>& m_list; + const ResourceVector<LDObject>& m_list; int m_i; };
--- a/src/linetypes/comment.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/comment.h Sun Mar 05 16:47:52 2017 +0200 @@ -37,9 +37,9 @@ void setText(QString value); protected: + friend class ResourceVector<LDObject>; LDComment(QString text, Model* model); LDComment(Model* model); - friend class Model; private: QString m_text;
--- a/src/linetypes/conditionaledge.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/conditionaledge.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -54,9 +54,13 @@ { LDEdgeLine* replacement = model()->emplaceReplacement<LDEdgeLine>(this); - for (int i = 0; i < replacement->numVertices(); ++i) - replacement->setVertex (i, vertex (i)); + if (replacement) + { + for (int i = 0; i < replacement->numVertices(); ++i) + replacement->setVertex (i, vertex (i)); - replacement->setColor (color()); + replacement->setColor (color()); + } + return replacement; }
--- a/src/linetypes/conditionaledge.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/conditionaledge.h Sun Mar 05 16:47:52 2017 +0200 @@ -40,7 +40,7 @@ QString typeName() const override { return "condline"; } protected: - friend class Model; + friend class ResourceVector<LDObject>; LDConditionalEdge (Model* model); LDConditionalEdge (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model = nullptr); };
--- a/src/linetypes/edgeline.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/edgeline.h Sun Mar 05 16:47:52 2017 +0200 @@ -39,7 +39,7 @@ QString typeName() const override { return "line"; } protected: - friend class Model; + friend class ResourceVector<LDObject>; LDEdgeLine (Model* model); LDEdgeLine (Vertex v1, Vertex v2, Model* model = nullptr); };
--- a/src/linetypes/empty.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/empty.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -41,3 +41,8 @@ { return ""; } + +bool LDEmpty::isScemantic() const +{ + return false; +}
--- a/src/linetypes/empty.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/empty.h Sun Mar 05 16:47:52 2017 +0200 @@ -28,11 +28,12 @@ static const LDObjectType SubclassType = LDObjectType::Empty; QString asText() const override; + bool isScemantic() const override; QString objectListText() const override; LDObjectType type() const override; QString typeName() const override; protected: - friend class Model; + friend class ResourceVector<LDObject>; LDEmpty(Model* model); };
--- a/src/linetypes/modelobject.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/modelobject.h Sun Mar 05 16:47:52 2017 +0200 @@ -22,6 +22,7 @@ #include "../basics.h" #include "../glShared.h" #include "../colors.h" +#include "../types/resourcevector.h" class Model; class LDDocument; @@ -95,7 +96,9 @@ void codeChanged(QString before, QString after); protected: + friend class ResourceVector<LDObject>; friend class Model; + LDObject (Model* model = nullptr); virtual ~LDObject(); void setDocument(Model* model); @@ -159,7 +162,7 @@ QString typeName() const override { return "error"; } protected: - friend class Model; + friend class ResourceVector<LDObject>; LDError (Model* model); LDError (QString contents, QString reason, Model* model = nullptr); @@ -202,7 +205,7 @@ virtual QString asText() const override; virtual void invert() override; protected: - friend class Model; + friend class ResourceVector<LDObject>; LDBfc (Model* model); public: @@ -249,7 +252,7 @@ QString typeName() const override { return "subfilereference"; } protected: - friend class Model; + friend class ResourceVector<LDObject>; LDSubfileReference (Model* model); LDSubfileReference(LDDocument* reference, const Matrix& transformationMatrix, const Vertex& position, Model* model = nullptr); @@ -280,7 +283,7 @@ QString typeName() const override { return "beziercurve"; } protected: - friend class Model; + friend class ResourceVector<LDObject>; LDBezierCurve (Model* model); LDBezierCurve (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model = nullptr); };
--- a/src/linetypes/quadrilateral.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/quadrilateral.h Sun Mar 05 16:47:52 2017 +0200 @@ -35,7 +35,7 @@ QString typeName() const override; protected: - friend class Model; + friend class ResourceVector<LDObject>; LDQuadrilateral(Model* model); LDQuadrilateral(const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex& v4, Model* model = nullptr); };
--- a/src/linetypes/triangle.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/linetypes/triangle.h Sun Mar 05 16:47:52 2017 +0200 @@ -39,7 +39,7 @@ QString typeName() const override { return "triangle"; } protected: - friend class Model; + friend class ResourceVector<LDObject>; LDTriangle (Model* model); LDTriangle (Vertex const& v1, Vertex const& v2, Vertex const& v3, Model* model = nullptr); -}; \ No newline at end of file +};
--- a/src/model.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/model.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <cassert> #include "model.h" #include "linetypes/modelobject.h" #include "documentmanager.h" @@ -30,20 +31,6 @@ QObject {manager}, _manager {manager} {} -Model::~Model() -{ - for (int i = 0; i < countof(_objects); ++i) - delete _objects[i]; -} - -/* - * Takes an existing object and migrates it to the end of this model. The object is removed from its old model in the process. - */ -void Model::addObject(LDObject *object) -{ - insertObject(size(), object); -} - /* * Returns the amount of objects in this model. */ @@ -55,28 +42,39 @@ /* * Returns the vector of objects in this model. */ -const QVector<LDObject*>& Model::objects() const +const ResourceVector<LDObject>& Model::objects() const +{ + return _objects; +} + +/* + * Returns the vector of objects in this model (private mutable access) + */ +ResourceVector<LDObject>& Model::mutableObjects() { return _objects; } /* - * Takes an existing object and migrates it to this model, at the specified position. + * Takes an existing object and adds it to this model, at the specified position. + * The object is assumed to be ownerless. */ -void Model::insertObject(int position, LDObject* object) +void Model::finalizeNewObject(int position, LDObject* object) { - if (object->model() and object->model() != this) - object->model()->withdraw(object); - - // TODO: check that the object isn't in the vector once there's a cheap way to do so! - _objects.insert(position, object); + assert(object->model() == this); _needsTriangleRecount = true; object->setDocument(this); - emit objectAdded(object); + + // Set default color. Relying on virtual functions, this cannot be done in the c-tor. + // TODO: store -1 as the default color + if (object->isColored()) + object->setColor(object->defaultColor()); + + emit objectAdded(object, position); } /* - * Swaps one object with another, assuming they both are in this model. + * Swaps one object with another, if they both are in this model. */ bool Model::swapObjects(LDObject* one, LDObject* other) { @@ -85,8 +83,8 @@ if (a != b and a != -1 and b != -1) { - _objects[b] = one; - _objects[a] = other; + _objects.swap(a, b); + emit objectsSwapped(one, other); return true; } else @@ -96,23 +94,6 @@ } /* - * Assigns a new object to the specified position in the model. The object that already is in the position is deleted in the process. - */ -bool Model::setObjectAt(int idx, LDObject* obj) -{ - if (idx < 0 or idx >= countof(_objects)) - { - return false; - } - else - { - removeAt(idx); - insertObject(idx, obj); - return true; - } -} - -/* * Returns the object at the specified position, or null if not found. */ LDObject* Model::getObject(int position) const @@ -138,8 +119,8 @@ */ void Model::removeAt(int position) { - LDObject* object = withdrawAt(position); - delete object; + emit aboutToRemoveObject(_objects[position], position); + _objects.removeAt(position); } /* @@ -150,11 +131,8 @@ if (object->model() == this) { int position = object->lineNumber(); - - for (int i = countof(model.objects()) - 1; i >= 1; i -= 1) - insertObject(position + i, model.objects()[i]); - - setObjectAt(position, model.objects()[0]); + merge(model, position); + remove(object); } } @@ -186,29 +164,42 @@ /* * Merges the given model into this model, starting at the given position. The other model is emptied in the process. + * If select is true, the new objects are added to the selection. */ -void Model::merge(Model& other, int position) +void Model::merge(Model& other, int position, Filter filter, Callback callback) { if (position < 0) position = countof(_objects); - // Copy the vector of objects to copy, so that we don't change the vector while iterating over it. - QVector<LDObject*> objectsCopy = other._objects; + if (filter == nullptr) + filter = [](LDObject*){return true;}; - // Inform the contents of their new owner - for (LDObject* object : objectsCopy) + _objects.merge(other.mutableObjects(), position, [&](LDObject* object, int objectPosition) { - insertObject(position, object); - position += 1; - } + if (filter(object)) + { + emit other.aboutToRemoveObject(object, objectPosition); + return true; + } + else + { + return false; + } + }, [&](LDObject* object, int objectPosition) + { + _needsTriangleRecount = true; + object->setDocument(this); + emit objectAdded(object, objectPosition); - other.clear(); + if (callback) + callback(object, position); + }); } /* * Returns the begin-iterator into this model, so that models can be used in foreach-loops. */ -QVector<LDObject*>::iterator Model::begin() +LDObject* const* Model::begin() { return _objects.begin(); } @@ -216,7 +207,7 @@ /* * Returns the end-iterator into this mode, so that models can be used in foreach-loops. */ -QVector<LDObject*>::iterator Model::end() +LDObject* const* Model::end() { return _objects.end(); } @@ -234,35 +225,6 @@ } /* - * Drops the object from the model. The object becomes a free object as a result (thus violating the invariant that every object - * has a model!). The caller must immediately add the withdrawn object to another model. - * - * This private method is only used to implement public API. - */ -void Model::withdraw(LDObject* object) -{ - if (object->model() == this) - { - int position = object->lineNumber(); - - if (_objects[position] == object) - withdrawAt(position); - } -} - -/* - * Drops an object from the model at the provided position. The caller must immediately put the result value object into a new model. - */ -LDObject* Model::withdrawAt(int position) -{ - LDObject* object = _objects[position]; - emit aboutToRemoveObject(object); - _objects.removeAt(position); - _needsTriangleRecount = true; - return object; -} - -/* * Returns whether or not this model is empty. */ bool Model::isEmpty() const
--- a/src/model.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/model.h Sun Mar 05 16:47:52 2017 +0200 @@ -19,6 +19,7 @@ #pragma once #include "main.h" #include "linetypes/modelobject.h" +#include "types/resourcevector.h" /* * This class represents a LDraw model, consisting of a vector of objects. It manages LDObject ownership. @@ -28,30 +29,28 @@ Q_OBJECT public: + using Filter = std::function<bool(LDObject*)>; + using Callback = std::function<void(LDObject*, int)>; + Model(class DocumentManager* manager); Model(const Model& other) = delete; - ~Model(); - void addObject(LDObject* object); - virtual void insertObject(int position, LDObject* object); - virtual bool swapObjects(LDObject* one, LDObject* other); - virtual bool setObjectAt(int idx, LDObject* obj); + bool swapObjects(LDObject* one, LDObject* other); template<typename T, typename... Args> T* emplace(Args&& ...args); template<typename T, typename... Args> T* emplaceAt(int position, Args&& ...args); template<typename T, typename... Args> T* emplaceReplacement(LDObject* object, Args&& ...args); - template<typename T, typename... Args> T* emplaceReplacementAt(int position, Args&& ...args); void removeAt(int position); void remove(LDObject* object); void replace(LDObject *object, Model& model); void clear(); - void merge(Model& other, int position = -1); + void merge(Model& other, int position = -1, Filter filter = nullptr, Callback callback = nullptr); int size() const; - const QVector<LDObject*>& objects() const; + const ResourceVector<LDObject>& objects() const; LDObject* getObject(int position) const; void recountTriangles(); int triangleCount() const; - QVector<LDObject*>::iterator begin(); - QVector<LDObject*>::iterator end(); + LDObject* const* begin(); + LDObject* const* end(); bool isEmpty() const; class DocumentManager* documentManager() const; LDObject* insertFromString(int position, QString line); @@ -59,19 +58,22 @@ LDObject* replaceWithFromString(LDObject* object, QString line); signals: - void objectAdded(LDObject* object); - void aboutToRemoveObject(LDObject* object); + void objectAdded(LDObject* object, int position); + void aboutToRemoveObject(LDObject* object, int position); void objectModified(LDObject* object); + void objectsSwapped(LDObject* one, LDObject* other); protected: template<typename T, typename... Args> T* constructObject(Args&& ...args); - void withdraw(LDObject* object); - virtual LDObject* withdrawAt(int position); - QVector<LDObject*> _objects; + ResourceVector<LDObject> _objects; class DocumentManager* _manager; mutable int _triangleCount = 0; mutable bool _needsTriangleRecount; + +private: + void finalizeNewObject(int position, LDObject* object); + ResourceVector<LDObject>& mutableObjects(); }; int countof(Model& model); @@ -92,8 +94,8 @@ template<typename T, typename... Args> T* Model::emplace(Args&& ...args) { - T* object = constructObject<T>(args...); - addObject(object); + T* object = _objects.append<T>(args..., this); + finalizeNewObject(size() - 1, object); return object; } @@ -104,8 +106,8 @@ template<typename T, typename... Args> T* Model::emplaceAt(int position, Args&& ...args) { - T* object = constructObject<T>(args...); - insertObject(position, object); + T* object = _objects.insert<T>(position, args..., this); + finalizeNewObject(position, object); return object; } @@ -119,39 +121,13 @@ if (object->model() == this) { int position = object->lineNumber(); - T* replacement = constructObject<T>(args...); - setObjectAt(position, replacement); + removeAt(position); + T* replacement = _objects.insert<T>(position, args..., this); + finalizeNewObject(position, replacement); return replacement; } else + { return nullptr; -} - -/* - * Like emplaceAt<>() but instead of inserting the constructed object, it replaces the document at the given spot instead. - * The replaced object is deleted in the process. - */ -template<typename T, typename... Args> -T* Model::emplaceReplacementAt(int position, Args&& ...args) -{ - T* replacement = constructObject<T>(args...); - setObjectAt(position, replacement); - return replacement; + } } - -/* - * Constructs an LDObject such that it gets this model as its model pointer. - */ -template<typename T, typename... Args> -T* Model::constructObject(Args&& ...args) -{ - static_assert (std::is_base_of<LDObject, T>::value, "Can only use this function with LDObject-derivatives"); - T* object = new T {args..., this}; - - // Set default color. Relying on virtual functions, this cannot be done in the c-tor. - // TODO: store -1 as the default color - if (object->isColored()) - object->setColor(object->defaultColor()); - - return object; -}
--- a/src/toolsets/algorithmtoolset.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/toolsets/algorithmtoolset.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -59,7 +59,6 @@ Vertex v1 = object->vertex(1); Vertex v2 = object->vertex(2); Vertex v3 = object->vertex(3); - LDColor color = object->color(); // Find the index of this quad int index = object->lineNumber(); @@ -72,12 +71,14 @@ // │ │ --→ │ ╱ ╱ │ // │ │ --→ │╱ ╱ │ // 1───2 1 1───2 - LDTriangle* triangle1 = currentDocument()->emplaceReplacementAt<LDTriangle>(index, v0, v1, v3); - LDTriangle* triangle2 = currentDocument()->emplaceAt<LDTriangle>(index + 1, v1, v2, v3); + Model replacement {m_documents}; + LDTriangle* triangle1 = replacement.emplace<LDTriangle>(v0, v1, v3); + LDTriangle* triangle2 = replacement.emplace<LDTriangle>(v1, v2, v3); // The triangles also inherit the quad's color - triangle1->setColor(color); - triangle2->setColor(color); + triangle1->setColor(object->color()); + triangle2->setColor(object->color()); + currentDocument()->replace(object, replacement); count += 1; } @@ -278,15 +279,15 @@ void AlgorithmToolset::demote() { - int num = 0; + int count = 0; for (LDConditionalEdge* line : filterByType<LDConditionalEdge>(selectedObjects())) { line->becomeEdgeLine(); - ++num; + count += 1; } - print (tr ("Converted %1 conditional lines"), num); + print (tr ("Converted %1 conditional lines"), count); } bool AlgorithmToolset::isColorUsed (LDColor color)
--- a/src/toolsets/basictoolset.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/toolsets/basictoolset.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -98,19 +98,16 @@ { // Get the index of the subfile so we know where to insert the // inlined contents. - int idx = reference->lineNumber(); + int position = reference->lineNumber(); - if (idx != -1) + if (position != -1) { Model inlined {m_documents}; reference->inlineContents(inlined, deep, false); - - // Merge in the inlined objects - for (LDObject* inlinedObject : inlined.objects()) + currentDocument()->merge(inlined, position, nullptr, [&](LDObject* object, int) { - currentDocument()->insertObject (idx++, inlinedObject); - currentDocument()->addToSelection(inlinedObject); - } + currentDocument()->addToSelection(object); + }); // Delete the subfile now as it's been inlined. currentDocument()->remove(reference); @@ -299,4 +296,4 @@ void BasicToolset::modeLinePath() { m_window->renderer()->setEditMode (EditModeType::LinePath); -} \ No newline at end of file +}
--- a/src/toolsets/extprogramtoolset.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/toolsets/extprogramtoolset.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -157,14 +157,14 @@ LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj); Model model {m_documents}; ref->inlineContents(model, true, false); - writeObjects(model.objects(), f); + writeObjects(model.objects().toQVector(), f); } else if (obj->type() == LDObjectType::BezierCurve) { LDBezierCurve* curve = static_cast<LDBezierCurve*> (obj); Model model {m_documents}; curve->rasterize(model, grid()->bezierCurveSegments()); - writeObjects(model.objects(), f); + writeObjects(model.objects().toQVector(), f); } else f.write ((obj->asText() + "\r\n").toUtf8()); @@ -321,15 +321,9 @@ for (LDColor color : colorsToReplace) m_window->deleteByColor (color); - // Insert the new objects + // Insert the new objects. currentDocument()->clearSelection(); - - for (LDObject* object : model.objects()) - { - if (object->isScemantic()) - currentDocument()->addObject(object); - } - + currentDocument()->merge(model, -1, [](LDObject* object) {return object->isScemantic();}); m_window->doFullRefresh(); }
--- a/src/toolsets/filetoolset.cpp Sun Mar 05 13:33:37 2017 +0200 +++ b/src/toolsets/filetoolset.cpp Sun Mar 05 16:47:52 2017 +0200 @@ -120,14 +120,10 @@ m_documents->loadFileContents(&file, model, nullptr, nullptr); currentDocument()->clearSelection(); - - for (LDObject* object : model.objects()) + currentDocument()->merge(model, position, nullptr, [&](LDObject* object, int) { - currentDocument()->insertObject (position, object); currentDocument()->addToSelection(object); - position++; - } - + }); m_window->refresh(); m_window->scrollToSelection(); }
--- a/src/types/resourcevector.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/types/resourcevector.h Sun Mar 05 16:47:52 2017 +0200 @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#pragma once #include <QVector> /* @@ -25,18 +26,27 @@ class ResourceVector { public: + using Filter = std::function<bool(T*, int)>; + using Callback = std::function<void(T*, int)>; + ~ResourceVector(); void append(T) = delete; template<typename TT = T, typename... Args> - T* append(Args&&... args); - T** const begin() const; - T** const end() const; + TT* append(Args&&... args); + void assimilate(int position, T* resource); + T* const* begin() const; + T* const* end() const; + int indexOf(T* resource) const; template<typename TT = T, typename... Args> - T* insert(int position, Args&&... args); + TT* insert(int position, Args&&... args); + bool isEmpty() const; void clear(); void removeAt(int position); T* operator[](int position) const; int size() const; + void swap(int position1, int position2); + void merge(ResourceVector<T>& other, int position = -1, Filter filter = nullptr, Callback callback = nullptr); + const QVector<T*>& toQVector() const; private: QVector<T*> _data; @@ -59,17 +69,18 @@ */ template<typename T> template<typename TT, typename... Args> -T* ResourceVector<T>::append(Args&&... args) +TT* ResourceVector<T>::append(Args&&... args) { - _data.append(new TT {args...}); - return _data[size() - 1]; + TT* resource = new TT {args...}; + _data.append(resource); + return resource; } /* * Returns an iterator to the beginning of this vector. */ template<typename T> -T** const ResourceVector<T>::begin() const +T* const* ResourceVector<T>::begin() const { return _data.cbegin(); } @@ -78,7 +89,7 @@ * Returns an iterator to the end of this vector. */ template<typename T> -T** const ResourceVector<T>::end() const +T* const* ResourceVector<T>::end() const { return _data.cend(); } @@ -88,9 +99,11 @@ */ template<typename T> template<typename TT, typename... Args> -T* ResourceVector<T>::insert(int position, Args&&... args) +TT* ResourceVector<T>::insert(int position, Args&&... args) { - _data.insert(position, new TT {args...}); + TT* resource = new TT {args...}; + _data.insert(position, resource); + return resource; } /* @@ -111,7 +124,7 @@ template<typename T> void ResourceVector<T>::removeAt(int position) { - if (position < _data.size()) + if (position >= 0 and position < _data.size()) { delete _data[position]; _data.removeAt(position); @@ -128,7 +141,7 @@ template<typename T> T* ResourceVector<T>::operator[](int position) const { - if (position < _data.size()) + if (position >= 0 and position < _data.size()) return _data[position]; else throw std::domain_error {"index out of range"}; @@ -144,6 +157,96 @@ } /* + * Inserts an already existing resource into the vector. The resource is assumed to not be managed by anything else! + * Please think twice before using this method. + */ +template<typename T> +void ResourceVector<T>::assimilate(int position, T* resource) +{ + _data.insert(position, resource); +} + +/* + * Returns the index of the provided resource in the vector, or -1 if not found. + * This operation is of linear complexity O(n). + */ +template<typename T> +int ResourceVector<T>::indexOf(T* resource) const +{ + return _data.indexOf(resource); +} + +/* + * Swaps the locations of two resource in this vector. + */ +template<typename T> +void ResourceVector<T>::swap(int position1, int position2) +{ + if (position1 >= 0 and position2 >= 0 and position1 < size() and position2 < size()) + { + qSwap(_data[position1], _data[position2]); + } + else + { + throw std::domain_error {"index out of range"}; + } +} + +/* + * Returns whether or not the vector is empty. + */ +template<typename T> +bool ResourceVector<T>::isEmpty() const +{ + return size() == 0; +} + +/* + * Migrates resources from the provided resource vector to this one. + * - `position` indicates where to insert the new resources. Default is to the end. + * - `filter` specifies a filter function for the migration. Objects not passing the filter will not be migrated. + * - `callback` specifies a function that is called for each successfully migrated object. + */ +template<typename T> +void ResourceVector<T>::merge(ResourceVector<T>& other, int position, Filter filter, Callback callback) +{ + if (position < 0) + position = size(); + + if (filter == nullptr) + filter = [](T*, int){return true;}; + + if (callback == nullptr) + callback = [](T*, int){}; + + for (int i = 0; i < other.size();) + { + T* resource = other[i]; + + if (filter(resource, i)) + { + _data.insert(position, resource); + other._data.removeAt(i); + callback(resource, position); + position += 1; + } + else + { + i += 1; + } + } +} + +/* + * Returns the underlying vector. + */ +template<typename T> +const QVector<T*>& ResourceVector<T>::toQVector() const +{ + return _data; +} + +/* * countof() overload for resource vectors. Returns the amount of resources in the given vector. */ template<typename T>