--- a/src/model.h Sat Feb 04 14:24:16 2017 +0200 +++ b/src/model.h Sat Feb 04 14:44:39 2017 +0200 @@ -1,7 +1,28 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2017 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #pragma once #include "main.h" #include "ldObject.h" +/* + * This class represents a LDraw model, consisting of a vector of objects. It manages LDObject ownership. + */ class Model { public: @@ -9,10 +30,14 @@ Model(const Model& other) = delete; ~Model(); - virtual void addObject(LDObject* object); + 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); + 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); @@ -31,59 +56,8 @@ LDObject* addFromString(QString line); LDObject* replaceWithFromString(LDObject* object, QString line); - template<typename T, typename... Args> - T* emplace(Args&& ...args) - { - T* object = constructObject<T>(args...); - addObject(object); - return object; - } - - template<typename T, typename... Args> - T* emplaceAt(int position, Args&& ...args) - { - T* object = constructObject<T>(args...); - insertObject(position, object); - return object; - } - - template<typename T, typename... Args> - T* emplaceReplacement(LDObject* object, Args&& ...args) - { - if (object->model() == this) - { - int position = object->lineNumber(); - T* replacement = constructObject<T>(args...); - setObjectAt(position, replacement); - return replacement; - } - else - return nullptr; - } - - template<typename T, typename... Args> - T* emplaceReplacementAt(int position, Args&& ...args) - { - T* replacement = constructObject<T>(args...); - setObjectAt(position, replacement); - return replacement; - } - protected: - template<typename T, typename... Args> - T* 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; - } - + template<typename T, typename... Args> T* constructObject(Args&& ...args); void withdraw(LDObject* object); virtual LDObject* withdrawAt(int position); @@ -94,3 +68,83 @@ }; int countof(Model& model); + +/* + * Given an LDObject type as the template parameter, and any number of variadic parameters, constructs an LDObject derivative + * and inserts it into this model. The variadic parameters and this model pointer are passed to the constructor. The constructed object + * is added to the end of the model. + * + * For instance, the LDLine contains a constructor as such: + * + * LDLine(Vertex v1, Vertex v2, Model* model); + * + * This constructor can be invoked as such: + * + * model->emplace<LDLine>(v1, v2); + */ +template<typename T, typename... Args> +T* Model::emplace(Args&& ...args) +{ + T* object = constructObject<T>(args...); + addObject(object); + return object; +} + +/* + * Like emplace<>() but also takes a position as the first argument and emplaces the object at the given position instead of the + * end of the model. + */ +template<typename T, typename... Args> +T* Model::emplaceAt(int position, Args&& ...args) +{ + T* object = constructObject<T>(args...); + insertObject(position, object); + return object; +} + +/* + * Like emplace<>() but instead of inserting the constructed object, the new object replaces the object given in the first parameter. + * If the old object cannot be replaced, the new object will not be constructed at all. + */ +template<typename T, typename... Args> +T* Model::emplaceReplacement(LDObject* object, Args&& ...args) +{ + if (object->model() == this) + { + int position = object->lineNumber(); + T* replacement = constructObject<T>(args...); + setObjectAt(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; +} \ No newline at end of file