From b6a37e153ff337b9cf2198c0e5c6eca6843e8eaf Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 18 Nov 2018 02:36:57 +0100 Subject: [PATCH] Example implementation --- src/App/ApplicationPy.cpp | 5 +- src/App/Document.cpp | 38 +++++++------- src/App/PropertyContainer.cpp | 64 ++++++++++------------- src/Mod/Part/App/Geometry.cpp | 57 ++++++++++---------- src/Mod/Part/App/PropertyGeometryList.cpp | 33 ++++-------- src/Mod/Web/Gui/BrowserView.cpp | 28 +++++----- 6 files changed, 99 insertions(+), 126 deletions(-) diff --git a/src/App/ApplicationPy.cpp b/src/App/ApplicationPy.cpp index c69db57686..2ff5c20a6e 100644 --- a/src/App/ApplicationPy.cpp +++ b/src/App/ApplicationPy.cpp @@ -205,9 +205,6 @@ PyObject* Application::sOpenDocument(PyObject * /*self*/, PyObject *args) // return new document return (GetApplication().openDocument(EncodedName.c_str())->getPyObject()); } - catch(const Base::RestoreError) { - throw; // propagate it to python/gui - } catch (const Base::Exception& e) { PyErr_SetString(PyExc_IOError, e.what()); return 0L; @@ -708,7 +705,7 @@ PyObject *Application::sSetLogLevel(PyObject * /*self*/, PyObject *args) "Unknown Log Level (use 'Default', 'Error', 'Warning', 'Message', 'Log', 'Trace' or an integer)"); return NULL; } - }else + }else l = PyLong_AsLong(pcObj); GetApplication().GetParameterGroupByPath("User parameter:BaseApp/LogLevels")->SetInt(tag,l); if(strcmp(tag,"Default") == 0) { diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 6257eca1d8..583c2a51b1 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -961,7 +961,7 @@ void Document::openTransaction(const char* name) d->activeUndoTransaction->Name = name; else d->activeUndoTransaction->Name = ""; - + signalOpenTransaction(*this, d->activeUndoTransaction->Name); } } @@ -1115,7 +1115,7 @@ void Document::onBeforeChange(const Property* prop) void Document::onChanged(const Property* prop) { signalChanged(*this, *prop); - + // the Name property is a label for display purposes if (prop == &Label) { App::GetApplication().signalRelabelDocument(*this); @@ -1158,7 +1158,7 @@ void Document::onBeforeChangeProperty(const TransactionalObject *Who, const Prop { if(Who->isDerivedFrom(App::DocumentObject::getClassTypeId())) signalBeforeChangeObject(*static_cast(Who), *What); - + if (d->activeUndoTransaction && !d->rollback) d->activeUndoTransaction->addObjectChange(Who,What); } @@ -1355,7 +1355,7 @@ void Document::Save (Base::Writer &writer) const } void Document::Restore(Base::XMLReader &reader) -{ +{ int i,Cnt; Base::ObjectStatusLocker restoreBit(Status::Restoring, this); @@ -1436,10 +1436,6 @@ void Document::Restore(Base::XMLReader &reader) } reader.readEndElement("Document"); - - if(testStatus(Document::PartialRestore)) { - THROW(Base::RestoreError); - } } void Document::exportObjects(const std::vector& obj, @@ -1514,7 +1510,7 @@ void Document::writeObjects(const std::vector& obj, std::vector Document::readObjects(Base::XMLReader& reader) -{ +{ bool keepDigits = testStatus(Document::KeepTrailingDigits); setStatus(Document::KeepTrailingDigits, !reader.doNameMapping()); std::vector objs; @@ -1555,12 +1551,14 @@ Document::readObjects(Base::XMLReader& reader) setStatus(Document::KeepTrailingDigits, keepDigits); // read the features itself + reader.clearPartialRestoreDocumentObject(); reader.readElement("ObjectData"); Cnt = reader.getAttributeAsInteger("Count"); for (int i=0 ;isetStatus(ObjectStatus::Restore, true); try { @@ -1580,14 +1578,13 @@ Document::readObjects(Base::XMLReader& reader) catch (const Base::RuntimeError &e) { e.ReportException(); } - catch(const Base::RestoreError &e) { - e.ReportException(); - Base::Console().Error("Object \"%s\" was subject to a partial restore. As a result geometry may have changed or be incomplete.",name.c_str()); - - setStatus(Document::PartialRestore, true); - } pObj->setStatus(ObjectStatus::Restore, false); + + if(reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestoreInDocumentObject)) { + Base::Console().Error("Object \"%s\" was subject to a partial restore. As a result geometry may have changed or be incomplete.\n",name.c_str()); + reader.clearPartialRestoreDocumentObject(); + } } reader.readEndElement("Object"); } @@ -1820,7 +1817,6 @@ bool Document::saveToFile(const char* filename) const // Open the document void Document::restore (void) { - bool partialrestore; // clean up if the document is not empty // !TODO mind exceptions while restoring! clearUndos(); @@ -1861,7 +1857,7 @@ void Document::restore (void) } catch(Base::RestoreError &e) { e.ReportException(); - partialrestore = true; + } catch (const Base::Exception& e) { Base::Console().Error("Invalid Document.xml: %s\n", e.what()); @@ -1889,9 +1885,11 @@ void Document::restore (void) GetApplication().signalFinishRestoreDocument(*this); setStatus(Document::Restoring, false); - - if(partialrestore) - THROWMT(Base::RestoreError,QT_TRANSLATE_NOOP("Exceptions", "There were errors while loading the file. Geometry might have been modified or not recovered at all. Look in the report view for more specific information about the objects involved.")); + + if(reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestore)) { + setStatus(Document::PartialRestore, true); + Base::Console().Error("There were errors while loading the file. Some data might have been modified or not recovered at all. Look above for more specific information about the objects involved.\n"); + } } bool Document::isSaved() const diff --git a/src/App/PropertyContainer.cpp b/src/App/PropertyContainer.cpp index a03a80a3d4..70ec3fcaa2 100644 --- a/src/App/PropertyContainer.cpp +++ b/src/App/PropertyContainer.cpp @@ -42,7 +42,7 @@ using namespace App; using namespace Base; using namespace std; - + TYPESYSTEM_SOURCE(App::PropertyContainer,Base::Persistence); @@ -94,12 +94,12 @@ void PropertyContainer::setPropertyStatus(unsigned char bit,bool value) (**it).StatusBits.set(bit,value); } -short PropertyContainer::getPropertyType(const Property* prop) const +short PropertyContainer::getPropertyType(const Property* prop) const { return getPropertyData().getType(this,prop); } -short PropertyContainer::getPropertyType(const char *name) const +short PropertyContainer::getPropertyType(const char *name) const { return getPropertyData().getType(this,name); } @@ -150,8 +150,8 @@ const char* PropertyContainer::getPropertyName(const Property* prop)const } -const PropertyData * PropertyContainer::getPropertyDataPtr(void){return &propertyData;} -const PropertyData & PropertyContainer::getPropertyData(void) const{return propertyData;} +const PropertyData * PropertyContainer::getPropertyDataPtr(void){return &propertyData;} +const PropertyData & PropertyContainer::getPropertyData(void) const{return propertyData;} /** * @brief PropertyContainer::handleChangedPropertyName is called during restore to possibly @@ -207,11 +207,11 @@ private: const PropertyContainer* cont; }; -void PropertyContainer::Save (Base::Writer &writer) const +void PropertyContainer::Save (Base::Writer &writer) const { std::map Map; getPropertyMap(Map); - + // ignore the properties we won't store size_t ct = std::count_if(Map.begin(), Map.end(), std::bind2nd(PropertyAttribute >(this), Prop_Transient)); @@ -222,11 +222,11 @@ void PropertyContainer::Save (Base::Writer &writer) const std::map::iterator it; for (it = Map.begin(); it != Map.end(); ++it) { - // Don't write transient properties + // Don't write transient properties if (!(getPropertyType(it->second) & Prop_Transient)) { writer.incInd(); // indentation for 'Property name' - writer.Stream() << writer.ind() << "first << "\" type=\"" + writer.Stream() << writer.ind() << "first << "\" type=\"" << it->second->getTypeId().getName() << "\">" << endl;; writer.incInd(); // indentation for the actual property try { @@ -250,7 +250,7 @@ void PropertyContainer::Save (Base::Writer &writer) const } #endif writer.decInd(); // indentation for the actual property - writer.Stream() << writer.ind() << "" << endl; + writer.Stream() << writer.ind() << "" << endl; writer.decInd(); // indentation for 'Property name' } } @@ -260,41 +260,38 @@ void PropertyContainer::Save (Base::Writer &writer) const void PropertyContainer::Restore(Base::XMLReader &reader) { - bool partialrestore = false; - + reader.clearPartialRestoreProperty(); reader.readElement("Properties"); int Cnt = reader.getAttributeAsInteger("Count"); for (int i=0 ;igetTypeId().getName(), TypeName) == 0) { - - try { + if (prop && strcmp(prop->getTypeId().getName(), TypeName.c_str()) == 0) { prop->Restore(reader); - } - catch(RestoreError &e) { - e.ReportException(); - Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName,TypeName); - partialrestore = true; - } + + if(reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestoreInProperty)) { + Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName.c_str(),TypeName.c_str()); + + reader.clearPartialRestoreProperty(); + } } // name matches but not the type else if (prop) { - handleChangedPropertyType(reader, TypeName, prop); + handleChangedPropertyType(reader, TypeName.c_str(), prop); } // name doesn't match, the sub-class then has to know // if the property has been renamed or removed else { - handleChangedPropertyName(reader, TypeName, PropName); + handleChangedPropertyName(reader, TypeName.c_str(), PropName.c_str()); } } catch (const Base::XMLParseException&) { @@ -318,9 +315,6 @@ void PropertyContainer::Restore(Base::XMLReader &reader) reader.readEndElement("Property"); } reader.readEndElement("Properties"); - - if(partialrestore) - THROW(Base::RestoreError); } void PropertyData::addProperty(OffsetBase offsetBase,const char* PropName, Property *Prop, const char* PropertyGroup , PropertyType Type, const char* PropertyDocu) @@ -351,7 +345,7 @@ const PropertyData::PropertySpec *PropertyData::findProperty(OffsetBase offsetBa if(parentPropertyData) return parentPropertyData->findProperty(offsetBase,PropName); - + return 0; } @@ -364,10 +358,10 @@ const PropertyData::PropertySpec *PropertyData::findProperty(OffsetBase offsetBa for (vector::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It) if(diff == It->Offset) return &(*It); - + if(parentPropertyData) return parentPropertyData->findProperty(offsetBase,prop); - + return 0; } @@ -480,7 +474,7 @@ const char* PropertyData::getDocumentation(OffsetBase offsetBase,const char* nam -Property *PropertyData::getPropertyByName(OffsetBase offsetBase,const char* name) const +Property *PropertyData::getPropertyByName(OffsetBase offsetBase,const char* name) const { const PropertyData::PropertySpec* Spec = findProperty(offsetBase,name); @@ -518,7 +512,7 @@ void PropertyData::getPropertyMap(OffsetBase offsetBase,std::mapgetPropertyMap(offsetBase,Map); - + } void PropertyData::getPropertyList(OffsetBase offsetBase,std::vector &List) const @@ -547,7 +541,7 @@ The property framework introduces the ability to access attributes (member varia knowing the class type. It's like the reflection mechanism of Java or C#. This ability is introduced by the App::PropertyContainer class and can be used by all derived classes. -This makes it possible in the first place to make an automatic mapping to python (e.g. in App::FeaturePy) and +This makes it possible in the first place to make an automatic mapping to python (e.g. in App::FeaturePy) and abstract editing properties in Gui::PropertyEditor. \section Examples diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 7ed1a0dfce..7d79678736 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -462,14 +462,14 @@ bool GeomCurve::normalAt(double u, Base::Vector3d& dir) const return false; } -bool GeomCurve::intersect( GeomCurve * c, - std::vector>& points, +bool GeomCurve::intersect( GeomCurve * c, + std::vector>& points, double tol) const { Handle(Geom_Curve) curve1 = Handle(Geom_Curve)::DownCast(handle()); Handle(Geom_Curve) curve2 = Handle(Geom_Curve)::DownCast(c->handle()); - if(!curve1.IsNull() && !curve2.IsNull()) { + if(!curve1.IsNull() && !curve2.IsNull()) { return intersect(curve1,curve2,points, tol); } else @@ -477,38 +477,38 @@ bool GeomCurve::intersect( GeomCurve * c, } -bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Curve) curve2, - std::vector>& points, +bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Curve) curve2, + std::vector>& points, double tol) const { // https://forum.freecadweb.org/viewtopic.php?f=10&t=31700 if (curve1->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && curve2->IsKind(STANDARD_TYPE(Geom_BoundedCurve))){ - + Handle(Geom_BoundedCurve) bcurve1 = Handle(Geom_BoundedCurve)::DownCast(curve1); Handle(Geom_BoundedCurve) bcurve2 = Handle(Geom_BoundedCurve)::DownCast(curve2); - + gp_Pnt c1s = bcurve1->StartPoint(); gp_Pnt c2s = bcurve2->StartPoint(); gp_Pnt c1e = bcurve1->EndPoint(); gp_Pnt c2e = bcurve2->EndPoint(); - + auto checkendpoints = [&points,tol]( gp_Pnt p1, gp_Pnt p2) { if(p1.Distance(p2) < tol) points.emplace_back(Base::Vector3d(p1.X(),p1.Y(),p1.Z()),Base::Vector3d(p2.X(),p2.Y(),p2.Z())); }; - + checkendpoints(c1s,c2s); checkendpoints(c1s,c2e); checkendpoints(c1e,c2s); checkendpoints(c1e,c2e); - + } - + try { - + GeomAPI_ExtremaCurveCurve intersector(curve1, curve2); - + if (intersector.NbExtrema() == 0 || intersector.LowerDistance() > tol) { // No intersection return false; @@ -517,7 +517,7 @@ bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Cur for (int i = 1; i <= intersector.NbExtrema(); i++) { if (intersector.Distance(i) > tol) continue; - + gp_Pnt p1, p2; intersector.Points(i, p1, p2); points.emplace_back(Base::Vector3d(p1.X(),p1.Y(),p1.Z()),Base::Vector3d(p2.X(),p2.Y(),p2.Z())); @@ -530,7 +530,7 @@ bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Cur else THROWM(Base::CADKernelError,e.GetMessageString()) } - + return points.size()>0?true:false; } @@ -547,7 +547,7 @@ bool GeomCurve::closestParameter(const Base::Vector3d& point, double &u) const } } catch (StdFail_NotDone& e) { - + if (c->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))){ Base::Vector3d firstpoint = this->pointAtParameter(c->FirstParameter()); Base::Vector3d lastpoint = this->pointAtParameter(c->LastParameter()); @@ -620,7 +620,7 @@ double GeomCurve::getLastParameter() const catch (Standard_Failure& e) { THROWM(Base::CADKernelError,e.GetMessageString()) - } + } } double GeomCurve::curvatureAt(double u) const @@ -849,7 +849,7 @@ void GeomBezierCurve::Restore(Base::XMLReader& reader) THROWM(Base::CADKernelError,"BezierCurve restore failed") } catch (Standard_Failure& e) { - + THROWM(Base::CADKernelError,e.GetMessageString()) } } @@ -1530,24 +1530,24 @@ PyObject *GeomTrimmedCurve::getPyObject(void) return 0; } -bool GeomTrimmedCurve::intersectBasisCurves( const GeomTrimmedCurve * c, - std::vector>& points, +bool GeomTrimmedCurve::intersectBasisCurves( const GeomTrimmedCurve * c, + std::vector>& points, double tol) const { Handle(Geom_TrimmedCurve) curve1 = Handle(Geom_TrimmedCurve)::DownCast(handle()); Handle(Geom_TrimmedCurve) curve2 = Handle(Geom_TrimmedCurve)::DownCast(c->handle()); - + Handle(Geom_Curve) bcurve1 = curve1->BasisCurve(); Handle(Geom_Curve) bcurve2 = curve2->BasisCurve(); if(!bcurve1.IsNull() && !bcurve2.IsNull()) { - + return intersect(bcurve1, bcurve2, points, tol); } else return false; - + } // ------------------------------------------------- @@ -3661,7 +3661,7 @@ void GeomLineSegment::setPoints(const Base::Vector3d& Start, const Base::Vector3 // Create line out of two points if (p1.Distance(p2) < gp::Resolution()) THROWM(Base::ValueError,"Both points are equal"); - + GC_MakeSegment ms(p1, p2); if (!ms.IsDone()) { THROWM(Base::CADKernelError,gce_ErrorStatusText(ms.Status())) @@ -3723,21 +3723,20 @@ void GeomLineSegment::Restore (Base::XMLReader &reader) EndY = reader.getAttributeAsFloat("EndY"); EndZ = reader.getAttributeAsFloat("EndZ"); - Base::Vector3d start(StartX,StartY,StartZ); + Base::Vector3d start(StartX,StartY,StartZ); Base::Vector3d end(EndX,EndY,EndZ); // set the read geometry try { setPoints(start, end); } catch(Base::ValueError &e) { - // for a line segment construction, the only possibility of a value error is that + // for a line segment construction, the only possibility of a value error is that // the points are too close. The best try to restore is incrementing the distance. // for other objects, the best effort may be just to leave default values. + reader.setPartialRestore(true); end = start + Base::Vector3d(start.x*DBL_EPSILON,0,0); - + setPoints(start, end); - - THROWM(Base::RestoreError, e.getMessage()); } } diff --git a/src/Mod/Part/App/PropertyGeometryList.cpp b/src/Mod/Part/App/PropertyGeometryList.cpp index 06ca234aa3..ac2924b15f 100644 --- a/src/Mod/Part/App/PropertyGeometryList.cpp +++ b/src/Mod/Part/App/PropertyGeometryList.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "Geometry.h" #include "GeometryPy.h" @@ -39,6 +40,7 @@ #include "PropertyGeometryList.h" #include "Part2DObject.h" + using namespace App; using namespace Base; using namespace std; @@ -168,29 +170,21 @@ void PropertyGeometryList::Save(Writer &writer) const void PropertyGeometryList::Restore(Base::XMLReader &reader) { - bool partialrestore = false; - // read my element + reader.clearPartialRestoreObject(); reader.readElement("GeometryList"); // get the value of my attribute int count = reader.getAttributeAsInteger("count"); - std::vector values; values.reserve(count); for (int i = 0; i < count; i++) { reader.readElement("Geometry"); const char* TypeName = reader.getAttribute("type"); Geometry *newG = (Geometry *)Base::Type::fromName(TypeName).createInstance(); + newG->Restore(reader); - try { - newG->Restore(reader); - values.push_back(newG); - reader.readEndElement("Geometry"); - } - catch(Base::RestoreError &e) { - - e.ReportException(); - + if(reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestoreInObject)) { + Base::Console().Error("Geometry \"%s\" within a PropertyGeometryList was subject to a partial restore.\n",reader.localName()); if(isOrderRelevant()) { // Pushes the best try by the Geometry class values.push_back(newG); @@ -198,24 +192,19 @@ void PropertyGeometryList::Restore(Base::XMLReader &reader) else { delete newG; } - - reader.readEndElement("Geometry"); - - partialrestore = true; - - continue; + reader.clearPartialRestoreObject(); + } + else { + values.push_back(newG); } - + reader.readEndElement("Geometry"); } reader.readEndElement("GeometryList"); // assignment setValues(values); - - if(partialrestore) - THROW(Base::RestoreError); } App::Property *PropertyGeometryList::Copy(void) const diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 1b3575917e..b380aaa384 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -133,7 +133,7 @@ Py::Object BrowserViewPy::setHtml(const Py::Tuple& args) /** * Constructs a WebView widget which can be zoomed with Ctrl+Mousewheel - * + * */ WebView::WebView(QWidget *parent) @@ -232,11 +232,11 @@ BrowserView::BrowserView(QWidget* parent) view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); view->page()->setForwardUnsupportedContent(true); - + // set our custom cookie manager FcCookieJar* cookiejar = new FcCookieJar(this); view->page()->networkAccessManager()->setCookieJar(cookiejar); - + // enable local storage so we can store stuff across sessions (startpage) QWebSettings* settings = view->settings(); settings->setAttribute(QWebSettings::LocalStorageEnabled, true); @@ -272,18 +272,18 @@ BrowserView::~BrowserView() delete view; } -void BrowserView::onLinkClicked (const QUrl & url) +void BrowserView::onLinkClicked (const QUrl & url) { QString scheme = url.scheme(); QString host = url.host(); //QString username = url.userName(); - // path handling + // path handling QString path = url.path(); QFileInfo fi(path); QString ext = fi.completeSuffix(); QUrl exturl(url); - + // query QString q; if (url.hasQuery()) @@ -320,21 +320,17 @@ void BrowserView::onLinkClicked (const QUrl & url) q = q.replace(QString::fromLatin1("="),QString::fromLatin1("=\""))+QString::fromLatin1("\""); q = q.replace(QString::fromLatin1("%"),QString::fromLatin1("%%")); // url queries in the form of somescript.py?key=value, the first key=value will be printed in the py console as key="value" - Gui::Command::doCommand(Gui::Command::Gui,q.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Gui,q.toStdString().c_str()); } // Gui::Command::doCommand(Gui::Command::Gui,"execfile('%s')",(const char*) fi.absoluteFilePath(). toLocal8Bit()); - Gui::Command::doCommand(Gui::Command::Gui,"exec(open('%s').read())",(const char*) fi.absoluteFilePath() .toLocal8Bit()); - } - catch (const Base::RestoreError& e) { - e.ReportException(); - if(e.getTranslatable()) { - QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Error loading file"), - QObject::tr(e.getMessage().c_str())); - } + Gui::Command::doCommand(Gui::Command::Gui,"exec(open('%s').read())",(const char*) fi.absoluteFilePath() .toLocal8Bit()); } catch (const Base::Exception& e) { QMessageBox::critical(this, tr("Error"), QString::fromUtf8(e.what())); } + + if(this->getAppDocument()->testStatus(App::Document::PartialRestore)) + QMessageBox::critical(this, tr("Error"), tr("There were errors while loading the file. Some data might have been modified or not recovered at all. Look in the report view for more specific information about the objects involved.")); } } else { @@ -346,7 +342,7 @@ void BrowserView::onLinkClicked (const QUrl & url) bool BrowserView::chckHostAllowed(const QString& host) { - // only check if a local file, later we can do here a dialog to ask the user if + // only check if a local file, later we can do here a dialog to ask the user if return host.isEmpty(); }