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.dev/sumo
3 // Copyright (C) 2001-2024 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 
28 // ===========================================================================
29 // FOX callback mapping
30 // ===========================================================================
31 
32 FXDEFMAP(GNEMatchAttribute) GNEMatchAttributeMap[] = {
36  FXMAPFUNC(SEL_COMMAND, MID_HELP, GNEMatchAttribute::onCmdHelp)
37 };
38 
39 // Object implementation
40 FXIMPLEMENT(GNEMatchAttribute, MFXGroupBoxModule, GNEMatchAttributeMap, ARRAYNUMBER(GNEMatchAttributeMap))
41 
42 // ===========================================================================
43 // method definitions
44 // ===========================================================================
45 
46 GNEMatchAttribute::GNEMatchAttribute(GNEElementSet* elementSet, SumoXMLTag defaultTag, SumoXMLAttr defaultAttr, const std::string& defaultValue) :
47  MFXGroupBoxModule(elementSet->getSelectorFrameParent(), TL("Match Attribute")),
48  myElementSet(elementSet),
49  myCurrentTag(defaultTag),
50  myCurrentAttribute(defaultAttr) {
51  // Create MFXComboBoxIcon for tags
52  myMatchTagComboBox = new MFXComboBoxIcon(getCollapsableFrame(), GUIDesignComboBoxNCol, true, GUIDesignComboBoxVisibleItemsMedium,
54  // Create MFXComboBoxIcon for Attributes
55  myMatchAttrComboBox = new MFXComboBoxIcon(getCollapsableFrame(), GUIDesignComboBoxNCol, true, GUIDesignComboBoxVisibleItemsMedium,
57  // Create TextField for Match string
58  myMatchString = new FXTextField(getCollapsableFrame(), GUIDesignTextFieldNCol, this, MID_GNE_SELECTORFRAME_PROCESSSTRING, GUIDesignTextField);
59  // create button
60  myMatchStringButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Apply selection"), "", "", nullptr, this, MID_GNE_SELECTORFRAME_PROCESSSTRING, GUIDesignButton);
61  // Create help button
62  GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Help"), "", "", nullptr, this, MID_HELP, GUIDesignButtonRectangular);
63  // Set default value for Match string
64  myMatchString->setText(defaultValue.c_str());
65 }
66 
67 
69 
70 
71 void
73  // enable comboBox, text field and button
76  myMatchString->enable();
77  myMatchStringButton->enable();
78 }
79 
80 
81 void
83  // disable comboboxes and text field
86  myMatchString->disable();
87  myMatchStringButton->disable();
88  // change colors to black (even if there are invalid values)
89  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
90  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
91  myMatchString->setTextColor(FXRGB(0, 0, 0));
92 }
93 
94 
95 void
97  // declare flag for proj
98  const bool proj = (GeoConvHelper::getFinal().getProjString() != "!");
99  // get tags for the given element set
100  std::vector<GNETagProperties> tagPropertiesStrings;
101  if (type == (GNEElementSet::Type::NETWORK)) {
102  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::NETWORKELEMENT);
103  } else if (type == GNEElementSet::Type::ADDITIONAL) {
104  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::ADDITIONALELEMENT);
105  } else if (type == GNEElementSet::Type::SHAPE) {
106  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::SHAPE);
107  } else if (type == GNEElementSet::Type::TAZ) {
108  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::TAZELEMENT);
109  } else if (type == GNEElementSet::Type::DEMAND) {
110  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::DEMANDELEMENT);
111  } else if (type == GNEElementSet::Type::GENERICDATA) {
112  tagPropertiesStrings = GNEAttributeCarrier::getTagPropertiesByType(GNETagProperties::TagType::GENERICDATA);
113  } else {
114  throw ProcessError(TL("Unknown set"));
115  }
116  // now filter to allow only drawables and proj
117  myTagPropertiesString.clear();
118  for (const auto& tagProperty : tagPropertiesStrings) {
119  if (tagProperty.isDrawable() && (!tagProperty.requireProj() || proj)) {
120  myTagPropertiesString.push_back(tagProperty);
121  }
122  }
123  // update tag
124  updateTag();
125  // update attribute
126  updateAttribute();
127  // show groupbox
128  show();
129 }
130 
131 
132 void
134  // hide groupbox
135  hide();
136 }
137 
138 
139 long
140 GNEMatchAttribute::onCmdSelMBTag(FXObject*, FXSelector, void*) {
141  // reset current tag
143  // set invalid color
144  myMatchTagComboBox->setTextColor(FXRGB(255, 0, 0));
145  // iterate over tags
146  for (const auto& tagString : myTagPropertiesString) {
147  if (tagString.getFieldString() == myMatchTagComboBox->getText().text()) {
148  // set valid tag
149  myCurrentTag = tagString.getTag();
150  // set valid color
151  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
152  }
153  }
154  // update attribute
155  updateAttribute();
156  return 1;
157 }
158 
159 
160 long
161 GNEMatchAttribute::onCmdSelMBAttribute(FXObject*, FXSelector, void*) {
162  // first obtain a copy of item attributes vinculated with current tag
163  auto tagPropertiesCopy = GNEAttributeCarrier::getTagProperty(myCurrentTag);
164  // obtain tag property (only for improve code legibility)
165  const auto& tagValue = GNEAttributeCarrier::getTagProperty(myCurrentTag);
166  // add an extra AttributeValues to allow select ACs using as criterium "parameters"
167  GNEAttributeProperties extraAttrProperty;
168  extraAttrProperty = GNEAttributeProperties(GNE_ATTR_PARAMETERS,
169  GNEAttributeProperties::AttrProperty::STRING,
170  "Parameters");
171  tagPropertiesCopy.addAttribute(extraAttrProperty);
172  // add extra attribute if item can close shape
173  if (tagValue.canCloseShape()) {
174  // add an extra AttributeValues to allow select ACs using as criterium "close shape"
175  extraAttrProperty = GNEAttributeProperties(GNE_ATTR_CLOSE_SHAPE,
176  GNEAttributeProperties::AttrProperty::BOOL | GNEAttributeProperties::AttrProperty::DEFAULTVALUE,
177  "Close shape",
178  "true");
179  tagPropertiesCopy.addAttribute(extraAttrProperty);
180  }
181  // add extra attribute if item can have parent
182  if (tagValue.isChild()) {
183  // add an extra AttributeValues to allow select ACs using as criterium "parent"
184  extraAttrProperty = GNEAttributeProperties(GNE_ATTR_PARENT,
185  GNEAttributeProperties::AttrProperty::STRING,
186  "Parent element");
187  tagPropertiesCopy.addAttribute(extraAttrProperty);
188  }
189  // set current selected attribute
191  for (const auto& attribute : tagPropertiesCopy) {
192  if (attribute.getAttrStr() == myMatchAttrComboBox->getText().text()) {
193  myCurrentAttribute = attribute.getAttr();
194  }
195  }
196  // check if selected attribute is valid
198  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
199  myMatchString->enable();
200  myMatchStringButton->enable();
201  } else {
202  myMatchAttrComboBox->setTextColor(FXRGB(255, 0, 0));
203  myMatchString->disable();
204  myMatchStringButton->disable();
205  }
206  return 1;
207 }
208 
209 
210 long
211 GNEMatchAttribute::onCmdSelMBString(FXObject*, FXSelector, void*) {
212  // obtain expresion
213  std::string expr(myMatchString->getText().text());
214  const auto& tagValue = GNEAttributeCarrier::getTagProperty(myCurrentTag);
215  bool valid = true;
216  if (expr == "") {
217  // the empty expression matches all objects
219  } else if (tagValue.hasAttribute(myCurrentAttribute) && tagValue.getAttributeProperties(myCurrentAttribute).isNumerical()) {
220  // The expression must have the form
221  // <val matches if attr < val
222  // >val matches if attr > val
223  // =val matches if attr = val
224  // val matches if attr = val
225  char compOp = expr[0];
226  if (compOp == '<' || compOp == '>' || compOp == '=') {
227  expr = expr.substr(1);
228  } else {
229  compOp = '=';
230  }
231  // check if value can be parsed to double
232  if (GNEAttributeCarrier::canParse<double>(expr.c_str())) {
233  myElementSet->getSelectorFrameParent()->handleIDs(myElementSet->getSelectorFrameParent()->getMatches(myCurrentTag, myCurrentAttribute, compOp, GNEAttributeCarrier::parse<double>(expr.c_str()), expr));
234  } else {
235  valid = false;
236  }
237  } else {
238  // The expression must have the form
239  // =str: matches if <str> is an exact match
240  // !str: matches if <str> is not a substring
241  // ^str: matches if <str> is not an exact match
242  // str: matches if <str> is a substring (sends compOp '@')
243  // Alternatively, if the expression is empty it matches all objects
244  char compOp = expr[0];
245  if (compOp == '=' || compOp == '!' || compOp == '^') {
246  expr = expr.substr(1);
247  } else {
248  compOp = '@';
249  }
251  }
252  if (valid) {
253  myMatchString->setTextColor(FXRGB(0, 0, 0));
254  myMatchString->killFocus();
255  myMatchStringButton->enable();
256  } else {
257  myMatchString->setTextColor(FXRGB(255, 0, 0));
258  myMatchStringButton->disable();
259  }
260  return 1;
261 }
262 
263 
264 long
265 GNEMatchAttribute::onCmdHelp(FXObject*, FXSelector, void*) {
266  // Create dialog box
267  FXDialogBox* additionalNeteditAttributesHelpDialog = new FXDialogBox(getCollapsableFrame(), TL("Netedit Parameters Help"), GUIDesignDialogBox);
268  additionalNeteditAttributesHelpDialog->setIcon(GUIIconSubSys::getIcon(GUIIcon::MODEADDITIONAL));
269  // set help text
270  std::ostringstream help;
271  help
272  << TL("- The 'Match Attribute' controls allow to specify a set of objects which are then applied to the current selection\n")
273  << TL(" according to the current 'Modification Mode'.\n")
274  << TL(" 1. Select an object type from the first input box\n")
275  << TL(" 2. Select an attribute from the second input box\n")
276  << TL(" 3. Enter a 'match expression' in the third input box and press <return>\n")
277  << "\n"
278  << TL("- The empty expression matches all objects\n")
279  << TL("- For numerical attributes the match expression must consist of a comparison operator ('<', '>', '=') and a number.\n")
280  << TL("- An object matches if the comparison between its attribute and the given number by the given operator evaluates to 'true'\n")
281  << "\n"
282  << TL("- For string attributes the match expression must consist of a comparison operator ('', '=', '!', '^') and a string.\n")
283  << TL(" '' (no operator) matches if string is a substring of that object's attribute.\n")
284  << TL(" '=' matches if string is an exact match.\n")
285  << TL(" '!' matches if string is not a substring.\n")
286  << TL(" '^' matches if string is not an exact match.\n")
287  << "\n"
288  << TL("- Examples:\n")
289  << TL(" junction; id; 'foo' -> match all junctions that have 'foo' in their id\n")
290  << TL(" junction; type; '=priority' -> match all junctions of type 'priority', but not of type 'priority_stop'\n")
291  << TL(" edge; speed; '>10' -> match all edges with a speed above 10\n");
292  // Create label with the help text
293  new FXLabel(additionalNeteditAttributesHelpDialog, help.str().c_str(), nullptr, GUIDesignLabelFrameInformation);
294  // Create horizontal separator
295  new FXHorizontalSeparator(additionalNeteditAttributesHelpDialog, GUIDesignHorizontalSeparator);
296  // Create frame for OK Button
297  FXHorizontalFrame* myHorizontalFrameOKButton = new FXHorizontalFrame(additionalNeteditAttributesHelpDialog, GUIDesignAuxiliarHorizontalFrame);
298  // Create Button Close (And two more horizontal frames to center it)
299  new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
300  GUIDesigns::buildFXButton(myHorizontalFrameOKButton, TL("OK"), "", TL("close"), GUIIconSubSys::getIcon(GUIIcon::ACCEPT), additionalNeteditAttributesHelpDialog, FXDialogBox::ID_ACCEPT, GUIDesignButtonOK);
301  new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
302  // Write Warning in console if we're in testing mode
303  WRITE_DEBUG("Opening help dialog of selector frame");
304  // create Dialog
305  additionalNeteditAttributesHelpDialog->create();
306  // show in the given position
307  additionalNeteditAttributesHelpDialog->show(PLACEMENT_CURSOR);
308  // refresh APP
309  getApp()->refresh();
310  // open as modal dialog (will block all windows until stop() or stopModal() is called)
311  getApp()->runModalFor(additionalNeteditAttributesHelpDialog);
312  // Write Warning in console if we're in testing mode
313  WRITE_DEBUG("Close help dialog of selector frame");
314  return 1;
315 }
316 
317 
318 void
320  // declare tag index
321  int tagIndex = -1;
322  // fill combo box tags
324  myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
325  // itreate over myTagPropertiesString
326  for (int i = 0; i < (int)myTagPropertiesString.size(); i++) {
327  // add tag in combo Box
328  myMatchTagComboBox->appendIconItem(myTagPropertiesString.at(i).getFieldString().c_str(), GUIIconSubSys::getIcon(myTagPropertiesString.at(i).getGUIIcon()));
329  // check tag index
330  if (myTagPropertiesString.at(i).getTag() == myCurrentTag) {
331  tagIndex = i;
332  }
333  }
334  // check tagIndex
335  if (tagIndex == -1) {
337  myCurrentTag = myTagPropertiesString.front().getTag();
338  } else {
340  }
341 }
342 
343 
344 void
346  // first check if tag is valid
348  // now continue with attributes
349  const auto& tagProperty = GNEAttributeCarrier::getTagProperty(myCurrentTag);
350  // set color and enable items
352  myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
354  // declare attr index
355  int attrIndex = -1;
356  // fill attribute combo box
357  for (int i = 0; i < (int)tagProperty.getNumberOfAttributes(); i++) {
358  myMatchAttrComboBox->appendIconItem(tagProperty.at(i).getAttrStr().c_str());
359  // check attr index
360  if (tagProperty.at(i).getAttr() == myCurrentAttribute) {
361  attrIndex = i;
362  }
363  }
364  // Check if are allowed "Parameter"
365  if (tagProperty.hasParameters()) {
368  attrIndex = (myMatchAttrComboBox->getNumItems() - 1);
369  }
370  }
371  // check if item can close shape
372  if (tagProperty.canCloseShape()) {
375  attrIndex = (myMatchAttrComboBox->getNumItems() - 1);
376  }
377  }
378  // check if item can have parent
379  if (tagProperty.isChild()) {
382  attrIndex = (myMatchAttrComboBox->getNumItems() - 1);
383  }
384  }
385  // check attrIndex
386  if (attrIndex == -1) {
388  myCurrentAttribute = tagProperty.begin()->getAttr();
389  } else {
391  }
392  // enable mach string
393  myMatchString->enable();
394  myMatchStringButton->enable();
395  } else {
396  // disable myMatchAttrComboBox
398  // disable mach string
399  myMatchString->disable();
400  myMatchStringButton->disable();
401  }
402 }
403 
404 /****************************************************************************/
FXDEFMAP(GNEMatchAttribute) GNEMatchAttributeMap[]
@ MID_GNE_SELECTORFRAME_SELECTATTRIBUTE
select attribute in selector frame
Definition: GUIAppEnum.h:1042
@ MID_GNE_SELECTORFRAME_SELECTTAG
select tag in selector frame
Definition: GUIAppEnum.h:1040
@ MID_HELP
help button
Definition: GUIAppEnum.h:648
@ MID_GNE_SELECTORFRAME_PROCESSSTRING
process string
Definition: GUIAppEnum.h:1044
#define GUIDesignButton
Definition: GUIDesigns.h:88
#define GUIDesignComboBox
Definition: GUIDesigns.h:299
#define GUIDesignComboBoxNCol
number of column of every combo box
Definition: GUIDesigns.h:317
#define GUIDesignTextField
Definition: GUIDesigns.h:65
#define GUIDesignAuxiliarHorizontalFrame
design for auxiliar (Without borders) horizontal frame used to pack another frames
Definition: GUIDesigns.h:405
#define GUIDesignDialogBox
Definition: GUIDesigns.h:602
#define GUIDesignButtonRectangular
little rectangular button used in frames (For example, in "help" buttons)
Definition: GUIDesigns.h:100
#define GUIDesignComboBoxVisibleItemsMedium
combo box medium small
Definition: GUIDesigns.h:53
#define GUIDesignTextFieldNCol
Num of column of text field.
Definition: GUIDesigns.h:80
#define GUIDesignButtonOK
Definition: GUIDesigns.h:159
#define GUIDesignHorizontalSeparator
Definition: GUIDesigns.h:466
#define GUIDesignLabelFrameInformation
label extended over frame without thick and with text justify to left, used to show information in fr...
Definition: GUIDesigns.h:285
@ MODEADDITIONAL
#define WRITE_DEBUG(msg)
Definition: MsgHandler.h:306
#define TL(string)
Definition: MsgHandler.h:315
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
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
MFXComboBoxIcon * myMatchAttrComboBox
attributes of the match box
FXButton * myMatchStringButton
match string button
SumoXMLAttr myCurrentAttribute
current SumoXMLTag Attribute
GNEElementSet * myElementSet
pointer to element set Parent
MFXComboBoxIcon * myMatchTagComboBox
tag of the match box
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 FXButton * buildFXButton(FXComposite *p, const std::string &text, const std::string &tip, const std::string &help, FXIcon *ic, FXObject *tgt, FXSelector sel, FXuint opts=BUTTON_NORMAL, FXint x=0, FXint y=0, FXint w=0, FXint h=0, FXint pl=DEFAULT_PAD, FXint pr=DEFAULT_PAD, FXint pt=DEFAULT_PAD, FXint pb=DEFAULT_PAD)
build button
Definition: GUIDesigns.cpp:128
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.
long setCurrentItem(const FXint index, FXbool notify=FALSE)
Set the current item (index is zero-based)
FXint getNumItems() const
Return the number of items in the list.
FXString getText() const
Get the text.
void setTextColor(FXColor clr)
Change text color.
void clearItems()
Remove all items from the list.
void disable()
Disable combo box.
FXint appendIconItem(const FXString &text, FXIcon *icon=nullptr, FXColor bgColor=FXRGB(255, 255, 255), void *ptr=nullptr)
append icon item in the last position
void enable()
Enable combo box.
MFXGroupBoxModule (based on FXGroupBox)
FXVerticalFrame * getCollapsableFrame()
get collapsable frame (used by all elements that will be collapsed if button is toggled)
Definition: json.hpp:4471