SUMO - Simulation of Urban MObility
GNEAdditionalFrame.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2018 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 /****************************************************************************/
15 // The Widget for add additional elements
16 /****************************************************************************/
17 
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 #include <config.h>
22 
31 #include <netedit/GNENet.h>
32 #include <netedit/GNEUndoList.h>
33 
34 #include "GNEAdditionalFrame.h"
35 
36 
37 // ===========================================================================
38 // FOX callback mapping
39 // ===========================================================================
40 
41 FXDEFMAP(GNEAdditionalFrame::SelectorLaneParents) ConsecutiveLaneSelectorMap[] = {
44 };
45 
46 FXDEFMAP(GNEAdditionalFrame::SelectorEdgeChilds) SelectorParentEdgesMap[] = {
52 };
53 
54 FXDEFMAP(GNEAdditionalFrame::SelectorLaneChilds) SelectorParentLanesMap[] = {
60 };
61 
62 // Object implementation
63 FXIMPLEMENT(GNEAdditionalFrame::SelectorLaneParents, FXGroupBox, ConsecutiveLaneSelectorMap, ARRAYNUMBER(ConsecutiveLaneSelectorMap))
64 FXIMPLEMENT(GNEAdditionalFrame::SelectorEdgeChilds, FXGroupBox, SelectorParentEdgesMap, ARRAYNUMBER(SelectorParentEdgesMap))
65 FXIMPLEMENT(GNEAdditionalFrame::SelectorLaneChilds, FXGroupBox, SelectorParentLanesMap, ARRAYNUMBER(SelectorParentLanesMap))
66 
67 
68 // ---------------------------------------------------------------------------
69 // GNEAdditionalFrame::SelectorLaneParents - methods
70 // ---------------------------------------------------------------------------
71 
73  FXGroupBox(additionalFrameParent->myContentFrame, "Lane Selector", GUIDesignGroupBoxFrame),
74  myAdditionalFrameParent(additionalFrameParent) {
75  // create start and stop buttons
76  myStopSelectingButton = new FXButton(this, "Stop selecting", nullptr, this, MID_GNE_ADDITIONALFRAME_STOPSELECTION, GUIDesignButton);
77  myAbortSelectingButton = new FXButton(this, "Abort selecting", nullptr, this, MID_GNE_ADDITIONALFRAME_ABORTSELECTION, GUIDesignButton);
78  // disable stop and abort functions as init
79  myStopSelectingButton->disable();
80  myAbortSelectingButton->disable();
81  // define colors
82  myCandidateLaneColor = RGBColor(0, 64, 0, 255);
83  mySelectedLaneColor = RGBColor::GREEN;
84 }
85 
86 
88 
89 
90 void
92  // abort current selection before show
94  // show FXGroupBox
95  FXGroupBox::show();
96 }
97 
98 
99 void
101  // abort current selection before hide
103  // hide FXGroupBox
104  FXGroupBox::hide();
105 }
106 
107 
108 void
110  // Only start selection if SelectorLaneParents modul is shown
111  if (shown()) {
112  // change buttons
113  myStopSelectingButton->enable();
114  myAbortSelectingButton->enable();
115  // add lane
116  addSelectedLane(lane, clickedPosition);
117  }
118 }
119 
120 
121 bool
123  // obtain tagproperty (only for improve code legibility)
125  // abort if there isn't at least two lanes
126  if (mySelectedLanes.size() < 2) {
128  // abort consecutive lane selector
130  return false;
131  }
132  // Declare map to keep attributes from Frames from Frame
133  std::map<SumoXMLAttr, std::string> valuesMap = myAdditionalFrameParent->myAdditionalAttributes->getAttributesAndValues();
134  // fill valuesOfElement with Netedit attributes from Frame
136  // Generate id of element
137  valuesMap[SUMO_ATTR_ID] = myAdditionalFrameParent->generateID(nullptr);
138  // obtain lane IDs
139  std::vector<std::string> laneIDs;
140  for (auto i : mySelectedLanes) {
141  laneIDs.push_back(i.first->getID());
142  }
143  valuesMap[SUMO_ATTR_LANES] = joinToString(laneIDs, " ");
144  // Obtain clicked position over first lane
145  valuesMap[SUMO_ATTR_POSITION] = toString(mySelectedLanes.front().second);
146  // Obtain clicked position over last lane
147  valuesMap[SUMO_ATTR_ENDPOS] = toString(mySelectedLanes.back().second);
148  // parse common attributes
149  if(!myAdditionalFrameParent->buildAdditionalCommonAttributes(valuesMap, tagValues)) {
150  return false;
151  }
152  // show warning dialogbox and stop check if input parameters are valid
155  return false;
157  // abort consecutive lane selector
159  return true;
160  } else {
161  return false;
162  }
163 }
164 
165 
166 void
168  // reset color of all candidate lanes
169  for (auto i : myCandidateLanes) {
170  i->setSpecialColor(nullptr);
171  }
172  // clear candidate colors
173  myCandidateLanes.clear();
174  // reset color of all selected lanes
175  for (auto i : mySelectedLanes) {
176  i.first->setSpecialColor(nullptr);
177  }
178  // clear selected lanes
179  mySelectedLanes.clear();
180  // disable buttons
181  myStopSelectingButton->disable();
182  myAbortSelectingButton->disable();
183  // update view (due colors)
184  myAdditionalFrameParent->getViewNet()->update();
185 }
186 
187 
188 bool
190  // first check that lane exist
191  if(lane == nullptr) {
192  return false;
193  }
194  // check that lane wasn't already selected
195  for (auto i : mySelectedLanes) {
196  if (i.first == lane) {
197  WRITE_WARNING("Duplicated lanes aren't allowed");
198  return false;
199  }
200  }
201  // check that there is candidate lanes
202  if(mySelectedLanes.size() > 0) {
203  if (myCandidateLanes.empty()) {
204  WRITE_WARNING("Only candidate lanes are allowed");
205  return false;
206  } else if((myCandidateLanes.size() > 0) && (std::find(myCandidateLanes.begin(), myCandidateLanes.end(), lane) == myCandidateLanes.end())) {
207  WRITE_WARNING("Only consecutive lanes are allowed");
208  return false;
209  }
210  }
211  // select lane and save the clicked position
212  mySelectedLanes.push_back(std::make_pair(lane, lane->getShape().nearest_offset_to_point2D(clickedPosition) / lane->getLengthGeometryFactor()));
213  // change color of selected lane
215  // restore original color of candidates (except already selected)
216  for (auto i : myCandidateLanes) {
217  if(!isLaneSelected(i)) {
218  i->setSpecialColor(nullptr);
219  }
220  }
221  // clear candidate lanes
222  myCandidateLanes.clear();
223  // fill candidate lanes
224  for (auto i : lane->getParentEdge().getGNEConnections()) {
225  // check that possible candidate lane isn't already selected
226  if((lane == i->getLaneFrom()) && (!isLaneSelected(i->getLaneTo()))) {
227  // set candidate lane
228  i->getLaneTo()->setSpecialColor(&myCandidateLaneColor);
229  myCandidateLanes.push_back(i->getLaneTo());
230  }
231  }
232  // update view (due colors)
233  myAdditionalFrameParent->getViewNet()->update();
234  return true;
235 }
236 
237 
238 void
240  if(mySelectedLanes.size() > 1) {
241  mySelectedLanes.pop_back();
242  } else {
243  WRITE_WARNING("First lane cannot be removed");
244  }
245 }
246 
247 
248 bool
250  return myStopSelectingButton->isEnabled();
251 }
252 
253 
254 bool
256  return shown();
257 }
258 
259 
260 const RGBColor&
262  return mySelectedLaneColor;
263 }
264 
265 
266 const std::vector<std::pair<GNELane*, double> >&
268  return mySelectedLanes;
269 }
270 
271 
272 long
275  return 0;
276 }
277 
278 
279 long
282  return 0;
283 }
284 
285 
286 bool
288  for (auto i : mySelectedLanes) {
289  if (i.first == lane) {
290  return true;
291  }
292  }
293  return false;
294 }
295 
296 // ---------------------------------------------------------------------------
297 // GNEAdditionalFrame::SelectorAdditionalParent - methods
298 // ---------------------------------------------------------------------------
299 
301  FXGroupBox(additionalFrameParent->myContentFrame, "Parent selector", GUIDesignGroupBoxFrame),
302  myAdditionalFrameParent(additionalFrameParent),
303  myAdditionalTypeParent(SUMO_TAG_NOTHING) {
304  // Create label with the type of SelectorAdditionalParent
305  myFirstAdditionalParentsLabel = new FXLabel(this, "No additional selected", nullptr, GUIDesignLabelLeftThick);
306  // Create list
307  myFirstAdditionalParentsList = new FXList(this, this, MID_GNE_SET_TYPE, GUIDesignListSingleElement, 0, 0, 0, 100);
308  // Hide List
310 }
311 
312 
314 
315 
316 std::string
318  for (int i = 0; i < myFirstAdditionalParentsList->getNumItems(); i++) {
319  if (myFirstAdditionalParentsList->isItemSelected(i)) {
320  return myFirstAdditionalParentsList->getItem(i)->getText().text();
321  }
322  }
323  return "";
324 }
325 
326 
327 void
329  // first unselect all
330  for (int i = 0; i < myFirstAdditionalParentsList->getNumItems(); i++) {
331  myFirstAdditionalParentsList->getItem(i)->setSelected(false);
332  }
333  // select element if correspond to given ID
334  for (int i = 0; i < myFirstAdditionalParentsList->getNumItems(); i++) {
335  if (myFirstAdditionalParentsList->getItem(i)->getText().text() == id) {
336  myFirstAdditionalParentsList->getItem(i)->setSelected(true);
337  }
338  }
339  // recalc myFirstAdditionalParentsList
341 }
342 
343 
344 bool
346  // make sure that we're editing an additional tag
347  auto listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TAGProperty::TAGPROPERTY_ADDITIONAL, false);
348  for (auto i : listOfTags) {
349  if (i == additionalType) {
350  myAdditionalTypeParent = additionalType;
351  myFirstAdditionalParentsLabel->setText(("Parent type: " + toString(additionalType)).c_str());
353  show();
354  return true;
355  }
356  }
357  return false;
358 }
359 
360 
361 void
364  hide();
365 }
366 
367 
368 void
370  myFirstAdditionalParentsList->clearItems();
372  // fill list with IDs of additionals
374  myFirstAdditionalParentsList->appendItem(i.first.c_str());
375  }
376  }
377 }
378 
379 // ---------------------------------------------------------------------------
380 // GNEAdditionalFrame::SelectorEdgeChilds - methods
381 // ---------------------------------------------------------------------------
382 
384  FXGroupBox(additionalFrameParent->myContentFrame, "Edges", GUIDesignGroupBoxFrame),
385  myAdditionalFrameParent(additionalFrameParent) {
386  // Create menuCheck for selected edges
387  myUseSelectedEdgesCheckButton = new FXCheckButton(this, ("Use selected " + toString(SUMO_TAG_EDGE) + "s").c_str(), this, MID_GNE_ADDITIONALFRAME_USESELECTED, GUIDesignCheckButtonAttribute);
388 
389  // Create search box
391 
392  // Create list
393  myList = new FXList(this, this, MID_GNE_ADDITIONALFRAME_SELECT, GUIDesignList, 0, 0, 0, 100);
394 
395  // Create horizontal frame
396  FXHorizontalFrame* buttonsFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
397 
398  // Create button for clear selection
399  myClearEdgesSelection = new FXButton(buttonsFrame, "Clear", nullptr, this, MID_GNE_ADDITIONALFRAME_CLEARSELECTION, GUIDesignButtonRectangular);
400 
401  // Create button for invert selection
402  myInvertEdgesSelection = new FXButton(buttonsFrame, "Invert", nullptr, this, MID_GNE_ADDITIONALFRAME_INVERTSELECTION, GUIDesignButtonRectangular);
403 
404  // Hide List
406 }
407 
408 
410 
411 
412 std::string
414  std::vector<std::string> vectorOfIds;
415  if (myUseSelectedEdgesCheckButton->getCheck()) {
416  // get Selected edges
417  std::vector<GNEEdge*> selectedEdges = myAdditionalFrameParent->getViewNet()->getNet()->retrieveEdges(true);
418  // Iterate over selectedEdges and getId
419  for (auto i : selectedEdges) {
420  vectorOfIds.push_back(i->getID());
421  }
422  } else {
423  // Obtain Id's of list
424  for (int i = 0; i < myList->getNumItems(); i++) {
425  if (myList->isItemSelected(i)) {
426  vectorOfIds.push_back(myList->getItem(i)->getText().text());
427  }
428  }
429  }
430  return joinToString(vectorOfIds, " ");
431 }
432 
433 
434 void
436  // clear list of egdge ids
437  myList->clearItems();
438  // get all edges of net
440  std::vector<GNEEdge*> vectorOfEdges = myAdditionalFrameParent->getViewNet()->getNet()->retrieveEdges(false);
441  // iterate over edges of net
442  for (auto i : vectorOfEdges) {
443  // If search criterium is correct, then append ittem
444  if (i->getID().find(search) != std::string::npos) {
445  myList->appendItem(i->getID().c_str());
446  }
447  }
448  // By default, CheckBox for useSelectedEdges isn't checked
449  myUseSelectedEdgesCheckButton->setCheck(false);
450  // Recalc Frame
451  recalc();
452  // Update Frame
453  update();
454  // Show dialog
455  show();
456 }
457 
458 
459 void
461  FXGroupBox::hide();
462 }
463 
464 
465 void
467  // Enable or disable use selected edges
468  if (myAdditionalFrameParent->getViewNet()->getNet()->retrieveEdges(true).size() > 0) {
470  } else {
472  }
473 }
474 
475 
476 long
478  if (myUseSelectedEdgesCheckButton->getCheck()) {
479  myEdgesSearch->hide();
480  myList->hide();
481  myClearEdgesSelection->hide();
482  myInvertEdgesSelection->hide();
483  } else {
484  myEdgesSearch->show();
485  myList->show();
486  myClearEdgesSelection->show();
487  myInvertEdgesSelection->show();
488  }
489  // Recalc Frame
490  recalc();
491  // Update Frame
492  update();
493  return 1;
494 }
495 
496 
497 long
499  // Show only Id's of SelectorEdgeChilds that contains the searched string
500  showSelectorEdgeChildsModul(myEdgesSearch->getText().text());
501  return 1;
502 }
503 
504 
505 long
507  return 1;
508 }
509 
510 
511 long
513  for (int i = 0; i < myList->getNumItems(); i++) {
514  if (myList->getItem(i)->isSelected()) {
515  myList->deselectItem(i);
516  }
517  }
518  return 1;
519 }
520 
521 
522 long
524  for (int i = 0; i < myList->getNumItems(); i++) {
525  if (myList->getItem(i)->isSelected()) {
526  myList->deselectItem(i);
527  } else {
528  myList->selectItem(i);
529  }
530  }
531  return 1;
532 }
533 
534 // ---------------------------------------------------------------------------
535 // GNEAdditionalFrame::SelectorLaneChilds - methods
536 // ---------------------------------------------------------------------------
537 
539  FXGroupBox(additionalFrameParent->myContentFrame, "Lanes", GUIDesignGroupBoxFrame),
540  myAdditionalFrameParent(additionalFrameParent) {
541  // Create CheckBox for selected lanes
542  myUseSelectedLanesCheckButton = new FXCheckButton(this, ("Use selected " + toString(SUMO_TAG_LANE) + "s").c_str(), this, MID_GNE_ADDITIONALFRAME_USESELECTED, GUIDesignCheckButtonAttribute);
543 
544  // Create search box
546 
547  // Create list
548  myList = new FXList(this, this, MID_GNE_ADDITIONALFRAME_SELECT, GUIDesignList, 0, 0, 0, 100);
549 
550  // Create horizontal frame
551  FXHorizontalFrame* buttonsFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);
552 
553  // Create button for clear selection
554  clearLanesSelection = new FXButton(buttonsFrame, "clear", nullptr, this, MID_GNE_ADDITIONALFRAME_CLEARSELECTION, GUIDesignButtonRectangular);
555 
556  // Create button for invert selection
557  invertLanesSelection = new FXButton(buttonsFrame, "invert", nullptr, this, MID_GNE_ADDITIONALFRAME_INVERTSELECTION, GUIDesignButtonRectangular);
558 
559  // Hide List
561 }
562 
563 
565 
566 
567 std::string
569  std::vector<std::string> vectorOfIds;
570  if (myUseSelectedLanesCheckButton->getCheck()) {
571  // get Selected lanes
572  std::vector<GNELane*> selectedLanes = myAdditionalFrameParent->getViewNet()->getNet()->retrieveLanes(true);
573  // Iterate over selectedLanes and getId
574  for (auto i : selectedLanes) {
575  vectorOfIds.push_back(i->getID());
576  }
577  } else {
578  // Obtain Id's of list
579  for (int i = 0; i < myList->getNumItems(); i++) {
580  if (myList->isItemSelected(i)) {
581  vectorOfIds.push_back(myList->getItem(i)->getText().text());
582  }
583  }
584  }
585  return joinToString(vectorOfIds, " ");
586 }
587 
588 
589 void
591  myList->clearItems();
592  std::vector<GNELane*> vectorOfLanes = myAdditionalFrameParent->getViewNet()->getNet()->retrieveLanes(false);
593  for (auto i : vectorOfLanes) {
594  if (i->getID().find(search) != std::string::npos) {
595  myList->appendItem(i->getID().c_str());
596  }
597  }
598  // By default, CheckBox for useSelectedLanes isn't checked
599  myUseSelectedLanesCheckButton->setCheck(false);
600  // Show list
601  show();
602 }
603 
604 
605 void
607  FXGroupBox::hide();
608 }
609 
610 
611 void
613  // Enable or disable use selected Lanes
614  if (myAdditionalFrameParent->getViewNet()->getNet()->retrieveLanes(true).size() > 0) {
616  } else {
618  }
619 }
620 
621 
622 long
624  if (myUseSelectedLanesCheckButton->getCheck()) {
625  myLanesSearch->hide();
626  myList->hide();
627  clearLanesSelection->hide();
628  invertLanesSelection->hide();
629  } else {
630  myLanesSearch->show();
631  myList->show();
632  clearLanesSelection->show();
633  invertLanesSelection->show();
634  }
635  // Recalc Frame
636  recalc();
637  // Update Frame
638  update();
639  return 1;
640 }
641 
642 
643 long
645  // Show only Id's of SelectorLaneChilds that contains the searched string
646  showSelectorLaneChildsModul(myLanesSearch->getText().text());
647  return 1;
648 }
649 
650 
651 long
653  return 1;
654 }
655 
656 
657 long
659  for (int i = 0; i < myList->getNumItems(); i++) {
660  if (myList->getItem(i)->isSelected()) {
661  myList->deselectItem(i);
662  }
663  }
664  return 1;
665 }
666 
667 
668 long
670  for (int i = 0; i < myList->getNumItems(); i++) {
671  if (myList->getItem(i)->isSelected()) {
672  myList->deselectItem(i);
673  } else {
674  myList->selectItem(i);
675  }
676  }
677  return 1;
678 }
679 
680 // ===========================================================================
681 // method definitions
682 // ===========================================================================
683 
684 GNEAdditionalFrame::GNEAdditionalFrame(FXHorizontalFrame* horizontalFrameParent, GNEViewNet* viewNet) :
685  GNEFrame(horizontalFrameParent, viewNet, "Additionals") {
686 
687  // create item Selector modul for additionals
688  myItemSelector = new ItemSelector(this, GNEAttributeCarrier::TAGProperty::TAGPROPERTY_ADDITIONAL);
689 
690  // Create additional parameters
692 
693  // Create Netedit parameter
695 
696  // Create consecutive Lane Selector
698 
699  // Create create list for additional Set
701 
704 
707 
708  // set BusStop as default additional
710 }
711 
712 
714 
715 
716 void
718  // refresh item selector
720  // show frame
721  GNEFrame::show();
722 }
723 
724 
725 bool
727  // first check that current selected additional is valid
729  myViewNet->setStatusBarText("Current selected additional isn't valid.");
730  return false;
731  }
732 
733  // obtain tagproperty (only for improve code legibility)
734  const auto& tagValues = myItemSelector->getCurrentTagProperties();
735 
736  // Declare map to keep attributes from Frames from Frame
737  std::map<SumoXMLAttr, std::string> valuesMap = myAdditionalAttributes->getAttributesAndValues();
738 
739  // fill netedit attributes
740  if(!myNeteditAttributes->getNeteditAttributesAndValues(valuesMap, objectsUnderCursor.getLaneFront())) {
741  return false;
742  }
743 
744  // If element owns an additional parent, get id of parent from AdditionalParentSelector
745  if (tagValues.hasParent() && !buildAdditionalWithParent(valuesMap, objectsUnderCursor.getAdditionalFront(), tagValues)) {
746  return false;
747  }
748  // If consecutive Lane Selector is enabled, it means that either we're selecting lanes or we're finished or we'rent started
749  if(tagValues.canBePlacedOverEdge()) {
750  return buildAdditionalOverEdge(valuesMap, objectsUnderCursor.getLaneFront(), tagValues);
751  } else if(tagValues.canBePlacedOverLane()) {
752  return buildAdditionalOverLane(valuesMap, objectsUnderCursor.getLaneFront(), tagValues);
753  } else if(tagValues.canBePlacedOverLanes()) {
754  return buildAdditionalOverLanes(valuesMap, objectsUnderCursor.getLaneFront(), tagValues);
755  } else {
756  return buildAdditionalOverView(valuesMap, tagValues);
757  }
758 }
759 
760 void
762  myViewNet->getUndoList()->p_begin("delete " + additional->getTagStr());
763  // first remove all additional childs of this additional calling this function recursively
764  while (additional->getAdditionalChilds().size() > 0) {
765  removeAdditional(additional->getAdditionalChilds().front());
766  }
767  // remove additional
768  myViewNet->getUndoList()->add(new GNEChange_Additional(additional, false), true);
770 }
771 
772 
773 void
775  // Show frame
776  GNEFrame::show();
777  // Update UseSelectedLane CheckBox
779  // Update UseSelectedLane CheckBox
781 }
782 
783 
786  return mySelectorLaneParents;
787 }
788 
789 
790 void
792  // show additional attributes modul
794  // show netedit attributes
796  // Show myAdditionalFrameParent if we're adding a additional with parent
797  if (tagProperties.hasParent()) {
799  } else {
801  }
802  // Show SelectorEdgeChilds if we're adding an additional that own the attribute SUMO_ATTR_EDGES
803  if (tagProperties.hasAttribute(SUMO_ATTR_EDGES)) {
805  } else {
807  }
808  // Show SelectorLaneChilds or consecutive lane selector if we're adding an additional that own the attribute SUMO_ATTR_LANES
809  if (tagProperties.hasAttribute(SUMO_ATTR_LANES)) {
810  if(tagProperties.hasParent() && tagProperties.getParentTag() == SUMO_TAG_LANE) {
811  // show selector lane parent and hide selector lane child
814  } else {
815  // show selector lane child and hide selector lane parent
818  }
819  } else {
822  }
823 }
824 
825 
826 void
828  // hide all moduls if additional isn't valid
835 }
836 
837 
838 std::string
840  // obtain current number of additionals to generate a new index faster
842  // obtain tag Properties (only for improve code legilibility
843  const auto &tagProperties = myItemSelector->getCurrentTagProperties();
844  if (netElement) {
845  // generate ID using netElement
846  while (myViewNet->getNet()->retrieveAdditional(tagProperties.getTag(), tagProperties.getTagStr() + "_" + netElement->getID() + "_" + toString(additionalIndex), false) != nullptr) {
847  additionalIndex++;
848  }
849  return tagProperties.getTagStr() + "_" + netElement->getID() + "_" + toString(additionalIndex);
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
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
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
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] == "") {
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) && !tagValues.canBePlacedOverEdges()) {
898  // obtain edge IDs
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) && !tagValues.canBePlacedOverLanes()) {
908  // obtain lane IDs
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
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
939  return false;
940  } else if (GNEAdditionalHandler::buildAdditional(myViewNet, true, myItemSelector->getCurrentTagProperties().getTag(), valuesMap) != nullptr) {
941  // Refresh additional Parent Selector (For additionals that have a limited number of childs)
943  // clear selected eddges and lanes
944  mySelectorEdgeChilds->onCmdClearSelection(nullptr, 0, nullptr);
945  mySelectorLaneChilds->onCmdClearSelection(nullptr, 0, nullptr);
946  return true;
947  } else {
948  return false;
949  }
950 }
951 
952 
953 bool
954 GNEAdditionalFrame::buildAdditionalOverLane(std::map<SumoXMLAttr, std::string> &valuesMap, GNELane* lane, const GNEAttributeCarrier::TagProperties &tagValues) {
955  // check that lane exist
956  if (lane != nullptr) {
957  // Get attribute lane
958  valuesMap[SUMO_ATTR_LANE] = lane->getID();
959  // Generate id of element based on the lane
960  valuesMap[SUMO_ATTR_ID] = generateID(lane);
961  } else {
962  return false;
963  }
964  // Obtain position of the mouse over lane (limited over grid)
966  // set attribute position as mouse position over lane
967  valuesMap[SUMO_ATTR_POSITION] = toString(mousePositionOverLane);
968  // parse common attributes
969  if(!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
970  return false;
971  }
972  // show warning dialogbox and stop check if input parameters are valid
975  return false;
977  // Refresh additional Parent Selector (For additionals that have a limited number of childs)
979  // clear selected eddges and lanes
980  mySelectorEdgeChilds->onCmdClearSelection(nullptr, 0, nullptr);
981  mySelectorLaneChilds->onCmdClearSelection(nullptr, 0, nullptr);
982  return true;
983  } else {
984  return false;
985  }
986 }
987 
988 
989  bool
990 GNEAdditionalFrame::buildAdditionalOverLanes(std::map<SumoXMLAttr, std::string> &valuesMap, GNELane* lane, const GNEAttributeCarrier::TagProperties &tagValues) {
991  // stop if lane isn't valid
992  if(lane == nullptr) {
993  return false;
994  }
996  // select clicked lane, but don't build additional
998  return false;
999  } else if(mySelectorLaneParents->getSelectedLanes().empty()) {
1000  // if there isn't selected lanes, that means that we will be start selecting lanes
1002  return false;
1003  } else {
1004  // Generate id of element based on the first lane
1005  valuesMap[SUMO_ATTR_ID] = generateID(mySelectorLaneParents->getSelectedLanes().front().first);
1006  // obtain lane IDs
1007  std::vector<std::string> laneIDs;
1008  for (auto i : mySelectorLaneParents->getSelectedLanes()) {
1009  laneIDs.push_back(i.first->getID());
1010  }
1011  valuesMap[SUMO_ATTR_LANES] = joinToString(laneIDs, " ");
1012  // Check if clicked position over first lane has to be obtained
1013  if(tagValues.hasAttribute(SUMO_ATTR_POSITION)) {
1014  valuesMap[SUMO_ATTR_POSITION] = toString(mySelectorLaneParents->getSelectedLanes().front().second);
1015  }
1016  // Check if clicked position over last lane has to be obtained
1017  if(tagValues.hasAttribute(SUMO_ATTR_ENDPOS)) {
1018  valuesMap[SUMO_ATTR_ENDPOS] = toString(mySelectorLaneParents->getSelectedLanes().back().second);
1019  }
1020  // parse common attributes
1021  if(!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
1022  return false;
1023  }
1024  // show warning dialogbox and stop check if input parameters are valid
1025  if (myAdditionalAttributes->areValuesValid() == false) {
1027  return false;
1029  // Refresh additional Parent Selector (For additionals that have a limited number of childs)
1031  // abort lane selector
1033  return true;
1034  } else {
1035  // additional cannot be build
1036  return false;
1037  }
1038  }
1039  }
1040 
1041 
1042 bool
1043 GNEAdditionalFrame::buildAdditionalOverView(std::map<SumoXMLAttr, std::string> &valuesMap, const GNEAttributeCarrier::TagProperties &tagValues) {
1044  // Generate id of element
1045  valuesMap[SUMO_ATTR_ID] = generateID(nullptr);
1046  // Obtain position as the clicked position over view
1048  // parse common attributes
1049  if(!buildAdditionalCommonAttributes(valuesMap, tagValues)) {
1050  return false;
1051  }
1052  // show warning dialogbox and stop check if input parameters are valid
1053  if (myAdditionalAttributes->areValuesValid() == false) {
1055  return false;
1057  // Refresh additional Parent Selector (For additionals that have a limited number of childs)
1059  // clear selected eddges and lanes
1060  mySelectorEdgeChilds->onCmdClearSelection(nullptr, 0, nullptr);
1061  mySelectorLaneChilds->onCmdClearSelection(nullptr, 0, nullptr);
1062  return true;
1063  } else {
1064  return false;
1065  }
1066 }
1067 
1068 /****************************************************************************/
void hideSelectorAdditionalParentModul()
hide SelectorAdditionalParent Modul
void enableModuls(const GNEAttributeCarrier::TagProperties &tagProperties)
enable moduls depending of item selected in ItemSelector
std::vector< GNELane * > retrieveLanes(bool onlySelected=false)
return all lanes
Definition: GNENet.cpp:1044
void hideNeteditAttributesModul()
hide Netedit attributes modul
Definition: GNEFrame.cpp:1435
SumoXMLTag
Numbers representing SUMO-XML - element names.
bool showSelectorAdditionalParentModul(SumoXMLTag additionalTypeParent)
Show list of SelectorAdditionalParent Modul.
clear selection of elements
Definition: GUIAppEnum.h:672
#define GUIDesignCheckButtonAttribute
checkButton without thick extended over the frame used for attributes
Definition: GUIDesigns.h:115
void hideSelectorLaneChildsModul()
hide SelectorLaneChilds Modul
std::map< SumoXMLAttr, std::string > getAttributesAndValues() const
get attributes and their values
Definition: GNEFrame.cpp:493
invert selection of eleents
Definition: GUIAppEnum.h:674
void hideSelectorEdgeChildsModul()
hide SelectorEdgeChilds Modul
const RGBColor & getSelectedLaneColor() const
get selected lane color
begin/end of the description of a single lane
GNEAdditionalFrame * myAdditionalFrameParent
pointer to additional frame parent
void showSelectorLaneParentsModul()
show SelectorLaneParents modul
long onCmdUseSelectedEdges(FXObject *, FXSelector, void *)
FXButton * myInvertEdgesSelection
button for invert selection
A calibrator placed over edge.
FXTextField * myEdgesSearch
text field for search edge IDs
SumoXMLTag myAdditionalTypeParent
current additional type parent
bool buildAdditionalCommonAttributes(std::map< SumoXMLAttr, std::string > &valuesMap, const GNEAttributeCarrier::TagProperties &tagValues)
build common additional attributes
#define GUIDesignListSingleElement
design for FXLists that only allow a single selected elements
Definition: GUIDesigns.h:496
FXLabel * myFirstAdditionalParentsLabel
Label with the name of additional.
struct with the attribute Properties
long onCmdClearSelection(FXObject *, FXSelector, void *)
called when clear selection button is pressed
Position snapToActiveGrid(const Position &pos) const
Returns a position that is mapped to the closest grid point if the grid is active.
FXList * myList
List of SelectorLaneChilds.
long onCmdTypeInSearchBox(FXObject *, FXSelector, void *)
called when user type in search box
abort selection of consecutive egdes/lanes
Definition: GUIAppEnum.h:680
bool isShown() const
return true if modul is shown
const std::string & getTagStr() const
get Tag vinculated with this attribute Property in String Format (used to avoid multiple calls to toS...
static std::vector< SumoXMLTag > allowedTagsByCategory(int tagPropertyCategory, bool onlyDrawables)
get tags of all editable element types using TagProperty Type (TAGPROPERTY_NETELEMENT, TAGPROPERTY_ADDITIONAL, etc.)
GNELane * getLaneFront() const
get front lane (or a pointer to nullptr if there isn&#39;t)
Definition: GNEViewNet.cpp:367
long onCmdAbortSelection(FXObject *, FXSelector, void *)
Called when the user press abort selection button.
This lane is powered by an underlying GNEEdge and basically knows how to draw itself.
Definition: GNELane.h:47
bool stopConsecutiveLaneSelector()
stop selection of consecutive lanes
void p_begin(const std::string &description)
Begin undo command sub-group. This begins a new group of commands that are treated as a single comman...
Definition: GNEUndoList.cpp:73
void setIDSelected(const std::string &id)
select manually a element of the list
long onCmdClearSelection(FXObject *, FXSelector, void *)
called when clear selection button is pressed
long onCmdStopSelection(FXObject *, FXSelector, void *)
std::vector< GNELane * > myCandidateLanes
Vector with the colored lanes.
int getNumberOfAdditionals(SumoXMLTag type=SUMO_TAG_NOTHING) const
Returns the number of additionals of the net.
Definition: GNENet.cpp:1818
long onCmdTypeInSearchBox(FXObject *, FXSelector, void *)
called when user type in search box
const std::vector< GNEConnection * > & getGNEConnections()
returns a reference to the GNEConnection vector
Definition: GNEEdge.cpp:879
void showSelectorLaneChildsModul(std::string search="")
Show list of SelectorLaneChilds Modul.
void refreshTagProperties()
due myCurrentTagProperties is a Reference, we need to refresh it when frameParent is show ...
Definition: GNEFrame.cpp:176
ACAttributes * myAdditionalAttributes
internal additional attributes
const std::vector< std::pair< GNELane *, double > > & getSelectedLanes() const
get current selected lanes
long onCmdInvertSelection(FXObject *, FXSelector, void *)
called when invert selection button is pressed
long onCmdInvertSelection(FXObject *, FXSelector, void *)
called when invert selection button is pressed
RGBColor myCandidateLaneColor
color for candidate lanes
FXList * myFirstAdditionalParentsList
List of additional sets.
GNEViewNet * getViewNet() const
get view net
Definition: GNEFrame.cpp:1720
bool buildAdditionalOverEdge(std::map< SumoXMLAttr, std::string > &valuesMap, GNELane *lane, const GNEAttributeCarrier::TagProperties &tagValues)
build additional over an edge (parent of lane)
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:241
GNEAdditionalFrame * myAdditionalFrameParent
pointer to Additional Frame Parent
void showSelectorEdgeChildsModul(std::string search="")
Show SelectorEdgeChilds Modul.
bool hasParent() const
return true if tag correspond to an element that can had another element as parent ...
FXButton * invertLanesSelection
button for invert selection
void showNeteditAttributesModul(const GNEAttributeCarrier::TagProperties &tagValue)
show Netedit attributes modul
Definition: GNEFrame.cpp:1384
GNEViewNet * myViewNet
View Net for changes.
Definition: GNEFrame.h:612
GNEAdditional * retrieveAdditional(SumoXMLTag type, const std::string &id, bool hardFail=true) const
Returns the named additional.
Definition: GNENet.cpp:1785
std::string getLaneIdsSelected() const
get list of selecte lane ids in string format
const GNEAttributeCarrier::TagProperties & getCurrentTagProperties() const
get current type tag
Definition: GNEFrame.cpp:149
bool isLaneSelected(GNELane *lane) const
check if certain lane is selected
GNEUndoList * getUndoList() const
get the undoList object
long onCmdUseSelectedLanes(FXObject *, FXSelector, void *)
static const RGBColor GREEN
Definition: RGBColor.h:185
#define GUIDesignList
design for FXLists
Definition: GUIDesigns.h:493
GNEAdditionalFrame::SelectorLaneParents * getConsecutiveLaneSelector() const
getConsecutive Lane Selector
bool addAdditional(const GNEViewNet::ObjectsUnderCursor &objectsUnderCursor)
add additional element
#define GUIDesignTextField
Definition: GUIDesigns.h:34
the edges of a route
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
SumoXMLTag getTag() const
get Tag vinculated with this attribute Property
FXVerticalFrame * myContentFrame
Vertical frame that holds all widgets of frame.
Definition: GNEFrame.h:615
GNEEdge & getParentEdge()
Returns underlying parent edge.
Definition: GNELane.cpp:1260
void removeLastSelectedLane()
remove last added point
void p_end()
End undo command sub-group. If the sub-group is still empty, it will be deleted; otherwise, the sub-group will be added as a new command into parent group. A matching begin() must have been called previously.
Definition: GNEUndoList.cpp:80
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
SelectorLaneChilds * mySelectorLaneChilds
Modul for select lane childs.
#define GUIDesignAuxiliarHorizontalFrame
design for auxiliar (Without borders) horizontal frame used to pack another frames ...
Definition: GUIDesigns.h:261
long onCmdSelectEdge(FXObject *, FXSelector, void *)
called when user select a edge of the list
GNEAdditionalFrame * myAdditionalFrameParent
pointer to additionalFrameParent
FXButton * myStopSelectingButton
button for stop selecting
bool buildAdditionalOverLane(std::map< SumoXMLAttr, std::string > &valuesMap, GNELane *lane, const GNEAttributeCarrier::TagProperties &tagValues)
build additional over a single lane
void removeAdditional(GNEAdditional *additional)
remove an additional element previously added
C++ TraCI client API implementation.
void showACAttributesModul(const GNEAttributeCarrier::TagProperties &myTagProperties)
show ACAttributes modul
Definition: GNEFrame.cpp:466
bool canBePlacedOverEdges() const
return true if tag correspond to an element that can be placed over a list of edges ...
~GNEAdditionalFrame()
Destructor.
double getLengthGeometryFactor() const
get lenght geometry factor
Definition: GNELane.cpp:1317
void showSelectorLaneChildsModul()
show selector lane child and update use selected edges/lanes
FXCheckButton * myUseSelectedEdgesCheckButton
CheckBox for selected edges.
FXList * myList
List of SelectorEdgeChilds.
void showWarningMessage(std::string extra="") const
show warning message with information about non-valid attributes
Definition: GNEFrame.cpp:506
FXButton * myAbortSelectingButton
button for abort selecting
const std::string getID() const
function to support debugging
std::vector< std::pair< GNELane *, double > > mySelectedLanes
Vector with the selected lanes and the clicked position.
void refreshSelectorAdditionalParentModul()
Refresh list of Additional Parents Modul.
bool getNeteditAttributesAndValues(std::map< SumoXMLAttr, std::string > &valuesMap, GNELane *lane) const
fill valuesMap with netedit attributes
Definition: GNEFrame.cpp:1441
#define GUIDesignButtonRectangular
little button rectangular (46x23) used in frames (For example, in "help" buttons) ...
Definition: GUIDesigns.h:60
begin/end of the description of an edge
GNEAdditional * getAdditionalFront() const
get front additional element (or a pointer to nullptr if there isn&#39;t)
Definition: GNEViewNet.cpp:327
FXTextField * myLanesSearch
text field for search lane IDs
#define GUIDesignTextFieldNCol
Num of column of text field.
Definition: GUIDesigns.h:46
FXButton * clearLanesSelection
button for clear selection
#define GUIDesignButton
Definition: GUIDesigns.h:54
const PositionVector & getShape() const
returns the shape of the lane
Definition: GNELane.cpp:669
virtual void show()
show Frame
Definition: GNEFrame.cpp:1695
ItemSelector * myItemSelector
item selector
bool addSelectedLane(GNELane *lane, const Position &clickedPosition)
return true if lane can be selected as consecutive lane
long onCmdSelectLane(FXObject *, FXSelector, void *)
called when user select a lane of the list
void show()
show Frame
std::vector< GNEEdge * > retrieveEdges(bool onlySelected=false)
return all edges
Definition: GNENet.cpp:1031
An Element which don&#39;t belongs to GNENet but has influency in the simulation.
Definition: GNEAdditional.h:48
#define GUIDesignGroupBoxFrame
Group box design extended over frame.
Definition: GUIDesigns.h:227
static GNEAdditional * buildAdditional(GNEViewNet *viewNet, bool allowUndoRedo, SumoXMLTag tag, std::map< SumoXMLAttr, std::string > values)
Build additionals.
SelectorAdditionalParent(GNEAdditionalFrame *additionalFrameParent)
constructor
const std::string & getTagStr() const
get tag assigned to this object in string format
weights: time range end
void disableModuls()
disable moduls if element selected in itemSelector isn&#39;t valid
FXDEFMAP(GNEAdditionalFrame::SelectorLaneParents) ConsecutiveLaneSelectorMap[]
void setSpecialColor(const RGBColor *Color2)
Definition: GNELane.cpp:982
NeteditAttributes * myNeteditAttributes
Netedit parameter.
FXCheckButton * myUseSelectedLanesCheckButton
CheckBox for selected lanes.
SelectorLaneParents * mySelectorLaneParents
Modul for select lane parents (currently only consecutives)
RGBColor mySelectedLaneColor
color for selected lanes
bool buildAdditionalOverView(std::map< SumoXMLAttr, std::string > &valuesMap, const GNEAttributeCarrier::TagProperties &tagValues)
build additional over view
void hideSelectorLaneParentsModul()
hide SelectorLaneParents
virtual void hide()
hide Frame
Definition: GNEFrame.cpp:1704
std::string getEdgeIdsSelected() const
get list of selecte id&#39;s in string format
std::string generateID(GNENetElement *netElement) const
generate a ID for an additiona element
GNENet * getNet() const
get the net object
const std::map< std::string, GNEAdditional * > & getAdditionalByType(SumoXMLTag type) const
get map with IDs and pointers to additionals
Definition: GNENet.cpp:1812
bool buildAdditionalWithParent(std::map< SumoXMLAttr, std::string > &valuesMap, GNEAdditional *parent, const GNEAttributeCarrier::TagProperties &tagValues)
build additional with Parent
SelectorAdditionalParent * mySelectorAdditionalParent
Modul for select a single additional parent (Used only for first Additional parent) ...
void setStatusBarText(const std::string &text)
set staturBar text
Definition: GNEViewNet.cpp:727
bool isSelectingLanes() const
return true if modul is selecting lane
SumoXMLTag getParentTag() const
if Tag owns a parent, return parent tag
void updateUseSelectedEdges()
Update use selectedEdges.
bool hasAttribute(SumoXMLAttr attr) const
check if current TagProperties owns the attribute attr
GNEAdditionalFrame * myAdditionalFrameParent
pointer to additional frame parent
std::string getIdSelected() const
get currently additional parent selected
const TagProperties & getTagProperty() const
get Tag Property assigned to this object
void startConsecutiveLaneSelector(GNELane *lane, const Position &clickedPosition)
start selection of consecutive lanes
Position getPositionInformation() const
Returns the cursor&#39;s x/y position within the network.
use selected elements
Definition: GUIAppEnum.h:668
bool areValuesValid() const
check if parameters of attributes are valid
Definition: GNEFrame.cpp:533
bool buildAdditionalOverLanes(std::map< SumoXMLAttr, std::string > &valuesMap, GNELane *lane, const GNEAttributeCarrier::TagProperties &tagValues)
build additional over lanes
parent of an additional element
used to select a type of element in a combo box
Definition: GUIAppEnum.h:541
FXButton * myClearEdgesSelection
button for clear selection
SelectorEdgeChilds * mySelectorEdgeChilds
Modul for select edge childs.
GNEAdditionalFrame(FXHorizontalFrame *horizontalFrameParent, GNEViewNet *viewNet)
Constructor.
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
const std::vector< GNEAdditional * > & getAdditionalChilds() const
return vector of additionals that have as Parent this edge (For example, Calibrators) ...
void setCurrentTypeTag(SumoXMLTag typeTag)
set current type manually
Definition: GNEFrame.cpp:155
void abortConsecutiveLaneSelector()
abort selection of consecutive lanes
void hideACAttributesModul()
hide group box
Definition: GNEFrame.cpp:487
#define GUIDesignLabelLeftThick
label extended over frame with thick and with text justify to left and height of 23 ...
Definition: GUIDesigns.h:157
bool canBePlacedOverLanes() const
return true if tag correspond
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:237
stop selection of consecutive egdes/lanes
Definition: GUIAppEnum.h:678