diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 47054b8ea..d4160d70e 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -2053,13 +2053,20 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName) } /// Remove an object out of the document -void Document::remObject(const char* sName) +void Document::remObject(const char* sName, bool forceIfUndeletable) { std::map::iterator pos = d->objectMap.find(sName); // name not found? if (pos == d->objectMap.end()) return; + + // undeletable? + if (pos->second->testStatus(ObjectStatus::Undeletable) && !forceIfUndeletable) { + std::stringstream str; + str << "Document object '" << pos->second->getNameInDocument() << "' is undeletable"; + throw Base::Exception(str.str()); + } _checkTransaction(pos->second); @@ -2123,7 +2130,7 @@ void Document::_remObject(DocumentObject* pcObject) _checkTransaction(pcObject); std::map::iterator pos = d->objectMap.find(pcObject->getNameInDocument()); - + if (d->activeObject == pcObject) d->activeObject = 0; diff --git a/src/App/Document.h b/src/App/Document.h index ef310e280..53138ec65 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -178,8 +178,13 @@ public: * is raisedd. */ void addObject(DocumentObject*, const char* pObjectName=0); - /// Remove a feature out of the document - void remObject(const char* sName); + + /** Remove a feature out of the document. + * If i is marked as undeletable an exeption is thrown. If you want to delete in nonetheless set + * the function parameter \a forceIfUndeletable to true + */ + void remObject(const char* sName, bool forceIfUndeletable = false); + /** Copy an object from another document to this document * If \a recursive is true then all objects this object depends on * are copied as well. By default \a recursive is false. diff --git a/src/App/Document.h.orig b/src/App/Document.h.orig new file mode 100644 index 000000000..5b0937b9a --- /dev/null +++ b/src/App/Document.h.orig @@ -0,0 +1,372 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef APP_DOCUMENT_H +#define APP_DOCUMENT_H + +#include +#include +#include +#include + +#include "PropertyContainer.h" +#include "PropertyStandard.h" +#include "PropertyLinks.h" + +#include +#include +#include + +#include +#include + + +namespace Base { + class Writer; +} + +namespace App +{ + class DocumentObject; + class DocumentObjectExecReturn; + class Document; + class DocumentPy; // the python document class + class Application; + class Transaction; +} + +namespace App +{ + +/// The document class +class AppExport Document : public App::PropertyContainer +{ + PROPERTY_HEADER(App::Document); + +public: + /** @name Properties */ + //@{ + /// holds the long name of the document (utf-8 coded) + PropertyString Label; + /// full qualified (with path) file name (utf-8 coded) + PropertyString FileName; + /// creators name (utf-8) + PropertyString CreatedBy; + PropertyString CreationDate; + /// user last modified the document + PropertyString LastModifiedBy; + PropertyString LastModifiedDate; + /// company name UTF8(optional) + PropertyString Company; + /// long comment or description (UTF8 with line breaks) + PropertyString Comment; + /// Id e.g. Part number + PropertyString Id; + /// unique identifier of the document + PropertyUUID Uid; + /** License string + * Holds the short license string for the Item, e.g. CC-BY + * for the Creative Commons license suit. + */ + App::PropertyString License; + /// License descripton/contract URL + App::PropertyString LicenseURL; + /// Meta descriptons + App::PropertyMap Meta; + /// Material descriptons, used and defined in the Material module. + App::PropertyMap Material; + /// read-only name of the temp dir created wen the document is opened + PropertyString TransientDir; + /// Tip object of the document (if any) + PropertyLink Tip; + /// Tip object of the document (if any) + PropertyString TipName; + //@} + + /** @name Signals of the document */ + //@{ + /// signal on new Object + boost::signal signalNewObject; + //boost::signal m_sig; + /// signal on deleted Object + boost::signal signalDeletedObject; + /// signal on changed Object + boost::signal signalChangedObject; + /// signal on relabeled Object + boost::signal signalRelabelObject; + /// signal on activated Object + boost::signal signalActivatedObject; + /// signal on undo + boost::signal signalUndo; + /// signal on redo + boost::signal signalRedo; + /** signal on load/save document + * this signal is given when the document gets streamed. + * you can use this hook to write additional information in + * the file (like the Gui::Document it does). + */ + boost::signal signalSaveDocument; + boost::signal signalRestoreDocument; + boost::signal&, + Base::Writer &)> signalExportObjects; + boost::signal&, + Base::Writer &)> signalExportViewObjects; + boost::signal&, + Base::XMLReader&)> signalImportObjects; + boost::signal&, Base::Reader&, + const std::map&)> signalImportViewObjects; + boost::signal signalRecomputed; + //@} + + /** @name File handling of the document */ + //@{ + /// Save the Document under a new Name + //void saveAs (const char* Name); + /// Save the document to the file in Property Path + bool save (void); + bool saveAs(const char* file); + bool saveCopy(const char* file); + /// Restore the document from the file in Property Path + void restore (void); + void exportObjects(const std::vector&, std::ostream&); + void exportGraphviz(std::ostream&) const; + std::vector importObjects(Base::XMLReader& reader); + /// Opens the document from its file name + //void open (void); + /// Is the document already saved to a file + bool isSaved() const; + /// Get the document name + const char* getName() const; + //@} + + virtual void Save (Base::Writer &writer) const; + virtual void Restore(Base::XMLReader &reader); + + /// returns the complet document mermory consumption, including all managed DocObjects and Undo Redo. + unsigned int getMemSize (void) const; + + /** @name Object handling */ + //@{ + /** Add a feature of sType with sName (ASCII) to this document and set it active. + * Unicode names are set through the Label property. + */ + DocumentObject *addObject(const char* sType, const char* pObjectName=0); +<<<<<<< 985ebdc55b761ed8ae81d7e610ccd5b9f1378473 + /** Add an existing feature with sName (ASCII) to this document and set it active. + * Unicode names are set through the Label property. + * This is an overloaded function of the function above and can be used to create + * a feature outside and add it to the document afterwards. + * \note The passed feature must not yet be added to a document, otherwise an exception + * is raisedd. + */ + void addObject(DocumentObject*, const char* pObjectName=0); + /// Remove a feature out of the document + void remObject(const char* sName); +======= + /** Remove a feature out of the document. + * If i is marked as undeletable an exeption is thrown. If you want to delete in nonetheless set + * the function parameter \a forceIfUndeletable to true + */ + void remObject(const char* sName, bool forceIfUndeletable = false); +>>>>>>> part deletion handling + /** Copy an object from another document to this document + * If \a recursive is true then all objects this object depends on + * are copied as well. By default \a recursive is false. + * Returns the copy of the object or 0 if the creation failed. + */ + DocumentObject* copyObject(DocumentObject* obj, bool recursive=false); + /** Move an object from another document to this document + * If \a recursive is true then all objects this object depends on + * are moved as well. By default \a recursive is false. + * Returns the moved object itself or 0 if the object is already part of this + * document.. + */ + DocumentObject* moveObject(DocumentObject* obj, bool recursive=false); + /// Returns the active Object of this document + DocumentObject *getActiveObject(void) const; + /// Returns a Object of this document + DocumentObject *getObject(const char *Name) const; + /// Returns true if the DocumentObject is contained in this document + const bool isIn(const DocumentObject *pFeat) const; + /// Returns a Name of an Object or 0 + const char *getObjectName(DocumentObject *pFeat) const; + /// Returns a Name of an Object or 0 + std::string getUniqueObjectName(const char *Name) const; + /// Returns a name of the form prefix_number. d specifies the number of digits. + std::string getStandardObjectName(const char *Name, int d) const; + /// Returns a list of all Objects + std::vector getObjects() const; + std::vector getObjectsOfType(const Base::Type& typeId) const; + std::vector findObjects(const Base::Type& typeId, const char* objname) const; + /// Returns an array with the correct types already. + template inline std::vector getObjectsOfType() const; + int countObjectsOfType(const Base::Type& typeId) const; + /// get the number of objects in the document + int countObjects(void) const; + //@} + + /** @name methods for modification and state handling + */ + //@{ + /// Remove all modifications. After this call The document becomes again Valid. + void purgeTouched(); + /// check if there is any touched object in this document + bool isTouched(void) const; + /// returns all touched objects + std::vector getTouched(void) const; + /// set the document to be closable, this is on by default. + void setClosable(bool); + /// check whether the document can be closed + bool isClosable() const; + /// Recompute all touched features + void recompute(); + /// Recompute only one feature + void recomputeFeature(DocumentObject* Feat); + /// get the error log from the recompute run + const std::vector &getRecomputeLog(void)const{return _RecomputeLog;} + /// get the text of the error of a spezified object + const char* getErrorDescription(const App::DocumentObject*) const; + //@} + + + /** @name methods for the UNDO REDO and Transaction handling */ + //@{ + /// switch the level of Undo/Redo + void setUndoMode(int iMode); + /// switch the level of Undo/Redo + int getUndoMode(void) const; + /// switch the tranaction mode + void setTransactionMode(int iMode); + /// Open a new command Undo/Redo, an UTF-8 name can be specified + void openTransaction(const char* name=0); + // Commit the Command transaction. Do nothing If there is no Command transaction open. + void commitTransaction(); + /// Abort the actually running transaction. + void abortTransaction(); + /// Check if a transaction is open + bool hasPendingTransaction() const; + /// Set the Undo limit in Byte! + void setUndoLimit(unsigned int UndoMemSize=0); + /// Returns the actual memory consumption of the Undo redo stuff. + unsigned int getUndoMemSize (void) const; + /// Set the Undo limit as stack size + void setMaxUndoStackSize(unsigned int UndoMaxStackSize=20); + /// Set the Undo limit as stack size + unsigned int getMaxUndoStackSize(void)const; + /// Remove all stored Undos and Redos + void clearUndos(); + /// Returns the number of stored Undos. If greater than 0 Undo will be effective. + int getAvailableUndos() const; + /// Returns a list of the Undo names + std::vector getAvailableUndoNames() const; + /// Will UNDO one step, returns False if no undo was done (Undos == 0). + bool undo(); + /// Returns the number of stored Redos. If greater than 0 Redo will be effective. + int getAvailableRedos() const; + /// Returns a list of the Redo names. + std::vector getAvailableRedoNames() const; + /// Will REDO one step, returns False if no redo was done (Redos == 0). + bool redo() ; + //@} + + /** @name dependency stuff */ + //@{ + /// write GraphViz file + void writeDependencyGraphViz(std::ostream &out); + /// checks if the graph is directed and has no cycles + bool checkOnCycle(void); + /// get a list of all objects linking to the given object + std::vector getInList(const DocumentObject* me) const; + /// Get a complete list of all objects the given objects depend on. The list + /// also contains the given objects! + std::vector getDependencyList + (const std::vector&) const; + // set Changed + //void setChanged(DocumentObject* change); + //@} + + /// Function called to signal that an object identifier has been renamed + void renameObjectIdentifiers(const std::map & paths); + + virtual PyObject *getPyObject(void); + + friend class Application; + /// because of transaction handling + friend class DocumentObject; + friend class Transaction; + friend class TransactionObject; + + /// Destruction + virtual ~Document(); + +protected: + /// Construction + Document(void); + + void _remObject(DocumentObject* pcObject); + void _addObject(DocumentObject* pcObject, const char* pObjectName); + /// checks if a valid transaction is open + void _checkTransaction(DocumentObject* pcObject); + void breakDependency(DocumentObject* pcObject, bool clear); + std::vector readObjects(Base::XMLReader& reader); + void writeObjects(const std::vector&, Base::Writer &writer) const; + + void onChanged(const Property* prop); + /// callback from the Document objects before property will be changed + void onBeforeChangeProperty(const DocumentObject *Who, const Property *What); + /// callback from the Document objects after property was changed + void onChangedProperty(const DocumentObject *Who, const Property *What); + /// helper which Recompute only this feature + bool _recomputeFeature(DocumentObject* Feat); + void _clearRedos(); + /// refresh the internal dependency graph + void _rebuildDependencyList(void); + std::string getTransientDirectoryName(const std::string& uuid, const std::string& filename) const; + + +private: + // # Data Member of the document +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + std::list mUndoTransactions; + std::list mRedoTransactions; + // recompute log + std::vector _RecomputeLog; + + // pointer to the python class + Py::Object DocumentPythonObject; + struct DocumentP* d; +}; + +template +inline std::vector Document::getObjectsOfType() const +{ + std::vector type; + std::vector obj = this->getObjectsOfType(T::getClassTypeId()); + type.reserve(obj.size()); + for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) + type.push_back(static_cast(*it)); + return type; +} + + +} //namespace App + +#endif // APP_DOCUMENT_H diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 8b32e7a5e..d35eee75d 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -47,6 +47,7 @@ enum ObjectStatus { New = 2, Recompute = 3, Restore = 4, + Undeletable = 5, Expand = 16 }; @@ -194,7 +195,7 @@ protected: * 2 - object is marked as 'new' * 3 - object is marked as 'recompute', i.e. the object gets recomputed now * 4 - object is marked as 'restoring', i.e. the object gets loaded at the moment - * 5 - reserved + * 5 - object is marked as 'undeletable', i.e. the user is not allowed to delete this object from the document * 6 - reserved * 7 - reserved * 16 - object is marked as 'expanded' in the tree view diff --git a/src/App/GeoFeatureGroup.cpp b/src/App/GeoFeatureGroup.cpp index feb88137f..ba4bf51c7 100644 --- a/src/App/GeoFeatureGroup.cpp +++ b/src/App/GeoFeatureGroup.cpp @@ -98,7 +98,7 @@ void GeoFeatureGroup::removeObjectFromDocument(DocumentObject* obj) } } - this->getDocument()->remObject(obj->getNameInDocument()); + this->getDocument()->remObject(obj->getNameInDocument(), true); } DocumentObject *GeoFeatureGroup::getObject(const char *Name) const diff --git a/src/App/Line.cpp b/src/App/Line.cpp index 84b1ee964..1e451eb0b 100644 --- a/src/App/Line.cpp +++ b/src/App/Line.cpp @@ -42,7 +42,10 @@ PROPERTY_SOURCE(App::Line, App::GeoFeature) Line::Line(void) { ADD_PROPERTY(LineType,("")); + //placement can't be changed Placement.StatusBits.set(3, true); + //line can not be deleted by user + StatusBits.set(ObjectStatus::Undeletable, true); } diff --git a/src/App/Line.h b/src/App/Line.h index 8c9463d7d..0766407e8 100644 --- a/src/App/Line.h +++ b/src/App/Line.h @@ -37,7 +37,7 @@ namespace App /** Line Object - * Used to define planar support for all kind of operations in the document space + * Used to define linear support for all kind of operations in the document space */ class AppExport Line: public App::GeoFeature { diff --git a/src/App/Origin.cpp b/src/App/Origin.cpp index 6181ec543..76533a34b 100644 --- a/src/App/Origin.cpp +++ b/src/App/Origin.cpp @@ -45,7 +45,10 @@ PROPERTY_SOURCE(App::Origin, App::GeoFeatureGroup) Origin::Origin(void) { + //placement can't be changed Placement.StatusBits.set(3, true); + //origin can not be deleted by user + StatusBits.set(ObjectStatus::Undeletable, true); } Origin::~Origin(void) diff --git a/src/App/Origin.h b/src/App/Origin.h index 47039274e..e64981af3 100644 --- a/src/App/Origin.h +++ b/src/App/Origin.h @@ -33,7 +33,7 @@ namespace App { -/** Base class of all geometric document objects. +/** Describe a origin of a local coordinate system */ class AppExport Origin : public App::GeoFeatureGroup { diff --git a/src/App/Part.cpp b/src/App/Part.cpp index c6f6079c9..e3fdda41f 100644 --- a/src/App/Part.cpp +++ b/src/App/Part.cpp @@ -30,8 +30,9 @@ #include #include "Part.h" +#include "Origin.h" #include "PartPy.h" - +#include using namespace App; @@ -64,7 +65,6 @@ Part::Part(void) ADD_PROPERTY_TYPE(LicenseURL, ("http://creativecommons.org/licenses/by/3.0/"), 0, App::Prop_None, "URL to the license text/contract"); // color and apperance ADD_PROPERTY(Color, (1.0, 1.0, 1.0, 1.0)); // set transparent -> not used - } Part::~Part(void) @@ -81,6 +81,23 @@ PyObject *Part::getPyObject() return Py::new_reference_to(PythonObject); } +void Part::onSettingDocument() { + + if(connection.connected()) + connection.disconnect(); + + getDocument()->signalDeletedObject.connect(boost::bind(&Part::onDelete, this, _1)); + App::DocumentObject::onSettingDocument(); +} + +void Part::onDelete(const App::DocumentObject& obj) { + + if(&obj == this) { + //delete all child objects if needed + this->removeObjectsFromDocument(); + } +} + // Python feature --------------------------------------------------------- diff --git a/src/App/Part.h b/src/App/Part.h index 2bf73717b..599cfe4d1 100644 --- a/src/App/Part.h +++ b/src/App/Part.h @@ -26,7 +26,7 @@ #include "GeoFeatureGroup.h" #include "PropertyLinks.h" - +#include namespace App @@ -91,6 +91,13 @@ public: static const char* BaseplaneTypes[3]; static const char* BaselineTypes[3]; + +protected: + virtual void onSettingDocument(); + +private: + boost::signals::scoped_connection connection; + void onDelete(const App::DocumentObject& obj); }; //typedef App::FeaturePythonT PartPython; diff --git a/src/App/Plane.cpp b/src/App/Plane.cpp index 14614f746..586e074b3 100644 --- a/src/App/Plane.cpp +++ b/src/App/Plane.cpp @@ -42,7 +42,10 @@ PROPERTY_SOURCE(App::Plane, App::GeoFeature) Plane::Plane(void) { ADD_PROPERTY(PlaneType,("")); + //placement can't be changed Placement.StatusBits.set(3, true); + //plane can not be deleted by user + StatusBits.set(ObjectStatus::Undeletable, true); } diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 2d449542d..2fd130dff 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -1050,6 +1050,19 @@ void StdCmdDelete::activated(int iMsg) // check if the edited view provider is selected for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject()); + + if (ft->getObject()->testStatus(App::ObjectStatus::Undeletable)) { + QString bodyMessage; + QTextStream bodyMessageStream(&bodyMessage); + bodyMessageStream << qApp->translate("Std_Delete", + "The object is marked as undeletable."); + + QMessageBox::warning(Gui::getMainWindow(), + qApp->translate("Std_Delete", "Object status"), bodyMessage); + + return; + } + if (vp == vpedit) { if (!ft->getSubNames().empty()) { // handle the view provider @@ -1072,6 +1085,19 @@ void StdCmdDelete::activated(int iMsg) for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { App::DocumentObject* obj = ft->getObject(); std::vector links = obj->getInList(); + + if (obj->testStatus(App::ObjectStatus::Undeletable)) { + QString bodyMessage; + QTextStream bodyMessageStream(&bodyMessage); + bodyMessageStream << qApp->translate("Std_Delete", + "The object is marked as undeletable."); + + QMessageBox::warning(Gui::getMainWindow(), + qApp->translate("Std_Delete", "Object status"), bodyMessage); + + return; + } + if (!links.empty()) { // check if the referenced objects are groups or are selected too for (std::vector::iterator lt = links.begin(); lt != links.end(); ++lt) {