/*************************************************************************** * Copyright (c) 2014 Luke Parry * * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "DrawPage.h" #include "DrawSVGTemplate.h" #include using namespace TechDraw; using namespace std; PROPERTY_SOURCE(TechDraw::DrawSVGTemplate, TechDraw::DrawTemplate) DrawSVGTemplate::DrawSVGTemplate() { static const char *group = "Drawing view"; //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, (0), group, App::Prop_Output, "Resulting SVG document of that page"); ADD_PROPERTY_TYPE(Template, (""), group, App::Prop_Transient, "Template for the page"); // Width and Height properties shouldn't be set by the user Height.setStatus(App::Property::ReadOnly,true); Width.setStatus(App::Property::ReadOnly,true); Orientation.setStatus(App::Property::ReadOnly,true); } DrawSVGTemplate::~DrawSVGTemplate() { } PyObject *DrawSVGTemplate::getPyObject(void) { if (PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new DrawSVGTemplatePy(this),true); } return Py::new_reference_to(PythonObject); } unsigned int DrawSVGTemplate::getMemSize(void) 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) { if (!isRestoring()) { EditableTexts.setValues(getEditableTextsFromTemplate()); updatePage = true; } } else if (prop == &EditableTexts) { if (!isRestoring()) { updatePage = true; } } if (updatePage) { execute(); // Update the parent page if exists TechDraw::DrawPage *page = getParentPage(); if (page) page->touch(); } TechDraw::DrawTemplate::onChanged(prop); } App::DocumentObjectExecReturn * DrawSVGTemplate::execute(void) { std::string templValue = Template.getValue(); if (templValue.empty()) return App::DocumentObject::StdReturn; Base::FileInfo fi(templValue); 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("DrawPage::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()); // open Template file string line; ifstream inTemplate (fi.filePath().c_str()); ostringstream copyTemplate; string tempendl = "--endOfLine--"; //inTemplate to copyTemplate //remove DrawingContent comment line //change line endings //capture TitleBlock dimensions while (!inTemplate.eof()) { getline(inTemplate,line); // copy every line except the DrawingContent comment? if(line.find("") == string::npos) { // if not - write through copyTemplate << line << tempendl; } //double t0, t1,t2,t3; float t0, t1,t2,t3; if(line.find("" blockDimensions = QRectF(t0, t1, t2 - t0, t3 - t1); } } inTemplate.close(); string outfragment(copyTemplate.str()); std::string newfragment = outfragment; // update EditableText SVG clauses with Property values std::map subs = EditableTexts.getValues(); if (subs.size() > 0) { boost::regex e1 ("(.*?)"); string::const_iterator begin, end; begin = outfragment.begin(); end = outfragment.end(); boost::match_results what; // Find editable texts while (boost::regex_search(begin, end, what, e1)) { //search in outfragment // if we have a replacement value for the text we've found if (subs.count(what[1].str())) { // change it to specified value boost::regex e2 ("((.*?)()"); newfragment = boost::regex_replace(newfragment, e2, "$1>" + subs[what[1].str()] + "$3"); //replace in newfragment } begin = what[0].second; } } // restoring linebreaks and saving the file boost::regex e3 ("--endOfLine--"); string fmt = "\\n"; outfragment = boost::regex_replace(newfragment, e3, fmt); const QString qsOut = QString::fromStdString(outfragment); QDomDocument doc(QString::fromLatin1("mydocument")); //if (!doc.setContent(&resultFile)) { if (!doc.setContent(qsOut)) { //setError(); //???? how/when does this get reset? std::string errMsg = std::string("Invalid SVG syntax in ") + getNameInDocument() + std::string(" - Check EditableTexts"); return new App::DocumentObjectExecReturn(errMsg); } else { // make a temp file for FileIncluded Property string tempName = PageResult.getExchangeTempFile(); ofstream outfinal(tempName.c_str()); outfinal << outfragment; outfinal.close(); PageResult.setValue(tempName.c_str()); } // Calculate the dimensions of the page and store for retrieval // Parse the document XML QDomElement docElem = doc.documentElement(); // Obtain the size of the SVG document by reading the document attirbutes Base::Quantity quantity; // Obtain the width QString str = docElem.attribute(QString::fromLatin1("width")); quantity = Base::Quantity::parse(str); quantity.setUnit(Base::Unit::Length); Width.setValue(quantity.getValue()); str = docElem.attribute(QString::fromLatin1("height")); quantity = Base::Quantity::parse(str); quantity.setUnit(Base::Unit::Length); Height.setValue(quantity.getValue()); bool isLandscape = getWidth() / getHeight() >= 1.; Orientation.setValue(isLandscape ? 1 : 0); // Housekeeping close the file //resultFile.close(); touch(); return TechDraw::DrawTemplate::execute(); } void DrawSVGTemplate::getBlockDimensions(double &x, double &y, double &width, double &height) const { x = blockDimensions.left(); y = blockDimensions.bottom(); width = blockDimensions.width(); height = blockDimensions.height(); } double DrawSVGTemplate::getWidth() const { return Width.getValue(); } double DrawSVGTemplate::getHeight() const { return Height.getValue(); } std::map DrawSVGTemplate::getEditableTextsFromTemplate() { std::map eds; std::string temp = Template.getValue(); if (!temp.empty()) { Base::FileInfo tfi(temp); if (!tfi.isReadable()) { // if there is a old absolute template file set use a redirect tfi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + tfi.fileName()); // try the redirect if (!tfi.isReadable()) { return eds; } } string tline, tfrag; ifstream tfile (tfi.filePath().c_str()); while (!tfile.eof()) { getline (tfile,tline); tfrag += tline; tfrag += "--endOfLine--"; } tfile.close(); //this catches all the tags: //keep tagRegex in sync with Gui/QGISVGTemplate.cpp boost::regex tagRegex ("]*freecad:editable=[^>]*)>[^<]*]*>([^<]*)"); boost::regex nameRegex("freecad:editable=\"(.*?)\""); boost::regex valueRegex("(.*?)"); string::const_iterator tbegin, tend; tbegin = tfrag.begin(); tend = tfrag.end(); boost::match_results tagMatch; boost::match_results nameMatch; boost::match_results valueMatch; while (boost::regex_search(tbegin, tend, tagMatch, tagRegex)) { if ( boost::regex_search(tagMatch[0].first, tagMatch[0].second, nameMatch, nameRegex) && boost::regex_search(tagMatch[0].first, tagMatch[0].second, valueMatch, valueRegex)) { //found valid name/value pair string name = nameMatch[1]; string value = valueMatch[1]; if (eds.count(name) > 0) { //TODO: Throw or [better] change key qDebug() << "Got duplicate value for key "< const char* TechDraw::DrawSVGTemplatePython::getViewProviderName(void) const { return "TechDrawGui::ViewProviderPython"; } /// @endcond // explicit template instantiation template class TechDrawExport FeaturePythonT; }