Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/tools/GNEPythonTool.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
14
/// @file GNEPythonTool.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jun 2022
17
///
18
// Python tools used in netedit
19
/****************************************************************************/
20
21
#include <netedit/GNEApplicationWindow.h>
22
#include <utils/common/FileHelpers.h>
23
#include <utils/common/MsgHandler.h>
24
#include <utils/common/SysUtils.h>
25
#include <utils/common/StringTokenizer.h>
26
#include <utils/gui/div/GUIDesigns.h>
27
#include <utils/handlers/TemplateHandler.h>
28
#include <utils/options/OptionsLoader.h>
29
#include <xercesc/parsers/SAXParser.hpp>
30
31
#include "GNEPythonTool.h"
32
33
// ============================================-===============================
34
// member method definitions
35
// ===========================================================================
36
37
GNEPythonTool::GNEPythonTool(GNEApplicationWindow* applicationWindow, const std::string& toolPath,
38
const std::string& templateStr, FXMenuPane* menu) :
39
myApplicationWindow(applicationWindow),
40
myToolPath(toolPath),
41
myPythonToolName(FileHelpers::getFileFromPath(toolPath, true)) {
42
// build menu command
43
myMenuCommand = GUIDesigns::buildFXMenuCommandShortcut(menu, myPythonToolName, "", TL("Execute python tool '") + myPythonToolName + "'.",
44
GUIIconSubSys::getIcon(GUIIcon::TOOL_PYTHON), applicationWindow, MID_GNE_OPENPYTHONTOOLDIALOG);
45
// parse tool options
46
if (templateStr.size() > 0) {
47
try {
48
TemplateHandler::parseTemplate(myPythonToolsOptions, templateStr);
49
// make a copy (needed for reset)
50
TemplateHandler::parseTemplate(myPythonToolsOptionsOriginal, templateStr);
51
} catch (ProcessError& e) {
52
WRITE_ERROR("Error parsing template of tool: " + myPythonToolName + " (" + e.what() + ")");
53
}
54
}
55
}
56
57
58
GNEPythonTool::~GNEPythonTool() {}
59
60
61
const std::string&
62
GNEPythonTool::getToolName() const {
63
return myPythonToolName;
64
}
65
66
67
OptionsCont&
68
GNEPythonTool::getToolsOptions() {
69
return myPythonToolsOptions;
70
}
71
72
73
FXMenuCommand*
74
GNEPythonTool::getMenuCommand() const {
75
return myMenuCommand;
76
}
77
78
79
void
80
GNEPythonTool::setCurrentValues() {
81
// nothing to do here, use in children
82
}
83
84
85
void
86
GNEPythonTool::postProcessing() {
87
// nothing to do here, use in children
88
}
89
90
91
std::string
92
GNEPythonTool::getCommandPath() const {
93
// add python script
94
const char* pythonEnv = getenv("PYTHON");
95
const std::string python = (pythonEnv == nullptr) ? "python" : pythonEnv;
96
const char* sumoHomeEnv = getenv("SUMO_HOME");
97
std::string sumoHome = "";
98
if (sumoHomeEnv != nullptr && sumoHomeEnv != std::string("")) {
99
sumoHome = std::string(sumoHomeEnv);
100
// harmonise slash
101
if (sumoHome.back() == '\\') {
102
sumoHome.pop_back();
103
}
104
if (sumoHome.back() != '/') {
105
sumoHome += "/";
106
}
107
// quote string to handle spaces but prevent double quotes
108
if (sumoHome.front() != '"') {
109
sumoHome = "\"" + sumoHome;
110
}
111
if (sumoHome.back() == '"') {
112
sumoHome.pop_back();
113
}
114
}
115
return python + " " + sumoHome + myToolPath + "\"";
116
}
117
118
119
std::string
120
GNEPythonTool::getCommand() const {
121
std::string arguments;
122
// add arguments
123
for (const auto& option : myPythonToolsOptions) {
124
// only add modified values
125
if (!option.second->isDefault()) {
126
// for boolean values avoid use "true"
127
if (option.second->isBool()) {
128
arguments += ("--" + option.first + " ");
129
} else {
130
if (!option.second->isPositional()) {
131
arguments += ("--" + option.first + " ");
132
}
133
const std::string listSeparator = option.second->getListSeparator();
134
if (listSeparator != "") {
135
StringTokenizer st(option.second->getValueString(), " ", true);
136
bool first = true;
137
for (const std::string& v : st.getVector()) {
138
if (first) {
139
first = false;
140
} else {
141
arguments += listSeparator;
142
}
143
arguments += ("\"" + v + "\"");
144
}
145
arguments += " ";
146
} else {
147
arguments += ("\"" + StringUtils::escapeShell(option.second->getValueString()) + "\" ");
148
}
149
}
150
}
151
}
152
return getCommandPath() + " " + arguments;
153
}
154
155
156
const std::string
157
GNEPythonTool::getDefaultValue(const std::string& name) const {
158
const auto value = myPythonToolsOptionsOriginal.getValueString(name);
159
// filter "none" values
160
if (value == "none") {
161
return "";
162
} else {
163
return value;
164
}
165
}
166
167
168
bool
169
GNEPythonTool::loadConfiguration(const std::string& file) {
170
// make all options writable
171
myPythonToolsOptions.resetWritable();
172
// build parser
173
XERCES_CPP_NAMESPACE::SAXParser parser;
174
parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
175
parser.setDisableDefaultEntityResolution(true);
176
// start the parsing
177
OptionsLoader handler(myPythonToolsOptions);
178
try {
179
parser.setDocumentHandler(&handler);
180
parser.setErrorHandler(&handler);
181
parser.parse(StringUtils::transcodeToLocal(file).c_str());
182
if (handler.errorOccurred()) {
183
WRITE_ERROR(TL("Could not load tool configuration '") + file + "'.");
184
return false;
185
}
186
} catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
187
WRITE_ERROR(TL("Could not load tool configuration '") + file + "':\n " + StringUtils::transcode(e.getMessage()));
188
return false;
189
}
190
// write info
191
WRITE_MESSAGE(TLF("Loaded % configuration.", myPythonToolName));
192
return true;
193
}
194
195
196
void
197
GNEPythonTool::saveConfiguration(const std::string& file) const {
198
std::string command = getCommand() + " -C \"" + file + "\" ";
199
// start in background
200
#ifndef WIN32
201
command = command + " &";
202
#else
203
// see "help start" for the parameters
204
command = "start /B \"\" " + command;
205
#endif
206
// write info
207
WRITE_MESSAGE(TLF("Saved % configuration.", myPythonToolName));
208
// yay! fun with dangerous commands... Never use this over the internet
209
SysUtils::runHiddenCommand(command);
210
}
211
212
/****************************************************************************/
213
214