1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file GNEFrame.cpp
11 /// @author Pablo Alvarez Lopez
12 /// @date Jun 2016
13 /// @version $Id$
14 ///
15 // The Widget for add additional elements
16 /****************************************************************************/
17
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21
22 #include <config.h>
23
24 #include <netedit/GNENet.h>
25 #include <netedit/GNEUndoList.h>
26 #include <netedit/GNEViewNet.h>
27 #include <netedit/GNEViewParent.h>
28 #include <netedit/additionals/GNEAdditional.h>
29 #include <netedit/additionals/GNEPOI.h>
30 #include <netedit/demandelements/GNEDemandElement.h>
31 #include <netedit/dialogs/GNEDialog_AllowDisallow.h>
32 #include <netedit/dialogs/GNEGenericParameterDialog.h>
33 #include <netedit/netelements/GNEConnection.h>
34 #include <netedit/netelements/GNECrossing.h>
35 #include <netedit/netelements/GNEEdge.h>
36 #include <netedit/netelements/GNEJunction.h>
37 #include <netedit/netelements/GNELane.h>
38 #include <utils/common/StringTokenizer.h>
39 #include <utils/foxtools/MFXMenuHeader.h>
40 #include <utils/foxtools/MFXUtils.h>
41 #include <utils/gui/div/GUIDesigns.h>
42 #include <utils/gui/images/GUIIconSubSys.h>
43 #include <utils/gui/images/GUITexturesHelper.h>
44 #include <utils/gui/windows/GUIAppEnum.h>
45 #include <utils/gui/windows/GUIMainWindow.h>
46
47 #include "GNEFrame.h"
48 #include "GNEInspectorFrame.h"
49 #include "GNEDeleteFrame.h"
50
51
52 // ===========================================================================
53 // FOX callback mapping
54 // ===========================================================================
55
56 FXDEFMAP(GNEFrame::ItemSelector) ItemSelectorMap[] = {
57 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_TYPE, GNEFrame::ItemSelector::onCmdSelectItem)
58 };
59
60 FXDEFMAP(GNEFrame::AttributesCreator) AttributesCreatorMap[] = {
61 FXMAPFUNC(SEL_COMMAND, MID_HELP, GNEFrame::AttributesCreator::onCmdHelp)
62 };
63
64 FXDEFMAP(GNEFrame::AttributesCreator::RowCreator) RowCreatorMap[] = {
65 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_TEXT, GNEFrame::AttributesCreator::RowCreator::onCmdSetAttribute),
66 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_BOOL, GNEFrame::AttributesCreator::RowCreator::onCmdSetBooleanAttribute),
67 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_DIALOG, GNEFrame::AttributesCreator::RowCreator::onCmdSetColorAttribute),
68 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_RADIOBUTTON, GNEFrame::AttributesCreator::RowCreator::onCmdSelectRadioButton)
69 };
70
71 FXDEFMAP(GNEFrame::AttributesEditor) AttributesEditorMap[] = {
72 FXMAPFUNC(SEL_COMMAND, MID_HELP, GNEFrame::AttributesEditor::onCmdAttributesEditorHelp)
73 };
74
75 FXDEFMAP(GNEFrame::AttributesEditor::RowEditor) RowEditorMap[] = {
76 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE, GNEFrame::AttributesEditor::RowEditor::onCmdSetAttribute),
77 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_DIALOG, GNEFrame::AttributesEditor::RowEditor::onCmdOpenAttributeDialog),
78 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_RADIOBUTTON, GNEFrame::AttributesEditor::RowEditor::onCmdSetDisjointAttribute)
79 };
80
81 FXDEFMAP(GNEFrame::AttributesEditorExtended) AttributesEditorExtendedMap[] = {
82 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_DIALOG, GNEFrame::AttributesEditorExtended::onCmdOpenDialog)
83 };
84
85 FXDEFMAP(GNEFrame::ACHierarchy) ACHierarchyMap[] = {
86 FXMAPFUNC(SEL_COMMAND, MID_GNE_INSPECTORFRAME_CENTER, GNEFrame::ACHierarchy::onCmdCenterItem),
87 FXMAPFUNC(SEL_COMMAND, MID_GNE_INSPECTORFRAME_INSPECT, GNEFrame::ACHierarchy::onCmdInspectItem),
88 FXMAPFUNC(SEL_COMMAND, MID_GNE_INSPECTORFRAME_DELETE, GNEFrame::ACHierarchy::onCmdDeleteItem),
89 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, MID_GNE_DELETEFRAME_CHILDS, GNEFrame::ACHierarchy::onCmdShowChildMenu)
90 };
91
92 FXDEFMAP(GNEFrame::GenericParametersEditor) GenericParametersEditorMap[] = {
93 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_DIALOG, GNEFrame::GenericParametersEditor::onCmdEditGenericParameter),
94 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE, GNEFrame::GenericParametersEditor::onCmdSetGenericParameter)
95 };
96
97 FXDEFMAP(GNEFrame::DrawingShape) DrawingShapeMap[] = {
98 FXMAPFUNC(SEL_COMMAND, MID_GNE_STARTDRAWING, GNEFrame::DrawingShape::onCmdStartDrawing),
99 FXMAPFUNC(SEL_COMMAND, MID_GNE_STOPDRAWING, GNEFrame::DrawingShape::onCmdStopDrawing),
100 FXMAPFUNC(SEL_COMMAND, MID_GNE_ABORTDRAWING, GNEFrame::DrawingShape::onCmdAbortDrawing)
101 };
102
103 FXDEFMAP(GNEFrame::NeteditAttributes) NeteditAttributesMap[] = {
104 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE, GNEFrame::NeteditAttributes::onCmdSetNeteditAttribute),
105 FXMAPFUNC(SEL_COMMAND, MID_HELP, GNEFrame::NeteditAttributes::onCmdHelp)
106 };
107
108 // Object implementation
109 FXIMPLEMENT(GNEFrame::ItemSelector, FXGroupBox, ItemSelectorMap, ARRAYNUMBER(ItemSelectorMap))
110 FXIMPLEMENT(GNEFrame::AttributesCreator, FXGroupBox, AttributesCreatorMap, ARRAYNUMBER(AttributesCreatorMap))
111 FXIMPLEMENT(GNEFrame::AttributesCreator::RowCreator, FXHorizontalFrame, RowCreatorMap, ARRAYNUMBER(RowCreatorMap))
112 FXIMPLEMENT(GNEFrame::AttributesEditor, FXGroupBox, AttributesEditorMap, ARRAYNUMBER(AttributesEditorMap))
113 FXIMPLEMENT(GNEFrame::AttributesEditor::RowEditor, FXHorizontalFrame, RowEditorMap, ARRAYNUMBER(RowEditorMap))
114 FXIMPLEMENT(GNEFrame::AttributesEditorExtended, FXGroupBox, AttributesEditorExtendedMap, ARRAYNUMBER(AttributesEditorExtendedMap))
115 FXIMPLEMENT(GNEFrame::ACHierarchy, FXGroupBox, ACHierarchyMap, ARRAYNUMBER(ACHierarchyMap))
116 FXIMPLEMENT(GNEFrame::GenericParametersEditor, FXGroupBox, GenericParametersEditorMap, ARRAYNUMBER(GenericParametersEditorMap))
117 FXIMPLEMENT(GNEFrame::DrawingShape, FXGroupBox, DrawingShapeMap, ARRAYNUMBER(DrawingShapeMap))
118 FXIMPLEMENT(GNEFrame::NeteditAttributes, FXGroupBox, NeteditAttributesMap, ARRAYNUMBER(NeteditAttributesMap))
119
120 // ===========================================================================
121 // static members
122 // ===========================================================================
123
124 FXFont* GNEFrame::myFrameHeaderFont = nullptr;
125
126 // ===========================================================================
127 // method definitions
128 // ===========================================================================
129
130 // ---------------------------------------------------------------------------
131 // GNEFrame::ItemSelector - methods
132 // ---------------------------------------------------------------------------
133
ItemSelector(GNEFrame * frameParent,GNEAttributeCarrier::TagType type,bool onlyDrawables)134 GNEFrame::ItemSelector::ItemSelector(GNEFrame* frameParent, GNEAttributeCarrier::TagType type, bool onlyDrawables) :
135 FXGroupBox(frameParent->myContentFrame, "Element", GUIDesignGroupBoxFrame),
136 myFrameParent(frameParent) {
137 // first check that property is valid
138 switch (type) {
139 case GNEAttributeCarrier::TagType::TAGTYPE_NETELEMENT:
140 setText("Net element");
141 break;
142 case GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL:
143 setText("Additional element");
144 break;
145 case GNEAttributeCarrier::TagType::TAGTYPE_SHAPE:
146 setText("Shape element");
147 break;
148 case GNEAttributeCarrier::TagType::TAGTYPE_TAZ:
149 setText("TAZ element");
150 break;
151 case GNEAttributeCarrier::TagType::TAGTYPE_VEHICLE:
152 setText("Vehicle");
153 break;
154 case GNEAttributeCarrier::TagType::TAGTYPE_STOP:
155 setText("Stop");
156 break;
157 default:
158 throw ProcessError("invalid tag property");
159 }
160 // fill myListOfTags
161 myListOfTags = GNEAttributeCarrier::allowedTagsByCategory(type, onlyDrawables);
162 // Create FXComboBox
163 myTypeMatchBox = new FXComboBox(this, GUIDesignComboBoxNCol, this, MID_GNE_SET_TYPE, GUIDesignComboBox);
164 // fill myTypeMatchBox with list of tags
165 for (const auto& i : myListOfTags) {
166 myTypeMatchBox->appendItem(toString(i).c_str());
167 }
168 // Set visible items
169 myTypeMatchBox->setNumVisible((int)myTypeMatchBox->getNumItems());
170 // ItemSelector is always shown
171 show();
172 }
173
174
~ItemSelector()175 GNEFrame::ItemSelector::~ItemSelector() {}
176
177
178 void
showItemSelector(bool enableModuls)179 GNEFrame::ItemSelector::showItemSelector(bool enableModuls) {
180 show();
181 // check if parent moduls has to be enabled
182 if (enableModuls && (myCurrentTagProperties.getTag() != SUMO_TAG_NOTHING)) {
183 myFrameParent->enableModuls(myCurrentTagProperties);
184 }
185 }
186
187
188 void
hideItemSelector()189 GNEFrame::ItemSelector::hideItemSelector() {
190 hide();
191 myFrameParent->disableModuls();
192 }
193
194
195 const GNEAttributeCarrier::TagProperties&
getCurrentTagProperties() const196 GNEFrame::ItemSelector::getCurrentTagProperties() const {
197 return myCurrentTagProperties;
198 }
199
200
201 void
setCurrentTypeTag(SumoXMLTag typeTag)202 GNEFrame::ItemSelector::setCurrentTypeTag(SumoXMLTag typeTag) {
203 // set empty tag properties
204 myCurrentTagProperties = GNEAttributeCarrier::TagProperties();
205 // make sure that tag is in myTypeMatchBox
206 for (int i = 0; i < (int)myTypeMatchBox->getNumItems(); i++) {
207 if (myTypeMatchBox->getItem(i).text() == toString(typeTag)) {
208 myTypeMatchBox->setCurrentItem(i);
209 // Set new current type
210 myCurrentTagProperties = GNEAttributeCarrier::getTagProperties(typeTag);
211 }
212 }
213 // Check that typeTag type is valid
214 if (myCurrentTagProperties.getTag() != SUMO_TAG_NOTHING) {
215 // show moduls if selected item is valid
216 myFrameParent->enableModuls(myCurrentTagProperties);
217 } else {
218 // hide all moduls if selected item isn't valid
219 myFrameParent->disableModuls();
220 }
221 }
222
223
224 void
refreshTagProperties()225 GNEFrame::ItemSelector::refreshTagProperties() {
226 // simply call onCmdSelectItem (to avoid duplicated code)
227 onCmdSelectItem(0, 0, 0);
228 }
229
230
231 long
onCmdSelectItem(FXObject *,FXSelector,void *)232 GNEFrame::ItemSelector::onCmdSelectItem(FXObject*, FXSelector, void*) {
233 // Check if value of myTypeMatchBox correspond of an allowed additional tags
234 for (const auto& i : myListOfTags) {
235 if (toString(i) == myTypeMatchBox->getText().text()) {
236 // set color of myTypeMatchBox to black (valid)
237 myTypeMatchBox->setTextColor(FXRGB(0, 0, 0));
238 // Set new current type
239 myCurrentTagProperties = GNEAttributeCarrier::getTagProperties(i);
240 // show moduls if selected item is valid
241 myFrameParent->enableModuls(myCurrentTagProperties);
242 // Write Warning in console if we're in testing mode
243 WRITE_DEBUG(("Selected item '" + myTypeMatchBox->getText() + "' in ItemSelector").text());
244 return 1;
245 }
246 }
247 // if additional name isn't correct, set SUMO_TAG_NOTHING as current type
248 myCurrentTagProperties = myInvalidTagProperty;
249 // hide all moduls if selected item isn't valid
250 myFrameParent->disableModuls();
251 // set color of myTypeMatchBox to red (invalid)
252 myTypeMatchBox->setTextColor(FXRGB(255, 0, 0));
253 // Write Warning in console if we're in testing mode
254 WRITE_DEBUG("Selected invalid item in ItemSelector");
255 return 1;
256 }
257
258 // ---------------------------------------------------------------------------
259 // GNEFrame::NeteditAttributes- methods
260 // ---------------------------------------------------------------------------
261
AttributesCreator(GNEFrame * frameParent)262 GNEFrame::AttributesCreator::AttributesCreator(GNEFrame* frameParent) :
263 FXGroupBox(frameParent->myContentFrame, "Internal attributes", GUIDesignGroupBoxFrame),
264 myFrameParent(frameParent) {
265 // Create single parameters
266 for (int i = 0; i < GNEAttributeCarrier::getHigherNumberOfAttributes(); i++) {
267 myRows.push_back(new RowCreator(this));
268 }
269 // Create help button
270 new FXButton(this, "Help", nullptr, this, MID_HELP, GUIDesignButtonRectangular);
271 }
272
273
~AttributesCreator()274 GNEFrame::AttributesCreator::~AttributesCreator() {
275 }
276
277
278 void
showAttributesCreatorModul(const GNEAttributeCarrier::TagProperties & tagProperties)279 GNEFrame::AttributesCreator::showAttributesCreatorModul(const GNEAttributeCarrier::TagProperties& tagProperties) {
280 // get current tag Properties
281 myTagProperties = tagProperties;
282 // Hide all fields
283 for (int i = 0; i < (int)myRows.size(); i++) {
284 myRows.at(i)->hideParameter();
285 }
286 // iterate over tag attributes and show it
287 for (auto i : myTagProperties) {
288 // make sure that only non-unique attributes are shown (And depending of includeExtendedAttributes)
289 if (!i.second.isUnique()) {
290 myRows.at(i.second.getPositionListed())->showParameter(i.second);
291 }
292 }
293 // update disjoint attributes
294 updateDisjointAttributes(nullptr);
295 // recalc frame and show again
296 recalc();
297 show();
298 }
299
300
301 void
hideAttributesCreatorModul()302 GNEFrame::AttributesCreator::hideAttributesCreatorModul() {
303 hide();
304 }
305
306
307 std::map<SumoXMLAttr, std::string>
getAttributesAndValues(bool includeAll) const308 GNEFrame::AttributesCreator::getAttributesAndValues(bool includeAll) const {
309 std::map<SumoXMLAttr, std::string> values;
310 // get standard parameters
311 for (int i = 0; i < (int)myRows.size(); i++) {
312 if (myRows.at(i)->getAttrProperties().getAttr() != SUMO_ATTR_NOTHING) {
313 // ignore default values (except for disjont attributes, that has to be always writted)
314 if (myRows.at(i)->isRowEnabled() &&
315 (includeAll || myTagProperties.isDisjointAttributes(myRows.at(i)->getAttrProperties().getAttr()) || !myRows.at(i)->getAttrProperties().hasDefaultValue() || (myRows.at(i)->getAttrProperties().getDefaultValue() != myRows.at(i)->getValue()))) {
316 values[myRows.at(i)->getAttrProperties().getAttr()] = myRows.at(i)->getValue();
317 }
318 }
319 }
320 return values;
321 }
322
323
324 void
showWarningMessage(std::string extra) const325 GNEFrame::AttributesCreator::showWarningMessage(std::string extra) const {
326 std::string errorMessage;
327 // iterate over standar parameters
328 for (auto i : myTagProperties) {
329 if (errorMessage.empty()) {
330 // Return string with the error if at least one of the parameter isn't valid
331 std::string attributeValue = myRows.at(i.second.getPositionListed())->isAttributeValid();
332 if (attributeValue.size() != 0) {
333 errorMessage = attributeValue;
334 }
335 }
336 }
337 // show warning box if input parameters aren't invalid
338 if (extra.size() == 0) {
339 errorMessage = "Invalid input parameter of " + myTagProperties.getTagStr() + ": " + errorMessage;
340 } else {
341 errorMessage = "Invalid input parameter of " + myTagProperties.getTagStr() + ": " + extra;
342 }
343
344 // set message in status bar
345 myFrameParent->getViewNet()->setStatusBarText(errorMessage);
346 // Write Warning in console if we're in testing mode
347 WRITE_DEBUG(errorMessage);
348 }
349
350
351 bool
areValuesValid() const352 GNEFrame::AttributesCreator::areValuesValid() const {
353 // iterate over standar parameters
354 for (auto i : myTagProperties) {
355 // Return false if error message of attriuve isn't empty
356 if (myRows.at(i.second.getPositionListed())->isAttributeValid().size() != 0) {
357 return false;
358 }
359 }
360 return true;
361 }
362
363
364 void
updateDisjointAttributes(AttributesCreator::RowCreator * row)365 GNEFrame::AttributesCreator::updateDisjointAttributes(AttributesCreator::RowCreator* row) {
366 // currently only Flows supports disjoint attributes
367 if (myTagProperties.getTag() == SUMO_TAG_FLOW) {
368 // obtain all rows (to improve code legibility)
369 RowCreator* endRow = myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_END).getPositionListed()];
370 RowCreator* numberRow = myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_NUMBER).getPositionListed()];
371 RowCreator* vehsperhourRow = myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_VEHSPERHOUR).getPositionListed()];
372 RowCreator* periodRow = myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_PERIOD).getPositionListed()];
373 RowCreator* probabilityRow = myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_PROB).getPositionListed()];
374 if (row == nullptr) {
375 // by default flows uses end and number
376 endRow->setRadioButtonCheck(true);
377 numberRow->setRadioButtonCheck(true);
378 vehsperhourRow->setRadioButtonCheck(false);
379 periodRow->setRadioButtonCheck(false);
380 probabilityRow->setRadioButtonCheck(false);
381 } else {
382 // check what row was clicked
383 switch (row->getAttrProperties().getAttr()) {
384 // end has more priority as number
385 case SUMO_ATTR_END:
386 endRow->setRadioButtonCheck(true);
387 // disable other combinations
388 vehsperhourRow->setRadioButtonCheck(false);
389 periodRow->setRadioButtonCheck(false);
390 probabilityRow->setRadioButtonCheck(false);
391 break;
392 case SUMO_ATTR_NUMBER:
393 numberRow->setRadioButtonCheck(true);
394 // disable number if begin and end are enabled because end has more priority as number
395 if (endRow->getRadioButtonCheck()) {
396 endRow->setRadioButtonCheck(false);
397 } else {
398 // disable other combinations
399 vehsperhourRow->setRadioButtonCheck(false);
400 periodRow->setRadioButtonCheck(false);
401 probabilityRow->setRadioButtonCheck(false);
402 }
403 break;
404 case SUMO_ATTR_VEHSPERHOUR:
405 // disable number if begin and end are enabled because end has more priority as number
406 if (endRow->getRadioButtonCheck() && numberRow->getRadioButtonCheck()) {
407 numberRow->setRadioButtonCheck(false);
408 }
409 // disable other combinations
410 vehsperhourRow->setRadioButtonCheck(true);
411 periodRow->setRadioButtonCheck(false);
412 probabilityRow->setRadioButtonCheck(false);
413 break;
414 case SUMO_ATTR_PERIOD:
415 // disable number if begin and end are enabled because end has more priority as number
416 if (endRow->getRadioButtonCheck() && numberRow->getRadioButtonCheck()) {
417 numberRow->setRadioButtonCheck(false);
418 }
419 // disable other combinations
420 vehsperhourRow->setRadioButtonCheck(false);
421 periodRow->setRadioButtonCheck(true);
422 probabilityRow->setRadioButtonCheck(false);
423 break;
424 case SUMO_ATTR_PROB:
425 // disable number if begin and end are enabled because end has more priority as number
426 if (endRow->getRadioButtonCheck() && numberRow->getRadioButtonCheck()) {
427 numberRow->setRadioButtonCheck(false);
428 }
429 // disable other combinations
430 vehsperhourRow->setRadioButtonCheck(false);
431 periodRow->setRadioButtonCheck(false);
432 probabilityRow->setRadioButtonCheck(true);
433 break;
434 default:
435 break;
436 }
437 }
438 } else if (myTagProperties.isStop()) {
439 // check if expected has to be enabled or disabled
440 if (myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_TRIGGERED).getPositionListed()]->getValue() == "1") {
441 myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_EXPECTED).getPositionListed()]->enableRow();
442 } else {
443 myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_EXPECTED).getPositionListed()]->disableRow();
444 }
445 // check if expected contaienrs has to be enabled or disabled
446 if (myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_CONTAINER_TRIGGERED).getPositionListed()]->getValue() == "1") {
447 myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_EXPECTED_CONTAINERS).getPositionListed()]->enableRow();
448 } else {
449 myRows[myTagProperties.getAttributeProperties(SUMO_ATTR_EXPECTED_CONTAINERS).getPositionListed()]->disableRow();
450 }
451 }
452 }
453
454
455 long
onCmdHelp(FXObject *,FXSelector,void *)456 GNEFrame::AttributesCreator::onCmdHelp(FXObject*, FXSelector, void*) {
457 // open Help attributes dialog
458 myFrameParent->openHelpAttributesDialog(myTagProperties);
459 return 1;
460 }
461
462 // ---------------------------------------------------------------------------
463 // GNEFrame::AttributesCreator::RowCreator - methods
464 // ---------------------------------------------------------------------------
465
RowCreator(AttributesCreator * AttributesCreatorParent)466 GNEFrame::AttributesCreator::RowCreator::RowCreator(AttributesCreator* AttributesCreatorParent) :
467 FXHorizontalFrame(AttributesCreatorParent, GUIDesignAuxiliarHorizontalFrame),
468 myAttributesCreatorParent(AttributesCreatorParent) {
469 // Create left visual elements
470 myLabel = new FXLabel(this, "name", nullptr, GUIDesignLabelAttribute);
471 myColorEditor = new FXButton(this, "ColorButton", nullptr, this, MID_GNE_SET_ATTRIBUTE_DIALOG, GUIDesignButtonAttribute);
472 myRadioButton = new FXRadioButton(this, "name", this, MID_GNE_SET_ATTRIBUTE_RADIOBUTTON, GUIDesignRadioButtonAttribute);
473 // Create right visual elements
474 myTextFieldInt = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE_TEXT, GUIDesignTextFieldInt);
475 myTextFieldReal = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE_TEXT, GUIDesignTextFieldReal);
476 myTextFieldStrings = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE_TEXT, GUIDesignTextField);
477 myBoolCheckButton = new FXCheckButton(this, "Disabled", this, MID_GNE_SET_ATTRIBUTE_BOOL, GUIDesignCheckButtonAttribute);
478 // Hide elements
479 hideParameter();
480 }
481
482
483 void
showParameter(const GNEAttributeCarrier::AttributeProperties & attrProperties)484 GNEFrame::AttributesCreator::RowCreator::showParameter(const GNEAttributeCarrier::AttributeProperties& attrProperties) {
485 myAttrProperties = attrProperties;
486 myInvalidValue = "";
487 // show label, button for edit colors or radio button
488 if (myAttrProperties.isColor()) {
489 myColorEditor->setTextColor(FXRGB(0, 0, 0));
490 myColorEditor->setText(myAttrProperties.getAttrStr().c_str());
491 myColorEditor->show();
492 } else if (myAttributesCreatorParent->myTagProperties.isDisjointAttributes(myAttrProperties.getAttr())) {
493 myRadioButton->setText(myAttrProperties.getAttrStr().c_str());
494 myRadioButton->show();
495 } else {
496 myLabel->setText(myAttrProperties.getAttrStr().c_str());
497 myLabel->show();
498 }
499 if (myAttrProperties.isInt()) {
500 myTextFieldInt->setTextColor(FXRGB(0, 0, 0));
501 myTextFieldInt->setText(attrProperties.getDefaultValue().c_str());
502 myTextFieldInt->show();
503 // if it's associated to a radio button and is disabled, then disabled myTextFieldInt
504 if (myRadioButton->shown() && (myRadioButton->getCheck() == FALSE)) {
505 myTextFieldInt->disable();
506 }
507 } else if (myAttrProperties.isFloat()) {
508 myTextFieldReal->setTextColor(FXRGB(0, 0, 0));
509 myTextFieldReal->setText(attrProperties.getDefaultValue().c_str());
510 myTextFieldReal->show();
511 // if it's associated to a radio button and is disabled, then disable myTextFieldReal
512 if (myRadioButton->shown() && (myRadioButton->getCheck() == FALSE)) {
513 myTextFieldReal->disable();
514 }
515 } else if (myAttrProperties.isBool()) {
516 if (GNEAttributeCarrier::parse<bool>(attrProperties.getDefaultValue())) {
517 myBoolCheckButton->setCheck(true);
518 myBoolCheckButton->setText("true");
519 } else {
520 myBoolCheckButton->setCheck(false);
521 myBoolCheckButton->setText("false");
522 }
523 myBoolCheckButton->show();
524 // if it's associated to a radio button and is disabled, then disable myBoolCheckButton
525 if (myRadioButton->shown() && (myRadioButton->getCheck() == FALSE)) {
526 myBoolCheckButton->disable();
527 }
528 } else {
529 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
530 myTextFieldStrings->setText(attrProperties.getDefaultValue().c_str());
531 myTextFieldStrings->show();
532 // if it's associated to a radio button and is disabled, then disable myTextFieldStrings
533 if (myRadioButton->shown() && (myRadioButton->getCheck() == FALSE)) {
534 myTextFieldStrings->disable();
535 }
536 }
537 show();
538 }
539
540
541 void
hideParameter()542 GNEFrame::AttributesCreator::RowCreator::hideParameter() {
543 myAttrProperties = GNEAttributeCarrier::AttributeProperties();
544 myLabel->hide();
545 myTextFieldInt->hide();
546 myTextFieldReal->hide();
547 myTextFieldStrings->hide();
548 myBoolCheckButton->hide();
549 myColorEditor->hide();
550 myRadioButton->hide();
551 hide();
552 }
553
554
555 const GNEAttributeCarrier::AttributeProperties&
getAttrProperties() const556 GNEFrame::AttributesCreator::RowCreator::getAttrProperties() const {
557 return myAttrProperties;
558 }
559
560
561 std::string
getValue() const562 GNEFrame::AttributesCreator::RowCreator::getValue() const {
563 if (myAttrProperties.isBool()) {
564 return (myBoolCheckButton->getCheck() == 1) ? "1" : "0";
565 } else if (myAttrProperties.isInt()) {
566 return myTextFieldInt->getText().text();
567 } else if (myAttrProperties.isFloat() || myAttrProperties.isTime()) {
568 return myTextFieldReal->getText().text();
569 } else {
570 return myTextFieldStrings->getText().text();
571 }
572 }
573
574
575 bool
getRadioButtonCheck() const576 GNEFrame::AttributesCreator::RowCreator::getRadioButtonCheck() const {
577 if (shown()) {
578 return myRadioButton->getCheck() == TRUE;
579 } else {
580 return false;
581 }
582 }
583
584
585 void
setRadioButtonCheck(bool value)586 GNEFrame::AttributesCreator::RowCreator::setRadioButtonCheck(bool value) {
587 if (shown()) {
588 // set radio button
589 myRadioButton->setCheck(value);
590 // enable or disable input fields
591 if (value) {
592 if (myAttrProperties.isBool()) {
593 myBoolCheckButton->enable();
594 } else if (myAttrProperties.isInt()) {
595 myTextFieldInt->enable();
596 } else if (myAttrProperties.isFloat() || myAttrProperties.isTime()) {
597 myTextFieldReal->enable();
598 } else {
599 myTextFieldStrings->enable();
600 }
601 } else {
602 if (myAttrProperties.isBool()) {
603 myBoolCheckButton->disable();
604 } else if (myAttrProperties.isInt()) {
605 myTextFieldInt->disable();
606 } else if (myAttrProperties.isFloat() || myAttrProperties.isTime()) {
607 myTextFieldReal->disable();
608 } else {
609 myTextFieldStrings->disable();
610 }
611 }
612 }
613 }
614
615
616 void
enableRow()617 GNEFrame::AttributesCreator::RowCreator::enableRow() {
618 if (myAttrProperties.isBool()) {
619 return myBoolCheckButton->enable();
620 } else if (myAttrProperties.isInt()) {
621 return myTextFieldInt->enable();
622 } else if (myAttrProperties.isFloat() || myAttrProperties.isTime()) {
623 return myTextFieldReal->enable();
624 } else {
625 return myTextFieldStrings->enable();
626 }
627 }
628
629
630 void
disableRow()631 GNEFrame::AttributesCreator::RowCreator::disableRow() {
632 if (myAttrProperties.isBool()) {
633 return myBoolCheckButton->disable();
634 } else if (myAttrProperties.isInt()) {
635 return myTextFieldInt->disable();
636 } else if (myAttrProperties.isFloat() || myAttrProperties.isTime()) {
637 return myTextFieldReal->disable();
638 } else {
639 return myTextFieldStrings->disable();
640 }
641 }
642
643
644 bool
isRowEnabled() const645 GNEFrame::AttributesCreator::RowCreator::isRowEnabled() const {
646 if (!shown()) {
647 return false;
648 } else if (myAttrProperties.isBool()) {
649 return myBoolCheckButton->isEnabled();
650 } else if (myAttrProperties.isInt()) {
651 return myTextFieldInt->isEnabled();
652 } else if (myAttrProperties.isFloat() || myAttrProperties.isTime()) {
653 return myTextFieldReal->isEnabled();
654 } else {
655 return myTextFieldStrings->isEnabled();
656 }
657 }
658
659
660 const std::string&
isAttributeValid() const661 GNEFrame::AttributesCreator::RowCreator::isAttributeValid() const {
662 return myInvalidValue;
663 }
664
665
666 GNEFrame::AttributesCreator*
getAttributesCreatorParent() const667 GNEFrame::AttributesCreator::RowCreator::getAttributesCreatorParent() const {
668 return myAttributesCreatorParent;
669 }
670
671
672 long
onCmdSetAttribute(FXObject *,FXSelector,void *)673 GNEFrame::AttributesCreator::RowCreator::onCmdSetAttribute(FXObject*, FXSelector, void*) {
674 // We assume that current value is valid
675 myInvalidValue = "";
676 // Check if format of current value of myTextField is correct
677 if (myAttrProperties.isInt()) {
678 if (GNEAttributeCarrier::canParse<int>(myTextFieldInt->getText().text())) {
679 // convert string to int
680 int intValue = GNEAttributeCarrier::parse<int>(myTextFieldInt->getText().text());
681 // Check if int value must be positive
682 if (myAttrProperties.isPositive() && (intValue < 0)) {
683 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' cannot be negative";
684 }
685 } else {
686 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' doesn't have a valid 'int' format";
687 }
688 } else if (myAttrProperties.isTime()) {
689 // time attributes work as positive doubles
690 if (GNEAttributeCarrier::canParse<double>(myTextFieldReal->getText().text())) {
691 // convert string to double
692 double doubleValue = GNEAttributeCarrier::parse<double>(myTextFieldReal->getText().text());
693 // Check if parsed value is negative
694 if (doubleValue < 0) {
695 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' cannot be negative";
696 }
697 } else {
698 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' doesn't have a valid 'time' format";
699 }
700 } else if (myAttrProperties.isFloat()) {
701 if (GNEAttributeCarrier::canParse<double>(myTextFieldReal->getText().text())) {
702 // convert string to double
703 double doubleValue = GNEAttributeCarrier::parse<double>(myTextFieldReal->getText().text());
704 // Check if double value must be positive
705 if (myAttrProperties.isPositive() && (doubleValue < 0)) {
706 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' cannot be negative";
707 // check if double value is a probability
708 } else if (myAttrProperties.isProbability() && ((doubleValue < 0) || doubleValue > 1)) {
709 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' takes only values between 0 and 1";
710 } else if (myAttrProperties.hasAttrRange() && ((doubleValue < myAttrProperties.getMinimumRange()) || doubleValue > myAttrProperties.getMaximumRange())) {
711 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' takes only values between " + toString(myAttrProperties.getMinimumRange()) + " and " + toString(myAttrProperties.getMaximumRange());
712 } else if ((myAttributesCreatorParent->myTagProperties.getTag() == SUMO_TAG_E2DETECTOR) && (myAttrProperties.getAttr() == SUMO_ATTR_LENGTH) && (doubleValue == 0)) {
713 myInvalidValue = "E2 length cannot be 0";
714 }
715 } else {
716 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' doesn't have a valid 'float' format";
717 }
718 } else if (myAttrProperties.isColor()) {
719 // check if filename format is valid
720 if (GNEAttributeCarrier::canParse<RGBColor>(myTextFieldStrings->getText().text()) == false) {
721 myInvalidValue = "'" + myAttrProperties.getAttrStr() + "' doesn't have a valid 'RBGColor' format";
722 }
723 } else if (myAttrProperties.isFilename()) {
724 std::string file = myTextFieldStrings->getText().text();
725 // check if filename format is valid
726 if (SUMOXMLDefinitions::isValidFilename(file) == false) {
727 myInvalidValue = "input contains invalid characters for a filename";
728 } else if (myAttrProperties.getAttr() == SUMO_ATTR_IMGFILE) {
729 if (!file.empty()) {
730 // only load value if file exist and can be loaded
731 if (GUITexturesHelper::getTextureID(file) == -1) {
732 myInvalidValue = "doesn't exist image '" + file + "'";
733 }
734 }
735 }
736 } else if (myAttrProperties.getAttr() == SUMO_ATTR_NAME) {
737 std::string name = myTextFieldStrings->getText().text();
738 // check if name format is valid
739 if (SUMOXMLDefinitions::isValidAttribute(name) == false) {
740 myInvalidValue = "input contains invalid characters";
741 }
742 } else if (myAttrProperties.getAttr() == SUMO_ATTR_VTYPES) {
743 std::string name = myTextFieldStrings->getText().text();
744 // if list of VTypes isn't empty, check that all characters are valid
745 if (!name.empty() && !SUMOXMLDefinitions::isValidListOfTypeID(name)) {
746 myInvalidValue = "list of IDs contains invalid characters";
747 }
748 } else if (myAttrProperties.getAttr() == SUMO_ATTR_INDEX) {
749 // special case for stop indx
750 std::string index = myTextFieldStrings->getText().text();
751 if ((index != "fit") && (index != "end") && !GNEAttributeCarrier::canParse<int>(index)) {
752 myInvalidValue = "index isn't either 'fit' or 'end' or a valid positive int";
753 } else if (GNEAttributeCarrier::parse<int>(index) < 0) {
754 myInvalidValue = "index cannot be negative";
755 }
756 }
757 // change color of text field depending of myCurrentValueValid
758 if (myInvalidValue.size() == 0) {
759 myTextFieldInt->setTextColor(FXRGB(0, 0, 0));
760 myTextFieldInt->killFocus();
761 myTextFieldReal->setTextColor(FXRGB(0, 0, 0));
762 myTextFieldReal->killFocus();
763 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
764 myTextFieldStrings->killFocus();
765 } else {
766 // IF value of TextField isn't valid, change their color to Red
767 myTextFieldInt->setTextColor(FXRGB(255, 0, 0));
768 myTextFieldReal->setTextColor(FXRGB(255, 0, 0));
769 myTextFieldStrings->setTextColor(FXRGB(255, 0, 0));
770 }
771 // Update aditional frame
772 update();
773 return 1;
774 }
775
776
777 long
onCmdSetBooleanAttribute(FXObject *,FXSelector,void *)778 GNEFrame::AttributesCreator::RowCreator::onCmdSetBooleanAttribute(FXObject*, FXSelector, void*) {
779 if (myBoolCheckButton->getCheck()) {
780 myBoolCheckButton->setText("true");
781 } else {
782 myBoolCheckButton->setText("false");
783 }
784 // update disjoint attribute
785 myAttributesCreatorParent->updateDisjointAttributes(nullptr);
786 return 0;
787 }
788
789
790 long
onCmdSetColorAttribute(FXObject *,FXSelector,void *)791 GNEFrame::AttributesCreator::RowCreator::onCmdSetColorAttribute(FXObject*, FXSelector, void*) {
792 // create FXColorDialog
793 FXColorDialog colordialog(this, tr("Color Dialog"));
794 colordialog.setTarget(this);
795 // If previous attribute wasn't correct, set black as default color
796 if (GNEAttributeCarrier::canParse<RGBColor>(myTextFieldStrings->getText().text())) {
797 colordialog.setRGBA(MFXUtils::getFXColor(RGBColor::parseColor(myTextFieldStrings->getText().text())));
798 } else {
799 colordialog.setRGBA(MFXUtils::getFXColor(RGBColor::parseColor(myAttrProperties.getDefaultValue())));
800 }
801 // execute dialog to get a new color
802 if (colordialog.execute()) {
803 myTextFieldStrings->setText(toString(MFXUtils::getRGBColor(colordialog.getRGBA())).c_str());
804 onCmdSetAttribute(nullptr, 0, nullptr);
805 }
806 return 0;
807 }
808
809 long
onCmdSelectRadioButton(FXObject *,FXSelector,void *)810 GNEFrame::AttributesCreator::RowCreator::onCmdSelectRadioButton(FXObject*, FXSelector, void*) {
811 // write debug (for Netedit tests)
812 WRITE_DEBUG("Selected radio button for attribute '" + myAttrProperties.getAttrStr() + "'");
813 // update disjoint attributes in AC Attributes parent
814 myAttributesCreatorParent->updateDisjointAttributes(this);
815 return 0;
816 }
817
818 // ---------------------------------------------------------------------------
819 // GNEFrame::AttributesEditor::RowEditor - methods
820 // ---------------------------------------------------------------------------
821
RowEditor(GNEFrame::AttributesEditor * attributeEditorParent)822 GNEFrame::AttributesEditor::RowEditor::RowEditor(GNEFrame::AttributesEditor* attributeEditorParent) :
823 FXHorizontalFrame(attributeEditorParent, GUIDesignAuxiliarHorizontalFrame),
824 myAttributesEditorParent(attributeEditorParent),
825 myMultiple(false) {
826 // Create and hide label
827 myLabel = new FXLabel(this, "attributeLabel", nullptr, GUIDesignLabelAttribute);
828 myLabel->hide();
829 // Create and hide radio button
830 myRadioButton = new FXRadioButton(this, "name", this, MID_GNE_SET_ATTRIBUTE_RADIOBUTTON, GUIDesignRadioButtonAttribute);
831 myRadioButton->hide();
832 // Create and hide ButtonCombinableChoices
833 myButtonCombinableChoices = new FXButton(this, "AttributeButton", nullptr, this, MID_GNE_SET_ATTRIBUTE_DIALOG, GUIDesignButtonAttribute);
834 myButtonCombinableChoices->hide();
835 // create and hidde color editor
836 myColorEditor = new FXButton(this, "ColorButton", nullptr, this, MID_GNE_SET_ATTRIBUTE_DIALOG, GUIDesignButtonAttribute);
837 myColorEditor->hide();
838 // Create and hide textField for int attributes
839 myTextFieldInt = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextFieldInt);
840 myTextFieldInt->hide();
841 // Create and hide textField for real/time attributes
842 myTextFieldReal = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextFieldReal);
843 myTextFieldReal->hide();
844 // Create and hide textField for string attributes
845 myTextFieldStrings = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);
846 myTextFieldStrings->hide();
847 // Create and hide ComboBox
848 myChoicesCombo = new FXComboBox(this, GUIDesignComboBoxNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignComboBoxAttribute);
849 myChoicesCombo->hide();
850 // Create and hide checkButton
851 myBoolCheckButton = new FXCheckButton(this, "", this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButtonAttribute);
852 myBoolCheckButton->hide();
853 }
854
855
856 void
showRow(const GNEAttributeCarrier::AttributeProperties & ACAttr,const std::string & value,bool disjointAttributeEnabled)857 GNEFrame::AttributesEditor::RowEditor::showRow(const GNEAttributeCarrier::AttributeProperties& ACAttr, const std::string& value, bool disjointAttributeEnabled) {
858 // start enabling all elements
859 myTextFieldInt->enable();
860 myTextFieldReal->enable();
861 myTextFieldStrings->enable();
862 myChoicesCombo->enable();
863 myBoolCheckButton->enable();
864 myButtonCombinableChoices->enable();
865 myColorEditor->enable();
866 myRadioButton->enable();
867 // Set current Attribute Property
868 myACAttr = ACAttr;
869 // set multiple
870 myMultiple = GNEAttributeCarrier::parse<std::vector<std::string>>(value).size() > 1;
871 if (myACAttr.isColor()) {
872 myColorEditor->setTextColor(FXRGB(0, 0, 0));
873 myColorEditor->setText(myACAttr.getAttrStr().c_str());
874 myColorEditor->show();
875 } else if (myACAttr.getTagPropertyParent().isDisjointAttributes(myACAttr.getAttr())) {
876 myRadioButton->setTextColor(FXRGB(0, 0, 0));
877 myRadioButton->setText(myACAttr.getAttrStr().c_str());
878 myRadioButton->setCheck(disjointAttributeEnabled);
879 myRadioButton->show();
880 } else {
881 // Show attribute Label
882 myLabel->setText(myACAttr.getAttrStr().c_str());
883 myLabel->show();
884 }
885 // Set field depending of the type of value
886 if (myACAttr.isBool()) {
887 // first we need to check if all boolean values are equal
888 bool allBooleanValuesEqual = true;
889 // declare boolean vector
890 std::vector<bool> booleanVector;
891 // check if value can be parsed to a boolean vector
892 if (GNEAttributeCarrier::canParse<std::vector<bool> >(value)) {
893 booleanVector = GNEAttributeCarrier::parse<std::vector<bool> >(value);
894 }
895 // iterate over pased booleans comparing all element with the first
896 for (const auto& i : booleanVector) {
897 if (i != booleanVector.front()) {
898 allBooleanValuesEqual = false;
899 }
900 }
901 // use checkbox or textfield depending if all booleans are equal
902 if (allBooleanValuesEqual) {
903 // set check button
904 if ((booleanVector.size() > 0) && booleanVector.front()) {
905 myBoolCheckButton->setCheck(true);
906 myBoolCheckButton->setText("true");
907 } else {
908 myBoolCheckButton->setCheck(false);
909 myBoolCheckButton->setText("false");
910 }
911 // show check button
912 myBoolCheckButton->show();
913 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
914 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
915 myBoolCheckButton->disable();
916 }
917 } else {
918 // show list of bools (0 1)
919 myTextFieldStrings->setText(value.c_str());
920 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
921 myTextFieldStrings->show();
922 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
923 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
924 myTextFieldStrings->disable();
925 }
926 }
927 } else if (myACAttr.isDiscrete()) {
928 // Check if are combinable choices
929 if ((myACAttr.getDiscreteValues().size() > 0) && myACAttr.isCombinable()) {
930 // hide label
931 myLabel->hide();
932 // Show button combinable choices
933 myButtonCombinableChoices->setText(myACAttr.getAttrStr().c_str());
934 myButtonCombinableChoices->show();
935 // Show string with the values
936 myTextFieldStrings->setText(value.c_str());
937 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
938 myTextFieldStrings->show();
939 } else if (!myMultiple) {
940 // fill comboBox
941 myChoicesCombo->clearItems();
942 for (const auto& it : myACAttr.getDiscreteValues()) {
943 myChoicesCombo->appendItem(it.c_str());
944 }
945 // show combo box with values
946 myChoicesCombo->setNumVisible((int)myACAttr.getDiscreteValues().size());
947 myChoicesCombo->setCurrentItem(myChoicesCombo->findItem(value.c_str()));
948 myChoicesCombo->setTextColor(FXRGB(0, 0, 0));
949 myChoicesCombo->show();
950 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
951 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
952 myChoicesCombo->disable();
953 }
954 } else {
955 // represent combinable choices in multiple selections always with a textfield instead with a comboBox
956 myTextFieldStrings->setText(value.c_str());
957 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
958 myTextFieldStrings->show();
959 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
960 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
961 myTextFieldStrings->disable();
962 }
963 }
964 } else if (myACAttr.isFloat() || myACAttr.isTime()) {
965 // show TextField for real/time values
966 myTextFieldReal->setText(value.c_str());
967 myTextFieldReal->setTextColor(FXRGB(0, 0, 0));
968 myTextFieldReal->show();
969 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
970 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
971 myTextFieldReal->disable();
972 }
973 } else if (myACAttr.isInt()) {
974 // Show textField for int attributes
975 myTextFieldInt->setText(value.c_str());
976 myTextFieldInt->setTextColor(FXRGB(0, 0, 0));
977 myTextFieldInt->show();
978 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
979 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
980 myTextFieldInt->disable();
981 }
982 // we need an extra check for connection attribute "TLIndex", because it cannot be edited if junction's connection doesn' have a TLS
983 if ((myACAttr.getTagPropertyParent().getTag() == SUMO_TAG_CONNECTION) && (myACAttr.getAttr() == SUMO_ATTR_TLLINKINDEX) && (value == "No TLS")) {
984 myTextFieldInt->disable();
985 }
986 } else {
987 // In any other case (String, list, etc.), show value as String
988 myTextFieldStrings->setText(value.c_str());
989 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
990 myTextFieldStrings->show();
991 // enable or disable depending if attribute is editable and is enabled (used by disjoint attributes)
992 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
993 myTextFieldStrings->disable();
994 }
995 }
996 // if Tag correspond to an network element but we're in demand mode (or vice versa), disable all elements
997 if (((myAttributesEditorParent->myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) && myACAttr.getTagPropertyParent().isDemandElement()) ||
998 ((myAttributesEditorParent->myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_DEMAND) && !myACAttr.getTagPropertyParent().isDemandElement())) {
999 myColorEditor->disable();
1000 myRadioButton->disable();
1001 myTextFieldInt->disable();
1002 myTextFieldReal->disable();
1003 myTextFieldStrings->disable();
1004 myChoicesCombo->disable();
1005 myBoolCheckButton->disable();
1006 myButtonCombinableChoices->disable();
1007 }
1008 // special case for Default vehicle types (ID cannot be edited)
1009 if ((ACAttr.getTagPropertyParent().getTag() == SUMO_TAG_VTYPE) && (ACAttr.getAttr() == SUMO_ATTR_ID) &&
1010 ((value == DEFAULT_VTYPE_ID) || (value == DEFAULT_PEDTYPE_ID) || (value == DEFAULT_BIKETYPE_ID))) {
1011 myTextFieldStrings->disable();
1012 }
1013 // Show Row
1014 show();
1015 }
1016
1017
1018 void
hideRow()1019 GNEFrame::AttributesEditor::RowEditor::hideRow() {
1020 // Hide all elements
1021 myLabel->hide();
1022 myColorEditor->hide();
1023 myRadioButton->hide();
1024 myTextFieldInt->hide();
1025 myTextFieldReal->hide();
1026 myTextFieldStrings->hide();
1027 myChoicesCombo->hide();
1028 myBoolCheckButton->hide();
1029 myButtonCombinableChoices->hide();
1030 // hide Row
1031 hide();
1032 // recalc after hide all elements
1033 recalc();
1034 }
1035
1036
1037 void
refreshRow(const std::string & value,bool forceRefresh,bool disjointAttributeEnabled)1038 GNEFrame::AttributesEditor::RowEditor::refreshRow(const std::string& value, bool forceRefresh, bool disjointAttributeEnabled) {
1039 // start enabling all elements
1040 myTextFieldInt->enable();
1041 myTextFieldReal->enable();
1042 myTextFieldStrings->enable();
1043 myChoicesCombo->enable();
1044 myBoolCheckButton->enable();
1045 myButtonCombinableChoices->enable();
1046 myColorEditor->enable();
1047 myRadioButton->enable();
1048 // set radio buton
1049 if (myRadioButton->shown()) {
1050 myRadioButton->setCheck(disjointAttributeEnabled);
1051 }
1052 if (myTextFieldInt->shown()) {
1053 // set last valid value and restore color if onlyValid is disabled
1054 if (myTextFieldInt->getTextColor() == FXRGB(0, 0, 0) || forceRefresh) {
1055 myTextFieldInt->setText(value.c_str());
1056 myTextFieldInt->setTextColor(FXRGB(0, 0, 0));
1057 }
1058 // disable depending of disjointAttributeEnabled
1059 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
1060 myTextFieldInt->disable();
1061 }
1062 } else if (myTextFieldReal->shown()) {
1063 // set last valid value and restore color if onlyValid is disabled
1064 if (myTextFieldReal->getTextColor() == FXRGB(0, 0, 0) || forceRefresh) {
1065 myTextFieldReal->setText(value.c_str());
1066 myTextFieldReal->setTextColor(FXRGB(0, 0, 0));
1067 }
1068 // disable depending of disjointAttributeEnabled
1069 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
1070 myTextFieldReal->disable();
1071 }
1072 } else if (myTextFieldStrings->shown()) {
1073 // set last valid value and restore color if onlyValid is disabled
1074 if (myTextFieldStrings->getTextColor() == FXRGB(0, 0, 0) || forceRefresh) {
1075 myTextFieldStrings->setText(value.c_str());
1076 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
1077 }
1078 // disable depending of disjointAttributeEnabled
1079 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
1080 myTextFieldStrings->disable();
1081 }
1082 } else if (myChoicesCombo->shown()) {
1083 // fill comboBox again
1084 myChoicesCombo->clearItems();
1085 for (const auto& it : myACAttr.getDiscreteValues()) {
1086 myChoicesCombo->appendItem(it.c_str());
1087 }
1088 // show combo box with values
1089 myChoicesCombo->setNumVisible((int)myACAttr.getDiscreteValues().size());
1090 myChoicesCombo->setCurrentItem(myChoicesCombo->findItem(value.c_str()));
1091 myChoicesCombo->setTextColor(FXRGB(0, 0, 0));
1092 myChoicesCombo->show();
1093 // disable depending of disjointAttributeEnabled
1094 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
1095 myChoicesCombo->disable();
1096 }
1097 } else if (myBoolCheckButton->shown()) {
1098 if (GNEAttributeCarrier::canParse<bool>(value)) {
1099 myBoolCheckButton->setCheck(GNEAttributeCarrier::parse<bool>(value));
1100 } else {
1101 myBoolCheckButton->setCheck(false);
1102 }
1103 // disable depending of disjointAttributeEnabled
1104 if (myACAttr.isNonEditable() || !disjointAttributeEnabled) {
1105 myBoolCheckButton->disable();
1106 }
1107 }
1108 // if Tag correspond to an network element but we're in demand mode (or vice versa), disable all elements
1109 if (myACAttr.getAttr() != SUMO_ATTR_NOTHING) {
1110 if (((myAttributesEditorParent->myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) && myACAttr.getTagPropertyParent().isDemandElement()) ||
1111 ((myAttributesEditorParent->myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_DEMAND) && !myACAttr.getTagPropertyParent().isDemandElement())) {
1112 myColorEditor->disable();
1113 myRadioButton->disable();
1114 myTextFieldInt->disable();
1115 myTextFieldReal->disable();
1116 myTextFieldStrings->disable();
1117 myChoicesCombo->disable();
1118 myBoolCheckButton->disable();
1119 myButtonCombinableChoices->disable();
1120 }
1121 // special case for Default vehicle types (ID cannot be edited)
1122 if ((myACAttr.getTagPropertyParent().getTag() == SUMO_TAG_VTYPE) && (myACAttr.getAttr() == SUMO_ATTR_ID) &&
1123 ((value == DEFAULT_VTYPE_ID) || (value == DEFAULT_PEDTYPE_ID) || (value == DEFAULT_BIKETYPE_ID))) {
1124 myTextFieldStrings->disable();
1125 }
1126 }
1127 }
1128
1129
1130 bool
isRowValid() const1131 GNEFrame::AttributesEditor::RowEditor::isRowValid() const {
1132 return ((myTextFieldInt->getTextColor() == FXRGB(0, 0, 0)) && (myTextFieldReal->getTextColor() == FXRGB(0, 0, 0)) &&
1133 (myTextFieldStrings->getTextColor() == FXRGB(0, 0, 0)) && (myChoicesCombo->getTextColor() == FXRGB(0, 0, 0)));
1134 }
1135
1136
1137 long
onCmdOpenAttributeDialog(FXObject * obj,FXSelector,void *)1138 GNEFrame::AttributesEditor::RowEditor::onCmdOpenAttributeDialog(FXObject* obj, FXSelector, void*) {
1139 if (obj == myColorEditor) {
1140 // create FXColorDialog
1141 FXColorDialog colordialog(this, tr("Color Dialog"));
1142 colordialog.setTarget(this);
1143 // If previous attribute wasn't correct, set black as default color
1144 if (GNEAttributeCarrier::canParse<RGBColor>(myTextFieldStrings->getText().text())) {
1145 colordialog.setRGBA(MFXUtils::getFXColor(RGBColor::parseColor(myTextFieldStrings->getText().text())));
1146 } else if (!myACAttr.getDefaultValue().empty()) {
1147 colordialog.setRGBA(MFXUtils::getFXColor(RGBColor::parseColor(myACAttr.getDefaultValue())));
1148 } else {
1149 colordialog.setRGBA(MFXUtils::getFXColor(RGBColor::BLACK));
1150 }
1151 // execute dialog to get a new color
1152 if (colordialog.execute()) {
1153 std::string newValue = toString(MFXUtils::getRGBColor(colordialog.getRGBA()));
1154 myTextFieldStrings->setText(newValue.c_str());
1155 if (myAttributesEditorParent->myEditedACs.front()->isValid(myACAttr.getAttr(), newValue)) {
1156 // if its valid for the first AC than its valid for all (of the same type)
1157 if (myAttributesEditorParent->myEditedACs.size() > 1) {
1158 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_begin("Change multiple attributes");
1159 }
1160 // Set new value of attribute in all selected ACs
1161 for (const auto& it_ac : myAttributesEditorParent->myEditedACs) {
1162 it_ac->setAttribute(myACAttr.getAttr(), newValue, myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList());
1163 }
1164 // If previously value was incorrect, change font color to black
1165 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
1166 myTextFieldStrings->killFocus();
1167 }
1168 }
1169 return 0;
1170 } else if (obj == myButtonCombinableChoices) {
1171 // if its valid for the first AC than its valid for all (of the same type)
1172 if (myAttributesEditorParent->myEditedACs.size() > 1) {
1173 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_begin("Change multiple attributes");
1174 }
1175 // open GNEDialog_AllowDisallow
1176 GNEDialog_AllowDisallow(myAttributesEditorParent->myFrameParent->getViewNet(), myAttributesEditorParent->myEditedACs.front()).execute();
1177 std::string allowed = myAttributesEditorParent->myEditedACs.front()->getAttribute(SUMO_ATTR_ALLOW);
1178 // Set new value of attribute in all selected ACs
1179 for (const auto& it_ac : myAttributesEditorParent->myEditedACs) {
1180 it_ac->setAttribute(SUMO_ATTR_ALLOW, allowed, myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList());
1181 }
1182 // finish change multiple attributes
1183 if (myAttributesEditorParent->myEditedACs.size() > 1) {
1184 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_end();
1185 }
1186 // update frame parent after attribute sucesfully set
1187 myAttributesEditorParent->myFrameParent->updateFrameAfterChangeAttribute();
1188 return 1;
1189 } else {
1190 throw ProcessError("Invalid call to onCmdOpenAttributeDialog");
1191 }
1192 }
1193
1194
1195 long
onCmdSetAttribute(FXObject *,FXSelector,void *)1196 GNEFrame::AttributesEditor::RowEditor::onCmdSetAttribute(FXObject*, FXSelector, void*) {
1197 // Declare changed value
1198 std::string newVal;
1199 // First, obtain the string value of the new attribute depending of their type
1200 if (myACAttr.isBool()) {
1201 // first check if we're editing boolean as a list of string or as a checkbox
1202 if (myBoolCheckButton->shown()) {
1203 // Set true o false depending of the checkBox
1204 if (myBoolCheckButton->getCheck()) {
1205 myBoolCheckButton->setText("true");
1206 newVal = "true";
1207 } else {
1208 myBoolCheckButton->setText("false");
1209 newVal = "false";
1210 }
1211 } else {
1212 // obtain boolean value of myTextFieldStrings (because we're inspecting multiple attribute carriers with different values)
1213 newVal = myTextFieldStrings->getText().text();
1214 }
1215 } else if (myACAttr.isDiscrete()) {
1216 // Check if are combinable choices (for example, Vehicle Types)
1217 if ((myACAttr.getDiscreteValues().size() > 0) &&
1218 myACAttr.isCombinable()) {
1219 // Get value obtained using AttributesEditor
1220 newVal = myTextFieldStrings->getText().text();
1221 } else if (!myMultiple) {
1222 // Get value of ComboBox
1223 newVal = myChoicesCombo->getText().text();
1224 } else {
1225 // due this is a multiple selection, obtain value of myTextFieldStrings instead of comboBox
1226 newVal = myTextFieldStrings->getText().text();
1227 }
1228 } else if (myACAttr.isFloat() || myACAttr.isTime()) {
1229 // Check if default value of attribute must be set
1230 if (myTextFieldReal->getText().empty() && myACAttr.hasDefaultValue()) {
1231 newVal = myACAttr.getDefaultValue();
1232 myTextFieldReal->setText(newVal.c_str());
1233 } else {
1234 // obtain value of myTextFieldReal
1235 newVal = myTextFieldReal->getText().text();
1236 }
1237 } else if (myACAttr.isInt()) {
1238 // Check if default value of attribute must be set
1239 if (myTextFieldInt->getText().empty() && myACAttr.hasDefaultValue()) {
1240 newVal = myACAttr.getDefaultValue();
1241 myTextFieldInt->setText(newVal.c_str());
1242 } else {
1243 // obtain value of myTextFieldInt
1244 newVal = myTextFieldInt->getText().text();
1245 }
1246 } else if (myACAttr.isString()) {
1247 // Check if default value of attribute must be set
1248 if (myTextFieldStrings->getText().empty() && myACAttr.hasDefaultValue()) {
1249 newVal = myACAttr.getDefaultValue();
1250 myTextFieldStrings->setText(newVal.c_str());
1251 } else {
1252 // obtain value of myTextFieldStrings
1253 newVal = myTextFieldStrings->getText().text();
1254 }
1255 }
1256
1257 // we need a extra check for Position and Shape Values, due #2658
1258 if ((myACAttr.getAttr() == SUMO_ATTR_POSITION) || (myACAttr.getAttr() == SUMO_ATTR_SHAPE)) {
1259 newVal = stripWhitespaceAfterComma(newVal);
1260 }
1261
1262 // Check if attribute must be changed
1263 if (myAttributesEditorParent->myEditedACs.front()->isValid(myACAttr.getAttr(), newVal)) {
1264 // if its valid for the first AC than its valid for all (of the same type)
1265 if (myAttributesEditorParent->myEditedACs.size() > 1) {
1266 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_begin("Change multiple attributes");
1267 } else if (myACAttr.getAttr() == SUMO_ATTR_ID) {
1268 // IDs attribute has to be encapsulated
1269 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_begin("change " + myACAttr.getTagPropertyParent().getTagStr() + " attribute");
1270 }
1271 // Set new value of attribute in all selected ACs
1272 for (const auto& it_ac : myAttributesEditorParent->myEditedACs) {
1273 it_ac->setAttribute(myACAttr.getAttr(), newVal, myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList());
1274 }
1275 // finish change multiple attributes or ID Attributes
1276 if (myAttributesEditorParent->myEditedACs.size() > 1) {
1277 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_end();
1278 } else if (myACAttr.getAttr() == SUMO_ATTR_ID) {
1279 myAttributesEditorParent->myFrameParent->getViewNet()->getUndoList()->p_end();
1280 }
1281 // If previously value was incorrect, change font color to black
1282 if (myACAttr.isCombinable()) {
1283 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
1284 myTextFieldStrings->killFocus();
1285 // in this case, we need to refresh the other values (For example, allow/Disallow objects)
1286 myAttributesEditorParent->refreshAttributeEditor(false, false);
1287 } else if (myACAttr.isDiscrete()) {
1288 myChoicesCombo->setTextColor(FXRGB(0, 0, 0));
1289 myChoicesCombo->killFocus();
1290 } else if (myACAttr.isFloat() || myACAttr.isTime()) {
1291 myTextFieldReal->setTextColor(FXRGB(0, 0, 0));
1292 myTextFieldReal->killFocus();
1293 } else if (myACAttr.isInt() && myTextFieldStrings != nullptr) {
1294 myTextFieldInt->setTextColor(FXRGB(0, 0, 0));
1295 myTextFieldInt->killFocus();
1296 } else if (myTextFieldStrings != nullptr) {
1297 myTextFieldStrings->setTextColor(FXRGB(0, 0, 0));
1298 myTextFieldStrings->killFocus();
1299 }
1300 // update frame parent after attribute sucesfully set
1301 myAttributesEditorParent->myFrameParent->updateFrameAfterChangeAttribute();
1302 } else {
1303 // If value of TextField isn't valid, change color to Red depending of type
1304 if (myACAttr.isCombinable()) {
1305 myTextFieldStrings->setTextColor(FXRGB(255, 0, 0));
1306 myTextFieldStrings->killFocus();
1307 } else if (myACAttr.isDiscrete()) {
1308 myChoicesCombo->setTextColor(FXRGB(255, 0, 0));
1309 myChoicesCombo->killFocus();
1310 } else if (myACAttr.isFloat() || myACAttr.isTime()) {
1311 myTextFieldReal->setTextColor(FXRGB(255, 0, 0));
1312 } else if (myACAttr.isInt() && myTextFieldStrings != nullptr) {
1313 myTextFieldInt->setTextColor(FXRGB(255, 0, 0));
1314 } else if (myTextFieldStrings != nullptr) {
1315 myTextFieldStrings->setTextColor(FXRGB(255, 0, 0));
1316 }
1317 // Write Warning in console if we're in testing mode
1318 WRITE_DEBUG("Value '" + newVal + "' for attribute " + myACAttr.getAttrStr() + " of " + myACAttr.getTagPropertyParent().getTagStr() + " isn't valid");
1319 }
1320 return 1;
1321 }
1322
1323
1324 long
onCmdSetDisjointAttribute(FXObject *,FXSelector,void *)1325 GNEFrame::AttributesEditor::RowEditor::onCmdSetDisjointAttribute(FXObject*, FXSelector, void*) {
1326 // write debug (for Netedit tests)
1327 WRITE_DEBUG("Selected radio button for attribute '" + myACAttr.getAttrStr() + "'");
1328 // change disjoint attribute with undo/redo
1329 myAttributesEditorParent->myEditedACs.front()->setDisjointAttribute(myACAttr.getAttr(),
1330 myAttributesEditorParent->myFrameParent->myViewNet->getUndoList());
1331 // refresh Attributes edito parent
1332 myAttributesEditorParent->refreshAttributeEditor(false, false);
1333 return 0;
1334 }
1335
1336
1337 std::string
stripWhitespaceAfterComma(const std::string & stringValue)1338 GNEFrame::AttributesEditor::RowEditor::stripWhitespaceAfterComma(const std::string& stringValue) {
1339 std::string result(stringValue);
1340 while (result.find(", ") != std::string::npos) {
1341 result = StringUtils::replace(result, ", ", ",");
1342 }
1343 return result;
1344 }
1345
1346 // ---------------------------------------------------------------------------
1347 // GNEFrame::AttributesEditor - methods
1348 // ---------------------------------------------------------------------------
1349
AttributesEditor(GNEFrame * FrameParent)1350 GNEFrame::AttributesEditor::AttributesEditor(GNEFrame* FrameParent) :
1351 FXGroupBox(FrameParent->myContentFrame, "Internal attributes", GUIDesignGroupBoxFrame),
1352 myFrameParent(FrameParent),
1353 myIncludeExtended(true) {
1354 // Create sufficient Row for all types of AttributeCarriers
1355 for (int i = 0; i < (int)GNEAttributeCarrier::getHigherNumberOfAttributes(); i++) {
1356 myVectorOfRows.push_back(new RowEditor(this));
1357 }
1358 // Create help button
1359 myHelpButton = new FXButton(this, "Help", nullptr, this, MID_HELP, GUIDesignButtonRectangular);
1360 }
1361
1362
1363 void
showAttributeEditorModul(const std::vector<GNEAttributeCarrier * > & ACs,bool includeExtended)1364 GNEFrame::AttributesEditor::showAttributeEditorModul(const std::vector<GNEAttributeCarrier*>& ACs, bool includeExtended) {
1365 myEditedACs = ACs;
1366 myIncludeExtended = includeExtended;
1367 // first hide all rows
1368 for (const auto& i : myVectorOfRows) {
1369 i->hideRow();
1370 }
1371 if (myEditedACs.size() > 0) {
1372 // check if current AC is a Junction without TLSs (needed to hidde TLS options)
1373 bool disableTLSinJunctions = (dynamic_cast<GNEJunction*>(myEditedACs.front()) && (dynamic_cast<GNEJunction*>(myEditedACs.front())->getNBNode()->getControllingTLS().empty()));
1374 // Iterate over attributes
1375 for (const auto& i : myEditedACs.front()->getTagProperty()) {
1376 // disable editing for unique attributes in case of multi-selection
1377 if ((myEditedACs.size() > 1) && i.second.isUnique()) {
1378 continue;
1379 }
1380 // disable editing of extended attributes if includeExtended isn't enabled
1381 if (i.second.isExtended() && !includeExtended) {
1382 continue;
1383 }
1384 // Declare a set of occuring values and insert attribute's values of item (note: We use a set to avoid repeated values)
1385 std::set<std::string> occuringValues;
1386 for (const auto& it_ac : myEditedACs) {
1387 occuringValues.insert(it_ac->getAttribute(i.first));
1388 }
1389 // get current value
1390 std::ostringstream oss;
1391 for (auto it_val = occuringValues.begin(); it_val != occuringValues.end(); it_val++) {
1392 if (it_val != occuringValues.begin()) {
1393 oss << " ";
1394 }
1395 oss << *it_val;
1396 }
1397 std::string value = oss.str();
1398 if ((myEditedACs.front()->getTagProperty().getTag() == SUMO_TAG_CONNECTION) &&
1399 (i.first == SUMO_ATTR_TLLINKINDEX)
1400 && value == toString(NBConnection::InvalidTlIndex)) {
1401 // possibly the connections are newly created (allow assigning
1402 // tlIndex if the junction(s) have a traffic light
1403 for (const auto& it_ac : myEditedACs) {
1404 if (!it_ac->isValid(SUMO_ATTR_TLLINKINDEX, "0")) {
1405 value = "No TLS";
1406 break;
1407 }
1408 }
1409 }
1410 // Show attribute
1411 if ((disableTLSinJunctions && (myEditedACs.front()->getTagProperty().getTag() == SUMO_TAG_JUNCTION) &&
1412 ((i.first == SUMO_ATTR_TLTYPE) || (i.first == SUMO_ATTR_TLID))) == false) {
1413 // first show AttributesEditor
1414 show();
1415 // show attribute
1416 myVectorOfRows[i.second.getPositionListed()]->showRow(i.second, value, myEditedACs.front()->isDisjointAttributeSet(i.first));
1417 }
1418 }
1419 }
1420 }
1421
1422
1423 void
hideAttributesEditorModul()1424 GNEFrame::AttributesEditor::hideAttributesEditorModul() {
1425 // hide al attributes
1426 for (const auto& i : myVectorOfRows) {
1427 i->hideRow();
1428 }
1429 // clear myEditedACs
1430 myEditedACs.clear();
1431 // hide also AttributesEditor
1432 hide();
1433 }
1434
1435
1436 void
refreshAttributeEditor(bool forceRefreshShape,bool forceRefreshPosition)1437 GNEFrame::AttributesEditor::refreshAttributeEditor(bool forceRefreshShape, bool forceRefreshPosition) {
1438 if (myEditedACs.size() > 0) {
1439 // check if current AC is a Junction without TLSs (needed to hidde TLS options)
1440 bool disableTLSinJunctions = (dynamic_cast<GNEJunction*>(myEditedACs.front()) && (dynamic_cast<GNEJunction*>(myEditedACs.front())->getNBNode()->getControllingTLS().empty()));
1441 // Iterate over attributes
1442 for (const auto& i : myEditedACs.front()->getTagProperty()) {
1443 // disable editing for unique attributes in case of multi-selection
1444 if ((myEditedACs.size() > 1) && i.second.isUnique()) {
1445 continue;
1446 }
1447 // Declare a set of occuring values and insert attribute's values of item
1448 std::set<std::string> occuringValues;
1449 for (const auto& it_ac : myEditedACs) {
1450 occuringValues.insert(it_ac->getAttribute(i.first));
1451 }
1452 // get current value
1453 std::ostringstream oss;
1454 for (auto it_val = occuringValues.begin(); it_val != occuringValues.end(); it_val++) {
1455 if (it_val != occuringValues.begin()) {
1456 oss << " ";
1457 }
1458 oss << *it_val;
1459 }
1460 // Show attribute
1461 if ((disableTLSinJunctions && (myEditedACs.front()->getTagProperty().getTag() == SUMO_TAG_JUNCTION) &&
1462 ((i.first == SUMO_ATTR_TLTYPE) || (i.first == SUMO_ATTR_TLID))) == false) {
1463 // check if is a disjoint attribute
1464 bool disjointAttributeSet = myEditedACs.front()->isDisjointAttributeSet(i.first);
1465 // Check if refresh of Position or Shape has to be forced
1466 if ((i.first == SUMO_ATTR_SHAPE) && forceRefreshShape) {
1467 myVectorOfRows[i.second.getPositionListed()]->refreshRow(oss.str(), true, disjointAttributeSet);
1468 } else if ((i.first == SUMO_ATTR_POSITION) && forceRefreshPosition) {
1469 // Refresh attributes maintain invalid values
1470 myVectorOfRows[i.second.getPositionListed()]->refreshRow(oss.str(), true, disjointAttributeSet);
1471 } else {
1472 // Refresh attributes maintain invalid values
1473 myVectorOfRows[i.second.getPositionListed()]->refreshRow(oss.str(), false, disjointAttributeSet);
1474 }
1475 }
1476 }
1477 }
1478 }
1479
1480
1481 const std::vector<GNEAttributeCarrier*>&
getEditedACs() const1482 GNEFrame::AttributesEditor::getEditedACs() const {
1483 return myEditedACs;
1484 }
1485
1486
1487 void
removeEditedAC(GNEAttributeCarrier * AC)1488 GNEFrame::AttributesEditor::removeEditedAC(GNEAttributeCarrier* AC) {
1489 // Only remove if there is inspected ACs
1490 if (myEditedACs.size() > 0) {
1491 // Try to find AC in myACs
1492 auto i = std::find(myEditedACs.begin(), myEditedACs.end(), AC);
1493 // if was found
1494 if (i != myEditedACs.end()) {
1495 // erase AC from inspected ACs
1496 myEditedACs.erase(i);
1497 // Write Warning in console if we're in testing mode
1498 WRITE_DEBUG("Removed inspected element from Inspected ACs. " + toString(myEditedACs.size()) + " ACs remains.");
1499 // Inspect multi selection again (To refresh Modul)
1500 showAttributeEditorModul(myEditedACs, myIncludeExtended);
1501 }
1502 }
1503 }
1504
1505
1506 long
onCmdAttributesEditorHelp(FXObject *,FXSelector,void *)1507 GNEFrame::AttributesEditor::onCmdAttributesEditorHelp(FXObject*, FXSelector, void*) {
1508 // open Help attributes dialog if there is inspected ACs
1509 if (myEditedACs.size() > 0) {
1510 // open Help attributes dialog
1511 myFrameParent->openHelpAttributesDialog(myEditedACs.front()->getTagProperty());
1512 }
1513 return 1;
1514 }
1515
1516 // ---------------------------------------------------------------------------
1517 // GNEFrame::AttributesEditorExtended- methods
1518 // ---------------------------------------------------------------------------
1519
AttributesEditorExtended(GNEFrame * frameParent)1520 GNEFrame::AttributesEditorExtended::AttributesEditorExtended(GNEFrame* frameParent) :
1521 FXGroupBox(frameParent->myContentFrame, "Extended attributes", GUIDesignGroupBoxFrame),
1522 myFrameParent(frameParent) {
1523 // Create open dialog button
1524 new FXButton(this, "Open attributes editor", nullptr, this, MID_GNE_SET_ATTRIBUTE_DIALOG, GUIDesignButton);
1525 }
1526
1527
~AttributesEditorExtended()1528 GNEFrame::AttributesEditorExtended::~AttributesEditorExtended() {}
1529
1530
1531 void
showAttributesEditorExtendedModul()1532 GNEFrame::AttributesEditorExtended::showAttributesEditorExtendedModul() {
1533 show();
1534 }
1535
1536
1537 void
hideAttributesEditorExtendedModul()1538 GNEFrame::AttributesEditorExtended::hideAttributesEditorExtendedModul() {
1539 hide();
1540 }
1541
1542
1543 long
onCmdOpenDialog(FXObject *,FXSelector,void *)1544 GNEFrame::AttributesEditorExtended::onCmdOpenDialog(FXObject*, FXSelector, void*) {
1545 // open AttributesCreator extended dialog
1546 myFrameParent->openAttributesEditorExtendedDialog();
1547 return 1;
1548 }
1549
1550 // ---------------------------------------------------------------------------
1551 // GNEFrame::ACHierarchy - methods
1552 // ---------------------------------------------------------------------------
1553
ACHierarchy(GNEFrame * frameParent)1554 GNEFrame::ACHierarchy::ACHierarchy(GNEFrame* frameParent) :
1555 FXGroupBox(frameParent->myContentFrame, "Hierarchy", GUIDesignGroupBoxFrame),
1556 myFrameParent(frameParent),
1557 myAC(nullptr) {
1558 // Create three list
1559 myTreelist = new FXTreeList(this, this, MID_GNE_DELETEFRAME_CHILDS, GUIDesignTreeListFrame);
1560 hide();
1561 }
1562
1563
~ACHierarchy()1564 GNEFrame::ACHierarchy::~ACHierarchy() {}
1565
1566
1567 void
showACHierarchy(GNEAttributeCarrier * AC)1568 GNEFrame::ACHierarchy::showACHierarchy(GNEAttributeCarrier* AC) {
1569 myAC = AC;
1570 // show ACHierarchy and refresh ACHierarchy
1571 if (myAC) {
1572 show();
1573 refreshACHierarchy();
1574 }
1575 }
1576
1577
1578 void
hideACHierarchy()1579 GNEFrame::ACHierarchy::hideACHierarchy() {
1580 myAC = nullptr;
1581 hide();
1582 }
1583
1584
1585 void
refreshACHierarchy()1586 GNEFrame::ACHierarchy::refreshACHierarchy() {
1587 // clear items
1588 myTreelist->clearItems();
1589 myTreeItemToACMap.clear();
1590 myTreeItemsConnections.clear();
1591 // show ACChilds of myAC
1592 if (myAC) {
1593 showAttributeCarrierChilds(myAC, showAttributeCarrierParents());
1594 }
1595 }
1596
1597
1598 long
onCmdShowChildMenu(FXObject *,FXSelector,void * eventData)1599 GNEFrame::ACHierarchy::onCmdShowChildMenu(FXObject*, FXSelector, void* eventData) {
1600 // Obtain event
1601 FXEvent* e = (FXEvent*)eventData;
1602 // obtain FXTreeItem in the given position
1603 FXTreeItem* item = myTreelist->getItemAt(e->win_x, e->win_y);
1604 // open Pop-up if FXTreeItem has a Attribute Carrier vinculated
1605 if (item && (myTreeItemsConnections.find(item) == myTreeItemsConnections.end())) {
1606 createPopUpMenu(e->root_x, e->root_y, myTreeItemToACMap[item]);
1607 }
1608 return 1;
1609 }
1610
1611
1612 long
onCmdCenterItem(FXObject *,FXSelector,void *)1613 GNEFrame::ACHierarchy::onCmdCenterItem(FXObject*, FXSelector, void*) {
1614 GUIGlObject* glObject = dynamic_cast<GUIGlObject*>(myRightClickedAC);
1615 if (glObject) {
1616 myFrameParent->getViewNet()->centerTo(glObject->getGlID(), false);
1617 myFrameParent->getViewNet()->update();
1618 }
1619 return 1;
1620 }
1621
1622
1623 long
onCmdInspectItem(FXObject *,FXSelector,void *)1624 GNEFrame::ACHierarchy::onCmdInspectItem(FXObject*, FXSelector, void*) {
1625 if ((myAC != nullptr) && (myRightClickedAC != nullptr)) {
1626 myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->inspectChild(myRightClickedAC, myAC);
1627 }
1628 return 1;
1629 }
1630
1631
1632 long
onCmdDeleteItem(FXObject *,FXSelector,void *)1633 GNEFrame::ACHierarchy::onCmdDeleteItem(FXObject*, FXSelector, void*) {
1634 // check if Inspector frame was opened before removing
1635 const std::vector<GNEAttributeCarrier*>& currentInspectedACs = myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->getAttributesEditor()->getEditedACs();
1636 // Remove Attribute Carrier
1637 /*
1638 myFrameParent->getViewNet()->getViewParent()->getDeleteFrame()->removeAttributeCarrier(myRightClickedAC);
1639 myFrameParent->getViewNet()->getViewParent()->getDeleteFrame()->hide();
1640 */
1641 // check if inspector frame has to be shown again
1642 if (currentInspectedACs.size() == 1) {
1643 if (currentInspectedACs.front() != myRightClickedAC) {
1644 myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->inspectSingleElement(currentInspectedACs.front());
1645 } else {
1646 // inspect a nullprt element to reset inspector frame
1647 myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->inspectSingleElement(nullptr);
1648 }
1649 }
1650 return 1;
1651 }
1652
1653
1654 void
createPopUpMenu(int X,int Y,GNEAttributeCarrier * ac)1655 GNEFrame::ACHierarchy::createPopUpMenu(int X, int Y, GNEAttributeCarrier* ac) {
1656 // create FXMenuPane
1657 FXMenuPane* pane = new FXMenuPane(myTreelist);
1658 // set current clicked AC
1659 myRightClickedAC = ac;
1660 // set name
1661 new MFXMenuHeader(pane, myFrameParent->getViewNet()->getViewParent()->getGUIMainWindow()->getBoldFont(), myRightClickedAC->getPopUpID().c_str(), myRightClickedAC->getIcon());
1662 new FXMenuSeparator(pane);
1663 // Fill FXMenuCommand
1664 new FXMenuCommand(pane, "Center", GUIIconSubSys::getIcon(ICON_RECENTERVIEW), this, MID_GNE_INSPECTORFRAME_CENTER);
1665 new FXMenuCommand(pane, "Inspect", GUIIconSubSys::getIcon(ICON_MODEINSPECT), this, MID_GNE_INSPECTORFRAME_INSPECT);
1666 new FXMenuCommand(pane, "Delete", GUIIconSubSys::getIcon(ICON_MODEDELETE), this, MID_GNE_INSPECTORFRAME_DELETE);
1667 // Center in the mouse position and create pane
1668 pane->setX(X);
1669 pane->setY(Y);
1670 pane->create();
1671 pane->show();
1672 }
1673
1674
1675 FXTreeItem*
showAttributeCarrierParents()1676 GNEFrame::ACHierarchy::showAttributeCarrierParents() {
1677 if (myAC->getTagProperty().isNetElement()) {
1678 // check demand element type
1679 switch (myAC->getTagProperty().getTag()) {
1680 case SUMO_TAG_EDGE: {
1681 // obtain Edge
1682 GNEEdge* edge = myFrameParent->getViewNet()->getNet()->retrieveEdge(myAC->getID(), false);
1683 if (edge) {
1684 // insert Junctions of edge in tree (Pararell because a edge has always two Junctions)
1685 FXTreeItem* junctionSourceItem = myTreelist->insertItem(nullptr, nullptr, (edge->getGNEJunctionSource()->getHierarchyName() + " origin").c_str(), edge->getGNEJunctionSource()->getIcon(), edge->getGNEJunctionSource()->getIcon());
1686 FXTreeItem* junctionDestinyItem = myTreelist->insertItem(nullptr, nullptr, (edge->getGNEJunctionSource()->getHierarchyName() + " destiny").c_str(), edge->getGNEJunctionSource()->getIcon(), edge->getGNEJunctionSource()->getIcon());
1687 junctionDestinyItem->setExpanded(true);
1688 // Save items in myTreeItemToACMap
1689 myTreeItemToACMap[junctionSourceItem] = edge->getGNEJunctionSource();
1690 myTreeItemToACMap[junctionDestinyItem] = edge->getGNEJunctionDestiny();
1691 // return junction destiny Item
1692 return junctionDestinyItem;
1693 } else {
1694 return nullptr;
1695 }
1696 }
1697 case SUMO_TAG_LANE: {
1698 // obtain lane
1699 GNELane* lane = myFrameParent->getViewNet()->getNet()->retrieveLane(myAC->getID(), false);
1700 if (lane) {
1701 // obtain edge parent
1702 GNEEdge* edge = myFrameParent->getViewNet()->getNet()->retrieveEdge(lane->getParentEdge().getID());
1703 //inser Junctions of lane of edge in tree (Pararell because a edge has always two Junctions)
1704 FXTreeItem* junctionSourceItem = myTreelist->insertItem(nullptr, nullptr, (edge->getGNEJunctionSource()->getHierarchyName() + " origin").c_str(), edge->getGNEJunctionSource()->getIcon(), edge->getGNEJunctionSource()->getIcon());
1705 FXTreeItem* junctionDestinyItem = myTreelist->insertItem(nullptr, nullptr, (edge->getGNEJunctionSource()->getHierarchyName() + " destiny").c_str(), edge->getGNEJunctionSource()->getIcon(), edge->getGNEJunctionSource()->getIcon());
1706 junctionDestinyItem->setExpanded(true);
1707 // Create edge item
1708 FXTreeItem* edgeItem = myTreelist->insertItem(nullptr, junctionDestinyItem, edge->getHierarchyName().c_str(), edge->getIcon(), edge->getIcon());
1709 edgeItem->setExpanded(true);
1710 // Save items in myTreeItemToACMap
1711 myTreeItemToACMap[junctionSourceItem] = edge->getGNEJunctionSource();
1712 myTreeItemToACMap[junctionDestinyItem] = edge->getGNEJunctionDestiny();
1713 myTreeItemToACMap[edgeItem] = edge;
1714 // return edge item
1715 return edgeItem;
1716 } else {
1717 return nullptr;
1718 }
1719 }
1720 case SUMO_TAG_CROSSING: {
1721 // obtain Crossing
1722 GNECrossing* crossing = myFrameParent->getViewNet()->getNet()->retrieveCrossing(myAC->getID(), false);
1723 if (crossing) {
1724 // obtain junction
1725 GNEJunction* junction = crossing->getParentJunction();
1726 // create junction item
1727 FXTreeItem* junctionItem = myTreelist->insertItem(nullptr, nullptr, junction->getHierarchyName().c_str(), junction->getIcon(), junction->getIcon());
1728 junctionItem->setExpanded(true);
1729 // Save items in myTreeItemToACMap
1730 myTreeItemToACMap[junctionItem] = junction;
1731 // return junction Item
1732 return junctionItem;
1733 } else {
1734 return nullptr;
1735 }
1736 }
1737 case SUMO_TAG_CONNECTION: {
1738 // obtain Connection
1739 GNEConnection* connection = myFrameParent->getViewNet()->getNet()->retrieveConnection(myAC->getID(), false);
1740 if (connection) {
1741 // create edge from item
1742 FXTreeItem* edgeFromItem = myTreelist->insertItem(nullptr, nullptr, connection->getEdgeFrom()->getHierarchyName().c_str(), connection->getEdgeFrom()->getIcon(), connection->getEdgeFrom()->getIcon());
1743 edgeFromItem->setExpanded(true);
1744 // create edge to item
1745 FXTreeItem* edgeToItem = myTreelist->insertItem(nullptr, nullptr, connection->getEdgeTo()->getHierarchyName().c_str(), connection->getEdgeTo()->getIcon(), connection->getEdgeTo()->getIcon());
1746 edgeToItem->setExpanded(true);
1747 // create connection item
1748 FXTreeItem* connectionItem = myTreelist->insertItem(nullptr, edgeToItem, connection->getHierarchyName().c_str(), connection->getIcon(), connection->getIcon());
1749 connectionItem->setExpanded(true);
1750 // Save items in myTreeItemToACMap
1751 myTreeItemToACMap[edgeFromItem] = connection->getEdgeFrom();
1752 myTreeItemToACMap[edgeToItem] = connection->getEdgeTo();
1753 myTreeItemToACMap[connectionItem] = connection;
1754 // return connection item
1755 return connectionItem;
1756 } else {
1757 return nullptr;
1758 }
1759 }
1760 default:
1761 break;
1762 }
1763 } else if (myAC->getTagProperty().getTag() == SUMO_TAG_POILANE) {
1764 // Obtain POILane
1765 GNEPOI* POILane = myFrameParent->getViewNet()->getNet()->retrievePOI(myAC->getID(), false);
1766 if (POILane) {
1767 // obtain lane parent
1768 GNELane* lane = myFrameParent->getViewNet()->getNet()->retrieveLane(POILane->getLaneParents().at(0)->getID());
1769 // obtain edge parent
1770 GNEEdge* edge = myFrameParent->getViewNet()->getNet()->retrieveEdge(lane->getParentEdge().getID());
1771 //inser Junctions of lane of edge in tree (Pararell because a edge has always two Junctions)
1772 FXTreeItem* junctionSourceItem = myTreelist->insertItem(nullptr, nullptr, (edge->getGNEJunctionSource()->getHierarchyName() + " origin").c_str(), edge->getGNEJunctionSource()->getIcon(), edge->getGNEJunctionSource()->getIcon());
1773 FXTreeItem* junctionDestinyItem = myTreelist->insertItem(nullptr, nullptr, (edge->getGNEJunctionSource()->getHierarchyName() + " destiny").c_str(), edge->getGNEJunctionSource()->getIcon(), edge->getGNEJunctionSource()->getIcon());
1774 junctionDestinyItem->setExpanded(true);
1775 // Create edge item
1776 FXTreeItem* edgeItem = myTreelist->insertItem(nullptr, junctionDestinyItem, edge->getHierarchyName().c_str(), edge->getIcon(), edge->getIcon());
1777 edgeItem->setExpanded(true);
1778 // Create lane item
1779 FXTreeItem* laneItem = myTreelist->insertItem(nullptr, edgeItem, lane->getHierarchyName().c_str(), lane->getIcon(), lane->getIcon());
1780 laneItem->setExpanded(true);
1781 // Save items in myTreeItemToACMap
1782 myTreeItemToACMap[junctionSourceItem] = edge->getGNEJunctionSource();
1783 myTreeItemToACMap[junctionDestinyItem] = edge->getGNEJunctionDestiny();
1784 myTreeItemToACMap[edgeItem] = edge;
1785 myTreeItemToACMap[laneItem] = lane;
1786 // return Lane item
1787 return laneItem;
1788 } else {
1789 return nullptr;
1790 }
1791 } else if (myAC->getTagProperty().isAdditional() || myAC->getTagProperty().isTAZ()) {
1792 // Obtain Additional
1793 GNEAdditional* additional = myFrameParent->getViewNet()->getNet()->retrieveAdditional(myAC->getTagProperty().getTag(), myAC->getID(), false);
1794 if (additional) {
1795 // declare auxiliar FXTreeItem, due a demand element can have multiple "roots"
1796 FXTreeItem* root = nullptr;
1797 // check if there is demand elements parents
1798 if (additional->getAdditionalParents().size() > 0) {
1799 // check if we have more than one edge
1800 if (additional->getAdditionalParents().size() > 1) {
1801 // insert first item
1802 addListItem(additional->getAdditionalParents().front());
1803 // insert "spacer"
1804 if (additional->getAdditionalParents().size() > 2) {
1805 addListItem(nullptr, ("..." + toString((int)additional->getAdditionalParents().size() - 2) + " additionals...").c_str(), 0, false);
1806 }
1807 }
1808 // return last inserted item
1809 root = addListItem(additional->getAdditionalParents().back());
1810 }
1811 // check if there is demand element parents
1812 if (additional->getDemandElementParents().size() > 0) {
1813 // check if we have more than one demand element
1814 if (additional->getDemandElementParents().size() > 1) {
1815 // insert first item
1816 addListItem(additional->getDemandElementParents().front());
1817 // insert "spacer"
1818 if (additional->getDemandElementParents().size() > 2) {
1819 addListItem(nullptr, ("..." + toString((int)additional->getDemandElementParents().size() - 2) + " demand elements...").c_str(), 0, false);
1820 }
1821 }
1822 // return last inserted item
1823 root = addListItem(additional->getDemandElementParents().back());
1824 }
1825 // check if there is edge parents
1826 if (additional->getEdgeParents().size() > 0) {
1827 // check if we have more than one edge
1828 if (additional->getEdgeParents().size() > 1) {
1829 // insert first item
1830 addListItem(additional->getEdgeParents().front());
1831 // insert "spacer"
1832 if (additional->getEdgeParents().size() > 2) {
1833 addListItem(nullptr, ("..." + toString((int)additional->getEdgeParents().size() - 2) + " edges...").c_str(), 0, false);
1834 }
1835 }
1836 // return last inserted item
1837 root = addListItem(additional->getEdgeParents().back());
1838 }
1839 // check if there is lane parents
1840 if (additional->getLaneParents().size() > 0) {
1841 // check if we have more than one lane parent
1842 if (additional->getLaneParents().size() > 1) {
1843 // insert first item
1844 addListItem(additional->getLaneParents().front());
1845 // insert "spacer"
1846 if (additional->getLaneParents().size() > 2) {
1847 addListItem(nullptr, ("..." + toString((int)additional->getLaneParents().size() - 2) + " lanes...").c_str(), 0, false);
1848 }
1849 }
1850 // return last inserted item
1851 root = addListItem(additional->getLaneParents().back());
1852 }
1853 // return last inserted list item
1854 return root;
1855 }
1856 } else if (myAC->getTagProperty().isDemandElement()) {
1857 // Obtain DemandElement
1858 GNEDemandElement* demandElement = myFrameParent->getViewNet()->getNet()->retrieveDemandElement(myAC->getTagProperty().getTag(), myAC->getID(), false);
1859 if (demandElement) {
1860 // declare auxiliar FXTreeItem, due a demand element can have multiple "roots"
1861 FXTreeItem* root = nullptr;
1862 // check if there is demand elements parents
1863 if (demandElement->getAdditionalParents().size() > 0) {
1864 // check if we have more than one edge
1865 if (demandElement->getAdditionalParents().size() > 1) {
1866 // insert first item
1867 addListItem(demandElement->getAdditionalParents().front());
1868 // insert "spacer"
1869 if (demandElement->getAdditionalParents().size() > 2) {
1870 addListItem(nullptr, ("..." + toString((int)demandElement->getAdditionalParents().size() - 2) + " additionals...").c_str(), 0, false);
1871 }
1872 }
1873 // return last inserted item
1874 root = addListItem(demandElement->getAdditionalParents().back());
1875 }
1876 // check if there is demand element parents
1877 if (demandElement->getDemandElementParents().size() > 0) {
1878 // check if we have more than one demand element
1879 if (demandElement->getDemandElementParents().size() > 1) {
1880 // insert first item
1881 addListItem(demandElement->getDemandElementParents().front());
1882 // insert "spacer"
1883 if (demandElement->getDemandElementParents().size() > 2) {
1884 addListItem(nullptr, ("..." + toString((int)demandElement->getDemandElementParents().size() - 2) + " demand elements...").c_str(), 0, false);
1885 }
1886 }
1887 // return last inserted item
1888 root = addListItem(demandElement->getDemandElementParents().back());
1889 }
1890 // check if there is edge parents
1891 if (demandElement->getEdgeParents().size() > 0) {
1892 // check if we have more than one edge
1893 if (demandElement->getEdgeParents().size() > 1) {
1894 // insert first item
1895 addListItem(demandElement->getEdgeParents().front());
1896 // insert "spacer"
1897 if (demandElement->getEdgeParents().size() > 2) {
1898 addListItem(nullptr, ("..." + toString((int)demandElement->getEdgeParents().size() - 2) + " edges...").c_str(), 0, false);
1899 }
1900 }
1901 // return last inserted item
1902 root = addListItem(demandElement->getEdgeParents().back());
1903 }
1904 // check if there is lane parents
1905 if (demandElement->getLaneParents().size() > 0) {
1906 // check if we have more than one lane parent
1907 if (demandElement->getLaneParents().size() > 1) {
1908 // insert first item
1909 addListItem(demandElement->getLaneParents().front());
1910 // insert "spacer"
1911 if (demandElement->getLaneParents().size() > 2) {
1912 addListItem(nullptr, ("..." + toString((int)demandElement->getLaneParents().size() - 2) + " lanes...").c_str(), 0, false);
1913 }
1914 }
1915 // return last inserted item
1916 root = addListItem(demandElement->getLaneParents().back());
1917 }
1918 // return last inserted list item
1919 return root;
1920 }
1921 }
1922 // there isn't parents
1923 return nullptr;
1924 }
1925
1926
1927 void
showAttributeCarrierChilds(GNEAttributeCarrier * AC,FXTreeItem * itemParent)1928 GNEFrame::ACHierarchy::showAttributeCarrierChilds(GNEAttributeCarrier* AC, FXTreeItem* itemParent) {
1929 if (AC->getTagProperty().isNetElement()) {
1930 // Switch gl type of ac
1931 switch (AC->getTagProperty().getTag()) {
1932 case SUMO_TAG_JUNCTION: {
1933 // retrieve junction
1934 GNEJunction* junction = myFrameParent->getViewNet()->getNet()->retrieveJunction(AC->getID(), false);
1935 if (junction) {
1936 // insert junction item
1937 FXTreeItem* junctionItem = addListItem(AC, itemParent);
1938 // insert edges
1939 for (auto i : junction->getGNEEdges()) {
1940 showAttributeCarrierChilds(i, junctionItem);
1941 }
1942 // insert crossings
1943 for (auto i : junction->getGNECrossings()) {
1944 showAttributeCarrierChilds(i, junctionItem);
1945 }
1946 }
1947 break;
1948 }
1949 case SUMO_TAG_EDGE: {
1950 // retrieve edge
1951 GNEEdge* edge = myFrameParent->getViewNet()->getNet()->retrieveEdge(AC->getID(), false);
1952 if (edge) {
1953 // insert edge item
1954 FXTreeItem* edgeItem = addListItem(AC, itemParent);
1955 // insert lanes
1956 for (const auto& i : edge->getLanes()) {
1957 showAttributeCarrierChilds(i, edgeItem);
1958 }
1959 // insert shape childs
1960 for (const auto& i : edge->getShapeChilds()) {
1961 showAttributeCarrierChilds(i, edgeItem);
1962 }
1963 // insert additional childs
1964 for (const auto& i : edge->getAdditionalChilds()) {
1965 showAttributeCarrierChilds(i, edgeItem);
1966 }
1967 // insert demand elements childs
1968 for (const auto& i : edge->getDemandElementChilds()) {
1969 showAttributeCarrierChilds(i, edgeItem);
1970 }
1971 }
1972 break;
1973 }
1974 case SUMO_TAG_LANE: {
1975 // retrieve lane
1976 GNELane* lane = myFrameParent->getViewNet()->getNet()->retrieveLane(AC->getID(), false);
1977 if (lane) {
1978 // insert lane item
1979 FXTreeItem* laneItem = addListItem(AC, itemParent);
1980 // insert shape childs
1981 for (const auto& i : lane->getShapeChilds()) {
1982 showAttributeCarrierChilds(i, laneItem);
1983 }
1984 // insert additional childs
1985 for (const auto& i : lane->getAdditionalChilds()) {
1986 showAttributeCarrierChilds(i, laneItem);
1987 }
1988 // insert demand elements childs
1989 for (const auto& i : lane->getDemandElementChilds()) {
1990 showAttributeCarrierChilds(i, laneItem);
1991 }
1992 // insert incoming connections of lanes (by default isn't expanded)
1993 if (lane->getGNEIncomingConnections().size() > 0) {
1994 std::vector<GNEConnection*> incomingLaneConnections = lane->getGNEIncomingConnections();
1995 // insert intermediate list item
1996 FXTreeItem* incomingConnections = addListItem(laneItem, "Incomings", incomingLaneConnections.front()->getIcon(), false);
1997 // insert incoming connections
1998 for (auto i : incomingLaneConnections) {
1999 showAttributeCarrierChilds(i, incomingConnections);
2000 }
2001 }
2002 // insert outcoming connections of lanes (by default isn't expanded)
2003 if (lane->getGNEOutcomingConnections().size() > 0) {
2004 std::vector<GNEConnection*> outcomingLaneConnections = lane->getGNEOutcomingConnections();
2005 // insert intermediate list item
2006 FXTreeItem* outgoingConnections = addListItem(laneItem, "Outgoing", outcomingLaneConnections.front()->getIcon(), false);
2007 // insert outcoming connections
2008 for (auto i : outcomingLaneConnections) {
2009 showAttributeCarrierChilds(i, outgoingConnections);
2010 }
2011 }
2012 }
2013 break;
2014 }
2015 case SUMO_TAG_CROSSING:
2016 case SUMO_TAG_CONNECTION: {
2017 // insert connection item
2018 addListItem(AC, itemParent);
2019 break;
2020 }
2021 default:
2022 break;
2023 }
2024 } else if (AC->getTagProperty().isShape()) {
2025 // insert shape item
2026 addListItem(AC, itemParent);
2027 } else if (AC->getTagProperty().isAdditional() || AC->getTagProperty().isTAZ()) {
2028 // retrieve additional
2029 GNEAdditional* additional = myFrameParent->getViewNet()->getNet()->retrieveAdditional(AC->getTagProperty().getTag(), AC->getID(), false);
2030 if (additional) {
2031 // insert additional item
2032 FXTreeItem* additionalItem = addListItem(AC, itemParent);
2033 // insert edge childs
2034 for (const auto& i : additional->getEdgeChilds()) {
2035 showAttributeCarrierChilds(i, additionalItem);
2036 }
2037 // insert lane childs
2038 for (const auto& i : additional->getLaneChilds()) {
2039 showAttributeCarrierChilds(i, additionalItem);
2040 }
2041 // insert shape childs
2042 for (const auto& i : additional->getShapeChilds()) {
2043 showAttributeCarrierChilds(i, additionalItem);
2044 }
2045 // insert additionals childs
2046 for (const auto& i : additional->getAdditionalChilds()) {
2047 showAttributeCarrierChilds(i, additionalItem);
2048 }
2049 // insert demand element childs
2050 for (const auto& i : additional->getDemandElementChilds()) {
2051 showAttributeCarrierChilds(i, additionalItem);
2052 }
2053 }
2054 } else if (AC->getTagProperty().isDemandElement()) {
2055 // retrieve demandElement
2056 GNEDemandElement* demandElement = myFrameParent->getViewNet()->getNet()->retrieveDemandElement(AC->getTagProperty().getTag(), AC->getID(), false);
2057 if (demandElement) {
2058 // insert demandElement item
2059 FXTreeItem* demandElementItem = addListItem(AC, itemParent);
2060 // insert edge childs
2061 for (const auto& i : demandElement->getEdgeChilds()) {
2062 showAttributeCarrierChilds(i, demandElementItem);
2063 }
2064 // insert lane childs
2065 for (const auto& i : demandElement->getLaneChilds()) {
2066 showAttributeCarrierChilds(i, demandElementItem);
2067 }
2068 // insert shape childs
2069 for (const auto& i : demandElement->getShapeChilds()) {
2070 showAttributeCarrierChilds(i, demandElementItem);
2071 }
2072 // insert additionals childs
2073 for (const auto& i : demandElement->getAdditionalChilds()) {
2074 showAttributeCarrierChilds(i, demandElementItem);
2075 }
2076 // insert demand element childs
2077 for (const auto& i : demandElement->getDemandElementChilds()) {
2078 showAttributeCarrierChilds(i, demandElementItem);
2079 }
2080 }
2081 }
2082 }
2083
2084
2085 FXTreeItem*
addListItem(GNEAttributeCarrier * AC,FXTreeItem * itemParent,std::string prefix,std::string sufix)2086 GNEFrame::ACHierarchy::addListItem(GNEAttributeCarrier* AC, FXTreeItem* itemParent, std::string prefix, std::string sufix) {
2087 // insert item in Tree list
2088 FXTreeItem* item = myTreelist->insertItem(nullptr, itemParent, (prefix + AC->getHierarchyName() + sufix).c_str(), AC->getIcon(), AC->getIcon());
2089 // insert item in map
2090 myTreeItemToACMap[item] = AC;
2091 // by default item is expanded
2092 item->setExpanded(true);
2093 return item;
2094 }
2095
2096
2097 FXTreeItem*
addListItem(FXTreeItem * itemParent,const std::string & text,FXIcon * icon,bool expanded)2098 GNEFrame::ACHierarchy::addListItem(FXTreeItem* itemParent, const std::string& text, FXIcon* icon, bool expanded) {
2099 // insert item in Tree list
2100 FXTreeItem* item = myTreelist->insertItem(nullptr, itemParent, text.c_str(), icon, icon);
2101 // set exapnded
2102 item->setExpanded(expanded);
2103 return item;
2104 }
2105
2106 // ---------------------------------------------------------------------------
2107 // GNEFrame::GenericParametersEditor - methods
2108 // ---------------------------------------------------------------------------
2109
GenericParametersEditor(GNEFrame * inspectorFrameParent)2110 GNEFrame::GenericParametersEditor::GenericParametersEditor(GNEFrame* inspectorFrameParent) :
2111 FXGroupBox(inspectorFrameParent->myContentFrame, "Generic parameters", GUIDesignGroupBoxFrame),
2112 myFrameParent(inspectorFrameParent),
2113 myAC(nullptr),
2114 myGenericParameters(nullptr) {
2115 // create empty vector with generic parameters
2116 myGenericParameters = new std::vector<std::pair<std::string, std::string> >;
2117 // create textfield and buttons
2118 myTextFieldGenericParameter = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);
2119 myEditGenericParameterButton = new FXButton(this, "Edit generic parameter", nullptr, this, MID_GNE_SET_ATTRIBUTE_DIALOG, GUIDesignButton);
2120 }
2121
2122
~GenericParametersEditor()2123 GNEFrame::GenericParametersEditor::~GenericParametersEditor() {
2124 delete myGenericParameters;
2125 }
2126
2127
2128 void
showGenericParametersEditor(GNEAttributeCarrier * AC)2129 GNEFrame::GenericParametersEditor::showGenericParametersEditor(GNEAttributeCarrier* AC) {
2130 if (AC != nullptr) {
2131 myAC = AC;
2132 myACs.clear();
2133 // obtain a copy of generic parameters of AC
2134 if (myAC) {
2135 *myGenericParameters = myAC->getGenericParameters();
2136 }
2137 // refresh GenericParametersEditor
2138 refreshGenericParametersEditor();
2139 // show groupbox
2140 show();
2141 }
2142 }
2143
2144
2145 void
showGenericParametersEditor(std::vector<GNEAttributeCarrier * > ACs)2146 GNEFrame::GenericParametersEditor::showGenericParametersEditor(std::vector<GNEAttributeCarrier*> ACs) {
2147 if (ACs.size() > 0) {
2148 myAC = nullptr;
2149 myACs = ACs;
2150 // check if generic parameters are different
2151 bool differentsGenericParameters = false;
2152 std::string genericParameter = myACs.front()->getAttribute(GNE_ATTR_GENERIC);
2153 for (auto i : myACs) {
2154 if (genericParameter != i->getAttribute(GNE_ATTR_GENERIC)) {
2155 differentsGenericParameters = true;
2156 }
2157 }
2158 // set generic Parameters editor
2159 if (differentsGenericParameters) {
2160 myGenericParameters->clear();
2161 } else {
2162 *myGenericParameters = myACs.front()->getGenericParameters();
2163 }
2164 // refresh GenericParametersEditor
2165 refreshGenericParametersEditor();
2166 // show groupbox
2167 show();
2168 }
2169 }
2170
2171
2172 void
hideGenericParametersEditor()2173 GNEFrame::GenericParametersEditor::hideGenericParametersEditor() {
2174 myAC = nullptr;
2175 // hide groupbox
2176 hide();
2177 }
2178
2179
2180 void
refreshGenericParametersEditor()2181 GNEFrame::GenericParametersEditor::refreshGenericParametersEditor() {
2182 // update text field depending of AC
2183 if (myAC) {
2184 myTextFieldGenericParameter->setText(myAC->getAttribute(GNE_ATTR_GENERIC).c_str());
2185 myTextFieldGenericParameter->setTextColor(FXRGB(0, 0, 0));
2186 // disable myTextFieldGenericParameter if Tag correspond to an network element but we're in demand mode (or vice versa), disable all elements
2187 if (((myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) && myAC->getTagProperty().isDemandElement()) ||
2188 ((myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_DEMAND) && !myAC->getTagProperty().isDemandElement())) {
2189 myTextFieldGenericParameter->disable();
2190 myEditGenericParameterButton->disable();
2191 } else {
2192 myTextFieldGenericParameter->enable();
2193 myEditGenericParameterButton->enable();
2194 }
2195 } else if (myACs.size() > 0) {
2196 // check if generic parameters of all inspected ACs are different
2197 std::string genericParameter = myACs.front()->getAttribute(GNE_ATTR_GENERIC);
2198
2199 for (auto i : myACs) {
2200 if (genericParameter != i->getAttribute(GNE_ATTR_GENERIC)) {
2201 genericParameter = "different generic attributes";
2202 }
2203 }
2204 myTextFieldGenericParameter->setText(genericParameter.c_str());
2205 myTextFieldGenericParameter->setTextColor(FXRGB(0, 0, 0));
2206 // disable myTextFieldGenericParameter if we're in demand mode and inspected AC isn't a demand element (or viceversa)
2207 if (((myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) && myACs.front()->getTagProperty().isDemandElement()) ||
2208 ((myFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_DEMAND) && !myACs.front()->getTagProperty().isDemandElement())) {
2209 myTextFieldGenericParameter->disable();
2210 myEditGenericParameterButton->disable();
2211 } else {
2212 myTextFieldGenericParameter->enable();
2213 myEditGenericParameterButton->enable();
2214 }
2215 }
2216 }
2217
2218
2219 std::string
getGenericParametersStr() const2220 GNEFrame::GenericParametersEditor::getGenericParametersStr() const {
2221 std::string result;
2222 // Generate an string using the following structure: "key1=value1|key2=value2|...
2223 for (auto i = myGenericParameters->begin(); i != myGenericParameters->end(); i++) {
2224 result += i->first + "=" + i->second + "|";
2225 }
2226 // remove the last "|"
2227 if (!result.empty()) {
2228 result.pop_back();
2229 }
2230 return result;
2231 }
2232
2233
2234 long
onCmdEditGenericParameter(FXObject *,FXSelector,void *)2235 GNEFrame::GenericParametersEditor::onCmdEditGenericParameter(FXObject*, FXSelector, void*) {
2236 // edit generic parameters using dialog
2237 if (GNEGenericParameterDialog(myFrameParent->getViewNet(), myGenericParameters).execute()) {
2238 // set values edited in Parameter dialog in Edited AC
2239 if (myAC) {
2240 myAC->setAttribute(GNE_ATTR_GENERIC, getGenericParametersStr(), myFrameParent->getViewNet()->getUndoList());
2241 } else if (myACs.size() > 0) {
2242 myFrameParent->getViewNet()->getUndoList()->p_begin("Change multiple generic attributes");
2243 for (auto i : myACs) {
2244 i->setAttribute(GNE_ATTR_GENERIC, getGenericParametersStr(), myFrameParent->getViewNet()->getUndoList());
2245 }
2246 myFrameParent->getViewNet()->getUndoList()->p_end();
2247 // update frame parent after attribute sucesfully set
2248 myFrameParent->updateFrameAfterChangeAttribute();
2249 }
2250 // Refresh parameter editor
2251 refreshGenericParametersEditor();
2252 }
2253 return 1;
2254 }
2255
2256
2257 long
onCmdSetGenericParameter(FXObject *,FXSelector,void *)2258 GNEFrame::GenericParametersEditor::onCmdSetGenericParameter(FXObject*, FXSelector, void*) {
2259 // separate value in a vector of string using | as separator
2260 std::vector<std::string> parsedValues;
2261 StringTokenizer st(myTextFieldGenericParameter->getText().text(), "|", true);
2262 while (st.hasNext()) {
2263 parsedValues.push_back(st.next());
2264 }
2265 // first check if parsed generic parameters are valid
2266 for (auto i : parsedValues) {
2267 if (!GNEAttributeCarrier::isGenericParametersValid(i)) {
2268 WRITE_WARNING("Invalid format of Generic Parameter (" + i + ")");
2269 myTextFieldGenericParameter->setTextColor(FXRGB(255, 0, 0));
2270 return 1;
2271 }
2272 }
2273 // now check if there is duplicated parameters
2274 std::sort(parsedValues.begin(), parsedValues.end());
2275 for (auto i = parsedValues.begin(); i != parsedValues.end(); i++) {
2276 if (((i + 1) != parsedValues.end())) {
2277 std::vector<std::string> firstKey, secondKey;
2278 StringTokenizer stKey1(*i, "=", true);
2279 StringTokenizer stKey2(*(i + 1), "=", true);
2280 //parse both keys
2281 while (stKey1.hasNext()) {
2282 firstKey.push_back(stKey1.next());
2283 }
2284 while (stKey2.hasNext()) {
2285 secondKey.push_back(stKey2.next());
2286 }
2287 // compare both keys and stop if are equal
2288 if ((firstKey.size() != 2) || (secondKey.size() != 2) || (firstKey.front() == secondKey.front())) {
2289 WRITE_WARNING("Generic Parameters wit the same key aren't allowed (" + (*i) + "," + * (i + 1) + ")");
2290 myTextFieldGenericParameter->setTextColor(FXRGB(255, 0, 0));
2291 return 1;
2292 }
2293 }
2294 }
2295 // parsed generic parameters ok, then set text field black and continue
2296 myTextFieldGenericParameter->setTextColor(FXRGB(0, 0, 0));
2297 myTextFieldGenericParameter->killFocus();
2298 // clear current existent generic parameters and set parsed generic parameters
2299 myGenericParameters->clear();
2300 for (auto i : parsedValues) {
2301 std::vector<std::string> parsedParameters;
2302 StringTokenizer stParam(i, "=", true);
2303 while (stParam.hasNext()) {
2304 parsedParameters.push_back(stParam.next());
2305 }
2306 // Check that parsed parameters are exactly two and contains valid chracters
2307 if (parsedParameters.size() == 2 && SUMOXMLDefinitions::isValidGenericParameterKey(parsedParameters.front()) && SUMOXMLDefinitions::isValidGenericParameterValue(parsedParameters.back())) {
2308 myGenericParameters->push_back(std::make_pair(parsedParameters.front(), parsedParameters.back()));
2309 }
2310 }
2311 // if we're editing generic attributes of an AttributeCarrier, set it
2312 if (myAC) {
2313 myAC->setAttribute(GNE_ATTR_GENERIC, getGenericParametersStr(), myFrameParent->getViewNet()->getUndoList());
2314 } else if (myACs.size() > 0) {
2315 myFrameParent->getViewNet()->getUndoList()->p_begin("Change multiple generic attributes");
2316 for (auto i : myACs) {
2317 i->setAttribute(GNE_ATTR_GENERIC, getGenericParametersStr(), myFrameParent->getViewNet()->getUndoList());
2318 }
2319 myFrameParent->getViewNet()->getUndoList()->p_end();
2320 // update frame parent after attribute sucesfully set
2321 myFrameParent->updateFrameAfterChangeAttribute();
2322 }
2323 return 1;
2324 }
2325
2326 // ---------------------------------------------------------------------------
2327 // GNEFrame::DrawingShape - methods
2328 // ---------------------------------------------------------------------------
2329
DrawingShape(GNEFrame * frameParent)2330 GNEFrame::DrawingShape::DrawingShape(GNEFrame* frameParent) :
2331 FXGroupBox(frameParent->myContentFrame, "Drawing", GUIDesignGroupBoxFrame),
2332 myFrameParent(frameParent),
2333 myDeleteLastCreatedPoint(false) {
2334 // create start and stop buttons
2335 myStartDrawingButton = new FXButton(this, "Start drawing", 0, this, MID_GNE_STARTDRAWING, GUIDesignButton);
2336 myStopDrawingButton = new FXButton(this, "Stop drawing", 0, this, MID_GNE_STOPDRAWING, GUIDesignButton);
2337 myAbortDrawingButton = new FXButton(this, "Abort drawing", 0, this, MID_GNE_ABORTDRAWING, GUIDesignButton);
2338
2339 // create information label
2340 std::ostringstream information;
2341 information
2342 << "- 'Start drawing' or ENTER\n"
2343 << " draws shape boundary.\n"
2344 << "- 'Stop drawing' or ENTER\n"
2345 << " creates shape.\n"
2346 << "- 'Shift + Click'\n"
2347 << " removes last created point.\n"
2348 << "- 'Abort drawing' or ESC\n"
2349 << " removes drawed shape.";
2350 myInformationLabel = new FXLabel(this, information.str().c_str(), 0, GUIDesignLabelFrameInformation);
2351 // disable stop and abort functions as init
2352 myStopDrawingButton->disable();
2353 myAbortDrawingButton->disable();
2354 }
2355
2356
~DrawingShape()2357 GNEFrame::DrawingShape::~DrawingShape() {}
2358
2359
showDrawingShape()2360 void GNEFrame::DrawingShape::showDrawingShape() {
2361 // abort current drawing before show
2362 abortDrawing();
2363 // show FXGroupBox
2364 FXGroupBox::show();
2365 }
2366
2367
hideDrawingShape()2368 void GNEFrame::DrawingShape::hideDrawingShape() {
2369 // abort current drawing before hide
2370 abortDrawing();
2371 // show FXGroupBox
2372 FXGroupBox::hide();
2373 }
2374
2375
2376 void
startDrawing()2377 GNEFrame::DrawingShape::startDrawing() {
2378 // Only start drawing if DrawingShape modul is shown
2379 if (shown()) {
2380 // change buttons
2381 myStartDrawingButton->disable();
2382 myStopDrawingButton->enable();
2383 myAbortDrawingButton->enable();
2384 }
2385 }
2386
2387
2388 void
stopDrawing()2389 GNEFrame::DrawingShape::stopDrawing() {
2390 // try to build shape
2391 if (myFrameParent->buildShape()) {
2392 // clear created points
2393 myTemporalShapeShape.clear();
2394 myFrameParent->getViewNet()->update();
2395 // change buttons
2396 myStartDrawingButton->enable();
2397 myStopDrawingButton->disable();
2398 myAbortDrawingButton->disable();
2399 } else {
2400 // abort drawing if shape cannot be created
2401 abortDrawing();
2402 }
2403 }
2404
2405
2406 void
abortDrawing()2407 GNEFrame::DrawingShape::abortDrawing() {
2408 // clear created points
2409 myTemporalShapeShape.clear();
2410 myFrameParent->getViewNet()->update();
2411 // change buttons
2412 myStartDrawingButton->enable();
2413 myStopDrawingButton->disable();
2414 myAbortDrawingButton->disable();
2415 }
2416
2417
2418 void
addNewPoint(const Position & P)2419 GNEFrame::DrawingShape::addNewPoint(const Position& P) {
2420 if (myStopDrawingButton->isEnabled()) {
2421 myTemporalShapeShape.push_back(P);
2422 } else {
2423 throw ProcessError("A new point cannot be added if drawing wasn't started");
2424 }
2425 }
2426
2427
2428 void
removeLastPoint()2429 GNEFrame::DrawingShape::removeLastPoint() {
2430
2431 }
2432
2433
2434 const PositionVector&
getTemporalShape() const2435 GNEFrame::DrawingShape::getTemporalShape() const {
2436 return myTemporalShapeShape;
2437 }
2438
2439
2440 bool
isDrawing() const2441 GNEFrame::DrawingShape::isDrawing() const {
2442 return myStopDrawingButton->isEnabled();
2443 }
2444
2445
2446 void
setDeleteLastCreatedPoint(bool value)2447 GNEFrame::DrawingShape::setDeleteLastCreatedPoint(bool value) {
2448 myDeleteLastCreatedPoint = value;
2449 }
2450
2451
2452 bool
getDeleteLastCreatedPoint()2453 GNEFrame::DrawingShape::getDeleteLastCreatedPoint() {
2454 return myDeleteLastCreatedPoint;
2455 }
2456
2457
2458 long
onCmdStartDrawing(FXObject *,FXSelector,void *)2459 GNEFrame::DrawingShape::onCmdStartDrawing(FXObject*, FXSelector, void*) {
2460 startDrawing();
2461 return 0;
2462 }
2463
2464
2465 long
onCmdStopDrawing(FXObject *,FXSelector,void *)2466 GNEFrame::DrawingShape::onCmdStopDrawing(FXObject*, FXSelector, void*) {
2467 stopDrawing();
2468 return 0;
2469 }
2470
2471
2472 long
onCmdAbortDrawing(FXObject *,FXSelector,void *)2473 GNEFrame::DrawingShape::onCmdAbortDrawing(FXObject*, FXSelector, void*) {
2474 abortDrawing();
2475 return 0;
2476 }
2477
2478 // ---------------------------------------------------------------------------
2479 // GNEFrame::NeteditAttributes- methods
2480 // ---------------------------------------------------------------------------
2481
NeteditAttributes(GNEFrame * frameParent)2482 GNEFrame::NeteditAttributes::NeteditAttributes(GNEFrame* frameParent) :
2483 FXGroupBox(frameParent->myContentFrame, "Netedit attributes", GUIDesignGroupBoxFrame),
2484 myFrameParent(frameParent),
2485 myCurrentLengthValid(true),
2486 myActualAdditionalReferencePoint(GNE_ADDITIONALREFERENCEPOINT_LEFT) {
2487 // Create FXListBox for the reference points and fill it
2488 myReferencePointMatchBox = new FXComboBox(this, GUIDesignComboBoxNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignComboBox);
2489 myReferencePointMatchBox->appendItem("reference left");
2490 myReferencePointMatchBox->appendItem("reference right");
2491 myReferencePointMatchBox->appendItem("reference center");
2492 // Create Frame for Length Label and textField
2493 FXHorizontalFrame* lengthFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
2494 myLengthLabel = new FXLabel(lengthFrame, toString(SUMO_ATTR_LENGTH).c_str(), 0, GUIDesignLabelAttribute);
2495 myLengthTextField = new FXTextField(lengthFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);
2496 myLengthTextField->setText("10");
2497 // Create Frame for block movement label and checkBox (By default disabled)
2498 FXHorizontalFrame* blockMovement = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
2499 myBlockMovementLabel = new FXLabel(blockMovement, "block move", 0, GUIDesignLabelAttribute);
2500 myBlockMovementCheckButton = new FXCheckButton(blockMovement, "false", this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButtonAttribute);
2501 myBlockMovementCheckButton->setCheck(false);
2502 // Create Frame for block shape label and checkBox (By default disabled)
2503 FXHorizontalFrame* blockShapeFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
2504 myBlockShapeLabel = new FXLabel(blockShapeFrame, "block shape", 0, GUIDesignLabelAttribute);
2505 myBlockShapeCheckButton = new FXCheckButton(blockShapeFrame, "false", this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButtonAttribute);
2506 // Create Frame for block close polygon and checkBox (By default disabled)
2507 FXHorizontalFrame* closePolygonFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
2508 myClosePolygonLabel = new FXLabel(closePolygonFrame, "Close shape", 0, GUIDesignLabelAttribute);
2509 myCloseShapeCheckButton = new FXCheckButton(closePolygonFrame, "false", this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButtonAttribute);
2510 myBlockShapeCheckButton->setCheck(false);
2511 // Create help button
2512 helpReferencePoint = new FXButton(this, "Help", 0, this, MID_HELP, GUIDesignButtonRectangular);
2513 // Set visible items
2514 myReferencePointMatchBox->setNumVisible((int)myReferencePointMatchBox->getNumItems());
2515 }
2516
2517
~NeteditAttributes()2518 GNEFrame::NeteditAttributes::~NeteditAttributes() {}
2519
2520
2521 void
showNeteditAttributesModul(const GNEAttributeCarrier::TagProperties & tagProperty)2522 GNEFrame::NeteditAttributes::showNeteditAttributesModul(const GNEAttributeCarrier::TagProperties& tagProperty) {
2523 // we assume that frame will not be show
2524 bool showFrame = false;
2525 // check if lenght text field has to be showed
2526 if (tagProperty.canMaskStartEndPos()) {
2527 myLengthLabel->show();
2528 myLengthTextField->show();
2529 myReferencePointMatchBox->show();
2530 showFrame = true;
2531 } else {
2532 myLengthLabel->hide();
2533 myLengthTextField->hide();
2534 myReferencePointMatchBox->hide();
2535 }
2536 // check if block movement check button has to be show
2537 if (tagProperty.canBlockMovement()) {
2538 myBlockMovementLabel->show();
2539 myBlockMovementCheckButton->show();
2540 showFrame = true;
2541 } else {
2542 myBlockMovementLabel->hide();
2543 myBlockMovementCheckButton->hide();
2544 }
2545 // check if block shape check button has to be show
2546 if (tagProperty.canBlockShape()) {
2547 myBlockShapeLabel->show();
2548 myBlockShapeCheckButton->show();
2549 showFrame = true;
2550 } else {
2551 myBlockShapeLabel->hide();
2552 myBlockShapeCheckButton->hide();
2553 }
2554 // check if close shape check button has to be show
2555 if (tagProperty.canCloseShape()) {
2556 myClosePolygonLabel->show();
2557 myCloseShapeCheckButton->show();
2558 showFrame = true;
2559 } else {
2560 myClosePolygonLabel->hide();
2561 myCloseShapeCheckButton->hide();
2562 }
2563 // if at least one element is show, show modul
2564 if (showFrame) {
2565 show();
2566 } else {
2567 hide();
2568 }
2569 }
2570
2571
2572 void
hideNeteditAttributesModul()2573 GNEFrame::NeteditAttributes::hideNeteditAttributesModul() {
2574 hide();
2575 }
2576
2577
2578 bool
getNeteditAttributesAndValues(std::map<SumoXMLAttr,std::string> & valuesMap,GNELane * lane) const2579 GNEFrame::NeteditAttributes::getNeteditAttributesAndValues(std::map<SumoXMLAttr, std::string>& valuesMap, GNELane* lane) const {
2580 // check if we need to obtain a start and end position over an edge
2581 if (myReferencePointMatchBox->shown()) {
2582 // we need a valid lane to calculate position over lane
2583 if (lane == nullptr) {
2584 return false;
2585 } else if (myCurrentLengthValid) {
2586 // Obtain position of the mouse over lane (limited over grid)
2587 double mousePositionOverLane = lane->getShape().nearest_offset_to_point2D(myFrameParent->myViewNet->snapToActiveGrid(myFrameParent->myViewNet->getPositionInformation())) / lane->getLengthGeometryFactor();
2588 // check if current reference point is valid
2589 if (myActualAdditionalReferencePoint == GNE_ADDITIONALREFERENCEPOINT_INVALID) {
2590 std::string errorMessage = "Current selected reference point isn't valid";
2591 myFrameParent->myViewNet->setStatusBarText(errorMessage);
2592 // Write Warning in console if we're in testing mode
2593 WRITE_DEBUG(errorMessage);
2594 return false;
2595 } else {
2596 // obtain lenght
2597 double lenght = GNEAttributeCarrier::parse<double>(myLengthTextField->getText().text());
2598 // set start and end position
2599 valuesMap[SUMO_ATTR_STARTPOS] = toString(setStartPosition(mousePositionOverLane, lenght));
2600 valuesMap[SUMO_ATTR_ENDPOS] = toString(setEndPosition(mousePositionOverLane, lenght));
2601 }
2602 } else {
2603 return false;
2604 }
2605 }
2606 // Save block value if element can be blocked
2607 if (myBlockMovementCheckButton->shown()) {
2608 if (myBlockMovementCheckButton->getCheck() == 1) {
2609 valuesMap[GNE_ATTR_BLOCK_MOVEMENT] = "1";
2610 } else {
2611 valuesMap[GNE_ATTR_BLOCK_MOVEMENT] = "0";
2612 }
2613 }
2614 // Save block shape value if shape's element can be blocked
2615 if (myBlockShapeCheckButton->shown()) {
2616 if (myBlockShapeCheckButton->getCheck() == 1) {
2617 valuesMap[GNE_ATTR_BLOCK_SHAPE] = "1";
2618 } else {
2619 valuesMap[GNE_ATTR_BLOCK_SHAPE] = "0";
2620 }
2621 }
2622 // Save close shape value if shape's element can be closed
2623 if (myCloseShapeCheckButton->shown()) {
2624 if (myCloseShapeCheckButton->getCheck() == 1) {
2625 valuesMap[GNE_ATTR_CLOSE_SHAPE] = "1";
2626 } else {
2627 valuesMap[GNE_ATTR_CLOSE_SHAPE] = "0";
2628 }
2629 }
2630 // all ok, then return true to continue creating element
2631 return true;
2632 }
2633
2634
2635 long
onCmdSetNeteditAttribute(FXObject * obj,FXSelector,void *)2636 GNEFrame::NeteditAttributes::onCmdSetNeteditAttribute(FXObject* obj, FXSelector, void*) {
2637 if (obj == myBlockMovementCheckButton) {
2638 if (myBlockMovementCheckButton->getCheck()) {
2639 myBlockMovementCheckButton->setText("true");
2640 } else {
2641 myBlockMovementCheckButton->setText("false");
2642 }
2643 } else if (obj == myBlockShapeCheckButton) {
2644 if (myBlockShapeCheckButton->getCheck()) {
2645 myBlockShapeCheckButton->setText("true");
2646 } else {
2647 myBlockShapeCheckButton->setText("false");
2648 }
2649 } else if (obj == myCloseShapeCheckButton) {
2650 if (myCloseShapeCheckButton->getCheck()) {
2651 myCloseShapeCheckButton->setText("true");
2652 } else {
2653 myCloseShapeCheckButton->setText("false");
2654 }
2655 } else if (obj == myLengthTextField) {
2656 // change color of text field depending of the input length
2657 if (GNEAttributeCarrier::canParse<double>(myLengthTextField->getText().text()) &&
2658 GNEAttributeCarrier::parse<double>(myLengthTextField->getText().text()) > 0) {
2659 myLengthTextField->setTextColor(FXRGB(0, 0, 0));
2660 myLengthTextField->killFocus();
2661 myCurrentLengthValid = true;
2662 } else {
2663 myLengthTextField->setTextColor(FXRGB(255, 0, 0));
2664 myCurrentLengthValid = false;
2665 }
2666 // Update aditional frame
2667 update();
2668 } else if (obj == myReferencePointMatchBox) {
2669 // Cast actual reference point type
2670 if (myReferencePointMatchBox->getText() == "reference left") {
2671 myReferencePointMatchBox->setTextColor(FXRGB(0, 0, 0));
2672 myActualAdditionalReferencePoint = GNE_ADDITIONALREFERENCEPOINT_LEFT;
2673 myLengthTextField->enable();
2674 } else if (myReferencePointMatchBox->getText() == "reference right") {
2675 myReferencePointMatchBox->setTextColor(FXRGB(0, 0, 0));
2676 myActualAdditionalReferencePoint = GNE_ADDITIONALREFERENCEPOINT_RIGHT;
2677 myLengthTextField->enable();
2678 } else if (myReferencePointMatchBox->getText() == "reference center") {
2679 myLengthTextField->enable();
2680 myReferencePointMatchBox->setTextColor(FXRGB(0, 0, 0));
2681 myActualAdditionalReferencePoint = GNE_ADDITIONALREFERENCEPOINT_CENTER;
2682 myLengthTextField->enable();
2683 } else {
2684 myReferencePointMatchBox->setTextColor(FXRGB(255, 0, 0));
2685 myActualAdditionalReferencePoint = GNE_ADDITIONALREFERENCEPOINT_INVALID;
2686 myLengthTextField->disable();
2687 }
2688 }
2689
2690 return 1;
2691 }
2692
2693
2694 long
onCmdHelp(FXObject *,FXSelector,void *)2695 GNEFrame::NeteditAttributes::onCmdHelp(FXObject*, FXSelector, void*) {
2696 // Create dialog box
2697 FXDialogBox* additionalNeteditAttributesHelpDialog = new FXDialogBox(this, "Netedit Parameters Help", GUIDesignDialogBox);
2698 additionalNeteditAttributesHelpDialog->setIcon(GUIIconSubSys::getIcon(ICON_MODEADDITIONAL));
2699 // set help text
2700 std::ostringstream help;
2701 help
2702 << "- Referece point: Mark the initial position of the additional element.\n"
2703 << " Example: If you want to create a busStop with a length of 30 in the point 100 of the lane:\n"
2704 << " - Reference Left will create it with startPos = 70 and endPos = 100.\n"
2705 << " - Reference Right will create it with startPos = 100 and endPos = 130.\n"
2706 << " - Reference Center will create it with startPos = 85 and endPos = 115.\n"
2707 << "\n"
2708 << "- Block movement: if is enabled, the created additional element will be blocked. i.e. cannot be moved with\n"
2709 << " the mouse. This option can be modified inspecting element.";
2710 // Create label with the help text
2711 new FXLabel(additionalNeteditAttributesHelpDialog, help.str().c_str(), 0, GUIDesignLabelFrameInformation);
2712 // Create horizontal separator
2713 new FXHorizontalSeparator(additionalNeteditAttributesHelpDialog, GUIDesignHorizontalSeparator);
2714 // Create frame for OK Button
2715 FXHorizontalFrame* myHorizontalFrameOKButton = new FXHorizontalFrame(additionalNeteditAttributesHelpDialog, GUIDesignAuxiliarHorizontalFrame);
2716 // Create Button Close (And two more horizontal frames to center it)
2717 new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
2718 new FXButton(myHorizontalFrameOKButton, "OK\t\tclose", GUIIconSubSys::getIcon(ICON_ACCEPT), additionalNeteditAttributesHelpDialog, FXDialogBox::ID_ACCEPT, GUIDesignButtonOK);
2719 new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
2720 // Write Warning in console if we're in testing mode
2721 WRITE_DEBUG("Opening NeteditAttributes help dialog");
2722 // create Dialog
2723 additionalNeteditAttributesHelpDialog->create();
2724 // show in the given position
2725 additionalNeteditAttributesHelpDialog->show(PLACEMENT_CURSOR);
2726 // refresh APP
2727 getApp()->refresh();
2728 // open as modal dialog (will block all windows until stop() or stopModal() is called)
2729 getApp()->runModalFor(additionalNeteditAttributesHelpDialog);
2730 // Write Warning in console if we're in testing mode
2731 WRITE_DEBUG("Closing NeteditAttributes help dialog");
2732 return 1;
2733 /**********
2734 help from PolygonFrame
2735 << "- Block movement: If enabled, the created polygon element will be blocked. i.e. cannot be moved with\n"
2736 << " the mouse. This option can be modified inspecting element.\n"
2737 << "\n"
2738 << "- Block shape: If enabled, the shape of created polygon element will be blocked. i.e. their geometry points\n"
2739 << " cannot be edited be moved with the mouse. This option can be modified inspecting element.\n"
2740 << "\n"
2741 << "- Close shape: If enabled, the created polygon element will be closed. i.e. the last created geometry point\n"
2742 << " will be connected with the first geometry point automatically. This option can be modified inspecting element.";
2743
2744 ****************/
2745 }
2746
2747
2748 double
setStartPosition(double positionOfTheMouseOverLane,double lengthOfAdditional) const2749 GNEFrame::NeteditAttributes::setStartPosition(double positionOfTheMouseOverLane, double lengthOfAdditional) const {
2750 switch (myActualAdditionalReferencePoint) {
2751 case GNE_ADDITIONALREFERENCEPOINT_LEFT:
2752 return positionOfTheMouseOverLane;
2753 case GNE_ADDITIONALREFERENCEPOINT_RIGHT:
2754 return positionOfTheMouseOverLane - lengthOfAdditional;
2755 case GNE_ADDITIONALREFERENCEPOINT_CENTER:
2756 return positionOfTheMouseOverLane - lengthOfAdditional / 2;
2757 default:
2758 throw InvalidArgument("Reference Point invalid");
2759 }
2760 }
2761
2762
2763 double
setEndPosition(double positionOfTheMouseOverLane,double lengthOfAdditional) const2764 GNEFrame::NeteditAttributes::setEndPosition(double positionOfTheMouseOverLane, double lengthOfAdditional) const {
2765 switch (myActualAdditionalReferencePoint) {
2766 case GNE_ADDITIONALREFERENCEPOINT_LEFT:
2767 return positionOfTheMouseOverLane + lengthOfAdditional;
2768 case GNE_ADDITIONALREFERENCEPOINT_RIGHT:
2769 return positionOfTheMouseOverLane;
2770 case GNE_ADDITIONALREFERENCEPOINT_CENTER:
2771 return positionOfTheMouseOverLane + lengthOfAdditional / 2;
2772 default:
2773 throw InvalidArgument("Reference Point invalid");
2774 }
2775 }
2776
2777 // ---------------------------------------------------------------------------
2778 // GNEFrame - methods
2779 // ---------------------------------------------------------------------------
2780
GNEFrame(FXHorizontalFrame * horizontalFrameParent,GNEViewNet * viewNet,const std::string & frameLabel)2781 GNEFrame::GNEFrame(FXHorizontalFrame* horizontalFrameParent, GNEViewNet* viewNet, const std::string& frameLabel) :
2782 FXVerticalFrame(horizontalFrameParent, GUIDesignAuxiliarFrame),
2783 myViewNet(viewNet),
2784 myEdgeCandidateColor(RGBColor(0, 64, 0, 255)),
2785 myEdgeCandidateSelectedColor(RGBColor::GREEN) {
2786
2787 // fill myPredefinedTagsMML (to avoid repeating this fill during every element creation)
2788 int i = 0;
2789 while (SUMOXMLDefinitions::attrs[i].key != SUMO_ATTR_NOTHING) {
2790 myPredefinedTagsMML[SUMOXMLDefinitions::attrs[i].key] = toString(SUMOXMLDefinitions::attrs[i].str);
2791 myPredefinedTagsMML[SUMOXMLDefinitions::attrs[i].key] = SUMOXMLDefinitions::attrs[i].str;
2792 i++;
2793 }
2794
2795 // Create font only one time
2796 if (myFrameHeaderFont == nullptr) {
2797 myFrameHeaderFont = new FXFont(getApp(), "Arial", 14, FXFont::Bold);
2798 }
2799
2800 // Create frame for header
2801 myHeaderFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
2802
2803 // Create frame for left elements of header (By default unused)
2804 myHeaderLeftFrame = new FXHorizontalFrame(myHeaderFrame, GUIDesignAuxiliarHorizontalFrame);
2805 myHeaderLeftFrame->hide();
2806
2807 // Create titel frame
2808 myFrameHeaderLabel = new FXLabel(myHeaderFrame, frameLabel.c_str(), nullptr, GUIDesignLabelFrameInformation);
2809
2810 // Create frame for right elements of header (By default unused)
2811 myHeaderRightFrame = new FXHorizontalFrame(myHeaderFrame, GUIDesignAuxiliarHorizontalFrame);
2812 myHeaderRightFrame->hide();
2813
2814 // Add separator
2815 new FXHorizontalSeparator(this, GUIDesignHorizontalSeparator);
2816
2817 // Create frame for contents
2818 myScrollWindowsContents = new FXScrollWindow(this, GUIDesignContentsScrollWindow);
2819
2820 // Create frame for contents
2821 myContentFrame = new FXVerticalFrame(myScrollWindowsContents, GUIDesignContentsFrame);
2822
2823 // Set font of header
2824 myFrameHeaderLabel->setFont(myFrameHeaderFont);
2825
2826 // Hide Frame
2827 FXVerticalFrame::hide();
2828 }
2829
2830
~GNEFrame()2831 GNEFrame::~GNEFrame() {
2832 // delete frame header only one time
2833 if (myFrameHeaderFont) {
2834 delete myFrameHeaderFont;
2835 myFrameHeaderFont = nullptr;
2836 }
2837 }
2838
2839
2840 void
focusUpperElement()2841 GNEFrame::focusUpperElement() {
2842 myFrameHeaderLabel->setFocus();
2843 }
2844
2845
2846 void
show()2847 GNEFrame::show() {
2848 // show scroll window
2849 FXVerticalFrame::show();
2850 // Show and update Frame Area in which this GNEFrame is placed
2851 myViewNet->getViewParent()->showFramesArea();
2852 }
2853
2854
2855 void
hide()2856 GNEFrame::hide() {
2857 // hide scroll window
2858 FXVerticalFrame::hide();
2859 // Hide Frame Area in which this GNEFrame is placed
2860 myViewNet->getViewParent()->hideFramesArea();
2861 }
2862
2863
2864 void
setFrameWidth(int newWidth)2865 GNEFrame::setFrameWidth(int newWidth) {
2866 setWidth(newWidth);
2867 myScrollWindowsContents->setWidth(newWidth);
2868 }
2869
2870
2871 GNEViewNet*
getViewNet() const2872 GNEFrame::getViewNet() const {
2873 return myViewNet;
2874 }
2875
2876
2877 FXLabel*
getFrameHeaderLabel() const2878 GNEFrame::getFrameHeaderLabel() const {
2879 return myFrameHeaderLabel;
2880 }
2881
2882
2883 FXFont*
getFrameHeaderFont() const2884 GNEFrame::getFrameHeaderFont() const {
2885 return myFrameHeaderFont;
2886 }
2887
2888
2889 void
updateFrameAfterUndoRedo()2890 GNEFrame::updateFrameAfterUndoRedo() {
2891 // this function has to be reimplemente in all child frames that needs to draw a polygon (for example, GNEFrame or GNETAZFrame)
2892 }
2893
2894 // ---------------------------------------------------------------------------
2895 // GNEFrame - protected methods
2896 // ---------------------------------------------------------------------------
2897
2898 bool
buildShape()2899 GNEFrame::buildShape() {
2900 // this function has to be reimplemente in all child frames that needs to draw a polygon (for example, GNEFrame or GNETAZFrame)
2901 return false;
2902 }
2903
2904
2905 void
enableModuls(const GNEAttributeCarrier::TagProperties &)2906 GNEFrame::enableModuls(const GNEAttributeCarrier::TagProperties&) {
2907 // this function has to be reimplemente in all child frames that uses a ItemSelector modul
2908 }
2909
2910
2911 void
disableModuls()2912 GNEFrame::disableModuls() {
2913 // this function has to be reimplemente in all child frames that uses a ItemSelector modul
2914 }
2915
2916
2917 void
updateFrameAfterChangeAttribute()2918 GNEFrame::updateFrameAfterChangeAttribute() {
2919 // this function has to be reimplemente in all child frames that uses a ItemSelector modul
2920 }
2921
2922 void
openAttributesEditorExtendedDialog()2923 GNEFrame::openAttributesEditorExtendedDialog() {
2924 // this function has to be reimplemente in all child frames that uses a AttributesCreator editor with extended attributes
2925 }
2926
2927
2928 void
openHelpAttributesDialog(const GNEAttributeCarrier::TagProperties & tagProperties) const2929 GNEFrame::openHelpAttributesDialog(const GNEAttributeCarrier::TagProperties& tagProperties) const {
2930 FXDialogBox* attributesHelpDialog = new FXDialogBox(myScrollWindowsContents, ("Parameters of " + tagProperties.getTagStr()).c_str(), GUIDesignDialogBoxResizable, 0, 0, 0, 0, 10, 10, 10, 38, 4, 4);
2931 // Create FXTable
2932 FXTable* myTable = new FXTable(attributesHelpDialog, attributesHelpDialog, MID_TABLE, GUIDesignTableNotEditable);
2933 attributesHelpDialog->setIcon(GUIIconSubSys::getIcon(ICON_MODEINSPECT));
2934 int sizeColumnDescription = 0;
2935 int sizeColumnDefinitions = 0;
2936 myTable->setVisibleRows((FXint)(tagProperties.getNumberOfAttributes()));
2937 myTable->setVisibleColumns(3);
2938 myTable->setTableSize((FXint)(tagProperties.getNumberOfAttributes()), 3);
2939 myTable->setBackColor(FXRGB(255, 255, 255));
2940 myTable->setColumnText(0, "Attribute");
2941 myTable->setColumnText(1, "Description");
2942 myTable->setColumnText(2, "Definition");
2943 myTable->getRowHeader()->setWidth(0);
2944 // Iterate over vector of additional parameters
2945 int itemIndex = 0;
2946 for (auto i : tagProperties) {
2947 // Set attribute
2948 FXTableItem* attribute = new FXTableItem(toString(i.first).c_str());
2949 attribute->setJustify(FXTableItem::CENTER_X);
2950 myTable->setItem(itemIndex, 0, attribute);
2951 // Set description of element
2952 FXTableItem* type = new FXTableItem("");
2953 type->setText(i.second.getDescription().c_str());
2954 sizeColumnDescription = MAX2(sizeColumnDescription, (int)i.second.getDescription().size());
2955 type->setJustify(FXTableItem::CENTER_X);
2956 myTable->setItem(itemIndex, 1, type);
2957 // Set definition
2958 FXTableItem* definition = new FXTableItem(i.second.getDefinition().c_str());
2959 definition->setJustify(FXTableItem::LEFT);
2960 myTable->setItem(itemIndex, 2, definition);
2961 sizeColumnDefinitions = MAX2(sizeColumnDefinitions, (int)i.second.getDefinition().size());
2962 itemIndex++;
2963 }
2964 // set header
2965 FXHeader* header = myTable->getColumnHeader();
2966 header->setItemJustify(0, JUSTIFY_CENTER_X);
2967 header->setItemSize(0, 120);
2968 header->setItemJustify(1, JUSTIFY_CENTER_X);
2969 header->setItemSize(1, sizeColumnDescription * 7);
2970 header->setItemJustify(2, JUSTIFY_CENTER_X);
2971 header->setItemSize(2, sizeColumnDefinitions * 6);
2972 // Create horizontal separator
2973 new FXHorizontalSeparator(attributesHelpDialog, GUIDesignHorizontalSeparator);
2974 // Create frame for OK Button
2975 FXHorizontalFrame* myHorizontalFrameOKButton = new FXHorizontalFrame(attributesHelpDialog, GUIDesignAuxiliarHorizontalFrame);
2976 // Create Button Close (And two more horizontal frames to center it)
2977 new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
2978 new FXButton(myHorizontalFrameOKButton, "OK\t\tclose", GUIIconSubSys::getIcon(ICON_ACCEPT), attributesHelpDialog, FXDialogBox::ID_ACCEPT, GUIDesignButtonOK);
2979 new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
2980 // Write Warning in console if we're in testing mode
2981 WRITE_DEBUG("Opening HelpAttributes dialog for tag '" + tagProperties.getTagStr() + "' showing " + toString(tagProperties.getNumberOfAttributes()) + " attributes");
2982 // create Dialog
2983 attributesHelpDialog->create();
2984 // show in the given position
2985 attributesHelpDialog->show(PLACEMENT_CURSOR);
2986 // refresh APP
2987 getApp()->refresh();
2988 // open as modal dialog (will block all windows until stop() or stopModal() is called)
2989 getApp()->runModalFor(attributesHelpDialog);
2990 // Write Warning in console if we're in testing mode
2991 WRITE_DEBUG("Closing HelpAttributes dialog for tag '" + tagProperties.getTagStr() + "'");
2992 }
2993
2994
2995 const RGBColor&
getEdgeCandidateColor() const2996 GNEFrame::getEdgeCandidateColor() const {
2997 return myEdgeCandidateColor;
2998 }
2999
3000
3001 const RGBColor&
getEdgeCandidateSelectedColor() const3002 GNEFrame::getEdgeCandidateSelectedColor() const {
3003 return myEdgeCandidateSelectedColor;
3004 }
3005
3006
3007 const std::map<int, std::string>&
getPredefinedTagsMML() const3008 GNEFrame::getPredefinedTagsMML() const {
3009 return myPredefinedTagsMML;
3010 }
3011
3012 /****************************************************************************/
3013