[TD]fix embedded template file handling
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user