Eclipse SUMO - Simulation of Urban MObility
GUIDialog_ChooserAbstract.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 /****************************************************************************/
20 // Class for the window that allows to choose a street, junction or vehicle
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <string>
25 #include <vector>
26 #include <fxkeys.h>
36 
38 
39 
40 // ===========================================================================
41 // FOX callback mapping
42 // ===========================================================================
43 FXDEFMAP(GUIDialog_ChooserAbstract) GUIDialog_ChooserAbstractMap[] = {
46  FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_ChooserAbstract::onCmdClose),
58  FXMAPFUNC(SEL_COMMAND, MID_UPDATE, GUIDialog_ChooserAbstract::onCmdUpdate),
59 };
60 
61 FXIMPLEMENT(GUIDialog_ChooserAbstract, FXMainWindow, GUIDialog_ChooserAbstractMap, ARRAYNUMBER(GUIDialog_ChooserAbstractMap))
62 
63 
64 // ===========================================================================
65 // method definitions
66 // ===========================================================================
68  FXIcon* icon, const FXString& title, const std::vector<GUIGlID>& ids, GUIGlObjectStorage& /*glStorage*/) :
69  FXMainWindow(windowsParent->getApp(), title, icon, nullptr, GUIDesignChooserDialog),
70  myWindowsParent(windowsParent),
71  myMessageId(messageId),
72  myLocateByName(false),
73  myHaveFilteredSubstring(false) {
74  FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);
75  // build the list
76  FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);
77  myTextEntry = new FXTextField(layoutLeft, 0, this, MID_CHOOSER_TEXT, TEXTFIELD_ENTER_ONLY | GUIDesignChooserTextField);
78  FXVerticalFrame* layoutList = new FXVerticalFrame(layoutLeft, GUIDesignChooserLayoutList);
79  myList = new FXList(layoutList, this, MID_CHOOSER_LIST, GUIDesignChooserListSingle);
80  // build the buttons
81  FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);
82  myCenterButton = new FXButton(layoutRight, "Center\t\t", GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_CHOOSER_CENTER, GUIDesignChooserButtons);
83  myTrackButton = new FXButton(layoutRight, "Track\t\t", GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_CHOOSER_TRACK, GUIDesignChooserButtons);
84  // only enable Track Button if we're locating vehicles
85  if (title.text() != std::string("Vehicle Chooser")) {
86  myTrackButton->disable();
87  myTrackButton->hide();
88  }
89  new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
90  new FXButton(layoutRight, "&Hide Unselected\t\t", GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSER_FILTER, GUIDesignChooserButtons);
91  new FXButton(layoutRight, "By &Name\tLocate item by name\t", nullptr, this, MID_CHOOSEN_NAME, GUIDesignChooserButtons);
92  new FXButton(layoutRight, "&Select/deselect\t\tSelect/deselect current object", GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_INVERT, GUIDesignChooserButtons);
93  new FXButton(layoutRight, "&Filter substring\t\t", nullptr, this, MID_CHOOSER_FILTER_SUBSTR, GUIDesignChooserButtons);
94  new FXButton(layoutRight, "Select &all\t\tSelect all items in list", GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_SELECT, GUIDesignChooserButtons);
95  new FXButton(layoutRight, "&Deselect all\t\tDeselect all items in list", GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);
96  new FXButton(layoutRight, "&Update\t\tReload all ids", GUIIconSubSys::getIcon(GUIIcon::RELOAD), this, MID_UPDATE, GUIDesignChooserButtons);
97  new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
98  new FXButton(layoutRight, "&Close\t\t", GUIIconSubSys::getIcon(GUIIcon::NO), this, MID_CANCEL, GUIDesignChooserButtons);
99  myCountLabel = new FXLabel(layoutRight, "placeholder", nullptr, LAYOUT_BOTTOM | LAYOUT_FILL_X | JUSTIFY_LEFT);
100  myCaseSensitive = new FXCheckButton(layoutRight, "case-sensitive search");
101  myCaseSensitive->setCheck(getApp()->reg().readIntEntry("LOCATOR", "caseSensitive", 0) == 1);
102  myInstantCenter = new FXCheckButton(layoutRight, "auto-center");
103  myInstantCenter->setCheck(getApp()->reg().readIntEntry("LOCATOR", "autoCenter", 0) == 1);
104  refreshList(ids);
105  // add child in windowsParent
106  myWindowsParent->getParent()->addChild(this);
107  // create and show dialog
108  create();
109  show();
110 
111  getApp()->reg().writeIntEntry("TL_TRACKER", "x", getX());
112 }
113 
114 
116  // remove child from windowsParent
118  getApp()->reg().writeIntEntry("LOCATOR", "autoCenter", myInstantCenter->getCheck());
119  getApp()->reg().writeIntEntry("LOCATOR", "caseSensitive", myCaseSensitive->getCheck());
120 }
121 
122 
125  return static_cast<GUIGlObject*>(mySelected);
126 }
127 
128 
129 void
131  FXMainWindow::show();
132  myTextEntry->setFocus();
133 }
134 
135 
136 long
137 GUIDialog_ChooserAbstract::onCmdCenter(FXObject*, FXSelector, void*) {
138  int selected = myList->getCurrentItem();
139  if (selected >= 0) {
141  myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));
142  }
143  return 1;
144 }
145 
146 
147 long
148 GUIDialog_ChooserAbstract::onCmdTrack(FXObject*, FXSelector, void*) {
149  int selected = myList->getCurrentItem();
150  if (selected >= 0) {
151  myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));
152  GUIGlID id = *static_cast<GUIGlID*>(myList->getItemData(selected));
154  if (o->getType() == GLO_VEHICLE) {
156  }
158  }
159  return 1;
160 }
161 
162 
163 long
164 GUIDialog_ChooserAbstract::onCmdClose(FXObject*, FXSelector, void*) {
165  close(true);
166  return 1;
167 }
168 
169 long
170 GUIDialog_ChooserAbstract::onChgList(FXObject*, FXSelector, void*) {
171  // mouse-click toggles item selection but changked current item with
172  // keyboard does not affect select
173  // Enabling the line blow toggles the behavior (which must be fixed via onChgListSel)
174  myList->selectItem(myList->getCurrentItem());
175  if (myInstantCenter->getCheck()) {
176  onCmdCenter(nullptr, 0, nullptr);
177  }
178  return 1;
179 }
180 
181 long
182 GUIDialog_ChooserAbstract::onChgListSel(FXObject*, FXSelector, void*) {
183  myList->selectItem(myList->getCurrentItem());
184  return 1;
185 }
186 
187 long
188 GUIDialog_ChooserAbstract::onChgText(FXObject*, FXSelector, void*) {
189  const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;
190  int id = -1;
192  // findItem does not support substring search
193  const int numItems = myList->getNumItems();
194  FXString t = myTextEntry->getText();
195  if (!caseSensitive) {
196  t = t.lower();
197  }
198  for (int i = 0; i < numItems; i++) {
199  FXString t2 = myList->getItemText(i);
200  if (!caseSensitive) {
201  t2 = t2.lower();
202  }
203  if (t2.find(t) >= 0) {
204  id = i;
205  break;
206  }
207  }
208  } else {
209  const int caseOpt = caseSensitive ? 0 : SEARCH_IGNORECASE;
210  id = myList->findItem(myTextEntry->getText(), -1, SEARCH_PREFIX | caseOpt);
211  }
212  if (id < 0) {
213  if (myList->getNumItems() > 0) {
214  myList->deselectItem(myList->getCurrentItem());
215  }
216  myCenterButton->disable();
217  myTrackButton->disable();
218  return 1;
219  }
220  myList->deselectItem(myList->getCurrentItem());
221  myList->makeItemVisible(id);
222  myList->selectItem(id);
223  myList->setCurrentItem(id, true);
224  myCenterButton->enable();
225  myTrackButton->enable();
226  return 1;
227 }
228 
229 
230 long
231 GUIDialog_ChooserAbstract::onCmdText(FXObject*, FXSelector, void*) {
232  int current = myList->getCurrentItem();
233  if (current >= 0 && myList->isItemSelected(current)) {
234  myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(current)));
235  }
236  return 1;
237 }
238 
239 
240 
241 long
242 GUIDialog_ChooserAbstract::onListKeyPress(FXObject*, FXSelector, void* ptr) {
243  FXEvent* event = (FXEvent*)ptr;
244  if (event->code == KEY_Return) {
245  onCmdText(nullptr, 0, nullptr);
246  if ((event->state & CONTROLMASK) != 0) {
247  close(true);
248  }
249  return 1;
250  } else if (event->code == KEY_Left || (event->code == KEY_Up && myList->getCurrentItem() == 0)) {
251  myTextEntry->setFocus();
252  return 1;
253  }
254  // let other elements handle the keypress
255  return 0;
256 }
257 
258 
259 long
260 GUIDialog_ChooserAbstract::onCmdFilter(FXObject*, FXSelector, void*) {
262  std::vector<GUIGlID> selectedGlIDs;
263  const int numItems = myList->getNumItems();
264  for (int i = 0; i < numItems; i++) {
265  const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
266  if (myList->getItemIcon(i) == flag) {
267  selectedGlIDs.push_back(glID);
268  }
269  }
270  refreshList(selectedGlIDs);
271  return 1;
272 }
273 
274 
275 long
276 GUIDialog_ChooserAbstract::onCmdFilterSubstr(FXObject*, FXSelector, void*) {
277  const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;
278  std::vector<GUIGlID> selectedGlIDs;
279  const int numItems = myList->getNumItems();
280  FXString t = myTextEntry->getText();
281  if (!caseSensitive) {
282  t = t.lower();
283  }
284  for (int i = 0; i < numItems; i++) {
285  FXString t2 = myList->getItemText(i);
286  if (!caseSensitive) {
287  t2 = t2.lower();
288  }
289  if (t2.find(t) >= 0) {
290  const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
291  selectedGlIDs.push_back(glID);
292  }
293  }
294  refreshList(selectedGlIDs);
295  // filter ACs in NETEDIT
296  filterACs(selectedGlIDs);
298  onChgText(nullptr, 0, nullptr);
299  return 1;
300 }
301 
302 
303 std::string
305  if (myLocateByName) {
306  return o->getOptionalName();
307  } else {
308  return o->getMicrosimID();
309  }
310 }
311 
312 void
313 GUIDialog_ChooserAbstract::refreshList(const std::vector<GUIGlID>& ids) {
314  myList->clearItems();
315  for (auto i : ids) {
317  if (o == nullptr) {
318  continue;
319  }
320  const std::string& name = getObjectName(o);
321  const bool selected = myWindowsParent->isSelected(o);
322  FXIcon* const ico = selected ? GUIIconSubSys::getIcon(GUIIcon::FLAG) : nullptr;
323  myIDs.insert(o->getGlID());
324  myList->appendItem(name.c_str(), ico, (void*) & (*myIDs.find(o->getGlID())));
326  }
327  myList->update();
328  myCountLabel->setText((toString(ids.size()) + " objects").c_str());
329 }
330 
331 
332 long
333 GUIDialog_ChooserAbstract::onCmdToggleSelection(FXObject*, FXSelector, void*) {
335  int i = myList->getCurrentItem();
336  if (i >= 0) {
337  toggleSelection(i);
338  if (myList->getItemIcon(i) == flag) {
339  myList->setItemIcon(i, nullptr);
340  } else {
341  myList->setItemIcon(i, flag);
342  }
343  }
344  myList->update();
345  myWindowsParent->getView()->update();
346  return 1;
347 }
348 
349 
350 long
353  const int numItems = myList->getNumItems();
354  for (int i = 0; i < numItems; i++) {
355  GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(i));
356  gSelected.select(*glID);
357  myList->setItemIcon(i, flag);
358  }
359  myList->update();
360  myWindowsParent->getView()->update();
361  return 1;
362 }
363 
364 
365 long
367  const int numItems = myList->getNumItems();
368  for (int i = 0; i < numItems; i++) {
369  GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(i));
370  gSelected.deselect(*glID);
371  myList->setItemIcon(i, nullptr);
372  }
373  myList->update();
374  myWindowsParent->getView()->update();
375  return 1;
376 }
377 
378 
379 long
380 GUIDialog_ChooserAbstract::onCmdLocateByName(FXObject*, FXSelector, void*) {
381  std::vector<std::pair<std::string, GUIGlID> > namesAndIDs;
382  myLocateByName = true;
383  const int numItems = myList->getNumItems();
384  for (int i = 0; i < numItems; i++) {
385  GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
387  if (o != 0) {
388  const std::string& name = getObjectName(o);
389  if (name != "") {
390  namesAndIDs.push_back(std::make_pair(name, glID));
391  }
392  }
394  }
395  std::sort(namesAndIDs.begin(), namesAndIDs.end());
396  std::vector<GUIGlID> selectedGlIDs;
397  for (const auto& item : namesAndIDs) {
398  selectedGlIDs.push_back(item.second);
399  }
400  refreshList(selectedGlIDs);
401  myTextEntry->setFocus();
402  return 1;
403 }
404 
405 long
406 GUIDialog_ChooserAbstract::onCmdUpdate(FXObject*, FXSelector, void*) {
408  return 1;
409 }
410 
411 void
413  GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
414  gSelected.toggleSelection(*glID);
415 }
416 
417 
418 void
419 GUIDialog_ChooserAbstract::filterACs(const std::vector<GUIGlID>& /*GLIDs*/) {
420  // overrided in GNEDialogACChooser
421 }
422 
423 /****************************************************************************/
@ MID_CHOOSER_TRACK
Track object.
Definition: GUIAppEnum.h:535
@ MID_CANCEL
Cancel-button pressed.
Definition: GUIAppEnum.h:255
@ MID_CHOOSER_TEXT
Text entry.
Definition: GUIAppEnum.h:537
@ MID_UPDATE
Update-button pressed.
Definition: GUIAppEnum.h:257
@ MID_CHOOSEN_INVERT
Deselect selected items.
Definition: GUIAppEnum.h:569
@ MID_CHOOSEN_SELECT
select all items
Definition: GUIAppEnum.h:565
@ MID_CHOOSER_LIST
Object list.
Definition: GUIAppEnum.h:539
@ MID_CHOOSEN_NAME
Deselect selected items.
Definition: GUIAppEnum.h:571
@ MID_CHOOSER_FILTER_SUBSTR
Filter list by substring.
Definition: GUIAppEnum.h:543
@ MID_CHOOSEN_CLEAR
Clear set.
Definition: GUIAppEnum.h:559
@ MID_CHOOSER_FILTER
Filter selected.
Definition: GUIAppEnum.h:541
@ MID_CHOOSER_CENTER
Center object.
Definition: GUIAppEnum.h:533
#define GUIDesignChooserTextField
design for Chooser TextField
Definition: GUIDesigns.h:576
#define GUIDesignChooserListSingle
design for Chooser List
Definition: GUIDesigns.h:579
#define GUIDesignChooserButtons
design for Chooser buttons
Definition: GUIDesigns.h:573
#define GUIDesignChooserLayoutLeft
design for Chooser Layout left
Definition: GUIDesigns.h:588
#define GUIDesignChooserLayoutRight
design for Chooser Layout right
Definition: GUIDesigns.h:591
#define GUIDesignHorizontalSeparator
Definition: GUIDesigns.h:395
#define GUIDesignChooserLayoutList
design for Chooser Layout list
Definition: GUIDesigns.h:594
#define GUIDesignAuxiliarFrame
design for auxiliar (Without borders) frames used to pack another frames extended in all directions
Definition: GUIDesigns.h:340
#define GUIDesignChooserDialog
Definition: GUIDesigns.h:570
FXDEFMAP(GUIDialog_ChooserAbstract) GUIDialog_ChooserAbstractMap[]
unsigned int GUIGlID
Definition: GUIGlObject.h:40
@ GLO_VEHICLE
a vehicle
GUISelectedStorage gSelected
A global holder of selected objects.
@ RECENTERVIEW
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
bool myLocateByName
whether to locate by object name instead of id
FXButton * myCenterButton
The button that triggers centering on the select object.
long onCmdText(FXObject *, FXSelector, void *)
Callback: Selects to current item if enter is pressed.
long onCmdClose(FXObject *, FXSelector, void *)
Callback: The dialog shall be closed.
void refreshList(const std::vector< GUIGlID > &ids)
update the list with the given ids
long onCmdCenter(FXObject *, FXSelector, void *)
Callback: The selected item shall be centered within the calling view.
FXCheckButton * myCaseSensitive
Whether search is case sensitive.
int myMessageId
the object type being chosen
virtual ~GUIDialog_ChooserAbstract()
Destructor.
long onCmdFilter(FXObject *, FXSelector, void *)
Callback: Hides unselected items if pressed.
long onCmdFilterSubstr(FXObject *, FXSelector, void *)
Callback: Hides unmatched items if pressed.
void show()
sets the focus after the window is created to work-around bug in libfox
long onCmdTrack(FXObject *, FXSelector, void *)
Callback: The selected vehicle shall be tracked within the calling view.
long onCmdLocateByName(FXObject *, FXSelector, void *)
Callback: Toggle locator by name.
bool myHaveFilteredSubstring
whether the list was filter by substring
FXLabel * myCountLabel
label for declaring list size
long onListKeyPress(FXObject *, FXSelector, void *)
Callback: Selects to current item if enter is pressed.
long onChgText(FXObject *, FXSelector, void *)
Callback: Something has been typed into the the field.
GUIGlChildWindow * myWindowsParent
window parent
long onCmdUpdate(FXObject *, FXSelector, void *)
Callback: Update list.
std::set< GUIGlID > myIDs
myList contains (void) pointers to elements of myIDs instead of the more volatile pointers to GUIGlOb...
long onChgListSel(FXObject *, FXSelector, void *)
Callback: Current list item selection has changed.
GUIGlObject * mySelected
The chosen id.
long onCmdClearListSelection(FXObject *, FXSelector, void *)
long onCmdAddListSelection(FXObject *, FXSelector, void *)
virtual void toggleSelection(int listIndex)
fox need this
FXButton * myTrackButton
The button that triggers tracking on the select vehicle.
virtual std::string getObjectName(GUIGlObject *o) const
@bbrief retrieve name for the given object
virtual void filterACs(const std::vector< GUIGlID > &GLIDs)
filter ACs (needed in NETEDIT)
FXTextField * myTextEntry
The text field.
long onCmdToggleSelection(FXObject *, FXSelector, void *)
Callback: Toggle selection status of current object / list.
FXCheckButton * myInstantCenter
Whether each change in the list should re-center the view.
long onChgList(FXObject *, FXSelector, void *)
Callback: Current list item has changed.
GUIGlObject * getObject() const
Returns the chosen (selected) object.
FXList * myList
The list that holds the ids.
virtual std::vector< GUIGlID > getObjectIDs(int messageId) const
void setView(GUIGlID id)
Centers the view onto the given artifact.
virtual bool isSelected(GUIGlObject *o) const
true if the object is selected (may include extra logic besides calling gSelected)
GUISUMOAbstractView * getView() const
return GUISUMOAbstractView
GUIMainWindow * getParent()
Returns the main window.
virtual const std::string & getMicrosimID() const
Returns the id of the object as known to microsim.
virtual const std::string getOptionalName() const
Returns the name of the object (default "")
GUIGlObjectType getType() const
Returns the type of the object as coded in GUIGlObjectType.
GUIGlID getGlID() const
Returns the numerical id of the object.
A storage for of displayed objects via their numerical id.
void unblockObject(GUIGlID id)
Marks an object as unblocked.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
GUIGlObject * getObjectBlocking(GUIGlID id)
Returns the object from the container locking it.
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
void removeChild(FXMainWindow *child)
removes the given child window from the list (FXMainWindow)
virtual void stopTrack()
stop track
virtual void startTrack(int)
star track
void toggleSelection(GUIGlID id)
Toggles selection of an object.
void select(GUIGlID id, bool update=true)
Adds the object with the given id.
void deselect(GUIGlID id)
Deselects the object with the given id.
const unsigned char flag[]
Definition: flag.cpp:24