[TD]fix embedded template file handling

This commit is contained in:
wandererfan
2022-11-07 21:43:45 -05:00
committed by WandererFan
parent 74d85eeeaa
commit 1cf51ec1c3
7 changed files with 104 additions and 181 deletions

View File

@@ -33,11 +33,14 @@
#endif
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h> //TODO: should be in DrawTemplate.h??
#include <Base/Console.h>
#include <Base/FileInfo.h>
#include <Base/Quantity.h>
#include <Base/Tools.h>
#include "DrawPage.h"
#include "DrawSVGTemplate.h"
#include "DrawSVGTemplatePy.h"
#include "DrawUtil.h"
@@ -51,12 +54,8 @@ DrawSVGTemplate::DrawSVGTemplate()
{
static const char *group = "Template";
//TODO: Do we need PageResult anymore? -wf Yes!
// PageResult points to a temporary file in tmp/FreeCAD-AB-CD-EF-.../myTemplate.svg
// which is really copy of original Template with EditableFields replaced
// When restoring saved document, Template is redundant/incorrect/not present - PageResult is the correct info. -wf-
ADD_PROPERTY_TYPE(PageResult, (nullptr), group, App::Prop_Output, "Current SVG code for template");
ADD_PROPERTY_TYPE(Template, (""), group, App::Prop_Transient, "Template for the page"); //sb TemplateFileName???
ADD_PROPERTY_TYPE(PageResult, (nullptr), group, App::Prop_Output, "Embedded SVG code for template. For system use."); //n/a for users
ADD_PROPERTY_TYPE(Template, (""), group, App::Prop_None, "Template file name.");
// Width and Height properties shouldn't be set by the user
Height.setStatus(App::Property::ReadOnly, true);
@@ -80,103 +79,44 @@ PyObject *DrawSVGTemplate::getPyObject()
return Py::new_reference_to(PythonObject);
}
unsigned int DrawSVGTemplate::getMemSize() const
{
return 0;
}
short DrawSVGTemplate::mustExecute() const
{
return TechDraw::DrawTemplate::mustExecute();
}
void DrawSVGTemplate::onChanged(const App::Property* prop)
{
bool updatePage = false;
if (prop == &PageResult) {
if (isRestoring()) {
//original template has been stored in fcstd file
Template.setValue(PageResult.getValue());
}
} else if (prop == &Template) { //fileName has changed
if (!isRestoring()) {
EditableTexts.setValues(getEditableTextsFromTemplate());
updatePage = true;
}
if (prop == &Template && !isRestoring()) {
//if we are restoring an existing file we just want the properties set as they were save,
//but if we are not restoring, we need to replace the embedded file and extract the new
//EditableTexts.
//We could try to find matching field names are preserve the values from
//the old template, but there is no guarantee that the same fields will be present.
replaceFileIncluded(Template.getValue());
EditableTexts.setValues(getEditableTextsFromTemplate());
} else if (prop == &EditableTexts) {
if (!isRestoring()) {
updatePage = true;
}
}
if (updatePage) {
execute();
//handled by ViewProvider
}
TechDraw::DrawTemplate::onChanged(prop);
}
App::DocumentObjectExecReturn * DrawSVGTemplate::execute()
//parse the Svg code, inserting current EditableTexts values, and return the result as a QString.
//While parsing, not the Orientation, Width and Height values in the Svg code.
QString DrawSVGTemplate::processTemplate()
{
std::string templateFilename = Template.getValue();
if (templateFilename.empty())
return App::DocumentObject::StdReturn;
// Base::Console().Message("DSVGT::processTemplate() - isRestoring: %d\n", isRestoring());
if (isRestoring()) {
//until everything is fully restored, the embedded file is not available, so we
//can't do anything
return QString();
}
Base::FileInfo fi(templateFilename);
if (!fi.isReadable()) {
// non-empty template value, but can't read file
// if there is a old absolute template file set use a redirect
fi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName());
// try the redirect
if (!fi.isReadable()) {
Base::Console().Log("DrawSVGTemplate::execute() not able to open %s!\n", Template.getValue());
std::string error = std::string("Cannot open file ") + Template.getValue();
return new App::DocumentObjectExecReturn(error);
}
}
if (std::string(PageResult.getValue()).empty()) //first time through?
PageResult.setValue(fi.filePath().c_str());
std::string templateFileSpec = fi.filePath();
QString qSpec = Base::Tools::fromStdString(templateFileSpec);
std::string documentImage;
QString qDocImage;
qDocImage = processTemplate(qSpec);
if (!qDocImage.isEmpty()) {
// make a temp file for FileIncluded Property
std::string tempName = PageResult.getExchangeTempFile();
std::ofstream outfinal(tempName.c_str());
std::string result = Base::Tools::toStdString(qDocImage);
outfinal << result;
outfinal.close();
PageResult.setValue(tempName.c_str());
}
else {
Base::Console().Error("QSVGT::execute - failed to process Template\n");
}
return TechDraw::DrawTemplate::execute();
}
QString DrawSVGTemplate::processTemplate(QString fileSpec)
{
QFile templateFile(fileSpec);
if (!templateFile.open(QIODevice::ReadOnly)) {
Base::Console().Log("DrawSVGTemplate::execute() can't read template %s!\n", Template.getValue());
std::string error = std::string("Cannot read file ") + Template.getValue();
return QString();
}
QFile templateFile(Base::Tools::fromStdString(PageResult.getValue()));
if (!templateFile.open(QIODevice::ReadOnly)) {
Base::Console().Error("DrawSVGTemplate::processTemplate can't read embedded template %s!\n", PageResult.getValue());
return QString();
}
QDomDocument templateDocument;
if (!templateDocument.setContent(&templateFile)) {
Base::Console().Message("DrawSVGTemplate::execute() - failed to parse file: %s\n",
Template.getValue());
std::string error = std::string("Cannot parse file ") + Template.getValue();
Base::Console().Error("DrawSVGTemplate::processTemplate - failed to parse file: %s\n",
PageResult.getValue());
return QString();
}
@@ -251,8 +191,24 @@ double DrawSVGTemplate::getHeight() const
return Height.getValue();
}
void DrawSVGTemplate::replaceFileIncluded(std::string newTemplateFileName)
{
// Base::Console().Message("DSVGT::replaceFileIncluded(%s)\n", newTemplateFileName.c_str());
if (newTemplateFileName.empty()) {
return;
}
Base::FileInfo tfi(newTemplateFileName);
if (tfi.isReadable()) {
PageResult.setValue(newTemplateFileName.c_str());
} else {
throw Base::RuntimeError("Could not read the new template file");
}
}
std::map<std::string, std::string> DrawSVGTemplate::getEditableTextsFromTemplate()
{
// Base::Console().Message("DSVGT::getEditableTextsFromTemplate()\n");
std::map<std::string, std::string> editables;
std::string templateFilename = Template.getValue();

View File

@@ -35,45 +35,32 @@ namespace TechDraw
class TechDrawExport DrawSVGTemplate: public TechDraw::DrawTemplate
{
PROPERTY_HEADER(TechDraw::DrawSVGTemplate);
PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawSVGTemplate);
public:
DrawSVGTemplate();
~DrawSVGTemplate();
~DrawSVGTemplate() override;
App::PropertyFileIncluded PageResult;
App::PropertyFile Template;
/** @name methods override Feature */
//@{
/// recalculate the Feature
virtual App::DocumentObjectExecReturn *execute(void);
//@}
short mustExecute() const;
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
void onChanged(const App::Property* prop) override;
/// returns the type name of the ViewProvider
const char* getViewProviderName(void) const override {
return "TechDrawGui::ViewProviderTemplate";
}
virtual PyObject *getPyObject(void);
virtual unsigned int getMemSize(void) const;
PyObject *getPyObject(void) override;
double getWidth() const;
double getHeight() const;
double getWidth() const override;
double getHeight() const override;
QString processTemplate();
protected:
void onChanged(const App::Property* prop);
/// Returns map with <editable name, default text>
/*!
* Also populates editableSvgIds
*/
void replaceFileIncluded(std::string newTemplateFileName);
std::map<std::string, std::string> getEditableTextsFromTemplate();
QString processTemplate(QString fileSpec);
};
using DrawSVGTemplatePython = App::FeaturePythonT<DrawSVGTemplate>;

