Eclipse SUMO - Simulation of Urban MObility
GNEPythonTool.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // Python tools used in netedit
19 /****************************************************************************/
20 
24 #include <utils/common/SysUtils.h>
29 #include <xercesc/parsers/SAXParser.hpp>
30 
31 #include "GNEPythonTool.h"
32 
33 // ============================================-===============================
34 // member method definitions
35 // ===========================================================================
36 
37 GNEPythonTool::GNEPythonTool(GNEApplicationWindow* GNEApp, const std::string& toolPath,
38  const std::string& templateStr, FXMenuPane* menu) :
39  myGNEApp(GNEApp),
40  myToolPath(toolPath),
41  myPythonToolName(FileHelpers::getFileFromPath(toolPath, true)) {
42  // build menu command
43  myMenuCommand = GUIDesigns::buildFXMenuCommandShortcut(menu, myPythonToolName, "", TL("Execute python tool '") + myPythonToolName + "'.",
45  // parse tool options
46  if (templateStr.size() > 0) {
47  try {
49  // make a copy (needed for reset)
51  } catch (ProcessError& e) {
52  WRITE_ERROR("Error parsing template of tool: " + myPythonToolName + " (" + e.what() + ")");
53  }
54  }
55 }
56 
57 
59 
60 
63  return myGNEApp;
64 }
65 
66 
67 const std::string&
69  return myPythonToolName;
70 }
71 
72 
75  return myPythonToolsOptions;
76 }
77 
78 
79 FXMenuCommand*
81  return myMenuCommand;
82 }
83 
84 
85 void
87  // nothing to do here, use in children
88 }
89 
90 
91 void
93  // nothing to do here, use in children
94 }
95 
96 
97 std::string
99  // add python script
100  const char* pythonEnv = getenv("PYTHON");
101  const std::string python = (pythonEnv == nullptr) ? "python" : pythonEnv;
102  const char* sumoHomeEnv = getenv("SUMO_HOME");
103  std::string sumoHome = "";
104  if (sumoHomeEnv != nullptr && sumoHomeEnv != std::string("")) {
105  sumoHome = std::string(sumoHomeEnv);
106  // harmonise slash
107  if (sumoHome.back() == '\\') {
108  sumoHome.pop_back();
109  }
110  if (sumoHome.back() != '/') {
111  sumoHome += "/";
112  }
113  // quote string to handle spaces but prevent double quotes
114  if (sumoHome.front() != '"') {
115  sumoHome = "\"" + sumoHome;
116  }
117  if (sumoHome.back() == '"') {
118  sumoHome.pop_back();
119  }
120  }
121  return python + " " + sumoHome + myToolPath + "\"";
122 }
123 
124 
125 std::string
127  std::string arguments;
128  // add arguments
129  for (const auto& option : myPythonToolsOptions) {
130  // only add modified values
131  if (!option.second->isDefault()) {
132  // for boolean values avoid use "true"
133  if (option.second->isBool()) {
134  arguments += ("--" + option.first + " ");
135  } else {
136  if (!option.second->isPositional()) {
137  arguments += ("--" + option.first + " ");
138  }
139  const std::string listSeparator = option.second->getListSeparator();
140  if (listSeparator != "") {
141  StringTokenizer st(option.second->getValueString(), " ", true);
142  bool first = true;
143  for (const std::string& v : st.getVector()) {
144  if (first) {
145  first = false;
146  } else {
147  arguments += listSeparator;
148  }
149  arguments += ("\"" + v + "\"");
150  }
151  arguments += " ";
152  } else {
153  arguments += ("\"" + option.second->getValueString() + "\" ");
154  }
155  }
156  }
157  }
158  return getCommandPath() + " " + arguments;
159 }
160 
161 
162 const std::string
163 GNEPythonTool::getDefaultValue(const std::string& name) const {
164  const auto value = myPythonToolsOptionsOriginal.getValueString(name);
165  // filter "none" values
166  if (value == "none") {
167  return "";
168  } else {
169  return value;
170  }
171 }
172 
173 
174 bool
175 GNEPythonTool::loadConfiguration(const std::string& file) {
176  // make all options writable
178  // build parser
179  XERCES_CPP_NAMESPACE::SAXParser parser;
180  parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
181  parser.setDisableDefaultEntityResolution(true);
182  // start the parsing
184  try {
185  parser.setDocumentHandler(&handler);
186  parser.setErrorHandler(&handler);
187  parser.parse(StringUtils::transcodeToLocal(file).c_str());
188  if (handler.errorOccurred()) {
189  WRITE_ERROR(TL("Could not load tool configuration '") + file + "'.");
190  return false;
191  }
192  } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
193  WRITE_ERROR(TL("Could not load tool configuration '") + file + "':\n " + StringUtils::transcode(e.getMessage()));
194  return false;
195  }
196  // write info
197  WRITE_MESSAGE(TLF("Loaded % configuration.", myPythonToolName));
198  return true;
199 }
200 
201 
202 void
203 GNEPythonTool::saveConfiguration(const std::string& file) const {
204  std::string command = getCommandPath() + " -C \"" + file + "\" ";
205  // add arguments
206  for (const auto& option : myPythonToolsOptions) {
207  // only write modified values
208  if (!option.second->isDefault()) {
209  if (option.second->isBool()) {
210  command += ("--" + option.first + " ");
211  } else {
212  command += ("--" + option.first + " \"" + option.second->getValueString() + "\" ");
213  }
214  }
215  }
216  // start in background
217 #ifndef WIN32
218  command = command + " &";
219 #else
220  // see "help start" for the parameters
221  command = "start /B \"\" " + command;
222 #endif
223  // write info
224  WRITE_MESSAGE(TLF("Saved % configuration.", myPythonToolName));
225  // yay! fun with dangerous commands... Never use this over the internet
227 }
228 
229 /****************************************************************************/
@ MID_GNE_OPENPYTHONTOOLDIALOG
call tool
Definition: GUIAppEnum.h:750
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:297
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
Functions for an easier usage of files and paths.
Definition: FileHelpers.h:38
The main window of Netedit.
GNEPythonTool(GNEApplicationWindow *GNEApp, const std::string &toolPath, const std::string &templateStr, FXMenuPane *menu)
Constructor.
OptionsCont myPythonToolsOptionsOriginal
original tools options
Definition: GNEPythonTool.h:91
FXMenuCommand * myMenuCommand
menu command associated with this tool
Definition: GNEPythonTool.h:85
virtual std::string getCommand() const
get command (python + script + arguments)
GNEApplicationWindow * getGNEApp() const
get to GNEApplicationWindow
void saveConfiguration(const std::string &file) const
save configuration
bool loadConfiguration(const std::string &file)
load configuration
virtual void setCurrentValues()
set current values (used for set values like current folder and similar)
virtual ~GNEPythonTool()
destructor
const std::string getDefaultValue(const std::string &name) const
get default value of the given parameter
GNEApplicationWindow * myGNEApp
pointer to GNEApplicationWindow
Definition: GNEPythonTool.h:82
std::string getCommandPath() const
get command (python + script)
const std::string & getToolName() const
get tool name
FXMenuCommand * getMenuCommand() const
get menu command
const std::string myPythonToolName
tool name
Definition: GNEPythonTool.h:97
virtual void postProcessing()
execute post processing
OptionsCont & getToolsOptions()
get tools options
const std::string myToolPath
python tool path relative to SUMO_HOME
Definition: GNEPythonTool.h:94
OptionsCont myPythonToolsOptions
tools options
Definition: GNEPythonTool.h:88
static FXMenuCommand * buildFXMenuCommandShortcut(FXComposite *p, const std::string &text, const std::string &shortcut, const std::string &info, FXIcon *icon, FXObject *tgt, FXSelector sel)
build menu command
Definition: GUIDesigns.cpp:74
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
A storage for options typed value containers)
Definition: OptionsCont.h:89
std::string getValueString(const std::string &name) const
Returns the string-value of the named option (all options)
void resetWritable()
Resets all options to be writeable.
A SAX-Handler for loading options.
Definition: OptionsLoader.h:44
bool errorOccurred() const
Returns the information whether an error occurred.
std::vector< std::string > getVector()
return vector of strings
static std::string transcode(const XMLCh *const data)
converts a 0-terminated XMLCh* array (usually UTF-16, stemming from Xerces) into std::string in UTF-8
Definition: StringUtils.h:146
static std::string transcodeToLocal(const std::string &utf8String)
convert a string from UTF-8 to the local codepage
static unsigned long runHiddenCommand(const std::string &cmd)
run a shell command without popping up any windows (particuarly on win32)
Definition: SysUtils.cpp:69
static void parseTemplate(OptionsCont &options, const std::string &templateString)
run parser