Eclipse SUMO - Simulation of Urban MObility
GNEMatchAttribute.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-2022 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // The Widget for modifying selections of network-elements
19 /****************************************************************************/
20 #include <config.h>
21 
25 
26 #include "GNEMatchAttribute.h"
27 #include "GNEElementSet.h"
28 
29 // ===========================================================================
30 // FOX callback mapping
31 // ===========================================================================
32 
33 FXDEFMAP(GNEMatchAttribute) GNEMatchAttributeMap[] = {
37  FXMAPFUNC(SEL_COMMAND, MID_HELP, GNEMatchAttribute::onCmdHelp)
38 };
39 
40 // Object implementation
41 FXIMPLEMENT(GNEMatchAttribute, FXGroupBoxModule, GNEMatchAttributeMap, ARRAYNUMBER(GNEMatchAttributeMap))
42 
43 // ===========================================================================
44 // method definitions
45 // ===========================================================================
46 
47 GNEMatchAttribute::GNEMatchAttribute(GNEElementSet* elementSet, SumoXMLTag defaultTag, SumoXMLAttr defaultAttr, const std::string& defaultValue) :
48  FXGroupBoxModule(elementSet->getSelectorFrameParent()->getContentFrame(), "Match Attribute"),
49  myElementSet(elementSet),
50  myCurrentTag(defaultTag),
51  myCurrentAttribute(defaultAttr) {
52  // Create MFXIconComboBox for tags
53  myMatchTagComboBox = new MFXIconComboBox(getCollapsableFrame(), GUIDesignComboBoxNCol, this, MID_GNE_SELECTORFRAME_SELECTTAG, GUIDesignComboBox);
54  // Create FXComboBox for Attributes
55  myMatchAttrComboBox = new FXComboBox(getCollapsableFrame(), GUIDesignComboBoxNCol, this, MID_GNE_SELECTORFRAME_SELECTATTRIBUTE, GUIDesignComboBox);
56  // Create TextField for Match string
57  myMatchString = new FXTextField(getCollapsableFrame(), GUIDesignTextFieldNCol, this, MID_GNE_SELECTORFRAME_PROCESSSTRING, GUIDesignTextField);
58  // create button
59  myMatchStringButton = new FXButton(getCollapsableFrame(), "Apply selection", nullptr, this, MID_GNE_SELECTORFRAME_PROCESSSTRING, GUIDesignButton);
60  // Create help button
61  new FXButton(getCollapsableFrame(), "Help", nullptr, this, MID_HELP, GUIDesignButtonRectangular);
62  // Set default value for Match string
63  myMatchString->setText(defaultValue.c_str());
64 }
65 
66 
68 
69 
70 void
72  // enable comboBox, text field and button
74  myMatchAttrComboBox->enable();
75  myMatchString->enable();
76  myMatchStringButton->enable();
77 }
78 
79 
80 void
82  // disable comboboxes and text field
84  myMatchAttrComboBox->disable();
85  myMatchString->disable();
86  myMatchStringButton->disable();
87  // change colors to black (even if there are invalid values)
88  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
89  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
90  myMatchString->setTextColor(FXRGB(0, 0, 0));
91 }
92 
93 
94 void
96  // declare flag for proj
97  const bool proj = (GeoConvHelper::getFinal().getProjString() != "!");
98  // get tags for the given element set
99  std::vector<GNETagProperties> tagPropertiesStrings;
100  if (type == (GNEElementSet::Type::NETWORK)) {
101  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::NETWORKELEMENT);
102  } else if (type == GNEElementSet::Type::ADDITIONAL) {
103  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::ADDITIONALELEMENT);
104  } else if (type == GNEElementSet::Type::SHAPE) {
105  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::SHAPE);
106  } else if (type == GNEElementSet::Type::TAZ) {
107  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::TAZELEMENT);
108  } else if (type == GNEElementSet::Type::DEMAND) {
109  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::DEMANDELEMENT | GNETagProperties::TagType::STOP);
110  } else if (type == GNEElementSet::Type::DATA) {
111  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::GENERICDATA);
112  } else {
113  throw ProcessError("Unkown set");
114  }
115  // now filter to allow only drawables and proj
116  myTagPropertiesString.clear();
117  for (const auto& tagProperty : tagPropertiesStrings) {
118  if (tagProperty.isDrawable() && (!tagProperty.requireProj() || proj)) {
119  myTagPropertiesString.push_back(tagProperty);
120  }
121  }
122  // update tag
123  updateTag();
124  // update attribute
125  updateAttribute();
126  // show groupbox
127  show();
128 }
129 
130 
131 void
133  // hide groupbox
134  hide();
135 }
136 
137 
138 long
139 GNEMatchAttribute::onCmdSelMBTag(FXObject*, FXSelector, void*) {
140  // reset current tag
142  // set invalid color
143  myMatchTagComboBox->setTextColor(FXRGB(255, 0, 0));
144  // iterate over tags
145  for (const auto& tagString : myTagPropertiesString) {
146  if (tagString.getFieldString() == myMatchTagComboBox->getText().text()) {
147  // set valid tag
148  myCurrentTag = tagString.getTag();
149  // set valid color
150  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
151  }
152  }
153  // update attribute
154  updateAttribute();
155  return 1;
156 }
157 
158 
159 long
160 GNEMatchAttribute::onCmdSelMBAttribute(FXObject*, FXSelector, void*) {
161  // first obtain a copy of item attributes vinculated with current tag
162  auto tagPropertiesCopy = GNEAttributeCarrier::getTagProperty(myCurrentTag);
163  // obtain tag property (only for improve code legibility)
164  const auto& tagValue = GNEAttributeCarrier::getTagProperty(myCurrentTag);
165  // add an extra AttributeValues to allow select ACs using as criterium "parameters"
166  GNEAttributeProperties extraAttrProperty;
167  extraAttrProperty = GNEAttributeProperties(GNE_ATTR_PARAMETERS,
168  GNEAttributeProperties::AttrProperty::STRING,
169  "Parameters");
170  tagPropertiesCopy.addAttribute(extraAttrProperty);
171  // add extra attribute if item can close shape
172  if (tagValue.canCloseShape()) {
173  // add an extra AttributeValues to allow select ACs using as criterium "close shape"
174  extraAttrProperty = GNEAttributeProperties(GNE_ATTR_CLOSE_SHAPE,
175  GNEAttributeProperties::AttrProperty::BOOL | GNEAttributeProperties::AttrProperty::DEFAULTVALUE,
176  "Close shape",
177  "true");
178  tagPropertiesCopy.addAttribute(extraAttrProperty);
179  }
180  // add extra attribute if item can have parent
181  if (tagValue.isChild()) {
182  // add an extra AttributeValues to allow select ACs using as criterium "parent"
183  extraAttrProperty = GNEAttributeProperties(GNE_ATTR_PARENT,
184  GNEAttributeProperties::AttrProperty::STRING,
185  "Parent element");
186  tagPropertiesCopy.addAttribute(extraAttrProperty);
187  }
188  // set current selected attribute
190  for (const auto& attribute : tagPropertiesCopy) {
191  if (attribute.getAttrStr() == myMatchAttrComboBox->getText().text()) {
192  myCurrentAttribute = attribute.getAttr();
193  }
194  }
195  // check if selected attribute is valid
197  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
198  myMatchString->enable();
199  myMatchStringButton->enable();
200  } else {
201  myMatchAttrComboBox->setTextColor(FXRGB(255, 0, 0));
202  myMatchString->disable();
203  myMatchStringButton->disable();
204  }
205  return 1;
206 }
207 
208 
209 long
210 GNEMatchAttribute::onCmdSelMBString(FXObject*, FXSelector, void*) {
211  // obtain expresion
212  std::string expr(myMatchString->getText().text());
213  const auto& tagValue = GNEAttributeCarrier::getTagProperty(myCurrentTag);
214  bool valid = true;
215  if (expr == "") {
216  // the empty expression matches all objects
218  } else if (tagValue.hasAttribute(myCurrentAttribute) && tagValue.getAttributeProperties(myCurrentAttribute).isNumerical()) {
219  // The expression must have the form
220  // <val matches if attr < val
221  // >val matches if attr > val
222  // =val matches if attr = val
223  // val matches if attr = val
224  char compOp = expr[0];
225  if (compOp == '<' || compOp == '>' || compOp == '=') {
226  expr = expr.substr(1);
227  } else {
228  compOp = '=';
229  }
230  // check if value can be parsed to double
231  if (GNEAttributeCarrier::canParse<double>(expr.c_str())) {
232  myElementSet->getSelectorFrameParent()->handleIDs(myElementSet->getSelectorFrameParent()->getMatches(myCurrentTag, myCurrentAttribute, compOp, GNEAttributeCarrier::parse<double>(expr.c_str()), expr));
233  } else {
234  valid = false;
235  }
236  } else {
237  // The expression must have the form
238  // =str: matches if <str> is an exact match
239  // !str: matches if <str> is not a substring
240  // ^str: matches if <str> is not an exact match
241  // str: matches if <str> is a substring (sends compOp '@')
242  // Alternatively, if the expression is empty it matches all objects
243  char compOp = expr[0];
244  if (compOp == '=' || compOp == '!' || compOp == '^') {
245  expr = expr.substr(1);
246  } else {
247  compOp = '@';
248  }
250  }
251  if (valid) {
252  myMatchString->setTextColor(FXRGB(0, 0, 0));
253  myMatchString->killFocus();
254  myMatchStringButton->enable();
255  } else {
256  myMatchString->setTextColor(FXRGB(255, 0, 0));
257  myMatchStringButton->disable();
258  }
259  return 1;
260 }
261 
262 
263 long
264 GNEMatchAttribute::onCmdHelp(FXObject*, FXSelector, void*) {
265  // Create dialog box
266  FXDialogBox* additionalNeteditAttributesHelpDialog = new FXDialogBox(getCollapsableFrame(), "Netedit Parameters Help", GUIDesignDialogBox);
267  additionalNeteditAttributesHelpDialog->setIcon(GUIIconSubSys::getIcon(GUIIcon::MODEADDITIONAL));
268  // set help text
269  std::ostringstream help;
270  help
271  << "- The 'Match Attribute' controls allow to specify a set of objects which are then applied to the current selection\n"
272  << " according to the current 'Modification Mode'.\n"
273  << " 1. Select an object type from the first input box\n"
274  << " 2. Select an attribute from the second input box\n"
275  << " 3. Enter a 'match expression' in the third input box and press <return>\n"
276  << "\n"
277  << "- The empty expression matches all objects\n"
278  << "- For numerical attributes the match expression must consist of a comparison operator ('<', '>', '=') and a number.\n"
279  << "- An object matches if the comparison between its attribute and the given number by the given operator evaluates to 'true'\n"
280  << "\n"
281  << "- For string attributes the match expression must consist of a comparison operator ('', '=', '!', '^') and a string.\n"
282  << " '' (no operator) matches if string is a substring of that object'ts attribute.\n"
283  << " '=' matches if string is an exact match.\n"
284  << " '!' matches if string is not a substring.\n"
285  << " '^' matches if string is not an exact match.\n"
286  << "\n"
287  << "- Examples:\n"
288  << " junction; id; 'foo' -> match all junctions that have 'foo' in their id\n"
289  << " junction; type; '=priority' -> match all junctions of type 'priority', but not of type 'priority_stop'\n"
290  << " edge; speed; '>10' -> match all edges with a speed above 10\n";
291  // Create label with the help text
292  new FXLabel(additionalNeteditAttributesHelpDialog, help.str().c_str(), nullptr, GUIDesignLabelFrameInformation);
293  // Create horizontal separator
294  new FXHorizontalSeparator(additionalNeteditAttributesHelpDialog, GUIDesignHorizontalSeparator);
295  // Create frame for OK Button
296  FXHorizontalFrame* myHorizontalFrameOKButton = new FXHorizontalFrame(additionalNeteditAttributesHelpDialog, GUIDesignAuxiliarHorizontalFrame);
297  // Create Button Close (And two more horizontal frames to center it)
298  new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
299  new FXButton(myHorizontalFrameOKButton, "OK\t\tclose", GUIIconSubSys::getIcon(GUIIcon::ACCEPT), additionalNeteditAttributesHelpDialog, FXDialogBox::ID_ACCEPT, GUIDesignButtonOK);
300  new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
301  // Write Warning in console if we're in testing mode
302  WRITE_DEBUG("Opening help dialog of selector frame");
303  // create Dialog
304  additionalNeteditAttributesHelpDialog->create();
305  // show in the given position
306  additionalNeteditAttributesHelpDialog->show(PLACEMENT_CURSOR);
307  // refresh APP
308  getApp()->refresh();
309  // open as modal dialog (will block all windows until stop() or stopModal() is called)
310  getApp()->runModalFor(additionalNeteditAttributesHelpDialog);
311  // Write Warning in console if we're in testing mode
312  WRITE_DEBUG("Close help dialog of selector frame");
313  return 1;
314 }
315 
316 
317 void
319  // declare tag index
320  int tagIndex = -1;
321  // fill combo box tags
323  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
324  // itreate over myTagPropertiesString
325  for (int i = 0; i < (int)myTagPropertiesString.size(); i++) {
326  // add tag in combo Box
327  myMatchTagComboBox->appendIconItem(myTagPropertiesString.at(i).getFieldString().c_str(), GUIIconSubSys::getIcon(myTagPropertiesString.at(i).getGUIIcon()));
328  // check tag index
329  if (myTagPropertiesString.at(i).getTag() == myCurrentTag) {
330  tagIndex = i;
331  }
332  }
333  // set num visible items
335  // check tagIndex
336  if (tagIndex == -1) {
338  myCurrentTag = myTagPropertiesString.front().getTag();
339  } else {
341  }
342 }
343 
344 
345 void
347  // first check if tag is valid
349  // now continue with attributes
350  const auto& tagProperty = GNEAttributeCarrier::getTagProperty(myCurrentTag);
351  // set color and enable items
352  myMatchAttrComboBox->enable();
353  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
354  myMatchAttrComboBox->clearItems();
355  // declare attr index
356  int attrIndex = -1;
357  // fill attribute combo box
358  for (int i = 0; i < (int)tagProperty.getNumberOfAttributes(); i++) {
359  myMatchAttrComboBox->appendItem(tagProperty.at(i).getAttrStr().c_str());
360  // check attr index
361  if (tagProperty.at(i).getAttr() == myCurrentAttribute) {
362  attrIndex = i;
363  }
364  }
365  // Add extra attribute "Parameter"
366  myMatchAttrComboBox->appendItem(toString(GNE_ATTR_PARAMETERS).c_str());
368  attrIndex = (myMatchAttrComboBox->getNumItems() - 1);
369  }
370  // check if item can close shape
371  if (tagProperty.canCloseShape()) {
372  myMatchAttrComboBox->appendItem(toString(GNE_ATTR_CLOSE_SHAPE).c_str());
374  attrIndex = (myMatchAttrComboBox->getNumItems() - 1);
375  }
376  }
377  // check if item can have parent
378  if (tagProperty.isChild()) {
379  myMatchAttrComboBox->appendItem(toString(GNE_ATTR_PARENT).c_str());
381  attrIndex = (myMatchAttrComboBox->getNumItems() - 1);
382  }
383  }
384  // set num visible items
385  myMatchAttrComboBox->setNumVisible(myMatchAttrComboBox->getNumItems());
386  // check attrIndex
387  if (attrIndex == -1) {
388  myMatchAttrComboBox->setCurrentItem(0);
389  myCurrentAttribute = tagProperty.begin()->getAttr();
390  } else {
391  myMatchAttrComboBox->setCurrentItem(attrIndex);
392  }
393  // enable mach string
394  myMatchString->enable();
395  myMatchStringButton->enable();
396  } else {
397  // disable myMatchAttrComboBox
398  myMatchAttrComboBox->disable();
399  // disable mach string
400  myMatchString->disable();
401  myMatchStringButton->disable();
402  }
403 }
404 
405 /****************************************************************************/
FXDEFMAP(GNEMatchAttribute) GNEMatchAttributeMap[]
@ MID_GNE_SELECTORFRAME_SELECTATTRIBUTE
select attribute in selector frame
Definition: GUIAppEnum.h:887
@ MID_GNE_SELECTORFRAME_SELECTTAG
select tag in selector frame
Definition: GUIAppEnum.h:885
@ MID_HELP
help button
Definition: GUIAppEnum.h:600
@ MID_GNE_SELECTORFRAME_PROCESSSTRING
process string
Definition: GUIAppEnum.h:889
#define GUIDesignButton
Definition: GUIDesigns.h:68
#define GUIDesignComboBox
Definition: GUIDesigns.h:267
#define GUIDesignComboBoxNCol
number of column of every combo box
Definition: GUIDesigns.h:285
#define GUIDesignTextField
Definition: GUIDesigns.h:42
#define GUIDesignAuxiliarHorizontalFrame
design for auxiliar (Without borders) horizontal frame used to pack another frames
Definition: GUIDesigns.h:343
#define GUIDesignDialogBox
Definition: GUIDesigns.h:527
#define GUIDesignButtonRectangular
little button rectangula used in frames (For example, in "help" buttons)
Definition: GUIDesigns.h:74
#define GUIDesignTextFieldNCol
Num of column of text field.
Definition: GUIDesigns.h:60
#define GUIDesignButtonOK
Definition: GUIDesigns.h:124
#define GUIDesignHorizontalSeparator
Definition: GUIDesigns.h:395
#define GUIDesignLabelFrameInformation
label extended over frame without thick and with text justify to left, used to show information in fr...
Definition: GUIDesigns.h:244
@ MODEADDITIONAL
#define WRITE_DEBUG(msg)
Definition: MsgHandler.h:290
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_TAG_NOTHING
invalid tag
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
@ GNE_ATTR_PARENT
parent of an additional element
@ GNE_ATTR_PARAMETERS
parameters "key1=value1|key2=value2|...|keyN=valueN"
@ GNE_ATTR_CLOSE_SHAPE
Close shape of a polygon (Used by GNEPolys)
@ SUMO_ATTR_NOTHING
invalid attribute
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
FXGroupBoxModule (based on FXGroupBox)
FXVerticalFrame * getCollapsableFrame()
get collapsable frame (used by all elements that will be collapsed if button is toogled)
static const std::vector< GNETagProperties > getTagPropertiesByType(const int tagPropertyCategory)
get tagProperties associated to the given GNETagProperties::TagType (NETWORKELEMENT,...
const GNETagProperties & getTagProperty() const
get tagProperty associated with this Attribute Carrier
Type
FOX-declaration.
Definition: GNEElementSet.h:42
GNESelectorFrame * getSelectorFrameParent() const
get Selector Frame Parent
void showMatchAttribute(const GNEElementSet::Type type)
show match attributes
~GNEMatchAttribute()
destructor
FXButton * myMatchStringButton
match string button
SumoXMLAttr myCurrentAttribute
current SumoXMLTag Attribute
FXComboBox * myMatchAttrComboBox
attributes of the match box
MFXIconComboBox * myMatchTagComboBox
tag of the match box
GNEElementSet * myElementSet
pointer to element set Parent
void updateTag()
FOX need this.
std::vector< GNETagProperties > myTagPropertiesString
vector with tagProperties
void updateAttribute()
update attribute
FXTextField * myMatchString
string of the match
void hideMatchAttribute()
hide match attributes
long onCmdSelMBTag(FXObject *, FXSelector, void *)
Called when the user selectes a tag in the match box.
long onCmdHelp(FXObject *, FXSelector, void *)
Called when the user clicks the help button.
long onCmdSelMBString(FXObject *, FXSelector, void *)
Called when the user enters a new selection expression.
long onCmdSelMBAttribute(FXObject *, FXSelector, void *)
Called when the user selectes a tag in the match box.
void enableMatchAttribute()
enable match attributes
void disableMatchAttribute()
disable match attributes
SumoXMLTag myCurrentTag
current SumoXMLTag tag
std::vector< GNEAttributeCarrier * > getMatches(const SumoXMLTag ACTag, const SumoXMLAttr ACAttr, const char compOp, const double val, const std::string &expr)
return ACs of the given type with matching attrs
void handleIDs(const std::vector< GNEAttributeCarrier * > &ACs, const ModificationMode::Operation setop=ModificationMode::Operation::DEFAULT)
apply list of ids to the current selection according to Operation,
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
const std::string & getProjString() const
Returns the original projection definition.
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
ComboBox with icon.
FXString getText() const
Get the text.
virtual void enable()
Enable combo box.
void setCurrentItem(FXint index, FXbool notify=FALSE)
Set the current item (index is zero-based)
void setTextColor(FXColor clr)
Change text color.
void clearItems()
Remove all items from the list.
FXint getNumItems() const
Return the number of items in the list.
void setNumVisible(FXint nvis)
Set the number of visible items in the drop down list.
FXint appendIconItem(const FXString &text, FXIcon *icon=nullptr, FXColor bgColor=FXRGB(255, 255, 255), void *ptr=nullptr)
append icon
virtual void disable()
Disable combo box.