Example implementation

This commit is contained in:
Abdullah Tahiri
2018-11-18 02:36:57 +01:00
committed by wmayer
parent 9a34a93db1
commit b6a37e153f
6 changed files with 99 additions and 126 deletions

View File

@@ -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) {

View File

@@ -961,7 +961,7 @@ void Document::openTransaction(const char* name)
d->activeUndoTransaction->Name = name;
else
d->activeUndoTransaction->Name = "<empty>";
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<const App::DocumentObject*>(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<Status, Document> 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<App::DocumentObject*>& obj,
@@ -1514,7 +1510,7 @@ void Document::writeObjects(const std::vector<App::DocumentObject*>& obj,
std::vector<App::DocumentObject*>
Document::readObjects(Base::XMLReader& reader)
{
{
bool keepDigits = testStatus(Document::KeepTrailingDigits);
setStatus(Document::KeepTrailingDigits, !reader.doNameMapping());
std::vector<App::DocumentObject*> 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 ;i<Cnt ;i++) {
reader.readElement("Object");
std::string name = reader.getName(reader.getAttribute("name"));
DocumentObject* pObj = getObject(name.c_str());
if (pObj) { // check if this feature has been registered
pObj->setStatus(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

View File

@@ -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<std::string,Property*> Map;
getPropertyMap(Map);
// ignore the properties we won't store
size_t ct = std::count_if(Map.begin(), Map.end(), std::bind2nd(PropertyAttribute
<std::pair<std::string,Property*> >(this), Prop_Transient));
@@ -222,11 +222,11 @@ void PropertyContainer::Save (Base::Writer &writer) const
std::map<std::string,Property*>::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() << "<Property name=\"" << it->first << "\" type=\""
writer.Stream() << writer.ind() << "<Property name=\"" << it->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() << "</Property>" << endl;
writer.Stream() << writer.ind() << "</Property>" << 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 ;i<Cnt ;i++) {
reader.readElement("Property");
const char* PropName = reader.getAttribute("name");
const char* TypeName = reader.getAttribute("type");
Property* prop = getPropertyByName(PropName);
std::string PropName = reader.getAttribute("name");
std::string TypeName = reader.getAttribute("type");
Property* prop = getPropertyByName(PropName.c_str());
// NOTE: We must also check the type of the current property because a
// subclass of PropertyContainer might change the type of a property but
// not its name. In this case we would force to read-in a wrong property
// type and the behaviour would be undefined.
try {
// name and type match
if (prop && strcmp(prop->getTypeId().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<PropertyData::PropertySpec>::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::map<std::string,Pro
if(parentPropertyData)
parentPropertyData->getPropertyMap(offsetBase,Map);
}
void PropertyData::getPropertyList(OffsetBase offsetBase,std::vector<Property*> &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

View File

@@ -462,14 +462,14 @@ bool GeomCurve::normalAt(double u, Base::Vector3d& dir) const
return false;
}
bool GeomCurve::intersect( GeomCurve * c,
std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& points,
bool GeomCurve::intersect( GeomCurve * c,
std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& 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<std::pair<Base::Vector3d, Base::Vector3d>>& points,
bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Curve) curve2,
std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& 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<std::pair<Base::Vector3d, Base::Vector3d>>& points,
bool GeomTrimmedCurve::intersectBasisCurves( const GeomTrimmedCurve * c,
std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& 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());
}
}

View File

@@ -32,6 +32,7 @@
#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>
#include <Base/Console.h>
#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<Geometry*> 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

View File

@@ -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();
}