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    GNEAdditionalFrame.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Dec 2015
13 /// @version $Id$
14 ///
15 // The Widget for add additional elements
16 /****************************************************************************/
17 
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 #include <config.h>
22 
23 #include <utils/gui/windows/GUIAppEnum.h>
24 #include <utils/gui/div/GUIDesigns.h>
25 #include <utils/xml/SUMOSAXAttributesImpl_Cached.h>
26 #include <netedit/changes/GNEChange_Additional.h>
27 #include <netedit/netelements/GNEEdge.h>
28 #include <netedit/netelements/GNELane.h>
29 #include <netedit/netelements/GNEConnection.h>
30 #include <netedit/additionals/GNEAdditional.h>
31 #include <netedit/additionals/GNEAdditionalHandler.h>
32 #include <netedit/GNENet.h>
33 #include <netedit/GNEViewNet.h>
34 #include <netedit/GNEUndoList.h>
35 
36 #include "GNEAdditionalFrame.h"
37 
38 
39 // ===========================================================================
40 // FOX callback mapping
41 // ===========================================================================
42 
43 FXDEFMAP(GNEAdditionalFrame::SelectorLaneParents) ConsecutiveLaneSelectorMap[] = {
44     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_STOPSELECTION,  GNEAdditionalFrame::SelectorLaneParents::onCmdStopSelection),
45     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_ABORTSELECTION, GNEAdditionalFrame::SelectorLaneParents::onCmdAbortSelection),
46 };
47 
48 FXDEFMAP(GNEAdditionalFrame::SelectorEdgeChilds) SelectorParentEdgesMap[] = {
49     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_USESELECTED,        GNEAdditionalFrame::SelectorEdgeChilds::onCmdUseSelectedEdges),
50     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_CLEARSELECTION,     GNEAdditionalFrame::SelectorEdgeChilds::onCmdClearSelection),
51     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_INVERTSELECTION,    GNEAdditionalFrame::SelectorEdgeChilds::onCmdInvertSelection),
52     FXMAPFUNC(SEL_CHANGED,  MID_GNE_ADDITIONALFRAME_SEARCH,             GNEAdditionalFrame::SelectorEdgeChilds::onCmdTypeInSearchBox),
53     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_SELECT,             GNEAdditionalFrame::SelectorEdgeChilds::onCmdSelectEdge),
54 };
55 
56 FXDEFMAP(GNEAdditionalFrame::SelectorLaneChilds) SelectorParentLanesMap[] = {
57     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_USESELECTED,        GNEAdditionalFrame::SelectorLaneChilds::onCmdUseSelectedLanes),
58     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_CLEARSELECTION,     GNEAdditionalFrame::SelectorLaneChilds::onCmdClearSelection),
59     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_INVERTSELECTION,    GNEAdditionalFrame::SelectorLaneChilds::onCmdInvertSelection),
60     FXMAPFUNC(SEL_CHANGED,  MID_GNE_ADDITIONALFRAME_SEARCH,             GNEAdditionalFrame::SelectorLaneChilds::onCmdTypeInSearchBox),
61     FXMAPFUNC(SEL_COMMAND,  MID_GNE_ADDITIONALFRAME_SELECT,             GNEAdditionalFrame::SelectorLaneChilds::onCmdSelectLane),
62 };
63 
64 // Object implementation
FXIMPLEMENT(GNEAdditionalFrame::SelectorLaneParents,FXGroupBox,ConsecutiveLaneSelectorMap,ARRAYNUMBER (ConsecutiveLaneSelectorMap))65 FXIMPLEMENT(GNEAdditionalFrame::SelectorLaneParents,        FXGroupBox,         ConsecutiveLaneSelectorMap,     ARRAYNUMBER(ConsecutiveLaneSelectorMap))
66 FXIMPLEMENT(GNEAdditionalFrame::SelectorEdgeChilds,         FXGroupBox,         SelectorParentEdgesMap,         ARRAYNUMBER(SelectorParentEdgesMap))
67 FXIMPLEMENT(GNEAdditionalFrame::SelectorLaneChilds,         FXGroupBox,         SelectorParentLanesMap,         ARRAYNUMBER(SelectorParentLanesMap))
68 
69 
70 // ---------------------------------------------------------------------------
71 // GNEAdditionalFrame::SelectorLaneParents - methods
72 // ---------------------------------------------------------------------------
73 
74 GNEAdditionalFrame::SelectorLaneParents::SelectorLaneParents(GNEAdditionalFrame* additionalFrameParent) :
75     FXGroupBox(additionalFrameParent->myContentFrame, "Lane Selector", GUIDesignGroupBoxFrame),
76     myAdditionalFrameParent(additionalFrameParent) {
77     // create start and stop buttons
78     myStopSelectingButton = new FXButton(this, "Stop selecting", nullptr, this, MID_GNE_ADDITIONALFRAME_STOPSELECTION, GUIDesignButton);
79     myAbortSelectingButton = new FXButton(this, "Abort selecting", nullptr, this, MID_GNE_ADDITIONALFRAME_ABORTSELECTION, GUIDesignButton);
80     // disable stop and abort functions as init
81     myStopSelectingButton->disable();
82     myAbortSelectingButton->disable();
83     // define colors
84     myCandidateLaneColor = RGBColor(0, 64, 0, 255);
85     mySelectedLaneColor = RGBColor::GREEN;
86 }
87 
88 
~SelectorLaneParents()89 GNEAdditionalFrame::SelectorLaneParents::~SelectorLaneParents() {}
90 
91 
92 void
showSelectorLaneParentsModul()93 GNEAdditionalFrame::SelectorLaneParents::showSelectorLaneParentsModul() {
94     // abort current selection before show
95     abortConsecutiveLaneSelector();
96     // show FXGroupBox
97     FXGroupBox::show();
98 }
99 
100 
101 void
hideSelectorLaneParentsModul()102 GNEAdditionalFrame::SelectorLaneParents::hideSelectorLaneParentsModul() {
103     // abort current selection before hide
104     abortConsecutiveLaneSelector();
105     // hide FXGroupBox
106     FXGroupBox::hide();
107 }
108 
109 
110 void
startConsecutiveLaneSelector(GNELane * lane,const Position & clickedPosition)111 GNEAdditionalFrame::SelectorLaneParents::startConsecutiveLaneSelector(GNELane* lane, const Position& clickedPosition) {
112     // Only start selection if SelectorLaneParents modul is shown
113     if (shown()) {
114         // change buttons
115         myStopSelectingButton->enable();
116         myAbortSelectingButton->enable();
117         // add lane
118         addSelectedLane(lane, clickedPosition);
119     }
120 }
121 
122 
123 bool
stopConsecutiveLaneSelector()124 GNEAdditionalFrame::SelectorLaneParents::stopConsecutiveLaneSelector() {
125     // obtain tagproperty (only for improve code legibility)
126     const auto& tagValues = myAdditionalFrameParent->myItemSelector->getCurrentTagProperties();
127     // abort if there isn't at least two lanes
128     if (mySelectedLanes.size() < 2) {
129         WRITE_WARNING(myAdditionalFrameParent->myItemSelector->getCurrentTagProperties().getTagStr() + " requieres at least two lanes.");
130         // abort consecutive lane selector
131         abortConsecutiveLaneSelector();
132         return false;
133     }
134     // Declare map to keep attributes from Frames from Frame
135     std::map<SumoXMLAttr, std::string> valuesMap = myAdditionalFrameParent->myAdditionalAttributes->getAttributesAndValues(true);
136     // fill valuesOfElement with Netedit attributes from Frame
137     myAdditionalFrameParent->myNeteditAttributes->getNeteditAttributesAndValues(valuesMap, nullptr);
138     // Generate id of element
139     valuesMap[SUMO_ATTR_ID] = myAdditionalFrameParent->generateID(nullptr);
140     // obtain lane IDs
141     std::vector<std::string> laneIDs;
142     for (auto i : mySelectedLanes) {
143         laneIDs.push_back(i.first->getID());
144     }
145     valuesMap[SUMO_ATTR_LANES] = joinToString(laneIDs, " ");
146     // Obtain clicked position over first lane
147     valuesMap[SUMO_ATTR_POSITION] = toString(mySelectedLanes.front().second);
148     // Obtain clicked position over last lane
149     valuesMap[SUMO_ATTR_ENDPOS] = toString(mySelectedLanes.back().second);
150     // parse common attributes
151     if (!myAdditionalFrameParent->buildAdditionalCommonAttributes(valuesMap, tagValues)) {
152         return false;
153     }
154     // show warning dialogbox and stop check if input parameters are valid
155     if (myAdditionalFrameParent->myAdditionalAttributes->areValuesValid() == false) {
156         myAdditionalFrameParent->myAdditionalAttributes->showWarningMessage();
157         return false;
158     } else {
159         // declare SUMOSAXAttributesImpl_Cached to convert valuesMap into SUMOSAXAttributes
160         SUMOSAXAttributesImpl_Cached SUMOSAXAttrs(valuesMap, myAdditionalFrameParent->getPredefinedTagsMML(), toString(tagValues.getTag()));
161         // try to build additional
162         if (GNEAdditionalHandler::buildAdditional(myAdditionalFrameParent->myViewNet, true, myAdditionalFrameParent->myItemSelector->getCurrentTagProperties().getTag(), SUMOSAXAttrs, nullptr)) {
163             // abort consecutive lane selector
164             abortConsecutiveLaneSelector();
165             return true;
166         } else {
167             return false;
168         }
169     }
170 }
171 
172 
173 void
abortConsecutiveLaneSelector()174 GNEAdditionalFrame::SelectorLaneParents::abortConsecutiveLaneSelector() {
175     // reset color of all candidate lanes
176     for (auto i : myCandidateLanes) {
177         i->setSpecialColor(nullptr);
178     }
179     // clear candidate colors
180     myCandidateLanes.clear();
181     // reset color of all selected lanes
182     for (auto i : mySelectedLanes) {
183         i.first->setSpecialColor(nullptr);
184     }
185     // clear selected lanes
186     mySelectedLanes.clear();
187     // disable buttons
188     myStopSelectingButton->disable();
189     myAbortSelectingButton->disable();
190     // update view (due colors)
191     myAdditionalFrameParent->getViewNet()->update();
192 }
193 
194 
195 bool
addSelectedLane(GNELane * lane,const Position & clickedPosition)196 GNEAdditionalFrame::SelectorLaneParents::addSelectedLane(GNELane* lane, const Position& clickedPosition) {
197     // first check that lane exist
198     if (lane == nullptr) {
199         return false;
200     }
201     // check that lane wasn't already selected
202     for (auto i : mySelectedLanes) {
203         if (i.first == lane) {
204             WRITE_WARNING("Duplicated lanes aren't allowed");
205             return false;
206         }
207     }
208     // check that there is candidate lanes
209     if (mySelectedLanes.size() > 0) {
210         if (myCandidateLanes.empty()) {
211             WRITE_WARNING("Only candidate lanes are allowed");
212             return false;
213         } else if ((myCandidateLanes.size() > 0) && (std::find(myCandidateLanes.begin(), myCandidateLanes.end(), lane) == myCandidateLanes.end())) {
214             WRITE_WARNING("Only consecutive lanes are allowed");
215             return false;
216         }
217     }
218     // select lane and save the clicked position
219     mySelectedLanes.push_back(std::make_pair(lane, lane->getShape().nearest_offset_to_point2D(clickedPosition) / lane->getLengthGeometryFactor()));
220     // change color of selected lane
221     lane->setSpecialColor(&mySelectedLaneColor);
222     // restore original color of candidates (except already selected)
223     for (auto i : myCandidateLanes) {
224         if (!isLaneSelected(i)) {
225             i->setSpecialColor(nullptr);
226         }
227     }
228     // clear candidate lanes
229     myCandidateLanes.clear();
230     // fill candidate lanes
231     for (auto i : lane->getParentEdge().getGNEConnections()) {
232         // check that possible candidate lane isn't already selected
233         if ((lane == i->getLaneFrom()) && (!isLaneSelected(i->getLaneTo()))) {
234             // set candidate lane
235             i->getLaneTo()->setSpecialColor(&myCandidateLaneColor);
236             myCandidateLanes.push_back(i->getLaneTo());
237         }
238     }
239     // update view (due colors)
240     myAdditionalFrameParent->getViewNet()->update();
241     return true;
242 }
243 
244 
245 void
removeLastSelectedLane()246 GNEAdditionalFrame::SelectorLaneParents::removeLastSelectedLane() {
247     if (mySelectedLanes.size() > 1) {
248         mySelectedLanes.pop_back();
249     } else {
250         WRITE_WARNING("First lane cannot be removed");
251     }
252 }
253 
254 
255 bool
isSelectingLanes() const256 GNEAdditionalFrame::SelectorLaneParents::isSelectingLanes() const {
257     return myStopSelectingButton->isEnabled();
258 }
259 
260 
261 bool
isShown() const262 GNEAdditionalFrame::SelectorLaneParents::isShown() const {
263     return shown();
264 }
265 
266 
267 const RGBColor&
getSelectedLaneColor() const268 GNEAdditionalFrame::SelectorLaneParents::getSelectedLaneColor() const {
269     return mySelectedLaneColor;
270 }
271 
272 
273 const std::vector<std::pair<GNELane*, double> >&
getSelectedLanes() const274 GNEAdditionalFrame::SelectorLaneParents::getSelectedLanes() const {
275     return mySelectedLanes;
276 }
277 
278 
279 long
onCmdStopSelection(FXObject *,FXSelector,void *)280 GNEAdditionalFrame::SelectorLaneParents::onCmdStopSelection(FXObject*, FXSelector, void*) {
281     stopConsecutiveLaneSelector();
282     return 0;
283 }
284 
285 
286 long
onCmdAbortSelection(FXObject *,FXSelector,void *)287 GNEAdditionalFrame::SelectorLaneParents::onCmdAbortSelection(FXObject*, FXSelector, void*) {
288     abortConsecutiveLaneSelector();
289     return 0;
290 }
291 
292 
293 bool
isLaneSelected(GNELane * lane) const294 GNEAdditionalFrame::SelectorLaneParents::isLaneSelected(GNELane* lane) const {
295     for (auto i : mySelectedLanes) {
296         if (i.first == lane) {
297             return true;
298         }
299     }
300     return false;
301 }
302 
303 // ---------------------------------------------------------------------------
304 // GNEAdditionalFrame::SelectorAdditionalParent - methods
305 // ---------------------------------------------------------------------------
306 
SelectorAdditionalParent(GNEAdditionalFrame * additionalFrameParent)307 GNEAdditionalFrame::SelectorAdditionalParent::SelectorAdditionalParent(GNEAdditionalFrame* additionalFrameParent) :
308     FXGroupBox(additionalFrameParent->myContentFrame, "Parent selector", GUIDesignGroupBoxFrame),
309     myAdditionalFrameParent(additionalFrameParent),
310     myAdditionalTypeParent(SUMO_TAG_NOTHING) {
311     // Create label with the type of SelectorAdditionalParent
312     myFirstAdditionalParentsLabel = new FXLabel(this, "No additional selected", nullptr, GUIDesignLabelLeftThick);
313     // Create list
314     myFirstAdditionalParentsList = new FXList(this, this, MID_GNE_SET_TYPE, GUIDesignListSingleElementFixedHeight);
315     // Hide List
316     hideSelectorAdditionalParentModul();
317 }
318 
319 
~SelectorAdditionalParent()320 GNEAdditionalFrame::SelectorAdditionalParent::~SelectorAdditionalParent() {}
321 
322 
323 std::string
getIdSelected() const324 GNEAdditionalFrame::SelectorAdditionalParent::getIdSelected() const {
325     for (int i = 0; i < myFirstAdditionalParentsList->getNumItems(); i++) {
326         if (myFirstAdditionalParentsList->isItemSelected(i)) {
327             return myFirstAdditionalParentsList->getItem(i)->getText().text();
328         }
329     }
330     return "";
331 }
332 
333 
334 void
setIDSelected(const std::string & id)335 GNEAdditionalFrame::SelectorAdditionalParent::setIDSelected(const std::string& id) {
336     // first unselect all
337     for (int i = 0; i < myFirstAdditionalParentsList->getNumItems(); i++) {
338         myFirstAdditionalParentsList->getItem(i)->setSelected(false);
339     }
340     // select element if correspond to given ID
341     for (int i = 0; i < myFirstAdditionalParentsList->getNumItems(); i++) {
342         if (myFirstAdditionalParentsList->getItem(i)->getText().text() == id) {
343             myFirstAdditionalParentsList->getItem(i)->setSelected(true);
344         }
345     }
346     // recalc myFirstAdditionalParentsList
347     myFirstAdditionalParentsList->recalc();
348 }
349 
350 
351 bool
showSelectorAdditionalParentModul(SumoXMLTag additionalType)352 GNEAdditionalFrame::SelectorAdditionalParent::showSelectorAdditionalParentModul(SumoXMLTag additionalType) {
353     // make sure that we're editing an additional tag
354     auto listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL, false);
355     for (auto i : listOfTags) {
356         if (i == additionalType) {
357             myAdditionalTypeParent = additionalType;
358             myFirstAdditionalParentsLabel->setText(("Parent type: " + toString(additionalType)).c_str());
359             refreshSelectorAdditionalParentModul();
360             show();
361             return true;
362         }
363     }
364     return false;
365 }
366 
367 
368 void
hideSelectorAdditionalParentModul()369 GNEAdditionalFrame::SelectorAdditionalParent::hideSelectorAdditionalParentModul() {
370     myAdditionalTypeParent = SUMO_TAG_NOTHING;
371     hide();
372 }
373 
374 
375 void
refreshSelectorAdditionalParentModul()376 GNEAdditionalFrame::SelectorAdditionalParent::refreshSelectorAdditionalParentModul() {
377     myFirstAdditionalParentsList->clearItems();
378     if (myAdditionalTypeParent != SUMO_TAG_NOTHING) {
379         // fill list with IDs of additionals
380         for (auto i : myAdditionalFrameParent->getViewNet()->getNet()->getAdditionalByType(myAdditionalTypeParent)) {
381             myFirstAdditionalParentsList->appendItem(i.first.c_str());
382         }
383     }
384 }
385 
386 // ---------------------------------------------------------------------------
387 // GNEAdditionalFrame::SelectorEdgeChilds - methods
388 // ---------------------------------------------------------------------------
389 
SelectorEdgeChilds(GNEAdditionalFrame * additionalFrameParent)390 GNEAdditionalFrame::SelectorEdgeChilds::SelectorEdgeChilds(GNEAdditionalFrame* additionalFrameParent) :
391     FXGroupBox(additionalFrameParent->myContentFrame, "Edges", GUIDesignGroupBoxFrame),
392     myAdditionalFrameParent(additionalFrameParent) {
393     // Create menuCheck for selected edges
394     myUseSelectedEdgesCheckButton = new FXCheckButton(this, ("Use selected " + toString(SUMO_TAG_EDGE) + "s").c_str(), this, MID_GNE_ADDITIONALFRAME_USESELECTED, GUIDesignCheckButtonAttribute);
395 
396     // Create search box
397     myEdgesSearch = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_ADDITIONALFRAME_SEARCH, GUIDesignTextField);
398 
399     // Create list
400     myList = new FXList(this, this, MID_GNE_ADDITIONALFRAME_SELECT, GUIDesignListFixedHeight, 0, 0, 0, 100);
401 
402     // Create horizontal frame
403     FXHorizontalFrame* buttonsFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
404 
405     // Create button for clear selection
406     myClearEdgesSelection = new FXButton(buttonsFrame, "Clear", nullptr, this, MID_GNE_ADDITIONALFRAME_CLEARSELECTION, GUIDesignButtonRectangular);
407 
408     // Create button for invert selection
409     myInvertEdgesSelection = new FXButton(buttonsFrame, "Invert", nullptr, this, MID_GNE_ADDITIONALFRAME_INVERTSELECTION, GUIDesignButtonRectangular);
410 
411     // Hide List
412     hideSelectorEdgeChildsModul();
413 }
414 
415 
~SelectorEdgeChilds()416 GNEAdditionalFrame::SelectorEdgeChilds::~SelectorEdgeChilds() {}
417 
418 
419 std::string
getEdgeIdsSelected() const420 GNEAdditionalFrame::SelectorEdgeChilds::getEdgeIdsSelected() const {
421     std::vector<std::string> vectorOfIds;
422     if (myUseSelectedEdgesCheckButton->getCheck()) {
423         // get Selected edges
424         std::vector<GNEEdge*> selectedEdges = myAdditionalFrameParent->getViewNet()->getNet()->retrieveEdges(true);
425         // Iterate over selectedEdges and getId
426         for (auto i : selectedEdges) {
427             vectorOfIds.push_back(i->getID());
428         }
429     } else {
430         // Obtain Id's of list
431         for (int i = 0; i < myList->getNumItems(); i++) {
432             if (myList->isItemSelected(i)) {
433                 vectorOfIds.push_back(myList->getItem(i)->getText().text());
434             }
435         }
436     }
437     return joinToString(vectorOfIds, " ");
438 }
439 
440 
441 void
showSelectorEdgeChildsModul(std::string search)442 GNEAdditionalFrame::SelectorEdgeChilds::showSelectorEdgeChildsModul(std::string search) {
443     // clear list of egdge ids
444     myList->clearItems();
445     // get all edges of net
446     /// @todo this function must be improved.
447     std::vector<GNEEdge*> vectorOfEdges = myAdditionalFrameParent->getViewNet()->getNet()->retrieveEdges(false);
448     // iterate over edges of net
449     for (auto i : vectorOfEdges) {
450         // If search criterium is correct, then append ittem
451         if (i->getID().find(search) != std::string::npos) {
452             myList->appendItem(i->getID().c_str());
453         }
454     }
455     // By default, CheckBox for useSelectedEdges isn't checked
456     myUseSelectedEdgesCheckButton->setCheck(false);
457     // Recalc Frame
458     recalc();
459     // Update Frame
460     update();
461     // Show dialog
462     show();
463 }
464 
465 
466 void
hideSelectorEdgeChildsModul()467 GNEAdditionalFrame::SelectorEdgeChilds::hideSelectorEdgeChildsModul() {
468     FXGroupBox::hide();
469 }
470 
471 
472 void
updateUseSelectedEdges()473 GNEAdditionalFrame::SelectorEdgeChilds::updateUseSelectedEdges() {
474     // Enable or disable use selected edges
475     if (myAdditionalFrameParent->getViewNet()->getNet()->retrieveEdges(true).size() > 0) {
476         myUseSelectedEdgesCheckButton->enable();
477     } else {
478         myUseSelectedEdgesCheckButton->disable();
479     }
480 }
481 
482 
483 long
onCmdUseSelectedEdges(FXObject *,FXSelector,void *)484 GNEAdditionalFrame::SelectorEdgeChilds::onCmdUseSelectedEdges(FXObject*, FXSelector, void*) {
485     if (myUseSelectedEdgesCheckButton->getCheck()) {
486         myEdgesSearch->hide();
487         myList->hide();
488         myClearEdgesSelection->hide();
489         myInvertEdgesSelection->hide();
490     } else {
491         myEdgesSearch->show();
492         myList->show();
493         myClearEdgesSelection->show();
494         myInvertEdgesSelection->show();
495     }
496     // Recalc Frame
497     recalc();
498     // Update Frame
499     update();
500     return 1;
501 }
502 
503 
504 long
onCmdTypeInSearchBox(FXObject *,FXSelector,void *)505 GNEAdditionalFrame::SelectorEdgeChilds::onCmdTypeInSearchBox(FXObject*, FXSelector, void*) {
506     // Show only Id's of SelectorEdgeChilds that contains the searched string
507     showSelectorEdgeChildsModul(myEdgesSearch->getText().text());
508     return 1;
509 }
510 
511 
512 long
onCmdSelectEdge(FXObject *,FXSelector,void *)513 GNEAdditionalFrame::SelectorEdgeChilds::onCmdSelectEdge(FXObject*, FXSelector, void*) {
514     return 1;
515 }
516 
517 
518 long
onCmdClearSelection(FXObject *,FXSelector,void *)519 GNEAdditionalFrame::SelectorEdgeChilds::onCmdClearSelection(FXObject*, FXSelector, void*) {
520     for (int i = 0; i < myList->getNumItems(); i++) {
521         if (myList->getItem(i)->isSelected()) {
522             myList->deselectItem(i);
523         }
524     }
525     return 1;
526 }
527 
528 
529 long
onCmdInvertSelection(FXObject *,FXSelector,void *)530 GNEAdditionalFrame::SelectorEdgeChilds::onCmdInvertSelection(FXObject*, FXSelector, void*) {
531     for (int i = 0; i < myList->getNumItems(); i++) {
532         if (myList->getItem(i)->isSelected()) {
533             myList->deselectItem(i);
534         } else {
535             myList->selectItem(i);
536         }
537     }
538     return 1;
539 }
540 
541 // ---------------------------------------------------------------------------
542 // GNEAdditionalFrame::SelectorLaneChilds - methods
543 // ---------------------------------------------------------------------------
544 
SelectorLaneChilds(GNEAdditionalFrame * additionalFrameParent)545 GNEAdditionalFrame::SelectorLaneChilds::SelectorLaneChilds(GNEAdditionalFrame* additionalFrameParent) :
546     FXGroupBox(additionalFrameParent->myContentFrame, "Lanes", GUIDesignGroupBoxFrame),
547     myAdditionalFrameParent(additionalFrameParent) {
548     // Create CheckBox for selected lanes
549     myUseSelectedLanesCheckButton = new FXCheckButton(this, ("Use selected " + toString(SUMO_TAG_LANE) + "s").c_str(), this, MID_GNE_ADDITIONALFRAME_USESELECTED, GUIDesignCheckButtonAttribute);
550 
551     // Create search box
552     myLanesSearch = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_ADDITIONALFRAME_SEARCH, GUIDesignTextField);
553 
554     // Create list
555     myList = new FXList(this, this, MID_GNE_ADDITIONALFRAME_SELECT, GUIDesignListFixedHeight, 0, 0, 0, 100);
556 
557     // Create horizontal frame
558     FXHorizontalFrame* buttonsFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
559 
560     // Create button for clear selection
561     clearLanesSelection = new FXButton(buttonsFrame, "clear", nullptr, this, MID_GNE_ADDITIONALFRAME_CLEARSELECTION, GUIDesignButtonRectangular);
562 
563     // Create button for invert selection
564     invertLanesSelection = new FXButton(buttonsFrame, "invert", nullptr, this, MID_GNE_ADDITIONALFRAME_INVERTSELECTION, GUIDesignButtonRectangular);
565 
566     // Hide List
567     hideSelectorLaneChildsModul();
568 }
569 
570 
~SelectorLaneChilds()571 GNEAdditionalFrame::SelectorLaneChilds::~SelectorLaneChilds() {}
572 
573 
574 std::string
getLaneIdsSelected() const575 GNEAdditionalFrame::SelectorLaneChilds::getLaneIdsSelected() const {
576     std::vector<std::string> vectorOfIds;
577     if (myUseSelectedLanesCheckButton->getCheck()) {
578         // get Selected lanes
579         std::vector<GNELane*> selectedLanes = myAdditionalFrameParent->getViewNet()->getNet()->retrieveLanes(true);
580         // Iterate over selectedLanes and getId
581         for (auto i : selectedLanes) {
582             vectorOfIds.push_back(i->getID());
583         }
584     } else {
585         // Obtain Id's of list
586         for (int i = 0; i < myList->getNumItems(); i++) {
587             if (myList->isItemSelected(i)) {
588                 vectorOfIds.push_back(myList->getItem(i)->getText().text());
589             }
590         }
591     }
592     return joinToString(vectorOfIds, " ");
593 }
594 
595 
596 void
showSelectorLaneChildsModul(std::string search)597 GNEAdditionalFrame::SelectorLaneChilds::showSelectorLaneChildsModul(std::string search) {
598     myList->clearItems();
599     std::vector<GNELane*> vectorOfLanes = myAdditionalFrameParent->getViewNet()->getNet()->retrieveLanes(false);
600     for (auto i : vectorOfLanes) {
601         if (i->getID().find(search) != std::string::npos) {
602             myList->appendItem(i->getID().c_str());
603         }
604     }
605     // By default, CheckBox for useSelectedLanes isn't checked
606     myUseSelectedLanesCheckButton->setCheck(false);
607     // Show list
608     show();
609 }
610 
611 
612 void
hideSelectorLaneChildsModul()613 GNEAdditionalFrame::SelectorLaneChilds::hideSelectorLaneChildsModul() {
614     FXGroupBox::hide();
615 }
616 
617 
618 void
updateUseSelectedLanes()619 GNEAdditionalFrame::SelectorLaneChilds::updateUseSelectedLanes() {
620     // Enable or disable use selected Lanes
621     if (myAdditionalFrameParent->getViewNet()->getNet()->retrieveLanes(true).size() > 0) {
622         myUseSelectedLanesCheckButton->enable();
623     } else {
624         myUseSelectedLanesCheckButton->disable();
625     }
626 }
627 
628 
629 long
onCmdUseSelectedLanes(FXObject *,FXSelector,void *)630 GNEAdditionalFrame::SelectorLaneChilds::onCmdUseSelectedLanes(FXObject*, FXSelector, void*) {
631     if (myUseSelectedLanesCheckButton->getCheck()) {
632         myLanesSearch->hide();
633         myList->hide();
634         clearLanesSelection->hide();
635         invertLanesSelection->hide();
636     } else {
637         myLanesSearch->show();
638         myList->show();
639         clearLanesSelection->show();
640         invertLanesSelection->show();
641     }
642     // Recalc Frame
643     recalc();
644     // Update Frame
645     update();
646     return 1;
647 }
648 
649 
650 long
onCmdTypeInSearchBox(FXObject *,FXSelector,void *)651 GNEAdditionalFrame::SelectorLaneChilds::onCmdTypeInSearchBox(FXObject*, FXSelector, void*) {
652     // Show only Id's of SelectorLaneChilds that contains the searched string
653     showSelectorLaneChildsModul(myLanesSearch->getText().text());
654     return 1;
655 }
656 
657 
658 long
onCmdSelectLane(FXObject *,FXSelector,void *)659 GNEAdditionalFrame::SelectorLaneChilds::onCmdSelectLane(FXObject*, FXSelector, void*) {
660     return 1;
661 }
662 
663 
664 long
onCmdClearSelection(FXObject *,FXSelector,void *)665 GNEAdditionalFrame::SelectorLaneChilds::onCmdClearSelection(FXObject*, FXSelector, void*) {
666     for (int i = 0; i < myList->getNumItems(); i++) {
667         if (myList->getItem(i)->isSelected()) {
668             myList->deselectItem(i);
669         }
670     }
671     return 1;
672 }
673 
674 
675 long
onCmdInvertSelection(FXObject *,FXSelector,void *)676 GNEAdditionalFrame::SelectorLaneChilds::onCmdInvertSelection(FXObject*, FXSelector, void*) {
677     for (int i = 0; i < myList->getNumItems(); i++) {
678         if (myList->getItem(i)->isSelected()) {
679             myList->deselectItem(i);
680         } else {
681             myList->selectItem(i);
682         }
683     }
684     return 1;
685 }
686 
687 // ===========================================================================
688 // method definitions
689 // ===========================================================================
690 
GNEAdditionalFrame(FXHorizontalFrame * horizontalFrameParent,GNEViewNet * viewNet)691 GNEAdditionalFrame::GNEAdditionalFrame(FXHorizontalFrame* horizontalFrameParent, GNEViewNet* viewNet) :
692     GNEFrame(horizontalFrameParent, viewNet, "Additionals") {
693 
694     // create item Selector modul for additionals
695     myItemSelector = new ItemSelector(this, GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL);
696 
697     // Create additional parameters
698     myAdditionalAttributes = new AttributesCreator(this);
699 
700     // Create Netedit parameter
701     myNeteditAttributes = new NeteditAttributes(this);
702 
703     // Create consecutive Lane Selector
704     mySelectorLaneParents = new SelectorLaneParents(this);
705 
706     // Create create list for additional Set
707     mySelectorAdditionalParent = new SelectorAdditionalParent(this);
708 
709     /// Create list for SelectorEdgeChilds
710     mySelectorEdgeChilds = new SelectorEdgeChilds(this);
711 
712     /// Create list for SelectorLaneChilds
713     mySelectorLaneChilds = new SelectorLaneChilds(this);
714 
715     // set BusStop as default additional
716     myItemSelector->setCurrentTypeTag(SUMO_TAG_BUS_STOP);
717 }
718 
719 
~GNEAdditionalFrame()720 GNEAdditionalFrame::~GNEAdditionalFrame() {}
721 
722 
723 void
show()724 GNEAdditionalFrame::show() {
725     // refresh item selector
726     myItemSelector->refreshTagProperties();
727     // show frame
728     GNEFrame::show();
729 }
730 
731 
732 bool
addAdditional(const GNEViewNetHelper::ObjectsUnderCursor & objectsUnderCursor)733 GNEAdditionalFrame::addAdditional(const GNEViewNetHelper::ObjectsUnderCursor& objectsUnderCursor) {
734     // first check that current selected additional is valid
735     if (myItemSelector->getCurrentTagProperties().getTag() == SUMO_TAG_NOTHING) {
736         myViewNet->setStatusBarText("Current selected additional isn't valid.");
737         return false;
738     }
739 
740     // obtain tagproperty (only for improve code legibility)
741     const auto& tagValues = myItemSelector->getCurrentTagProperties();
742 
743     // Declare map to keep attributes from Frames from Frame
744     std::map<SumoXMLAttr, std::string> valuesMap = myAdditionalAttributes->getAttributesAndValues(true);
745 
746     // fill netedit attributes
747     if (!myNeteditAttributes->getNeteditAttributesAndValues(valuesMap, objectsUnderCursor.getLaneFront())) {
748         return false;
749     }
750 
751     // If element owns an additional parent, get id of parent from AdditionalParentSelector
752     if (tagValues.hasParent() && !buildAdditionalWithParent(valuesMap, objectsUnderCursor.getAdditionalFront(), tagValues)) {
753         return false;
754     }
755     // If consecutive Lane Selector is enabled, it means that either we're selecting lanes or we're finished or we'rent started
756     if (tagValues.hasAttribute(SUMO_ATTR_EDGE)) {
757         return buildAdditionalOverEdge(valuesMap, objectsUnderCursor.getLaneFront(), tagValues);
758     } else if (tagValues.hasAttribute(SUMO_ATTR_LANE)) {
759         return buildAdditionalOverLane(valuesMap, objectsUnderCursor.getLaneFront(), tagValues);
760     } else if (tagValues.hasAttribute(SUMO_ATTR_LANES)) {
761         return buildAdditionalOverLanes(valuesMap, objectsUnderCursor.getLaneFront(), tagValues);
762     } else {
763         return buildAdditionalOverView(valuesMap, tagValues);
764     }
765 }
766 
767 
768 void
showSelectorLaneChildsModul()769 GNEAdditionalFrame::showSelectorLaneChildsModul() {
770     // Show frame
771     GNEFrame::show();
772     // Update UseSelectedLane CheckBox
773     mySelectorEdgeChilds->updateUseSelectedEdges();
774     // Update UseSelectedLane CheckBox
775     mySelectorLaneChilds->updateUseSelectedLanes();
776 }
777 
778 
779 GNEAdditionalFrame::SelectorLaneParents*
getConsecutiveLaneSelector() const780 GNEAdditionalFrame::getConsecutiveLaneSelector() const {
781     return mySelectorLaneParents;
782 }
783 
784 
785 void
enableModuls(const GNEAttributeCarrier::TagProperties & tagProperties)786 GNEAdditionalFrame::enableModuls(const GNEAttributeCarrier::TagProperties& tagProperties) {
787     // show additional attributes modul
788     myAdditionalAttributes->showAttributesCreatorModul(tagProperties);
789     // show netedit attributes
790     myNeteditAttributes->showNeteditAttributesModul(tagProperties);
791     // Show myAdditionalFrameParent if we're adding a additional with parent
792     if (tagProperties.hasParent()) {
793         mySelectorAdditionalParent->showSelectorAdditionalParentModul(tagProperties.getParentTag());
794     } else {
795         mySelectorAdditionalParent->hideSelectorAdditionalParentModul();
796     }
797     // Show SelectorEdgeChilds if we're adding an additional that own the attribute SUMO_ATTR_EDGES
798     if (tagProperties.hasAttribute(SUMO_ATTR_EDGES)) {
799         mySelectorEdgeChilds->showSelectorEdgeChildsModul();
800     } else {
801         mySelectorEdgeChilds->hideSelectorEdgeChildsModul();
802     }
803     // Show SelectorLaneChilds or consecutive lane selector if we're adding an additional that own the attribute SUMO_ATTR_LANES
804     if (tagProperties.hasAttribute(SUMO_ATTR_LANES)) {
805         if (tagProperties.hasParent() && tagProperties.getParentTag() == SUMO_TAG_LANE) {
806             // show selector lane parent and hide selector lane child
807             mySelectorLaneParents->showSelectorLaneParentsModul();
808             mySelectorLaneChilds->hideSelectorLaneChildsModul();
809         } else {
810             // show selector lane child and hide selector lane parent
811             mySelectorLaneChilds->showSelectorLaneChildsModul();
812             mySelectorLaneParents->hideSelectorLaneParentsModul();
813         }
814     } else {
815         mySelectorLaneChilds->hideSelectorLaneChildsModul();
816         mySelectorLaneParents->hideSelectorLaneParentsModul();
817     }
818 }
819 
820 
821 void
disableModuls()822 GNEAdditionalFrame::disableModuls() {
823     // hide all moduls if additional isn't valid
824     myAdditionalAttributes->hideAttributesCreatorModul();
825     myNeteditAttributes->hideNeteditAttributesModul();
826     mySelectorAdditionalParent->hideSelectorAdditionalParentModul();
827     mySelectorEdgeChilds->hideSelectorEdgeChildsModul();
828     mySelectorLaneChilds->hideSelectorLaneChildsModul();
829     mySelectorLaneParents->hideSelectorLaneParentsModul();
830 }
831 
832 
833 std::string
generateID(GNENetElement * netElement) const834 GNEAdditionalFrame::generateID(GNENetElement* netElement) const {
835     // obtain current number of additionals to generate a new index faster
836     int additionalIndex = myViewNet->getNet()->getNumberOfAdditionals(myItemSelector->getCurrentTagProperties().getTag());
837     // obtain tag Properties (only for improve code legilibility
838     const auto& tagProperties = myItemSelector->getCurrentTagProperties();
839     if (netElement) {
840         // special case for vaporizers
841         if (tagProperties.getTag() == SUMO_TAG_VAPORIZER) {
842             return netElement->getID();
843         } else {
844             // generate ID using netElement
845             while (myViewNet->getNet()->retrieveAdditional(tagProperties.getTag(), tagProperties.getTagStr() + "_" + netElement->getID() + "_" + toString(additionalIndex), false) != nullptr) {
846                 additionalIndex++;
847             }
848             return tagProperties.getTagStr() + "_" + netElement->getID() + "_" + toString(additionalIndex);
849         }
850     } else {
851         // generate ID without netElement
852         while (myViewNet->getNet()->retrieveAdditional(tagProperties.getTag(), tagProperties.getTagStr() + "_" + toString(additionalIndex), false) != nullptr) {
853             additionalIndex++;
854         }
855         return tagProperties.getTagStr() + "_" + toString(additionalIndex);
856     }
857 }
858 
859 
860 bool
buildAdditionalWithParent(std::map<SumoXMLAttr,std::string> & valuesMap,GNEAdditional * additionalParent,const GNEAttributeCarrier::TagProperties & tagValues)861 GNEAdditionalFrame::buildAdditionalWithParent(std::map<SumoXMLAttr, std::string>& valuesMap, GNEAdditional* additionalParent, const GNEAttributeCarrier::TagProperties& tagValues) {
862     // if user click over an additional element parent, mark int in AdditionalParentSelector
863     if (additionalParent && (additionalParent->getTagProperty().getTag() == tagValues.getParentTag())) {
864         valuesMap[GNE_ATTR_PARENT] = additionalParent->getID();
865         mySelectorAdditionalParent->setIDSelected(additionalParent->getID());
866     }
867     // stop if currently there isn't a valid selected parent
868     if (mySelectorAdditionalParent->getIdSelected() != "") {
869         valuesMap[GNE_ATTR_PARENT] = mySelectorAdditionalParent->getIdSelected();
870     } else {
871         myAdditionalAttributes->showWarningMessage("A " + toString(tagValues.getParentTag()) + " must be selected before insertion of " + myItemSelector->getCurrentTagProperties().getTagStr() + ".");
872         return false;
873     }
874     return true;
875 }
876 
877 
878 bool
buildAdditionalCommonAttributes(std::map<SumoXMLAttr,std::string> & valuesMap,const GNEAttributeCarrier::TagProperties & tagValues)879 GNEAdditionalFrame::buildAdditionalCommonAttributes(std::map<SumoXMLAttr, std::string>& valuesMap, const GNEAttributeCarrier::TagProperties& tagValues) {
880     // If additional has a interval defined by a begin or end, check that is valid
881     if (tagValues.hasAttribute(SUMO_ATTR_STARTTIME) && tagValues.hasAttribute(SUMO_ATTR_END)) {
882         double begin = GNEAttributeCarrier::parse<double>(valuesMap[SUMO_ATTR_STARTTIME]);
883         double end = GNEAttributeCarrier::parse<double>(valuesMap[SUMO_ATTR_END]);
884         if (begin > end) {
885             myAdditionalAttributes->showWarningMessage("Attribute '" + toString(SUMO_ATTR_STARTTIME) + "' cannot be greater than attribute '" + toString(SUMO_ATTR_END) + "'.");
886             return false;
887         }
888     }
889     // If additional own the attribute SUMO_ATTR_FILE but was't defined, will defined as <ID>.xml
890     if (tagValues.hasAttribute(SUMO_ATTR_FILE) && valuesMap[SUMO_ATTR_FILE] == "") {
891         if ((myItemSelector->getCurrentTagProperties().getTag() != SUMO_TAG_CALIBRATOR) && (myItemSelector->getCurrentTagProperties().getTag() != SUMO_TAG_REROUTER)) {
892             // SUMO_ATTR_FILE is optional for calibrators and rerouters (fails to load in sumo when given and the file does not exist)
893             valuesMap[SUMO_ATTR_FILE] = (valuesMap[SUMO_ATTR_ID] + ".xml");
894         }
895     }
896     // If element own a list of SelectorEdgeChilds as attribute
897     if (tagValues.hasAttribute(SUMO_ATTR_EDGES) && valuesMap[SUMO_ATTR_EDGES].empty()) {
898         // obtain edge IDs
899         valuesMap[SUMO_ATTR_EDGES] = mySelectorEdgeChilds->getEdgeIdsSelected();
900         // check if attribute has at least one edge
901         if (valuesMap[SUMO_ATTR_EDGES] == "") {
902             myAdditionalAttributes->showWarningMessage("List of " + toString(SUMO_TAG_EDGE) + "s cannot be empty");
903             return false;
904         }
905     }
906     // get values of mySelectorLaneChilds, if tag correspond to an element that has lanes as childs
907     if (tagValues.hasAttribute(SUMO_ATTR_LANES) && valuesMap[SUMO_ATTR_LANES].empty()) {
908         // obtain lane IDs
909         valuesMap[SUMO_ATTR_LANES] = mySelectorLaneChilds->getLaneIdsSelected();
910         // check if attribute has at least a lane
911         if (valuesMap[SUMO_ATTR_LANES] == "") {
912             myAdditionalAttributes->showWarningMessage("List of " + toString(SUMO_TAG_LANE) + "s cannot be empty");
913             return false;
914         }
915     }
916     // all ok, continue building additionals
917     return true;
918 }
919 
920 
921 bool
buildAdditionalOverEdge(std::map<SumoXMLAttr,std::string> & valuesMap,GNELane * lane,const GNEAttributeCarrier::TagProperties & tagValues)922 GNEAdditionalFrame::buildAdditionalOverEdge(std::map<SumoXMLAttr, std::string>& valuesMap, GNELane* lane, const GNEAttributeCarrier::TagProperties& tagValues) {
923     // check that edge exist
924     if (lane) {
925         // Get attribute lane's edge
926         valuesMap[SUMO_ATTR_EDGE] = lane->getParentEdge().getID();
927         // Generate id of element based on the lane's edge
928         valuesMap[SUMO_ATTR_ID] = generateID(&lane->getParentEdge());
929     } else {
930         return false;
931     }
932     // parse common attributes
933     if (!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
934         return false;
935     }
936     // show warning dialogbox and stop check if input parameters are valid
937     if (!myAdditionalAttributes->areValuesValid()) {
938         myAdditionalAttributes->showWarningMessage();
939         return false;
940     } else {
941         // declare SUMOSAXAttributesImpl_Cached to convert valuesMap into SUMOSAXAttributes
942         SUMOSAXAttributesImpl_Cached SUMOSAXAttrs(valuesMap, getPredefinedTagsMML(), toString(tagValues.getTag()));
943         // try to build additional
944         if (GNEAdditionalHandler::buildAdditional(myViewNet, true, myItemSelector->getCurrentTagProperties().getTag(), SUMOSAXAttrs, nullptr)) {
945             // Refresh additional Parent Selector (For additionals that have a limited number of childs)
946             mySelectorAdditionalParent->refreshSelectorAdditionalParentModul();
947             // clear selected eddges and lanes
948             mySelectorEdgeChilds->onCmdClearSelection(nullptr, 0, nullptr);
949             mySelectorLaneChilds->onCmdClearSelection(nullptr, 0, nullptr);
950             return true;
951         } else {
952             return false;
953         }
954     }
955 }
956 
957 
958 bool
buildAdditionalOverLane(std::map<SumoXMLAttr,std::string> & valuesMap,GNELane * lane,const GNEAttributeCarrier::TagProperties & tagValues)959 GNEAdditionalFrame::buildAdditionalOverLane(std::map<SumoXMLAttr, std::string>& valuesMap, GNELane* lane, const GNEAttributeCarrier::TagProperties& tagValues) {
960     // check that lane exist
961     if (lane != nullptr) {
962         // Get attribute lane
963         valuesMap[SUMO_ATTR_LANE] = lane->getID();
964         // Generate id of element based on the lane
965         valuesMap[SUMO_ATTR_ID] = generateID(lane);
966     } else {
967         return false;
968     }
969     // Obtain position of the mouse over lane (limited over grid)
970     double mousePositionOverLane = lane->getShape().nearest_offset_to_point2D(myViewNet->snapToActiveGrid(myViewNet->getPositionInformation())) / lane->getLengthGeometryFactor();
971     // set attribute position as mouse position over lane
972     valuesMap[SUMO_ATTR_POSITION] = toString(mousePositionOverLane);
973     // parse common attributes
974     if (!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
975         return false;
976     }
977     // show warning dialogbox and stop check if input parameters are valid
978     if (!myAdditionalAttributes->areValuesValid()) {
979         myAdditionalAttributes->showWarningMessage();
980         return false;
981     } else {
982         // declare SUMOSAXAttributesImpl_Cached to convert valuesMap into SUMOSAXAttributes
983         SUMOSAXAttributesImpl_Cached SUMOSAXAttrs(valuesMap, getPredefinedTagsMML(), toString(tagValues.getTag()));
984         // try to build additional
985         if (GNEAdditionalHandler::buildAdditional(myViewNet, true, myItemSelector->getCurrentTagProperties().getTag(), SUMOSAXAttrs, nullptr)) {
986             // Refresh additional Parent Selector (For additionals that have a limited number of childs)
987             mySelectorAdditionalParent->refreshSelectorAdditionalParentModul();
988             // clear selected eddges and lanes
989             mySelectorEdgeChilds->onCmdClearSelection(nullptr, 0, nullptr);
990             mySelectorLaneChilds->onCmdClearSelection(nullptr, 0, nullptr);
991             return true;
992         } else {
993             return false;
994         }
995     }
996 }
997 
998 
999 bool
buildAdditionalOverLanes(std::map<SumoXMLAttr,std::string> & valuesMap,GNELane * lane,const GNEAttributeCarrier::TagProperties & tagValues)1000 GNEAdditionalFrame::buildAdditionalOverLanes(std::map<SumoXMLAttr, std::string>& valuesMap, GNELane* lane, const GNEAttributeCarrier::TagProperties& tagValues) {
1001     // stop if lane isn't valid
1002     if (lane == nullptr) {
1003         return false;
1004     }
1005     if (mySelectorLaneParents->isSelectingLanes()) {
1006         // select clicked lane, but don't build additional
1007         mySelectorLaneParents->addSelectedLane(lane, myViewNet->getPositionInformation());
1008         return false;
1009     } else if (mySelectorLaneParents->getSelectedLanes().empty()) {
1010         // if there isn't selected lanes, that means that we will be start selecting lanes
1011         mySelectorLaneParents->startConsecutiveLaneSelector(lane, myViewNet->getPositionInformation());
1012         return false;
1013     } else {
1014         // Generate id of element based on the first lane
1015         valuesMap[SUMO_ATTR_ID] = generateID(mySelectorLaneParents->getSelectedLanes().front().first);
1016         // obtain lane IDs
1017         std::vector<std::string> laneIDs;
1018         for (auto i : mySelectorLaneParents->getSelectedLanes()) {
1019             laneIDs.push_back(i.first->getID());
1020         }
1021         valuesMap[SUMO_ATTR_LANES] = joinToString(laneIDs, " ");
1022         // Check if clicked position over first lane has to be obtained
1023         if (tagValues.hasAttribute(SUMO_ATTR_POSITION)) {
1024             valuesMap[SUMO_ATTR_POSITION] = toString(mySelectorLaneParents->getSelectedLanes().front().second);
1025         }
1026         // Check if clicked position over last lane has to be obtained
1027         if (tagValues.hasAttribute(SUMO_ATTR_ENDPOS)) {
1028             valuesMap[SUMO_ATTR_ENDPOS] = toString(mySelectorLaneParents->getSelectedLanes().back().second);
1029         }
1030         // parse common attributes
1031         if (!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
1032             return false;
1033         }
1034         // show warning dialogbox and stop check if input parameters are valid
1035         if (myAdditionalAttributes->areValuesValid() == false) {
1036             myAdditionalAttributes->showWarningMessage();
1037             return false;
1038         } else {
1039             // declare SUMOSAXAttributesImpl_Cached to convert valuesMap into SUMOSAXAttributes
1040             SUMOSAXAttributesImpl_Cached SUMOSAXAttrs(valuesMap, getPredefinedTagsMML(), toString(tagValues.getTag()));
1041             // try to build additional
1042             if (GNEAdditionalHandler::buildAdditional(myViewNet, true, myItemSelector->getCurrentTagProperties().getTag(), SUMOSAXAttrs, nullptr)) {
1043                 // Refresh additional Parent Selector (For additionals that have a limited number of childs)
1044                 mySelectorAdditionalParent->refreshSelectorAdditionalParentModul();
1045                 // abort lane selector
1046                 mySelectorLaneParents->abortConsecutiveLaneSelector();
1047                 return true;
1048             } else {
1049                 // additional cannot be build
1050                 return false;
1051             }
1052         }
1053     }
1054 }
1055 
1056 
1057 bool
buildAdditionalOverView(std::map<SumoXMLAttr,std::string> & valuesMap,const GNEAttributeCarrier::TagProperties & tagValues)1058 GNEAdditionalFrame::buildAdditionalOverView(std::map<SumoXMLAttr, std::string>& valuesMap, const GNEAttributeCarrier::TagProperties& tagValues) {
1059     // Generate id of element
1060     valuesMap[SUMO_ATTR_ID] = generateID(nullptr);
1061     // Obtain position as the clicked position over view
1062     valuesMap[SUMO_ATTR_POSITION] = toString(myViewNet->snapToActiveGrid(myViewNet->getPositionInformation()));
1063     // parse common attributes
1064     if (!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
1065         return false;
1066     }
1067     // show warning dialogbox and stop check if input parameters are valid
1068     if (myAdditionalAttributes->areValuesValid() == false) {
1069         myAdditionalAttributes->showWarningMessage();
1070         return false;
1071     } else {
1072         // declare SUMOSAXAttributesImpl_Cached to convert valuesMap into SUMOSAXAttributes
1073         SUMOSAXAttributesImpl_Cached SUMOSAXAttrs(valuesMap, getPredefinedTagsMML(), toString(tagValues.getTag()));
1074         // try to build additional
1075         if (GNEAdditionalHandler::buildAdditional(myViewNet, true, myItemSelector->getCurrentTagProperties().getTag(), SUMOSAXAttrs, nullptr)) {
1076             // Refresh additional Parent Selector (For additionals that have a limited number of childs)
1077             mySelectorAdditionalParent->refreshSelectorAdditionalParentModul();
1078             // clear selected eddges and lanes
1079             mySelectorEdgeChilds->onCmdClearSelection(nullptr, 0, nullptr);
1080             mySelectorLaneChilds->onCmdClearSelection(nullptr, 0, nullptr);
1081             return true;
1082         } else {
1083             return false;
1084         }
1085     }
1086 }
1087 
1088 /****************************************************************************/
1089