[TD]fix embedded template file handling

This commit is contained in:
wandererfan
2022-11-07 21:43:45 -05:00
committed by WandererFan
parent eed9b6480f
commit 9c9013810e
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[];

View File

@@ -84,17 +84,9 @@ void QGISVGTemplate::openFile(const QFile &file)
Q_UNUSED(file);
}
void QGISVGTemplate::load(const QString &fileName)
void QGISVGTemplate::load(const QByteArray &svgCode)
{
if (fileName.isEmpty()){
return;
}
QFile file(fileName);
if (!file.exists()) {
return;
}
m_svgRender->load(file.fileName());
m_svgRender->load(svgCode);
QSize size = m_svgRender->defaultSize();
m_svgItem->setSharedRenderer(m_svgRender);
@@ -107,11 +99,11 @@ void QGISVGTemplate::load(const QString &fileName)
//convert from pixels or mm or inches in svg file to mm page size
TechDraw::DrawSVGTemplate *tmplte = getSVGTemplate();
double xaspect, yaspect;
xaspect = tmplte->getWidth() / (double) size.width();
yaspect = tmplte->getHeight() / (double) size.height();
xaspect = tmplte->getWidth() / static_cast<double>(size.width());
yaspect = tmplte->getHeight() / static_cast<double>(size.height());
QTransform qtrans;
qtrans.translate(0.f, Rez::guiX(-tmplte->getHeight()));
qtrans.translate(0.0, Rez::guiX(-tmplte->getHeight()));
qtrans.scale(Rez::guiX(xaspect) , Rez::guiX(yaspect));
m_svgItem->setTransform(qtrans);
}
@@ -129,7 +121,7 @@ void QGISVGTemplate::draw()
TechDraw::DrawSVGTemplate *tmplte = getSVGTemplate();
if(!tmplte)
throw Base::RuntimeError("Template Feature not set for QGISVGTemplate");
load(QString::fromUtf8(tmplte->PageResult.getValue()));
load(tmplte->processTemplate().toUtf8());
}
void QGISVGTemplate::updateView(bool update)
@@ -141,6 +133,11 @@ void QGISVGTemplate::updateView(bool update)
void QGISVGTemplate::createClickHandles()
{
TechDraw::DrawSVGTemplate *svgTemplate = getSVGTemplate();
if (svgTemplate->isRestoring()) {
//the embedded file is not available yet, so just return
return;
}
QString templateFilename(QString::fromUtf8(svgTemplate->PageResult.getValue()));
if (templateFilename.isEmpty()) {

View File

@@ -25,13 +25,13 @@
#include <Mod/TechDraw/TechDrawGlobal.h>
QT_BEGIN_NAMESPACE
#include <QObject>
class QGraphicsScene;
class QGraphicsSvgItem;
class QSvgRenderer;
class QFile;
class QString;
QT_END_NAMESPACE
namespace TechDraw {
class DrawSVGTemplate;
@@ -61,7 +61,7 @@ public:
protected:
void openFile(const QFile &file);
void load (const QString & fileName);
void load (const QByteArray& svgCode);
void createClickHandles(void);
protected:

View File

@@ -69,6 +69,7 @@ ViewProviderTemplate::~ViewProviderTemplate()
void ViewProviderTemplate::updateData(const App::Property* prop)
{
//This doesn't belong here. Should be in attach?
if (getTemplate()->isDerivedFrom(TechDraw::DrawSVGTemplate::getClassTypeId())) {
auto t = static_cast<TechDraw::DrawSVGTemplate*>(getTemplate());
if (prop == &(t->Template)) {
@@ -80,6 +81,14 @@ void ViewProviderTemplate::updateData(const App::Property* prop)
}
}
}
if (prop == &(getTemplate()->EditableTexts)) {
QGITemplate* qgiv = getQTemplate();
if (qgiv) {
qgiv->updateView(true);
}
}
Gui::ViewProviderDocumentObject::updateData(prop);
}