View File

@@ -47,23 +47,20 @@ DrawTemplate::DrawTemplate()
const char *group = "Page Properties";
Orientation.setEnums(OrientationEnums);
ADD_PROPERTY(Orientation, ((long)0));
ADD_PROPERTY(Orientation, (0l));
// Physical Properties inherent to every template class
ADD_PROPERTY_TYPE(Width, (0), group, (App::PropertyType)(App::Prop_None), "Width of page");
ADD_PROPERTY_TYPE(Height, (0), group, (App::PropertyType)(App::Prop_None), "Height of page");
//ADD_PROPERTY_TYPE(PaperSize, (""), group, (App::PropertyType)(App::Prop_None), "Paper Format"); //obs?
ADD_PROPERTY_TYPE(Width, (0), group, App::PropertyType::Prop_None, "Width of page");
ADD_PROPERTY_TYPE(Height, (0), group, App::PropertyType::Prop_None, "Height of page");
ADD_PROPERTY_TYPE(EditableTexts, (), group, (App::PropertyType)(App::Prop_None),
ADD_PROPERTY_TYPE(EditableTexts, (), group, App::PropertyType::Prop_None,
"Editable strings in the template");
}
DrawTemplate::~DrawTemplate()
{
Base::Console().Log("template destroyed");
}
PyObject *DrawTemplate::getPyObject()
{
if (PythonObject.is(Py::_None())) {
@@ -73,11 +70,6 @@ PyObject *DrawTemplate::getPyObject()
return Py::new_reference_to(PythonObject);
}
unsigned int DrawTemplate::getMemSize() const
{
return 0;
}
double DrawTemplate::getWidth() const
{
return Width.getValue();
@@ -88,41 +80,30 @@ double DrawTemplate::getHeight() const
return Height.getValue();
}
short DrawTemplate::mustExecute() const
{
return App::DocumentObject::mustExecute();
}
/// get called by the container when a Property was changed
void DrawTemplate::onChanged(const App::Property* prop)
{
App::DocumentObject::onChanged(prop);
}
App::DocumentObjectExecReturn *DrawTemplate::execute()
{
DrawPage *page = nullptr;
std::vector<App::DocumentObject*> parent = getInList();
for (std::vector<App::DocumentObject*>::iterator it = parent.begin(); it != parent.end(); ++it) {
if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) {
page = dynamic_cast<TechDraw::DrawPage *>(*it);
}
}
// DrawPage *page = nullptr;
// std::vector<App::DocumentObject*> parent = getInList();
// for (std::vector<App::DocumentObject*>::iterator it = parent.begin(); it != parent.end(); ++it) {
// if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) {
// page = dynamic_cast<TechDraw::DrawPage *>(*it);
// }
// }
if(page) {
page->Template.touch(); //if you are on a page, execute yourself???
}
// if(page) {
// page->Template.touch();
// }
return App::DocumentObject::execute();
}
DrawPage* DrawTemplate::getParentPage() const
{
TechDraw::DrawPage* page = nullptr;
std::vector<App::DocumentObject*> parent = getInList();
for (std::vector<App::DocumentObject*>::iterator it = parent.begin(); it != parent.end(); ++it) {
if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) {
page = static_cast<TechDraw::DrawPage *>(*it);
TechDraw::DrawPage* page(nullptr);
std::vector<App::DocumentObject*> parents = getInList();
for (auto& obj : parents) {
if (obj->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) {
page = static_cast<TechDraw::DrawPage *>(obj);
}
}
return page;

View File

@@ -36,17 +36,16 @@ class DrawPage;
class TechDrawExport DrawTemplate : public App::DocumentObject
{
PROPERTY_HEADER(TechDraw::DrawTemplate);
PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawTemplate);
public:
DrawTemplate(); /// Constructor
~DrawTemplate();
~DrawTemplate() override;
// Page Physical Properties
App::PropertyLength Width;
App::PropertyLength Height;
App::PropertyEnumeration Orientation;
//App::PropertyString PaperSize;
App::PropertyMap EditableTexts;
@@ -62,23 +61,17 @@ public:
/** @name methods override Feature */
//@{
/// recalculate the Feature
virtual App::DocumentObjectExecReturn *execute(void);
App::DocumentObjectExecReturn *execute(void) override;
//@}
virtual short mustExecute() const;
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
const char* getViewProviderName(void) const override{
return "TechDrawGui::ViewProviderTemplate";
}
// from base class
virtual PyObject *getPyObject(void);
virtual unsigned int getMemSize(void) const;
protected:
void onChanged(const App::Property* prop);
virtual PyObject *getPyObject(void) override;
private:
static const char* OrientationEnums[];