Implementing agnostic version of ParameterGrp for reading XML, replacing XMLReader from src/Base/reader.cpp with new class DocumentReader

This commit is contained in:
AgCaliva
2023-06-16 15:36:17 -03:00
parent 8db6ab544a
commit 52c55f59a8
18 changed files with 862 additions and 176 deletions

View File

@@ -273,6 +273,7 @@ public:
//@{
virtual void extensionSave(Base::Writer&) const {}
virtual void extensionRestore(Base::XMLReader&) {}
virtual void extensionRestore(Base::DocumentReader&) {}
//@}
/** @name TypeHandling */

View File

@@ -30,6 +30,7 @@
#include "Extension.h"
#include "ExtensionContainer.h"
#include <Base/DocumentReader.h>
using namespace App;
@@ -307,6 +308,18 @@ void ExtensionContainer::Restore(Base::XMLReader& reader) {
App::PropertyContainer::Restore(reader);
}
void ExtensionContainer::Restore(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl) {
//restore dynamic extensions.
//Note 1: The extension element must be read first, before all other object elements. That is
// needed as the element works together with an object element attribute, which would be
// cleared if another attribute is read first
//Note 2: This must happen before the py object of this container is used, as only in the
// pyobject constructor the extension methods are added to the container.
restoreExtensions(reader,viewProviderEl);
//TODO NOW:
//App::PropertyContainer::Restore(reader);
}
void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
//we don't save anything if there are no dynamic extensions
@@ -352,6 +365,70 @@ void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
writer.decInd();
}
void ExtensionContainer::restoreExtensions(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl) {
//Dynamic extensions are optional (also because they are introduced late into the document format)
//and hence it is possible that the element does not exist. As we cannot check for the existence of
//an element a object attribute is set if extensions are available. Here we check that
//attribute, and only if it exists the extensions element will be available.
const char* expanded_cstr = reader.GetAttribute(viewProviderEl,"expanded");
if(!expanded_cstr)
return;
auto ExtensionsDOM = reader.FindElement(viewProviderEl,"Extensions");
if(ExtensionsDOM){
const char* cnt_cstr = reader.GetAttribute(ExtensionsDOM,"Count");
if(cnt_cstr){
long Cnt = reader.ContentToInt( cnt_cstr );
for (int i=0 ;i<Cnt ;i++) {
auto ExtensionDOM_i = reader.FindElement(ExtensionsDOM,"Extension");
const char* type_cstr = reader.GetAttribute(ExtensionDOM_i,"type");
const char* name_cstr = reader.GetAttribute(ExtensionDOM_i,"name");
try {
App::Extension* ext = getExtension(name_cstr);
if(!ext) {
//get the extension type asked for
Base::Type extension = Base::Type::fromName(type_cstr);
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
std::stringstream str;
str << "No extension found of type '" << type_cstr << "'" << std::ends;
throw Base::TypeError(str.str());
}
//register the extension
ext = static_cast<App::Extension*>(extension.createInstance());
//check if this really is a python extension!
if (!ext->isPythonExtension()) {
delete ext;
std::stringstream str;
str << "Extension is not a python addable version: '" << type_cstr << "'" << std::ends;
throw Base::TypeError(str.str());
}
ext->initExtension(this);
if( strcmp(ext->getExtensionTypeId().getName(), type_cstr) == 0 )
ext->extensionRestore(reader);
}
}
catch (const Base::XMLParseException&) {
throw; // re-throw
}
catch (const Base::Exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
Base::Console().Error("ExtensionContainer::Restore: Unknown C++ exception thrown\n");
}
#endif
}
}
}
}
void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
//Dynamic extensions are optional (also because they are introduced late into the document format)

View File

@@ -25,6 +25,14 @@
#define APP_EXTENSIONCONTAINER_H
#include "PropertyContainer.h"
#include <xercesc/util/XercesDefs.hpp>
XERCES_CPP_NAMESPACE_BEGIN
class DOMNode;
class DOMElement;
// class DefaultHandler;
// class SAX2XMLReader;
XERCES_CPP_NAMESPACE_END
namespace App {
@@ -177,11 +185,13 @@ public:
void Save(Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
void Restore(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl);
//those methods save/restore the dynamic extensions without handling properties, which is something
//done by the default Save/Restore methods.
void saveExtensions(Base::Writer& writer) const;
void restoreExtensions(Base::XMLReader& reader);
void restoreExtensions(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl);
/** Extends the rules for handling property name changed, so that extensions are given an opportunity to handle it.
* If an extension handles a change, neither the rest of the extensions, nor the container itself get to handle it.

View File

@@ -30,6 +30,7 @@
#include "Property.h"
#include "PropertyContainer.h"
#include <Base/DocumentReader.h>
FC_LOG_LEVEL_INIT("App",true,true)
@@ -402,6 +403,103 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
reader.readEndElement("Properties");
}
void PropertyContainer::Restore(Base::DocumentReader &reader)
{
//TODO NOW
Base::Console().Error("PropertyContainer::Restore: DocumentReader\n");
reader.clearPartialRestoreProperty();
/*
reader.clearPartialRestoreProperty();
reader.readElement("Properties");
int Cnt = reader.getAttributeAsInteger("Count");
int transientCount = 0;
if(reader.hasAttribute("TransientCount"))
transientCount = reader.getAttributeAsUnsigned("TransientCount");
for (int i=0;i<transientCount; ++i) {
reader.readElement("_Property");
Property* prop = getPropertyByName(reader.getAttribute("name"));
if(prop)
FC_TRACE("restore transient '" << prop->getName() << "'");
if(prop && reader.hasAttribute("status"))
prop->setStatusValue(reader.getAttributeAsUnsigned("status"));
}
for (int i=0 ;i<Cnt ;i++) {
reader.readElement("Property");
std::string PropName = reader.getAttribute("name");
std::string TypeName = reader.getAttribute("type");
// 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 {
auto prop = getPropertyByName(PropName.c_str());
if(!prop || prop->getContainer() != this)
prop = dynamicProps.restore(*this,PropName.c_str(),TypeName.c_str(),reader);
decltype(Property::StatusBits) status;
if(reader.hasAttribute("status")) {
status = decltype(status)(reader.getAttributeAsUnsigned("status"));
if(prop)
prop->setStatusValue(status.to_ulong());
}
// name and type match
if (prop && strcmp(prop->getTypeId().getName(), TypeName.c_str()) == 0) {
if (!prop->testStatus(Property::Transient)
&& !status.test(Property::Transient)
&& !status.test(Property::PropTransient)
&& !prop->testStatus(Property::PropTransient))
{
FC_TRACE("restore property '" << prop->getName() << "'");
prop->Restore(reader);
}else
FC_TRACE("skip transient '" << prop->getName() << "'");
}
// name matches but not the type
else if (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.c_str(), PropName.c_str());
}
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();
}
}
catch (const Base::XMLParseException&) {
throw; // re-throw
}
catch (const Base::RestoreError &) {
reader.setPartialRestore(true);
reader.clearPartialRestoreProperty();
Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName.c_str(),TypeName.c_str());
}
catch (const Base::Exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown\n");
}
#endif
reader.readEndElement("Property");
}
reader.readEndElement("Properties");
*/
}
void PropertyContainer::onPropertyStatusChanged(const Property &prop, unsigned long oldStatus)
{
(void)prop;

View File

@@ -220,6 +220,7 @@ public:
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
void Restore(Base::DocumentReader &reader) override;
virtual void editProperty(const char * /*propName*/) {}