/*************************************************************************** * Copyright (c) 2013 Yorik van Havre * * * * 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 #endif #include #include #include #include #include #include #include #include #include #include "QDomNodeModel.h" #include "DrawUtil.h" #include "DrawPage.h" #include "DrawViewSymbol.h" #include // generated from DrawViewSymbolPy.xml using namespace TechDraw; using namespace std; //=========================================================================== // DrawViewSymbol //=========================================================================== PROPERTY_SOURCE(TechDraw::DrawViewSymbol, TechDraw::DrawView) DrawViewSymbol::DrawViewSymbol(void) { static const char *vgroup = "Drawing view"; ADD_PROPERTY_TYPE(Symbol,(""),vgroup,App::Prop_None,"The SVG code defining this symbol"); ADD_PROPERTY_TYPE(EditableTexts,(""),vgroup,App::Prop_None,"Substitution values for the editable strings in this symbol"); ScaleType.setValue("Custom"); } DrawViewSymbol::~DrawViewSymbol() { } void DrawViewSymbol::onChanged(const App::Property* prop) { // Base::Console().Message("DVS::onChanged(%s) \n",prop->getName()); if (prop == &Symbol) { if (!isRestoring() && Symbol.getValue()[0]) { //this pulls the initial values from svg into editabletexts // should only happen first time?? extra loop onChanged->execute->onChanged std::vector editables; QDomDocument symbolDocument; const char* symbol = Symbol.getValue(); QByteArray qba(symbol); QString errorMsg; int errorLine; int errorCol; bool nsProcess = false; bool rc = symbolDocument.setContent(qba, nsProcess, &errorMsg, &errorLine, &errorCol); if (rc) { QDomElement symbolDocElem = symbolDocument.documentElement(); QXmlQuery query(QXmlQuery::XQuery10); QDomNodeModel model(query.namePool(), symbolDocument); query.setFocus(QXmlItem(model.fromDomNode(symbolDocElem))); // XPath query to select all nodes whose parent // has "freecad:editable" attribute query.setQuery(QString::fromUtf8( "declare default element namespace \"" SVG_NS_URI "\"; " "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; " "//text[@freecad:editable]/tspan")); QXmlResultItems queryResult; query.evaluateTo(&queryResult); while (!queryResult.next().isNull()) { QDomElement tspanElement = model.toDomNode(queryResult.current().toNodeModelIndex()).toElement(); editables.push_back(Base::Tools::escapedUnicodeFromUtf8(tspanElement.text().toStdString().c_str())); } } else { Base::Console().Warning("DVS::onChanged - %s - SVG for Symbol is not valid. See log.\n"); Base::Console().Log( "Warning: DVS::onChanged(Symbol) for %s - len: %d rc: %d error: %s line: %d col: %d\n", getNameInDocument(), strlen(symbol), rc, qPrintable(errorMsg), errorLine, errorCol); } EditableTexts.setValues(editables); // requestPaint(); } } TechDraw::DrawView::onChanged(prop); } App::DocumentObjectExecReturn *DrawViewSymbol::execute(void) { // Base::Console().Message("DVS::execute() \n"); // //dvs::execute is pretty fast. doesn't need to be blocked? // if (!keepUpdated()) { // return App::DocumentObject::StdReturn; // } std::string svg = Symbol.getValue(); if (svg.empty()) { return App::DocumentObject::StdReturn; } const std::vector& editText = EditableTexts.getValues(); if (!editText.empty()) { QDomDocument symbolDocument; const char* symbol = Symbol.getValue(); QByteArray qba(symbol); QString errorMsg; int errorLine; int errorCol; bool nsProcess = false; bool rc = symbolDocument.setContent(qba, nsProcess, &errorMsg, &errorLine, &errorCol); if (rc) { QDomElement symbolDocElem = symbolDocument.documentElement(); QXmlQuery query(QXmlQuery::XQuery10); QDomNodeModel model(query.namePool(), symbolDocument); query.setFocus(QXmlItem(model.fromDomNode(symbolDocElem))); // XPath query to select all nodes whose parent // has "freecad:editable" attribute query.setQuery(QString::fromUtf8( "declare default element namespace \"" SVG_NS_URI "\"; " "declare namespace freecad=\"" FREECAD_SVG_NS_URI "\"; " "//text[@freecad:editable]/tspan")); QXmlResultItems queryResult; query.evaluateTo(&queryResult); unsigned int count = 0; while (!queryResult.next().isNull()) { QDomElement tspanElement = model.toDomNode(queryResult.current().toNodeModelIndex()).toElement(); // Keep all spaces in the text node tspanElement.setAttribute(QString::fromUtf8("xml:space"), QString::fromUtf8("preserve")); // Remove all child nodes (if any) while (!tspanElement.lastChild().isNull()) { tspanElement.removeChild(tspanElement.lastChild()); } // Finally append text node with editable replacement as the only descendant tspanElement.appendChild(symbolDocument.createTextNode( QString::fromUtf8(Base::Tools::escapedUnicodeToUtf8(editText[count]).c_str()))); ++count; } Symbol.setValue(symbolDocument.toString(1).toStdString()); } else { Base::Console().Warning("DVS::execute - %s - SVG for Symbol is not valid. See log.\n"); Base::Console().Log( "Warning: DVS::execute() - %s - len: %d rc: %d error: %s line: %d col: %d\n", getNameInDocument(), strlen(symbol), rc, qPrintable(errorMsg), errorLine, errorCol); } } // requestPaint(); return DrawView::execute(); } QRectF DrawViewSymbol::getRect() const { double w = 64.0; //must default to something double h = 64.0; return (QRectF(0,0,w,h)); // std::string svg = Symbol.getValue(); // string::const_iterator begin, end; // begin = svg.begin(); // end = svg.end(); // boost::match_results what; // boost::regex e1 ("width=\"([0-9.]*?)[a-zA-Z]*?\""); // if (boost::regex_search(begin, end, what, e1)) { // //std::string wText = what[0].str(); //this is the whole match 'width="100"' // std::string wNum = what[1].str(); //this is just the number 100 // w = std::stod(wNum); // } // // boost::regex e2 ("height=\"([0-9.]*?)[a-zA-Z]*?\""); // if (boost::regex_search(begin, end, what, e2)) { // //std::string hText = what[0].str(); // std::string hNum = what[1].str(); // h = std::stod(hNum); // } // return (QRectF(0,0,getScale() * w,getScale() * h)); //we now have a w x h, but we don't really know what it means - px,mm,in,... } //!Assume all svg files fit the page and/or the user will scale manually //see getRect() above bool DrawViewSymbol::checkFit(TechDraw::DrawPage* p) const { (void)p; bool result = true; return result; } short DrawViewSymbol::mustExecute() const { short result = 0; if (!isRestoring()) { result = (Scale.isTouched() || EditableTexts.isTouched()); } if ((bool) result) { return result; } return DrawView::mustExecute(); } PyObject *DrawViewSymbol::getPyObject(void) { if (PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new DrawViewSymbolPy(this),true); } return Py::new_reference_to(PythonObject); } // Python Drawing feature --------------------------------------------------------- namespace App { /// @cond DOXERR PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSymbolPython, TechDraw::DrawViewSymbol) template<> const char* TechDraw::DrawViewSymbolPython::getViewProviderName(void) const { return "TechDrawGui::ViewProviderSymbol"; } /// @endcond // explicit template instantiation template class TechDrawExport FeaturePythonT; }