/*************************************************************************** * Copyright (c) 2019 Werner Mayer * * * * 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 * * * ***************************************************************************/ #ifndef GUI_COMMAND_T_H #define GUI_COMMAND_T_H #include #include #include #include #include #include #include namespace Gui { class FormatString { public: static std::string str(const std::string& s) { return s; } static std::string str(const char* s) { return s; } static std::string str(const QString& s) { return s.toStdString(); } static std::string str(const std::stringstream& s) { return s.str(); } static std::string str(const std::ostringstream& s) { return s.str(); } static std::string str(const std::ostream& s) { if (typeid(s) == typeid(std::ostringstream)) return dynamic_cast(s).str(); else if (typeid(s) == typeid(std::stringstream)) return dynamic_cast(s).str(); throw Base::TypeError("Not a std::stringstream or std::ostringstream"); } static std::string toStr(boost::format& f) { return f.str(); } template static std::string toStr(boost::format& f, T&& t, Args&&... args) { return toStr(f % std::forward(t), std::forward(args)...); } }; /** @defgroup CommandFuncs Helper functions for running commands through Python interpreter */ //@{ /** Runs a command for accessing document attribute or method * This function is an alternative to _FCMD_DOC_CMD * @param doc: pointer to a document * @param mod: module name, "Gui" or "App" * @param cmd: command string, streamable * * Example: * @code{.cpp} * _cmdDocument(Gui::Command::Gui, doc, "Gui", std::stringstream() << "getObject('" << objName << "')"); * @endcode * * Translates to command (assuming doc's name is 'DocName', and * and objName contains value 'ObjName'): * @code{.py} * Gui.getDocument('DocName').getObject('ObjName') * @endcode */ template void _cmdDocument(Gui::Command::DoCmd_Type cmdType, const App::Document* doc, const std::string& mod, T&& cmd) { if (doc && doc->getName()) { std::stringstream str; str << mod << ".getDocument('" << doc->getName() << "')." << FormatString::str(cmd); Gui::Command::runCommand(cmdType, str.str().c_str()); } } /** Runs a command for accessing document attribute or method * This function is an alternative to _FCMD_DOC_CMD * @param doc: document name * @param mod: module name, "Gui" or "App" * @param cmd: command string, streamable * * Example: * @code{.cpp} * _cmdDocument(Gui::Command::Gui, doc, "Gui", std::stringstream() << "getObject('" << objName << "')"); * @endcode * * Translates to command (assuming doc's name is 'DocName', and * and objName contains value 'ObjName'): * @code{.py} * Gui.getDocument('DocName').getObject('ObjName') * @endcode */ template void _cmdDocument(Gui::Command::DoCmd_Type cmdType, const std::string& doc, const std::string& mod, T&& cmd) { if (!doc.empty()) { std::stringstream str; str << mod << ".getDocument('" << doc << "')." << FormatString::str(cmd); Gui::Command::runCommand(cmdType, str.str().c_str()); } } /** Runs a command for accessing App.Document attribute or method * This function is an alternative to FCMD_DOC_CMD * * @param doc: pointer to a document * @param cmd: command string, streamable * @sa _cmdDocument() * * Example: * @code{.cpp} * cmdAppDocument(doc, std::stringstream() << "getObject('" << objName << "')"); * @endcode * * Translates to command (assuming doc's name is 'DocName', and * and objName contains value 'ObjName'): * @code{.py} * App.getDocument('DocName').getObject('ObjName') * @endcode */ template inline void cmdAppDocument(const App::Document* doc, T&& cmd) { _cmdDocument(Gui::Command::Doc, doc, "App", std::forward(cmd)); } /** Runs a command for accessing App.Document attribute or method * This function is an alternative to FCMD_DOC_CMD * * @param doc: document name * @param cmd: command string, streamable * @sa _cmdDocument() * * Example: * @code{.cpp} * cmdAppDocument(doc, std::stringstream() << "getObject('" << objName << "')"); * @endcode * * Translates to command (assuming doc's name is 'DocName', and * and objName contains value 'ObjName'): * @code{.py} * App.getDocument('DocName').getObject('ObjName') * @endcode */ template inline void cmdAppDocument(const std::string& doc, T&& cmd) { _cmdDocument(Gui::Command::Doc, doc, "App", std::forward(cmd)); } /** Runs a command for accessing App.Document attribute or method * * @param doc: pointer to a document * @param cmd: command string, streamable * @sa _cmdDocument() * * Example: * @code{.cpp} * cmdGuiDocument(doc, std::stringstream() << "getObject('" << objName << "')"); * @endcode * * Translates to command (assuming doc's name is 'DocName', and * and objName contains value 'ObjName'): * @code{.py} * Gui.getDocument('DocName').getObject('ObjName') * @endcode */ template inline void cmdGuiDocument(const App::Document* doc, T&& cmd) { _cmdDocument(Gui::Command::Gui, doc, "Gui", std::forward(cmd)); } /** Runs a command for accessing App.Document attribute or method * * @param doc: document name * @param cmd: command string, streamable * @sa _cmdDocument() * * Example: * @code{.cpp} * cmdGuiDocument(doc, std::stringstream() << "getObject('" << objName << "')"); * @endcode * * Translates to command (assuming doc's name is 'DocName', and * and objName contains value 'ObjName'): * @code{.py} * Gui.getDocument('DocName').getObject('ObjName') * @endcode */ template inline void cmdGuiDocument(const std::string& doc, T&& cmd) { _cmdDocument(Gui::Command::Gui, doc, "Gui", std::forward(cmd)); } /** Runs a command for accessing an object's document attribute or method * This function is an alternative to _FCMD_OBJ_DOC_CMD * @param obj: pointer to a DocumentObject * @param mod: module name, "Gui" or "App" * @param cmd: command string, streamable */ template inline void _cmdDocument(Gui::Command::DoCmd_Type cmdType, const App::DocumentObject* obj, const std::string& mod, T&& cmd) { if (obj) _cmdDocument(cmdType, obj->getDocument(), mod, std::forward(cmd)); } /** Runs a command for accessing an object's App::Document attribute or method * This function is an alternative to FCMD_OBJ_DOC_CMD * @param obj: pointer to a DocumentObject * @param cmd: command string, streamable */ template inline void cmdAppDocument(const App::DocumentObject* obj, T&& cmd) { _cmdDocument(Gui::Command::Doc, obj, "App", std::forward(cmd)); } /** Runs a command for accessing a document's attribute or method * @param doc: pointer to a Document * @param cmd: command string, supporting printf like formatter * * Example: * @code{.cpp} * cmdAppDocumentArgs(obj, "addObject('%s')", "Part::Feature"); * @endcode * * Translates to command (assuming obj's document name is 'DocName': * @code{.py} * App.getDocument('DocName').addObject('Part::Feature') * @endcode */ template void cmdAppDocumentArgs(const App::Document* doc, const std::string& cmd, Args&&... args) { std::string _cmd; try { boost::format fmt(cmd); _cmd = FormatString::toStr(fmt, std::forward(args)...); Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').%s", doc->getName(), _cmd.c_str()); } catch (const std::exception& e) { Base::Console().Error("%s: %s\n", e.what(), cmd.c_str()); } catch (const Base::Exception&) { Base::Console().Error("App.getDocument('%s').%s\n", doc->getName(), _cmd.c_str()); throw; } } /** Runs a command for accessing an object's Gui::Document attribute or method * This function is an alternative to FCMD_VOBJ_DOC_CMD * @param obj: pointer to a DocumentObject * @param cmd: command string, streamable */ template inline void cmdGuiDocument(const App::DocumentObject* obj, T&& cmd) { _cmdDocument(Gui::Command::Gui, obj, "Gui", std::forward(cmd)); } /** Runs a command for accessing a document/view object's attribute or method * This function is an alternative to _FCMD_OBJ_CMD * @param cmdType: Command type * @param obj: pointer to a DocumentObject * @param mod: module name, "Gui" or "App" * @param cmd: command string, streamable * * Example: * @code{.cpp} * _cmdObject(Command::Gui,obj,"Gui", "Visibility = " << (visible?"True":"False")); * @endcode * * Translates to command (assuming obj's document name is 'DocName', obj's name * is 'ObjName', and visible is true): * @code{.py} * Gui.getDocument('DocName').getObject('ObjName').Visibility = True * @endcode */ template void _cmdObject(Gui::Command::DoCmd_Type cmdType, const App::DocumentObject* obj, const std::string& mod, T&& cmd) { if (obj && obj->getNameInDocument()) { std::ostringstream str; str << mod << ".getDocument('" << obj->getDocument()->getName() << "')" ".getObject('" << obj->getNameInDocument() << "')." << FormatString::str(cmd); Gui::Command::runCommand(cmdType, str.str().c_str()); } } /** Runs a command for accessing an document object's attribute or method * This function is an alternative to FCMD_OBJ_CMD * @param obj: pointer to a DocumentObject * @param cmd: command string, streamable * @sa _cmdObject() */ template inline void cmdAppObject(const App::DocumentObject* obj, T&& cmd) { _cmdObject(Gui::Command::Doc, obj, "App", std::forward(cmd)); } /** Runs a command for accessing an view object's attribute or method * This function is an alternative to FCMD_VOBJ_CMD * @param obj: pointer to a DocumentObject * @param cmd: command string, streamable * @sa _cmdObject() */ template inline void cmdGuiObject(const App::DocumentObject* obj, T&& cmd) { _cmdObject(Gui::Command::Gui, obj, "Gui", std::forward(cmd)); } /// Hides an object inline void cmdAppObjectHide(const App::DocumentObject* obj) { cmdAppObject(obj, "Visibility = False"); } /// Shows an object inline void cmdAppObjectShow(const App::DocumentObject* obj) { cmdAppObject(obj, "Visibility = True"); } /** Runs a command to start editing a give object * This function is an alternative to FCMD_SET_EDIT * @param obj: pointer to a DocumentObject * * Unlike other helper functions, this one editing the object using the current * active document, instead of the object's owner document. This allows * in-place editing an object, which may be brought in through linking to an * external group. */ inline void cmdSetEdit(const App::DocumentObject* obj, int mod = 0) { if (obj && obj->getNameInDocument()) { Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.setEdit(App.getDocument('%s').getObject('%s'), %d)", obj->getDocument()->getName(), obj->getNameInDocument(), mod); } } /** Runs a command for accessing a document object's attribute or method * This function is an alternative to FCMD_OBJ_CMD2 * @param cmd: command string, supporting printf like formatter * @param obj: pointer to a DocumentObject * * Example: * @code{.cpp} * cmdAppObjectArgs(obj, "Visibility = %s", visible ? "True" : "False"); * @endcode * * Translates to command (assuming obj's document name is 'DocName', obj's name * is 'ObjName', and visible is true): * @code{.py} * App.getDocument('DocName').getObject('ObjName').Visibility = True * @endcode */ template void cmdAppObjectArgs(const App::DocumentObject* obj, const std::string& cmd, Args&&... args) { std::string _cmd; try { boost::format fmt(cmd); _cmd = FormatString::toStr(fmt, std::forward(args)...); Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').getObject('%s').%s", obj->getDocument()->getName(), obj->getNameInDocument(), _cmd.c_str()); } catch (const std::exception& e) { Base::Console().Error("%s: %s\n", e.what(), cmd.c_str()); } catch (const Base::Exception&) { Base::Console().Error("App.getDocument('%s').getObject('%s').%s\n", obj->getDocument()->getName(), obj->getNameInDocument(), _cmd.c_str()); throw; } } /** Runs a command for accessing a view object's attribute or method * This function is an alternative to FCMD_VOBJ_CMD2 * @param cmd: command string, supporting printf like formatter * @param obj: pointer to a DocumentObject * @sa cmdAppObjectArgs() */ template void cmdGuiObjectArgs(const App::DocumentObject* obj, const std::string& cmd, Args&&... args) { std::string _cmd; try { boost::format fmt(cmd); _cmd = FormatString::toStr(fmt, std::forward(args)...); Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').getObject('%s').%s", obj->getDocument()->getName(), obj->getNameInDocument(), _cmd.c_str()); } catch (const std::exception& e) { Base::Console().Error("%s: %s\n", e.what(), cmd.c_str()); } catch (const Base::Exception&) { Base::Console().Error("Gui.getDocument('%s').getObject('%s').%s\n", obj->getDocument()->getName(), obj->getNameInDocument(), _cmd.c_str()); throw; } } /** Runs a command * @param cmdType: command type * @param cmd: command string, supporting printf like formatter * * Example: * @code{.cpp} * doCommandT(Gui::Command::Gui, "Gui.getDocument(%s).getObject(%s).Visibility = %s", "DocName", "ObjName", visible?"True":"False"); * @endcode * * Translates to command (assuming obj's document name is 'DocName', obj's name * is 'ObjName', and visible is true): * @code{.py} * Gui.getDocument('DocName').getObject('ObjName').Visibility = True * @endcode */ template void doCommandT(Gui::Command::DoCmd_Type cmdType, const std::string& cmd, Args&&... args) { std::string _cmd; try { boost::format fmt(cmd); _cmd = FormatString::toStr(fmt, std::forward(args)...); Gui::Command::doCommand(cmdType,"%s", _cmd.c_str()); } catch (const std::exception& e) { Base::Console().Error("%s: %s\n", e.what(), cmd.c_str()); } catch (const Base::Exception&) { Base::Console().Error("%s\n", _cmd.c_str()); throw; } } /** Copy visual attributes from a source to a target object */ template void copyVisualT(Args&&... args) { // file and line number is useless here. Check C++'s source location function once available Gui::Command::_copyVisual(__FILE__, __LINE__, std::forward(args)...); } //@} }; #endif // GUI_COMMAND_T_H