From 3e862bd5574b418833b8aa9a48330b1d701fc769 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 5 May 2017 21:21:09 +0200 Subject: [PATCH] Add addObjects to add multiple objects in one step --- src/App/Document.cpp | 87 ++++++++++++++++++++++++++++++++++++++ src/App/Document.h | 7 +++ src/App/GroupExtension.cpp | 23 ++++++++++ src/App/GroupExtension.h | 5 ++- src/Base/Type.cpp | 36 ++++++++-------- src/Base/Type.h | 1 + 6 files changed, 140 insertions(+), 19 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 187a2cf19b..198e22c204 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -2206,6 +2206,93 @@ DocumentObject * Document::addObject(const char* sType, const char* pObjectName, return pcObject; } +std::vector Document::addObjects(const char* sType, const std::vector& objectNames, bool isNew) +{ + Base::Type::importModule(sType); + Base::Type type = Base::Type::fromName(sType); + if (!type.isDerivedFrom(App::DocumentObject::getClassTypeId())) { + std::stringstream str; + str << "'" << sType << "' is not a document object type"; + throw Base::TypeError(str.str()); + } + + std::vector objects; + objects.resize(objectNames.size()); + std::generate(objects.begin(), objects.end(), + [&]{ return static_cast(type.createInstance()); }); + + // get all existing object names + std::vector reservedNames; + reservedNames.reserve(d->objectMap.size()); + for (auto pos = d->objectMap.begin();pos != d->objectMap.end();++pos) { + reservedNames.push_back(pos->first); + } + + for (auto it = objects.begin(); it != objects.end(); ++it) { + auto index = std::distance(objects.begin(), it); + App::DocumentObject* pcObject = *it; + pcObject->setDocument(this); + + // do no transactions if we do a rollback! + if (!d->rollback) { + // Undo stuff + if (d->activeUndoTransaction) { + d->activeUndoTransaction->addObjectDel(pcObject); + } + } + + // get unique name + std::string ObjectName = objectNames[index]; + if (ObjectName.empty()) + ObjectName = sType; + ObjectName = Base::Tools::getIdentifier(ObjectName); + if (d->objectMap.find(ObjectName) != d->objectMap.end()) { + // remove also trailing digits from clean name which is to avoid to create lengthy names + // like 'Box001001' + if (!testStatus(KeepTrailingDigits)) { + std::string::size_type index = ObjectName.find_last_not_of("0123456789"); + if (index+1 < ObjectName.size()) { + ObjectName = ObjectName.substr(0,index+1); + } + } + + ObjectName = Base::Tools::getUniqueName(ObjectName, reservedNames, 3); + } + + reservedNames.push_back(ObjectName); + + // insert in the name map + d->objectMap[ObjectName] = pcObject; + // cache the pointer to the name string in the Object (for performance of DocumentObject::getNameInDocument()) + pcObject->pcNameInDocument = &(d->objectMap.find(ObjectName)->first); + // insert in the vector + d->objectArray.push_back(pcObject); + + pcObject->Label.setValue(ObjectName); + + // Call the object-specific initialization + if (!d->undoing && !d->rollback && isNew) { + pcObject->setupObject(); + } + + // mark the object as new (i.e. set status bit 2) and send the signal + pcObject->StatusBits.set(2); + signalNewObject(*pcObject); + + // do no transactions if we do a rollback! + if (!d->rollback && d->activeUndoTransaction) { + signalTransactionAppend(*pcObject, d->activeUndoTransaction); + } + } + + if (!objects.empty()) { + d->activeObject = objects.back(); + signalActivatedObject(*objects.back()); + } + + return objects; +} + void Document::addObject(DocumentObject* pcObject, const char* pObjectName) { if (pcObject->getDocument()) { diff --git a/src/App/Document.h b/src/App/Document.h index d4274915a7..37aff37abf 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -182,6 +182,13 @@ public: * @param isNew if false don't call the \c DocumentObject::setupObject() callback (default is true) */ DocumentObject *addObject(const char* sType, const char* pObjectName=0, bool isNew=true); + /** Add an array of features of the given types and names. + * Unicode names are set through the Label propery. + * @param sType The type of created object + * @param objectNames A list of object names + * @param isNew If false don't call the \c DocumentObject::setupObject() callback (default is true) + */ + std::vectoraddObjects(const char* sType, const std::vector& objectNames, bool isNew=true); /// Remove a feature out of the document void remObject(const char* sName); /** Add an existing feature with sName (ASCII) to this document and set it active. diff --git a/src/App/GroupExtension.cpp b/src/App/GroupExtension.cpp index 0ed16d8f15..3e2b9541d9 100644 --- a/src/App/GroupExtension.cpp +++ b/src/App/GroupExtension.cpp @@ -75,6 +75,29 @@ void GroupExtension::addObject(DocumentObject* obj) } } +void GroupExtension::addObjects(const std::vector& objs) +{ + bool objectAdded = false; + std::vector grp = Group.getValues(); + for (auto obj : objs) { + if (allowObject(obj)) { + + //only one group per object + auto *group = App::GroupExtension::getGroupOfObject(obj); + if (group && group != getExtendedObject()) + group->getExtensionByType()->removeObject(obj); + + if (std::find(grp.begin(), grp.end(), obj) == grp.end()) { + grp.push_back(obj); + objectAdded = true; + } + } + } + + if (objectAdded) + Group.setValues(grp); +} + void GroupExtension::removeObject(DocumentObject* obj) { const std::vector & grp = Group.getValues(); diff --git a/src/App/GroupExtension.h b/src/App/GroupExtension.h index f6531020f4..8fd70d4273 100644 --- a/src/App/GroupExtension.h +++ b/src/App/GroupExtension.h @@ -53,9 +53,12 @@ public: /* Adds the object \a obj to this group. */ virtual void addObject(DocumentObject* obj); + /* Adds an array of object \a objs to this group. + */ + virtual void addObjects(const std::vector& objs); /*override this function if you want only special objects */ - virtual bool allowObject(DocumentObject* ) {return true;}; + virtual bool allowObject(DocumentObject* ) {return true;} /** Removes an object from this group. */ diff --git a/src/Base/Type.cpp b/src/Base/Type.cpp index 6c35e9235c..7c9848712a 100644 --- a/src/Base/Type.cpp +++ b/src/Base/Type.cpp @@ -92,24 +92,7 @@ void *Type::createInstanceByName(const char* TypeName, bool bLoadModule) { // if not already, load the module if(bLoadModule) - { - // cut out the module name - string Mod = getModuleName(TypeName); - // ignore base modules - if(Mod != "App" && Mod != "Gui" && Mod != "Base") - { - // remember already loaded modules - set::const_iterator pos = loadModuleSet.find(Mod); - if(pos == loadModuleSet.end()) - { - Interpreter().loadModule(Mod.c_str()); -#ifdef FC_LOGLOADMODULE - Console().Log("Act: Module %s loaded through class %s \n",Mod.c_str(),TypeName); -#endif - loadModuleSet.insert(Mod); - } - } - } + importModule(TypeName); // now the type should be in the type map Type t = fromName(TypeName); @@ -117,7 +100,24 @@ void *Type::createInstanceByName(const char* TypeName, bool bLoadModule) return 0; return t.createInstance(); +} +void Type::importModule(const char* TypeName) +{ + // cut out the module name + string Mod = getModuleName(TypeName); + // ignore base modules + if (Mod != "App" && Mod != "Gui" && Mod != "Base") { + // remember already loaded modules + set::const_iterator pos = loadModuleSet.find(Mod); + if (pos == loadModuleSet.end()) { + Interpreter().loadModule(Mod.c_str()); +#ifdef FC_LOGLOADMODULE + Console().Log("Act: Module %s loaded through class %s \n",Mod.c_str(),TypeName); +#endif + loadModuleSet.insert(Mod); + } + } } string Type::getModuleName(const char* ClassName) diff --git a/src/Base/Type.h b/src/Base/Type.h index 517f5947ed..50bc86cf68 100644 --- a/src/Base/Type.h +++ b/src/Base/Type.h @@ -87,6 +87,7 @@ public: void *createInstance(void); /// creates a instance of the named type static void *createInstanceByName(const char* TypeName, bool bLoadModule=false); + static void importModule(const char* TypeName); typedef void * (*instantiationMethod)(void);