Line data Source code
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 CommonHandler.cpp
15 : /// @author Pablo Alvarez Lopez
16 : /// @date Dec 2024
17 : ///
18 : // Collection of functions used in handlers
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/common/MsgHandler.h>
23 : #include <utils/common/StringUtils.h>
24 : #include <utils/xml/XMLSubSys.h>
25 :
26 : #include "CommonHandler.h"
27 :
28 :
29 : // ===========================================================================
30 : // method definitions
31 : // ===========================================================================
32 :
33 0 : CommonHandler::CommonHandler(const std::string& filename) :
34 0 : myFilename(filename) {
35 0 : }
36 :
37 :
38 0 : CommonHandler::~CommonHandler() {}
39 :
40 :
41 : void
42 0 : CommonHandler::forceOverwriteElements() {
43 0 : myOverwriteElements = true;
44 0 : }
45 :
46 :
47 : void
48 0 : CommonHandler::forceRemainElements() {
49 0 : myRemainElements = true;
50 0 : }
51 :
52 :
53 : void
54 0 : CommonHandler::abortLoading() {
55 0 : myAbortLoading = true;
56 0 : }
57 :
58 :
59 : bool
60 0 : CommonHandler::isErrorCreatingElement() const {
61 0 : return myErrorCreatingElement;
62 : }
63 :
64 :
65 : bool
66 0 : CommonHandler::isForceOverwriteElements() const {
67 0 : return myOverwriteElements;
68 : }
69 :
70 :
71 : bool
72 0 : CommonHandler::isForceRemainElements() const {
73 0 : return myRemainElements;
74 : }
75 :
76 :
77 : bool
78 0 : CommonHandler::isAbortLoading() const {
79 0 : return myAbortLoading;
80 : }
81 :
82 :
83 : void
84 0 : CommonHandler::parseParameters(const SUMOSAXAttributes& attrs) {
85 : // declare Ok Flag
86 0 : bool parsedOk = true;
87 : // get key
88 0 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, parsedOk);
89 : // get SumoBaseObject parent
90 0 : CommonXMLStructure::SumoBaseObject* SumoBaseObjectParent = myCommonXMLStructure.getCurrentSumoBaseObject()->getParentSumoBaseObject();
91 : // check parent
92 0 : if ((SumoBaseObjectParent == nullptr) || (SumoBaseObjectParent->getTag() == SUMO_TAG_ROOTFILE)) {
93 0 : writeError(TL("Parameters must be defined within an object"));
94 0 : } else if (SumoBaseObjectParent->getTag() == SUMO_TAG_PARAM) {
95 0 : writeError(TL("Parameters cannot be defined within another parameter."));
96 0 : } else if ((SumoBaseObjectParent->getTag() != SUMO_TAG_ERROR) && parsedOk) {
97 : // get tag str
98 0 : const std::string parentTagStr = toString(SumoBaseObjectParent->getTag());
99 : // circumventing empty string value
100 0 : const std::string value = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
101 : // show warnings if values are invalid
102 0 : if (key.empty()) {
103 0 : writeError(TLF("Error parsing key from % generic parameter. Key cannot be empty", parentTagStr));
104 0 : } else if (!SUMOXMLDefinitions::isValidParameterKey(key)) {
105 0 : writeError(TLF("Error parsing key from % generic parameter. Key contains invalid characters", parentTagStr));
106 : } else {
107 : // insert parameter in SumoBaseObjectParent
108 0 : SumoBaseObjectParent->addParameter(key, value);
109 : }
110 : }
111 0 : }
112 :
113 :
114 : CommonXMLStructure::SumoBaseObject*
115 0 : CommonHandler::getEmbeddedRoute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject) const {
116 : // locate route in childrens
117 0 : for (const auto& embeddedRoute : sumoBaseObject->getSumoBaseObjectChildren()) {
118 0 : if ((embeddedRoute->getTag() == SUMO_TAG_ROUTE) && (!embeddedRoute->hasStringAttribute(SUMO_ATTR_ID))) {
119 0 : return embeddedRoute;
120 : }
121 : }
122 : return nullptr;
123 : }
124 :
125 :
126 : void
127 0 : CommonHandler::checkParsedParent(const SumoXMLTag currentTag, const std::vector<SumoXMLTag>& parentTags, bool& ok) {
128 0 : if (parentTags.size() > 0) {
129 : std::string tagsStr;
130 0 : for (auto it = parentTags.begin(); it != parentTags.end(); it++) {
131 0 : tagsStr.append(toString(*it));
132 0 : if ((it + 1) != parentTags.end()) {
133 0 : if ((it + 2) != parentTags.end()) {
134 0 : tagsStr.append(", ");
135 : } else {
136 0 : tagsStr.append(" or ");
137 : }
138 : }
139 : }
140 : // obtain parent
141 0 : CommonXMLStructure::SumoBaseObject* const parent = myCommonXMLStructure.getCurrentSumoBaseObject()->getParentSumoBaseObject();
142 0 : if (parent == nullptr) {
143 0 : ok = writeError(TLF("'%' must be defined within the definition of a %.", toString(currentTag), tagsStr));
144 0 : } else if ((parent->getTag() != SUMO_TAG_ERROR) && std::find(parentTags.begin(), parentTags.end(), parent->getTag()) == parentTags.end()) {
145 0 : if (parent->hasStringAttribute(SUMO_ATTR_ID)) {
146 0 : ok = writeError(TLF("'%' must be defined within the definition of a '%' (found % '%').", toString(currentTag), tagsStr,
147 : toString(parent->getTag()), parent->getStringAttribute(SUMO_ATTR_ID)));
148 : } else {
149 0 : ok = writeError(TLF("'%' must be defined within the definition of a '%' (found %).", toString(currentTag), tagsStr,
150 : toString(parent->getTag())));
151 : }
152 : }
153 : }
154 0 : }
155 :
156 :
157 : bool
158 0 : CommonHandler::checkListOfVehicleTypes(const SumoXMLTag tag, const std::string& id, const std::vector<std::string>& vTypeIDs) {
159 0 : for (const auto& vTypeID : vTypeIDs) {
160 0 : if (!SUMOXMLDefinitions::isValidTypeID(vTypeID)) {
161 0 : return writeError(TLF("Could not build % with ID '%' in netedit; '%' ist not a valid vType ID.", toString(tag), id, vTypeID));
162 : }
163 : }
164 : return true;
165 : }
166 :
167 :
168 : bool
169 0 : CommonHandler::checkWithinDistribution(CommonXMLStructure::SumoBaseObject* obj) {
170 0 : if (obj->getParentSumoBaseObject() == nullptr) {
171 : return false;
172 0 : } else if (obj->getParentSumoBaseObject()->getTag() == SUMO_TAG_ROUTE_DISTRIBUTION) {
173 : return true;
174 0 : } else if (obj->getParentSumoBaseObject()->getTag() == SUMO_TAG_VTYPE_DISTRIBUTION) {
175 : return true;
176 : } else {
177 : return false;
178 : }
179 : }
180 :
181 :
182 : bool
183 0 : CommonHandler::checkVehicleParents(CommonXMLStructure::SumoBaseObject* obj) {
184 0 : if (obj == nullptr) {
185 : return false;
186 0 : } else if (!obj->hasStringAttribute(SUMO_ATTR_ID)) {
187 : return false;
188 : } else {
189 0 : SumoXMLTag tag = obj->getTag();
190 0 : const std::string id = obj->getStringAttribute(SUMO_ATTR_ID);
191 0 : const bool hasRoute = obj->hasStringAttribute(SUMO_ATTR_ROUTE);
192 0 : const bool hasEmbeddedRoute = (getEmbeddedRoute(obj) != nullptr);
193 0 : const bool overEdges = obj->hasStringAttribute(SUMO_ATTR_FROM) && obj->hasStringAttribute(SUMO_ATTR_TO);
194 0 : const bool overJunctions = obj->hasStringAttribute(SUMO_ATTR_FROM_JUNCTION) && obj->hasStringAttribute(SUMO_ATTR_TO_JUNCTION);
195 0 : const bool overTAZs = obj->hasStringAttribute(SUMO_ATTR_FROM_TAZ) && obj->hasStringAttribute(SUMO_ATTR_TO_TAZ);
196 0 : if (hasRoute && hasEmbeddedRoute) {
197 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Cannot have an external route and an embedded route in the same definition.", toString(tag), id));
198 : }
199 0 : if ((overEdges + overJunctions + overTAZs) > 1) {
200 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Cannot have multiple from-to attributes.", toString(tag), id));
201 : }
202 0 : if ((hasRoute + hasEmbeddedRoute + overEdges + overJunctions + overTAZs) > 1) {
203 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Cannot have from-to attributes and route attributes in the same definition.", toString(tag), id));
204 : }
205 0 : if ((hasRoute + hasEmbeddedRoute + overEdges + overJunctions + overTAZs) == 0) {
206 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Requires either a route or an embedded route or a from-to attribute (Edges, junctions or TAZs).", toString(tag), id));
207 : }
208 : return true;
209 : }
210 : }
211 :
212 :
213 : bool
214 0 : CommonHandler::checkPersonPlanParents(CommonXMLStructure::SumoBaseObject* obj) {
215 0 : const auto parent = obj->getParentSumoBaseObject();
216 0 : if (parent == nullptr) {
217 : return false;
218 0 : } else if (!parent->wasCreated()) {
219 : return false;
220 0 : } else if ((parent->getTag() == SUMO_TAG_PERSON) || (parent->getTag() == SUMO_TAG_PERSONFLOW)) {
221 0 : return true;
222 : } else {
223 : return false;
224 : }
225 : }
226 :
227 :
228 : bool
229 0 : CommonHandler::checkContainerPlanParents(CommonXMLStructure::SumoBaseObject* obj) {
230 0 : const auto parent = obj->getParentSumoBaseObject();
231 0 : if (parent == nullptr) {
232 : return false;
233 0 : } else if (!parent->wasCreated()) {
234 : return false;
235 0 : } else if ((parent->getTag() == SUMO_TAG_CONTAINER) || (parent->getTag() == SUMO_TAG_CONTAINERFLOW)) {
236 0 : return true;
237 : } else {
238 : return false;
239 : }
240 : }
241 :
242 :
243 : bool
244 0 : CommonHandler::checkStopParents(CommonXMLStructure::SumoBaseObject* obj) {
245 0 : const auto parent = obj->getParentSumoBaseObject();
246 0 : if (parent == nullptr) {
247 : return false;
248 0 : } else if (!parent->wasCreated()) {
249 : return false;
250 0 : } else if ((parent->getTag() == SUMO_TAG_ROUTE) || (parent->getTag() == SUMO_TAG_TRIP) ||
251 0 : (parent->getTag() == SUMO_TAG_VEHICLE) || (parent->getTag() == SUMO_TAG_FLOW) ||
252 0 : (parent->getTag() == SUMO_TAG_PERSON) || (parent->getTag() == SUMO_TAG_PERSONFLOW) ||
253 0 : (parent->getTag() == SUMO_TAG_CONTAINER) || (parent->getTag() == SUMO_TAG_CONTAINERFLOW)) {
254 0 : return true;
255 : } else {
256 : return false;
257 : }
258 : }
259 :
260 :
261 : bool
262 0 : CommonHandler::checkNegative(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const int value, const bool canBeZero) {
263 0 : if (canBeZero) {
264 0 : if (value < 0) {
265 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % cannot be negative.", toString(tag), id, toString(attribute)));
266 : } else {
267 : return true;
268 : }
269 : } else {
270 0 : if (value <= 0) {
271 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % must be greather than zero.", toString(tag), id, toString(attribute)));
272 : } else {
273 : return true;
274 : }
275 : }
276 : }
277 :
278 :
279 : bool
280 0 : CommonHandler::checkNegative(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const double value, const bool canBeZero) {
281 0 : if (canBeZero) {
282 0 : if (value < 0) {
283 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % cannot be negative (%).", toString(tag), id, toString(attribute), toString(value)));
284 : } else {
285 : return true;
286 : }
287 : } else {
288 0 : if (value <= 0) {
289 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % must be greather than zero (%).", toString(tag), id, toString(attribute), toString(value)));
290 : } else {
291 : return true;
292 : }
293 : }
294 : }
295 :
296 :
297 : bool
298 0 : CommonHandler::checkNegative(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const SUMOTime value, const bool canBeZero) {
299 0 : if (canBeZero) {
300 0 : if (value < 0) {
301 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % cannot be negative (%).", toString(tag), id, toString(attribute), time2string(value)));
302 : } else {
303 : return true;
304 : }
305 : } else {
306 0 : if (value <= 0) {
307 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % must be greather than zero (%).", toString(tag), id, toString(attribute), time2string(value)));
308 : } else {
309 : return true;
310 : }
311 : }
312 : }
313 :
314 :
315 : bool
316 0 : CommonHandler::checkFileName(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const std::string& value) {
317 0 : if (SUMOXMLDefinitions::isValidFilename(value)) {
318 : return true;
319 : } else {
320 0 : return writeError(TLF("Could not build % with ID '%' in netedit; % is invalid % ()", toString(tag), id, toString(attribute), value));
321 : }
322 : }
323 :
324 :
325 : bool
326 0 : CommonHandler::checkValidAdditionalID(const SumoXMLTag tag, const std::string& value) {
327 0 : if (value.empty()) {
328 0 : return writeError(TLF("Could not build %; ID cannot be empty", toString(tag)));
329 0 : } else if (!SUMOXMLDefinitions::isValidVehicleID(value)) {
330 0 : return writeError(TLF("Could not build % with ID '%' in netedit; ID contains invalid characters.", toString(tag), value));
331 : } else {
332 : return true;
333 : }
334 : }
335 :
336 :
337 : bool
338 0 : CommonHandler::checkValidDetectorID(const SumoXMLTag tag, const std::string& value) {
339 0 : if (value.empty()) {
340 0 : return writeError(TLF("Could not build %; ID cannot be empty", toString(tag)));
341 0 : } else if (!SUMOXMLDefinitions::isValidDetectorID(value)) {
342 0 : return writeError(TLF("Could not build % with ID '%' in netedit; detector ID contains invalid characters.", toString(tag), value));
343 : } else {
344 : return true;
345 : }
346 : }
347 :
348 :
349 : bool
350 0 : CommonHandler::checkValidDemandElementID(const SumoXMLTag tag, const std::string& value) {
351 0 : if (value.empty()) {
352 0 : return writeError(TLF("Could not build %; ID cannot be empty", toString(tag)));
353 0 : } else if (!SUMOXMLDefinitions::isValidVehicleID(value)) {
354 0 : return writeError(TLF("Could not build % with ID '%' in netedit; ID contains invalid characters.", toString(tag), value));
355 : } else {
356 : return true;
357 : }
358 : }
359 :
360 :
361 : void
362 0 : CommonHandler::writeWarningOverwriting(const SumoXMLTag tag, const std::string& id) {
363 0 : WRITE_WARNING(TLF("Overwriting % with ID '%'", toString(tag), id));
364 0 : }
365 :
366 :
367 : bool
368 0 : CommonHandler::writeWarningDuplicated(const SumoXMLTag tag, const std::string& id, const SumoXMLTag checkedTag) {
369 0 : WRITE_WARNING(TLF("Could not build % with ID '%' in netedit; Found another % with the same ID.", toString(tag), id, toString(checkedTag)));
370 0 : return false;
371 : }
372 :
373 :
374 : bool
375 0 : CommonHandler::writeError(const std::string& error) {
376 0 : WRITE_ERROR(error);
377 0 : myErrorCreatingElement = true;
378 0 : return false;
379 : }
380 :
381 :
382 : bool
383 0 : CommonHandler::writeErrorInvalidPosition(const SumoXMLTag tag, const std::string& id) {
384 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Invalid position over lane.", toString(tag), id));
385 : }
386 :
387 :
388 : bool
389 0 : CommonHandler::writeErrorInvalidLanes(const SumoXMLTag tag, const std::string& id) {
390 0 : return writeError(TLF("Could not build % with ID '%' in netedit; List of lanes isn't valid.", toString(tag), id));
391 : }
392 :
393 :
394 : bool
395 0 : CommonHandler::writeErrorInvalidParent(const SumoXMLTag tag, const std::string& id, const std::vector<SumoXMLTag> parentTags, const std::string& parentID) {
396 0 : if (parentTags.size() == 1) {
397 0 : return writeError(TLF("Could not build % with ID '%' in netedit; % parent with ID '%' doesn't exist.", toString(tag), id, toString(parentTags.front()), parentID));
398 : } else {
399 0 : return writeError(TLF("Could not build % with ID '%' in netedit; doesn't exist a % parent with ID '%'.", toString(tag), id, parseParentTags(parentTags), parentID));
400 : }
401 : }
402 :
403 :
404 : bool
405 0 : CommonHandler::writeErrorInvalidParent(const SumoXMLTag tag, const std::vector<SumoXMLTag> parentTags, const std::string& parentID) {
406 0 : if (parentTags.size() == 1) {
407 0 : return writeError(TLF("Could not build % in netedit; % parent with ID '%' doesn't exist.", toString(tag), toString(parentTags.front()), parentID));
408 : } else {
409 0 : return writeError(TLF("Could not build % in netedit; doesn't exist a % parent with ID '%'.", toString(tag), parseParentTags(parentTags), parentID));
410 : }
411 : }
412 :
413 :
414 : bool
415 0 : CommonHandler::writeErrorInvalidParent(const SumoXMLTag tag, const std::vector<SumoXMLTag> parentTags) {
416 0 : if (parentTags.size() == 1) {
417 0 : return writeError(TLF("Could not build % in netedit; % parent doesn't exist.", toString(tag), toString(parentTags.front())));
418 : } else {
419 0 : return writeError(TLF("Could not build % in netedit; doesn't exist a % parent.", toString(tag), parseParentTags(parentTags)));
420 : }
421 : }
422 :
423 :
424 : std::string
425 0 : CommonHandler::parseParentTags(std::vector<SumoXMLTag> parentTags) const {
426 : std::string parentTagsStr;
427 : // Join all but the last with ", ", then add " or " + last
428 : std::string result;
429 0 : for (int i = 0; i < ((int)parentTags.size() - 1); i++) {
430 0 : if (i != 0) {
431 0 : result.append(", ");
432 : }
433 0 : result.append(toString(parentTags[i]));
434 : }
435 0 : result.append(TL(" or "));
436 0 : result.append(toString(parentTags.back()));
437 0 : return result;
438 : }
439 :
440 : /****************************************************************************/
|