diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 1eec492b3f..622a659ce7 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -499,6 +499,7 @@ SET(Command_SRCS Action.h ActionFunction.h Command.h + CommandT.h ) SOURCE_GROUP("Command" FILES ${Command_SRCS}) diff --git a/src/Gui/CommandT.h b/src/Gui/CommandT.h new file mode 100644 index 0000000000..1ecc87e963 --- /dev/null +++ b/src/Gui/CommandT.h @@ -0,0 +1,335 @@ +/*************************************************************************** + * 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 + +namespace Gui { + +class FormatString +{ +public: + static std::string str(const std::string& s) { + return s; + } + static std::string str(const std::stringstream& s) { + return s.str(); + } + static std::string str(const std::ostream& s) { + return dynamic_cast(s).str(); + } + 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 + * @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, 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 App.Document attribute or method + * + * @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(App::Document* 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(App::Document* doc, T&& cmd) { + _cmdDocument(Gui::Command::Gui, doc, "Gui", std::forward(cmd)); +} + +/** Runs a command for accessing an object's document attribute or method + * @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, 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 + * @param obj: pointer to a DocumentObject + * @param cmd: command string, streamable + */ +template +inline void cmdAppDocument(App::DocumentObject* obj, T&& cmd) { + _cmdDocument(Gui::Command::Doc, obj, "App", std::forward(cmd)); +} + +/** Runs a command for accessing an object's Gui::Document attribute or method + * @param obj: pointer to a DocumentObject + * @param cmd: command string, streamable + */ +template +inline void cmdGuiDocument(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 + * @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, 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 + * @param obj: pointer to a DocumentObject + * @param cmd: command string, streamable + * @sa _cmdObject() + */ +template +inline void cmdAppObject(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 + * @param obj: pointer to a DocumentObject + * @param cmd: command string, streamable + * @sa _cmdObject() + */ +template +inline void cmdGuiObject(App::DocumentObject* obj, T&& cmd) { + _cmdObject(Gui::Command::Gui, obj, "Gui", std::forward(cmd)); +} + +/// Hides an object +inline void cmdAppObjectHide(App::DocumentObject* obj) { + cmdAppObject(obj, "Visibility = False"); +} + +/// Shows an object +inline void cmdAppObjectShow(App::DocumentObject* obj) { + cmdAppObject(obj, "Visibility = True"); +} + +/** Runs a command to start editing a give object + * @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(App::DocumentObject* obj) { + if (obj && obj->getNameInDocument()) { + Gui::Command::doCommand(Gui::Command::Gui, + "Gui.ActiveDocument.setEdit(App.getDocument('%s').getObject('%s'))", + obj->getDocument()->getName(), obj->getNameInDocument()); + } +} + +/** Runs a command for accessing a document object's attribute or method + * @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(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 + * @param cmd: command string, supporting printf like formatter + * @param obj: pointer to a DocumentObject + * @sa cmdObject() + */ +template +void cmdGuiObjectArgs(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 +