SUMO - Simulation of Urban MObility
GNESelectorFrame.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-2017 German Aerospace Center (DLR) and others.
4 /****************************************************************************/
5 //
6 // This program and the accompanying materials
7 // are made available under the terms of the Eclipse Public License v2.0
8 // which accompanies this distribution, and is available at
9 // http://www.eclipse.org/legal/epl-v20.html
10 //
11 /****************************************************************************/
17 // The Widget for modifying selections of network-elements
18 // (some elements adapted from GUIDialog_GLChosenEditor)
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #ifdef _MSC_VER
26 #include <windows_config.h>
27 #else
28 #include <config.h>
29 #endif
30 
31 #include <iostream>
41 
42 #include "GNESelectorFrame.h"
43 #include "GNEViewNet.h"
44 #include "GNEViewParent.h"
45 #include "GNENet.h"
46 #include "GNEJunction.h"
47 #include "GNEEdge.h"
48 #include "GNELane.h"
49 #include "GNEPoly.h"
50 #include "GNEPOI.h"
51 #include "GNEUndoList.h"
52 #include "GNEChange_Selection.h"
53 #include "GNEAttributeCarrier.h"
54 
55 
56 // ===========================================================================
57 // FOX callback mapping
58 // ===========================================================================
59 FXDEFMAP(GNESelectorFrame) GNESelectorFrameMap[] = {
61  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_ELEMENTS, GNESelectorFrame::onCmdSubset),
62  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_LOAD, GNESelectorFrame::onCmdLoad),
63  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SAVE, GNESelectorFrame::onCmdSave),
64  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_INVERT, GNESelectorFrame::onCmdInvert),
65  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GNESelectorFrame::onCmdClear),
70  FXMAPFUNC(SEL_COMMAND, MID_HELP, GNESelectorFrame::onCmdHelp)
71 };
72 
73 // Object implementation
74 FXIMPLEMENT(GNESelectorFrame, FXVerticalFrame, GNESelectorFrameMap, ARRAYNUMBER(GNESelectorFrameMap))
75 
76 // ===========================================================================
77 // method definitions
78 // ===========================================================================
79 
80 GNESelectorFrame::ObjectTypeEntry::ObjectTypeEntry(FXMatrix* parent, const std::string& label, const std::string& label2) {
81  count = new FXLabel(parent, "0", 0, GUIDesignLabelLeft);
82  typeName = new FXLabel(parent, label.c_str(), 0, GUIDesignLabelLeft);
83  locked = new FXMenuCheck(parent, ("lock\t\tLock " + label2 + " selection").c_str(), 0, 0, LAYOUT_FILL_X | LAYOUT_RIGHT);
84 }
85 
86 
87 GNESelectorFrame::GNESelectorFrame(FXHorizontalFrame* horizontalFrameParent, GNEViewNet* viewNet):
88  GNEFrame(horizontalFrameParent, viewNet, "Selection"),
89  mySetOperation(SET_ADD),
90  myCurrentTag(SUMO_TAG_NOTHING),
91  myCurrentAttribute(SUMO_ATTR_NOTHING) {
92  // create combo box and labels for selected items
93  FXGroupBox* mySelectedItemsComboBox = new FXGroupBox(myContentFrame, "Selected items", 0, GUIDesignGroupBoxFrame);
94  FXMatrix* mSelectedItems = new FXMatrix(mySelectedItemsComboBox, 3, (LAYOUT_FILL_X | LAYOUT_BOTTOM | LAYOUT_LEFT | MATRIX_BY_COLUMNS), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
95 
96  myTypeEntries[GLO_JUNCTION] = ObjectTypeEntry(mSelectedItems, "Junctions", "junction");
97  myTypeEntries[GLO_EDGE] = ObjectTypeEntry(mSelectedItems, "Edges", "edge");
98  myTypeEntries[GLO_LANE] = ObjectTypeEntry(mSelectedItems, "Lanes", "lane");
99  myTypeEntries[GLO_CONNECTION] = ObjectTypeEntry(mSelectedItems, "Connections", "connection");
100  myTypeEntries[GLO_ADDITIONAL] = ObjectTypeEntry(mSelectedItems, "Additionals", "additional");
101  myTypeEntries[GLO_CROSSING] = ObjectTypeEntry(mSelectedItems, "Crossings", "crossing");
102  myTypeEntries[GLO_POLYGON] = ObjectTypeEntry(mSelectedItems, "Polygons", "polygon");
103  myTypeEntries[GLO_POI] = ObjectTypeEntry(mSelectedItems, "POIs", "POI");
104  // create combo box for selection modification mode
105  FXGroupBox* selBox = new FXGroupBox(myContentFrame, "Modification Mode", GUIDesignGroupBoxFrame);
106  // Create all options buttons
107  myAddRadioButton = new FXRadioButton(selBox, "add\t\tSelected objects are added to the previous selection",
109  myRemoveRadioButton = new FXRadioButton(selBox, "remove\t\tSelected objects are removed from the previous selection",
111  myKeepRadioButton = new FXRadioButton(selBox, "keep\t\tRestrict previous selection by the current selection",
113  myReplaceRadioButton = new FXRadioButton(selBox, "replace\t\tReplace previous selection by the current selection",
115  myAddRadioButton->setCheck(true);
116  // Create groupBox for selection by expression matching (match box)
117  FXGroupBox* elementBox = new FXGroupBox(myContentFrame, "type of element", GUIDesignGroupBoxFrame);
118  // Create MatchTagBox for tags and fill it
119  mySetComboBox = new FXComboBox(elementBox, GUIDesignComboBoxNCol, this, MID_CHOOSEN_ELEMENTS, GUIDesignComboBox);
120  mySetComboBox->appendItem("Net Element");
121  mySetComboBox->appendItem("Additional");
122  mySetComboBox->appendItem("Shape");
123  mySetComboBox->setNumVisible(mySetComboBox->getNumItems());
124  // Create groupBox fro selection by expression matching (match box)
125  FXGroupBox* matchBox = new FXGroupBox(myContentFrame, "Match Attribute", GUIDesignGroupBoxFrame);
126  // Create MatchTagBox for tags
128  // Create listBox for Attributes
130  // Create TextField for Match string
132  // Fill list of sub-items
133  onCmdSubset(0, 0, 0);
134  // Set speed of edge as default attribute
136  myMatchAttrComboBox->setCurrentItem(3);
138  // Set default value for Match string
139  myMatchString->setText(">10.0");
140  // Create help button
141  new FXButton(matchBox, "Help", 0, this, MID_HELP, GUIDesignButtonRectangular);
142  // Create Groupbox for visual scalings
143  FXGroupBox* selSizeBox = new FXGroupBox(myContentFrame, "Visual Scaling", GUIDesignGroupBoxFrame);
144  // Create spin button and configure it
147  mySelectionScaling->setIncrements(0.1, .5, 1);
148  mySelectionScaling->setRange(1, 100);
150  mySelectionScaling->setHelpText("Enlarge selected objects");
151  // Create groupbox for additional buttons
152  FXGroupBox* additionalButtons = new FXGroupBox(myContentFrame, "Operations for selections", GUIDesignGroupBoxFrame);
153  // Create "Clear List" Button
154  new FXButton(additionalButtons, "Clear\t\t", 0, this, MID_CHOOSEN_CLEAR, GUIDesignButton);
155  // Create "Invert" Button
156  new FXButton(additionalButtons, "Invert\t\t", 0, this, MID_CHOOSEN_INVERT, GUIDesignButton);
157  // Create "Save" Button
158  new FXButton(additionalButtons, "Save\t\tSave ids of currently selected objects to a file.", 0, this, MID_CHOOSEN_SAVE, GUIDesignButton);
159  // Create "Load" Button
160  new FXButton(additionalButtons, "Load\t\tLoad ids from a file according to the current modfication mode.", 0, this, MID_CHOOSEN_LOAD, GUIDesignButton);
161  // Create groupbox for information about selections
162  FXGroupBox* selectionHintGroupBox = new FXGroupBox(myContentFrame, "Information", GUIDesignGroupBoxFrame);
163  // Create Selection Hint
164  new FXLabel(selectionHintGroupBox, " - Hold <SHIFT> for \n rectangle selection.\n - Press <DEL> to\n delete selected items.", 0, GUIDesignLabelFrameInformation);
165 }
166 
167 
170 }
171 
172 
173 long
174 GNESelectorFrame::onCmdSelectOperation(FXObject* obj, FXSelector, void*) {
175  if (obj == myAddRadioButton) {
177  myAddRadioButton->setCheck(true);
178  myRemoveRadioButton->setCheck(false);
179  myKeepRadioButton->setCheck(false);
180  myReplaceRadioButton->setCheck(false);
181  return 1;
182  } else if (obj == myRemoveRadioButton) {
184  myAddRadioButton->setCheck(false);
185  myRemoveRadioButton->setCheck(true);
186  myKeepRadioButton->setCheck(false);
187  myReplaceRadioButton->setCheck(false);
188  return 1;
189  } else if (obj == myKeepRadioButton) {
191  myAddRadioButton->setCheck(false);
192  myRemoveRadioButton->setCheck(false);
193  myKeepRadioButton->setCheck(true);
194  myReplaceRadioButton->setCheck(false);
195  return 1;
196  } else if (obj == myReplaceRadioButton) {
198  myAddRadioButton->setCheck(false);
199  myRemoveRadioButton->setCheck(false);
200  myKeepRadioButton->setCheck(false);
201  myReplaceRadioButton->setCheck(true);
202  return 1;
203  } else {
204  return 0;
205  }
206 }
207 
208 
209 long
210 GNESelectorFrame::onCmdSubset(FXObject*, FXSelector, void*) {
211  if (mySetComboBox->getText() == "Net Element") {
212  mySetComboBox->setTextColor(FXRGB(0, 0, 0));
213  myMatchTagComboBox->enable();
214  myMatchAttrComboBox->enable();
215  myMatchString->enable();
216  // Clear items of myMatchTagComboBox
217  myMatchTagComboBox->clearItems();
218  // Set items depending of current items
220  myMatchTagComboBox->appendItem(toString(i).c_str());
221  }
222  myMatchTagComboBox->setCurrentItem(0); // edges
223  myMatchTagComboBox->setNumVisible(myMatchTagComboBox->getNumItems());
224  // Fill attributes with the current element type
225  onCmdSelMBTag(0, 0, 0);
226  } else if (mySetComboBox->getText() == "Additional") {
227  mySetComboBox->setTextColor(FXRGB(0, 0, 0));
228  myMatchTagComboBox->enable();
229  myMatchAttrComboBox->enable();
230  myMatchString->enable();
231  // Clear items of myMatchTagComboBox
232  myMatchTagComboBox->clearItems();
233  // Set items depending of current items
235  myMatchTagComboBox->appendItem(toString(i).c_str());
236  }
237  myMatchTagComboBox->setCurrentItem(0); // edges
238  myMatchTagComboBox->setNumVisible(myMatchTagComboBox->getNumItems());
239  // Fill attributes with the current element type
240  onCmdSelMBTag(0, 0, 0);
241  } else if (mySetComboBox->getText() == "Shape") {
242  mySetComboBox->setTextColor(FXRGB(0, 0, 0));
243  myMatchTagComboBox->enable();
244  myMatchAttrComboBox->enable();
245  myMatchString->enable();
246  // Clear items of myMatchTagComboBox
247  myMatchTagComboBox->clearItems();
248  // Set items depending of current items
249  for (auto i : GNEAttributeCarrier::allowedShapeTags()) {
250  myMatchTagComboBox->appendItem(toString(i).c_str());
251  }
252  myMatchTagComboBox->setCurrentItem(0); // edges
253  myMatchTagComboBox->setNumVisible(myMatchTagComboBox->getNumItems());
254  // Fill attributes with the current element type
255  onCmdSelMBTag(0, 0, 0);
256  } else {
257  mySetComboBox->setTextColor(FXRGB(255, 0, 0));
258  myMatchTagComboBox->disable();
259  myMatchAttrComboBox->disable();
260  myMatchString->disable();
261  }
262  return 1;
263 }
264 
265 
266 long
267 GNESelectorFrame::onCmdLoad(FXObject*, FXSelector, void*) {
268  // get the new file name
269  FXFileDialog opendialog(this, "Open List of Selected Items");
270  opendialog.setIcon(GUIIconSubSys::getIcon(ICON_EMPTY));
271  opendialog.setSelectMode(SELECTFILE_EXISTING);
272  opendialog.setPatternList("Selection files (*.txt)\nAll files (*)");
273  if (gCurrentFolder.length() != 0) {
274  opendialog.setDirectory(gCurrentFolder);
275  }
276  if (opendialog.execute()) {
277  gCurrentFolder = opendialog.getDirectory();
278  std::string file = opendialog.getFilename().text();
279  // @todo maybe rewrite so that mySetOperation also applies to loaded items?
280  std::string errors;
281  std::set<GUIGlID> ids = gSelected.loadIDs(file, errors);
282  handleIDs(std::vector<GUIGlID>(ids.begin(), ids.end()), false);
283  if (errors != "") {
284  // write warning if netedit is running in testing mode
285  if (OptionsCont::getOptions().getBool("gui-testing-debug")) {
286  WRITE_WARNING("Opening FXMessageBox 'error loading selection'");
287  }
288  // open message box error
289  FXMessageBox::error(this, MBOX_OK, "Errors while loading Selection", "%s", errors.c_str());
290  // write warning if netedit is running in testing mode
291  if (OptionsCont::getOptions().getBool("gui-testing-debug")) {
292  WRITE_WARNING("Closed FXMessageBox 'error loading selection' with 'OK'");
293  }
294  }
295  }
296  myViewNet->update();
297  return 1;
298 }
299 
300 
301 long
302 GNESelectorFrame::onCmdSave(FXObject*, FXSelector, void*) {
303  FXString file = MFXUtils::getFilename2Write(
304  this, "Save List of selected Items", ".txt", GUIIconSubSys::getIcon(ICON_EMPTY), gCurrentFolder);
305  if (file == "") {
306  return 1;
307  }
308  try {
309  gSelected.save(file.text());
310  } catch (IOError& e) {
311  // write warning if netedit is running in testing mode
312  if (OptionsCont::getOptions().getBool("gui-testing-debug")) {
313  WRITE_WARNING("Opening FXMessageBox 'error storing selection'");
314  }
315  // open message box error
316  FXMessageBox::error(this, MBOX_OK, "Storing Selection failed", "%s", e.what());
317  // write warning if netedit is running in testing mode
318  if (OptionsCont::getOptions().getBool("gui-testing-debug")) {
319  WRITE_WARNING("Closed FXMessageBox 'error storing selection' with 'OK'");
320  }
321  }
322  return 1;
323 }
324 
325 
326 long
327 GNESelectorFrame::onCmdClear(FXObject*, FXSelector, void*) {
328  myViewNet->getUndoList()->p_begin("clear selection");
329  myViewNet->getUndoList()->add(new GNEChange_Selection(myViewNet->getNet(), std::set<GUIGlID>(), gSelected.getSelected(), true), true);
331  myViewNet->update();
332  return 1;
333 }
334 
335 
336 long
337 GNESelectorFrame::onCmdInvert(FXObject*, FXSelector, void*) {
338  // declare a set to keep unselected elements
339  std::set<GUIGlID> unselectedElements;
340  // iterate over all junctions to obtain unselected
341  std::set<GUIGlID> ids = myViewNet->getNet()->getGlIDs(GLO_JUNCTION);
342  for (auto it : ids) {
343  if (gSelected.isSelected(GLO_JUNCTION, it) == false) {
344  unselectedElements.insert(it);
345  }
346 
347  }
348  // iterate over all edges or lanes (Depending of checkbox) to obtain unselected
349  GUIGlObjectType currentEdgeOrLane = myViewNet->selectEdges() ? GLO_EDGE : GLO_LANE;
350  ids = myViewNet->getNet()->getGlIDs(currentEdgeOrLane);
351  for (auto it : ids) {
352  if (gSelected.isSelected(currentEdgeOrLane, it) == false) {
353  unselectedElements.insert(it);
354  }
355 
356  }
357  // iterate over all additionals to obtain unselected
359  for (auto it : ids) {
360  if (gSelected.isSelected(GLO_ADDITIONAL, it) == false) {
361  unselectedElements.insert(it);
362  }
363  }
364  // iterate over all connections to obtain unselected
366  for (auto it : ids) {
367  if (gSelected.isSelected(GLO_CONNECTION, it) == false) {
368  unselectedElements.insert(it);
369  }
370  }
371  // iterate over all crossings to obtain unselected
373  for (auto it : ids) {
374  if (gSelected.isSelected(GLO_CROSSING, it) == false) {
375  unselectedElements.insert(it);
376  }
377  }
378  // iterate over all visible polygons to obtain unselected
379  for (const auto& it : myViewNet->getNet()->getPolygons()) {
380  GNEPoly* poly = dynamic_cast<GNEPoly*>(it.second);
381  if (gSelected.isSelected(GLO_POLYGON, poly->getGlID()) == false) {
382  unselectedElements.insert(poly->getGlID());
383  }
384  }
385  // iterate over all visible POIs to obtain unselected
386  for (const auto& it : myViewNet->getNet()->getPOIs()) {
387  GNEPOI* POI = dynamic_cast<GNEPOI*>(it.second);
388  if (gSelected.isSelected(GLO_POI, POI->getGlID()) == false) {
389  unselectedElements.insert(POI->getGlID());
390  }
391  }
392  // invert selection first cleaning current selection and next selecting elements of set "unselectedElements"
393  myViewNet->getUndoList()->p_begin("invert selection");
394  myViewNet->getUndoList()->add(new GNEChange_Selection(myViewNet->getNet(), std::set<GUIGlID>(), gSelected.getSelected(), true), true);
395  myViewNet->getUndoList()->add(new GNEChange_Selection(myViewNet->getNet(), unselectedElements, std::set<GUIGlID>(), true), true);
397  myViewNet->update();
398  return 1;
399 }
400 
401 
402 long
403 GNESelectorFrame::onCmdSelMBTag(FXObject*, FXSelector, void*) {
405  // find current element tag
406  if (mySetComboBox->getText() == "Net Element") {
408  if (toString(i) == myMatchTagComboBox->getText().text()) {
409  myCurrentTag = i;
410  }
411  }
412  } else if (mySetComboBox->getText() == "Additional") {
414  if (toString(i) == myMatchTagComboBox->getText().text()) {
415  myCurrentTag = i;
416  }
417  }
418  } else if (mySetComboBox->getText() == "Shape") {
419  for (auto i : GNEAttributeCarrier::allowedShapeTags()) {
420  if (toString(i) == myMatchTagComboBox->getText().text()) {
421  myCurrentTag = i;
422  }
423  }
424  } else {
425  throw ProcessError("Unkown set");
426  }
427 
428  // check that typed by user value is correct
430  // set color and enable items
431  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
432  myMatchAttrComboBox->enable();
433  myMatchString->enable();
434  myMatchAttrComboBox->clearItems();
436  myMatchAttrComboBox->appendItem(toString(it.first).c_str());
437  }
438  // @ToDo: Here can be placed a butto to set the default value
439  myMatchAttrComboBox->setNumVisible(myMatchAttrComboBox->getNumItems());
440  onCmdSelMBAttribute(0, 0, 0);
441  } else {
442  // change color to red and disable items
443  myMatchTagComboBox->setTextColor(FXRGB(255, 0, 0));
444  myMatchAttrComboBox->disable();
445  myMatchString->disable();
446  }
447  update();
448  return 1;
449 }
450 
451 
452 long
453 GNESelectorFrame::onCmdSelMBAttribute(FXObject*, FXSelector, void*) {
454  const std::vector<std::pair <SumoXMLAttr, std::string> >& attrs = GNEAttributeCarrier::allowedAttributes(myCurrentTag);
456  for (auto i : attrs) {
457  if (toString(i.first) == myMatchAttrComboBox->getText().text()) {
458  myCurrentAttribute = i.first;
459  }
460  }
462  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
463  myMatchString->enable();
464  } else {
465  myMatchAttrComboBox->setTextColor(FXRGB(255, 0, 0));
466  myMatchString->disable();
467  }
468  return 1;
469 }
470 
471 
472 long
473 GNESelectorFrame::onCmdSelMBString(FXObject*, FXSelector, void*) {
474  std::string expr(myMatchString->getText().text());
475  bool valid = true;
476  if (expr == "") {
477  // the empty expression matches all objects
478  handleIDs(getMatches(myCurrentTag, myCurrentAttribute, '@', 0, expr), false);
480  // The expression must have the form
481  // <val matches if attr < val
482  // >val matches if attr > val
483  // =val matches if attr = val
484  // val matches if attr = val
485  char compOp = expr[0];
486  if (compOp == '<' || compOp == '>' || compOp == '=') {
487  expr = expr.substr(1);
488  } else {
489  compOp = '=';
490  }
491  try {
492  handleIDs(getMatches(myCurrentTag, myCurrentAttribute, compOp, GNEAttributeCarrier::parse<double>(expr.c_str()), expr), false);
493  } catch (EmptyData&) {
494  valid = false;
495  } catch (NumberFormatException&) {
496  valid = false;
497  }
498  } else {
499  // The expression must have the form
500  // =str: matches if <str> is an exact match
501  // !str: matches if <str> is not a substring
502  // ^str: matches if <str> is not an exact match
503  // str: matches if <str> is a substring (sends compOp '@')
504  // Alternatively, if the expression is empty it matches all objects
505  char compOp = expr[0];
506  if (compOp == '=' || compOp == '!' || compOp == '^') {
507  expr = expr.substr(1);
508  } else {
509  compOp = '@';
510  }
511  handleIDs(getMatches(myCurrentTag, myCurrentAttribute, compOp, 0, expr), false);
512  }
513  if (valid) {
514  myMatchString->setTextColor(FXRGB(0, 0, 0));
515  myMatchString->killFocus();
516  } else {
517  myMatchString->setTextColor(FXRGB(255, 0, 0));
518  }
519  return 1;
520 }
521 
522 
523 long
524 GNESelectorFrame::onCmdHelp(FXObject*, FXSelector, void*) {
525  FXDialogBox* helpDialog = new FXDialogBox(this, "Match Attribute Help", GUIDesignDialogBox);
526  std::ostringstream help;
527  help
528  << "The 'Match Attribute' controls allow to specify a set of objects which are then applied to the current selection "
529  << "according to the current 'Modification Mode'.\n"
530  << "1. Select an object type from the first input box\n"
531  << "2. Select an attribute from the second input box\n"
532  << "3. Enter a 'match expression' in the third input box and press <return>\n"
533  << "\n"
534  << "The empty expression matches all objects\n"
535  << "For numerical attributes the match expression must consist of a comparison operator ('<', '>', '=') and a number.\n"
536  << "An object matches if the comparison between its attribute and the given number by the given operator evaluates to 'true'\n"
537  << "\n"
538  << "For string attributes the match expression must consist of a comparison operator ('', '=', '!', '^') and a string.\n"
539  << " '' (no operator) matches if string is a substring of that object'ts attribute.\n"
540  << " '=' matches if string is an exact match.\n"
541  << " '!' matches if string is not a substring.\n"
542  << " '^' matches if string is not an exact match.\n"
543  << "\n"
544  << "Examples:\n"
545  << "junction; id; 'foo' -> match all junctions that have 'foo' in their id\n"
546  << "junction; type; '=priority' -> match all junctions of type 'priority', but not of type 'priority_stop'\n"
547  << "edge; speed; '>10' -> match all edges with a speed above 10\n";
548  new FXLabel(helpDialog, help.str().c_str(), 0, GUIDesignLabelFrameInformation);
549  // "OK"
550  new FXButton(helpDialog, "OK\t\tSave modifications", GUIIconSubSys::getIcon(ICON_ACCEPT), helpDialog, FXDialogBox::ID_ACCEPT, GUIDesignButtonOK);
551  helpDialog->create();
552  helpDialog->show();
553  return 1;
554 }
555 
556 
557 long
558 GNESelectorFrame::onCmdScaleSelection(FXObject*, FXSelector, void*) {
560  myViewNet->update();
561  return 1;
562 }
563 
564 
565 void
567  // selection may have changed due to deletions
568  gSelected.add2Update(this);
570  // Show frame
571  GNEFrame::show();
572 }
573 
574 
575 void
577  // selection may have changed due to deletions
579  // hide frame
580  GNEFrame::hide();
581 }
582 
583 
584 void
586  // show extra information for tests
587  if (OptionsCont::getOptions().getBool("gui-testing-debug")) {
588  WRITE_WARNING("Current selection: " +
589  toString(gSelected.getSelected(GLO_JUNCTION).size()) + " Junctions, " +
590  toString(gSelected.getSelected(GLO_EDGE).size()) + " Edges, " +
591  toString(gSelected.getSelected(GLO_LANE).size()) + " Lanes, " +
592  toString(gSelected.getSelected(GLO_CONNECTION).size()) + " connections, " +
593  toString(gSelected.getSelected(GLO_ADDITIONAL).size()) + " Additionals, " +
594  toString(gSelected.getSelected(GLO_CROSSING).size()) + " Crossings, " +
595  toString(gSelected.getSelected(GLO_POLYGON).size()) + " Polygons, " +
596  toString(gSelected.getSelected(GLO_POI).size()) + " POIs");
597  }
598  // update labels
599 
600  myTypeEntries[GLO_JUNCTION].count->setText(toString(gSelected.getSelected(GLO_JUNCTION).size()).c_str());
601  myTypeEntries[GLO_EDGE].count->setText(toString(gSelected.getSelected(GLO_EDGE).size()).c_str());
602  myTypeEntries[GLO_LANE].count->setText(toString(gSelected.getSelected(GLO_LANE).size()).c_str());
603  myTypeEntries[GLO_CONNECTION].count->setText(toString(gSelected.getSelected(GLO_CONNECTION).size()).c_str());
604  myTypeEntries[GLO_ADDITIONAL].count->setText(toString(gSelected.getSelected(GLO_ADDITIONAL).size()).c_str());
605  myTypeEntries[GLO_CROSSING].count->setText(toString(gSelected.getSelected(GLO_CROSSING).size()).c_str());
606  myTypeEntries[GLO_POLYGON].count->setText(toString(gSelected.getSelected(GLO_POLYGON).size()).c_str());
607  myTypeEntries[GLO_POI].count->setText(toString(gSelected.getSelected(GLO_POI).size()).c_str());
608  update();
609 }
610 
611 
612 void
613 GNESelectorFrame::handleIDs(std::vector<GUIGlID> ids, bool selectEdgesEnabled, SetOperation setop) {
614  const SetOperation setOperation = (setop == SET_DEFAULT ? (SetOperation)mySetOperation : setop);
615  std::set<GUIGlID> previousSelection;
616  myViewNet->getUndoList()->p_begin("change selection");
617  if (setOperation == SET_REPLACE) {
618  myViewNet->getUndoList()->add(new GNEChange_Selection(myViewNet->getNet(), std::set<GUIGlID>(), gSelected.getSelected(), true), true);
619  } else if (setOperation == SET_RESTRICT) {
620  previousSelection = gSelected.getSelected(); // have to make a copy
621  myViewNet->getUndoList()->add(new GNEChange_Selection(myViewNet->getNet(), std::set<GUIGlID>(), gSelected.getSelected(), true), true);
622  }
623  // handle ids
624  GUIGlObject* object;
625  GUIGlObjectType type;
626  std::set<GUIGlID> idsSet(ids.begin(), ids.end());
627  std::set<GUIGlID> selected;
628  std::set<GUIGlID> deselected;
629  if (myViewNet->autoSelectNodes()) {
630  for (auto it : ids) {
631  if (it > 0) { // net object?
633  if ((object->getType() == GLO_LANE) && selectEdgesEnabled) {
634  const GNEEdge& edge = (static_cast<GNELane*>(object))->getParentEdge();
635  idsSet.insert(edge.getGNEJunctionSource()->getGlID());
636  idsSet.insert(edge.getGNEJunctionDestiny()->getGlID());
637  }
639  }
640  }
641  }
642  for (auto it : idsSet) {
643  if (it > 0) { // net object?
645  if (object == 0) {
646  // in debug mode we would like to know about this.
647  // It might be caused by a corrupted gl-name stack.
648  // However, most cases of uninitizliaed values would go hidden since 0 is assumed to be the net object anyway
649  assert(false);
650  continue;
651  }
652  type = object->getType();
653  if (type == GLO_LANE && selectEdgesEnabled) {
654  type = GLO_EDGE;
655  it = (dynamic_cast<GNELane*>(object))->getParentEdge().getGlID();
656  }
657  if (myTypeEntries[type].locked->getCheck()) {
658  continue;
659  }
661  // doing the switch outside the loop requires functional techniques. this was deemed to ugly
662  switch (setOperation) {
665  selected.insert(it);
666  break;
668  deselected.insert(it);
669  break;
671  if (previousSelection.count(it)) {
672  selected.insert(it);
673  }
674  break;
675  default:
676  break;
677  }
678  }
679  }
680  myViewNet->getUndoList()->add(new GNEChange_Selection(myViewNet->getNet(), selected, deselected, true), true);
682  myViewNet->update();
683 }
684 
685 
686 std::vector<GUIGlID>
687 GNESelectorFrame::getMatches(SumoXMLTag ACTag, SumoXMLAttr ACAttr, char compOp, double val, const std::string& expr) {
689  std::vector<GUIGlID> result;
690  const std::set<GUIGlID> allIDs = myViewNet->getNet()->getGlIDs();
691  const bool numerical = GNEAttributeCarrier::isNumerical(ACTag, ACAttr);
692  for (auto it : allIDs) {
693  // retrieve Attribute Carrier related to GLID
695  // not all objects need to be attribute carriers
696  if (ac->getTag() == ACTag) {
697  if (expr == "") {
698  result.push_back(it);
699  } else if (numerical) {
700  double acVal;
701  std::istringstream buf(ac->getAttribute(ACAttr));
702  buf >> acVal;
703  switch (compOp) {
704  case '<':
705  if (acVal < val) {
706  result.push_back(it);
707  }
708  break;
709  case '>':
710  if (acVal > val) {
711  result.push_back(it);
712  }
713  break;
714  case '=':
715  if (acVal == val) {
716  result.push_back(it);
717  }
718  break;
719  }
720  } else {
721  // string match
722  std::string acVal = ac->getAttributeForSelection(ACAttr);
723  switch (compOp) {
724  case '@':
725  if (acVal.find(expr) != std::string::npos) {
726  result.push_back(it);
727  }
728  break;
729  case '!':
730  if (acVal.find(expr) == std::string::npos) {
731  result.push_back(it);
732  }
733  break;
734  case '=':
735  if (acVal == expr) {
736  result.push_back(it);
737  }
738  break;
739  case '^':
740  if (acVal != expr) {
741  result.push_back(it);
742  }
743  break;
744  }
745  }
746  }
748  }
749  return result;
750 }
751 
752 /****************************************************************************/
FXRadioButton * myReplaceRadioButton
replace radio button
a tl-logic
SumoXMLTag
Numbers representing SUMO-XML - element names.
const std::set< GUIGlID > & getSelected() const
Returns the set of ids of all selected objects.
bool selectEdges()
whether inspection, selection and inversion should apply to edges or to lanes
Definition: GNEViewNet.cpp:328
void selectionUpdated()
called if currently registered for updates for changes of global selection
#define GUIDesignComboBoxNCol
number of column of every combo box
Definition: GUIDesigns.h:199
long onCmdSelMBString(FXObject *, FXSelector, void *)
Called when the user enters a new selection expression.
a polygon
FXComboBox * myMatchAttrComboBox
attributes of the match box
select tag in selector frame
Definition: GUIAppEnum.h:539
GUIGlObjectType
SetOperation
FOX-declaration.
FXDEFMAP(GNESelectorFrame) GNESelectorFrameMap[]
long onCmdSave(FXObject *, FXSelector, void *)
Called when the user presses the Save-button.
const Polygons & getPolygons() const
Returns all polygons.
static const std::vector< SumoXMLTag > & allowedShapeTags()
get all editable for tag shape elements
GUIGlID getGlID() const
Returns the numerical id of the object.
Definition: GNEPOI.cpp:118
Definition: GNEPOI.h:46
GNEAttributeCarrier * retrieveAttributeCarrier(const GUIGlID id, bool failHard=true)
get a single attribute carrier based on a GLID
Definition: GNENet.cpp:1100
std::set< GUIGlID > getGlIDs(GUIGlObjectType type=GLO_MAX)
get ids of currently active objects
Definition: GNENet.cpp:1138
a connection
void show()
show Frame
static const std::vector< SumoXMLTag > & allowedNetElementsTags()
get all editable for tag net elements
std::vector< GUIGlID > getMatches(SumoXMLTag ACTag, SumoXMLAttr ACAttr, char compOp, double val, const std::string &expr)
return objects of the given type with matching attrs
SumoXMLAttr myCurrentAttribute
current SumoXMLTag Attribute
FXTextField * myMatchString
string of the match
FXRealSpinDial * mySelectionScaling
selection scaling
virtual void setValue(FXdouble value)
Change current value.
Deselect selected items.
Definition: GUIAppEnum.h:354
void setNumberFormat(FXint prec, FXbool bExp=FALSE)
SumoXMLTag myCurrentTag
current SumoXMLTag tag
set subset of elements
Definition: GUIAppEnum.h:342
void remove2Update()
Removes the dialog to be updated.
bool isSelected(GUIGlObjectType type, GUIGlID id)
Returns the information whether the object with the given type and id is selected.
This lane is powered by an underlying GNEEdge and basically knows how to draw itself.
Definition: GNELane.h:53
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:84
long onCmdLoad(FXObject *, FXSelector, void *)
Called when the user presses the Load-button.
Clear set.
Definition: GUIAppEnum.h:348
FXString gCurrentFolder
The folder used as last.
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
void handleIDs(std::vector< GUIGlID > ids, bool selectEdgesEnabled, SetOperation setop=SET_DEFAULT)
apply list of ids to the current selection according to SetOperation,
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
GNESelectorFrame()
FOX needs this.
virtual std::string getAttribute(SumoXMLAttr key) const =0
This functions has to be implemented in all GNEAttributeCarriers.
static FXString getFilename2Write(FXWindow *parent, const FXString &header, const FXString &extension, FXIcon *icon, FXString &currentFolder)
Returns the file name to write.
Definition: MFXUtils.cpp:90
help button
Definition: GUIAppEnum.h:396
static const std::vector< std::pair< SumoXMLAttr, std::string > > & allowedAttributes(SumoXMLTag tag)
get all editable attributes for tag and their default values.
long onCmdHelp(FXObject *, FXSelector, void *)
Called when the user clicks the help button.
set type of selection
Definition: GUIAppEnum.h:340
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:199
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:64
#define GUIDesignComboBox
Definition: GUIDesigns.h:189
GNEViewNet * myViewNet
View Net for changes.
Definition: GNEFrame.h:337
std::set< GUIGlID > loadIDs(const std::string &filename, std::string &msgOut, GUIGlObjectType type=GLO_MAX, int maxErrors=16)
Loads a selection list (optionally with restricted type) and returns the ids of all active objects...
~GNESelectorFrame()
Destructor.
long onCmdScaleSelection(FXObject *, FXSelector, void *)
Called when the user changes visual scaling.
GNEUndoList * getUndoList() const
get the undoList object
long onCmdClear(FXObject *, FXSelector, void *)
Called when the user presses the Clear-button.
select attribute in selector frame
Definition: GUIAppEnum.h:541
Load set.
Definition: GUIAppEnum.h:344
void setRange(FXdouble lo, FXdouble hi)
Change the spinner&#39;s range.
GUIGlObjectType getType() const
Returns the type of the object as coded in GUIGlObjectType.
#define GUIDesignTextField
Definition: GUIDesigns.h:40
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:55
FXVerticalFrame * myContentFrame
Vertical frame that holds all widgets of frame.
Definition: GNEFrame.h:340
SetOperation mySetOperation
how to modify selection
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:91
long onCmdSelMBAttribute(FXObject *, FXSelector, void *)
Called when the user selectes a tag in the match box.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
GNEJunction * getGNEJunctionDestiny() const
returns the destination-junction
Definition: GNEEdge.cpp:323
invalid attribute
bool autoSelectNodes()
whether to autoselect nodes or to lanes
Definition: GNEViewNet.cpp:346
#define GUIDesignLabelFrameInformation
label extended over frame without thick and with text justify to left, used to show information in fr...
Definition: GUIDesigns.h:182
GNEJunction * getGNEJunctionSource() const
returns the source-junction
Definition: GNEEdge.cpp:317
FXRadioButton * myKeepRadioButton
keep button
#define GUIDesignButtonRectangular
little button rectangular (46x23) used in frames (For example, in "help" buttons) ...
Definition: GUIDesigns.h:62
long onCmdSelectOperation(FXObject *, FXSelector, void *)
begin/end of the description of an edge
void setSelectionScaling(double selectionScale)
set selection scaling
Definition: GNEViewNet.cpp:352
Save set.
Definition: GUIAppEnum.h:346
A road/street connecting two junctions (netedit-version)
Definition: GNEEdge.h:56
#define GUIDesignTextFieldNCol
Num of column of text field.
Definition: GUIDesigns.h:49
compound additional
#define GUIDesignButton
Definition: GUIDesigns.h:56
long onCmdSubset(FXObject *, FXSelector, void *)
Called when the user change the type of element to search (netElement or Additional) ...
virtual void show()
show Frame
Definition: GNEFrame.cpp:546
#define GUIDesignDialogBox
Definition: GUIDesigns.h:395
FXRadioButton * myRemoveRadioButton
remove radio button
static const std::vector< SumoXMLTag > & allowedAdditionalTags()
get all editable for tag additional elements
void add2Update(UpdateTarget *updateTarget)
Adds a dialog to be updated.
#define GUIDesignGroupBoxFrame
Group box design extended over frame.
Definition: GUIDesigns.h:221
virtual std::string getAttributeForSelection(SumoXMLAttr key) const
method for getting the attribute in the context of object selection
GUIGlID getGlID() const
Returns the numerical id of the object.
Definition: GNEPoly.cpp:188
FXComboBox * myMatchTagComboBox
tag of the match box
long onCmdInvert(FXObject *, FXSelector, void *)
Called when the user presses the Invert-button.
an edge
FXdouble getValue() const
Return current value.
changes the visual scaling of selected items
Definition: GUIAppEnum.h:545
virtual void hide()
hide Frame
Definition: GNEFrame.cpp:555
void setHelpText(const FXString &text)
Set the status line help text for this spinner.
GNENet * getNet() const
get the net object
GUIGlID getGlID() const
Returns the numerical id of the object.
#define GUIDesignButtonOK
Definition: GUIDesigns.h:97
void setIncrements(FXdouble fine, FXdouble norm, FXdouble coarse)
Change all spinner increment.
#define GUIDesignSpinDial
Definition: GUIDesigns.h:303
void unblockObject(GUIGlID id)
Marks an object as unblocked.
void hide()
hide Frame
#define GUIDesignLabelLeft
Definition: GUIDesigns.h:143
static bool isNumerical(SumoXMLTag tag, SumoXMLAttr attr)
whether an attribute is numerical (int or float)
FXRadioButton * myAddRadioButton
add radio button
bool locked(GUIGlObjectType type)
Spinner control.
GUIGlObject * getObjectBlocking(GUIGlID id)
Returns the object from the container locking it.
#define GUIDesignRadioButton
Definition: GUIDesigns.h:133
long onCmdSelMBTag(FXObject *, FXSelector, void *)
Called when the user selectes a tag in the match box.
C++ TraCI client API implementation.
Definition: POI.h:42
FXComboBox * mySetComboBox
tag of the sets of elements
GUISelectedStorage gSelected
A global holder of selected objects.
std::map< GUIGlObjectType, ObjectTypeEntry > myTypeEntries
check boxes for type-based selection locking and selected object counts
static FXIcon * getIcon(GUIIcon which)
returns a icon previously defined in the enum GUIIcon
void save(GUIGlObjectType type, const std::string &filename)
Saves a selection list.
a junction
SumoXMLTag getTag() const
get XML Tag assigned to this object
const POIs & getPOIs() const
Returns all pois.