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.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 /****************************************************************************/
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>
37 
39 
40 
41 // ===========================================================================
42 // FOX callback mapping
43 // ===========================================================================
44 FXDEFMAP(GUIDialog_ChooserAbstract) GUIDialog_ChooserAbstractMap[] = {
47  FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_ChooserAbstract::onCmdClose),
59  FXMAPFUNC(SEL_COMMAND, MID_UPDATE, GUIDialog_ChooserAbstract::onCmdUpdate),
60 };
61 
62 FXIMPLEMENT(GUIDialog_ChooserAbstract, FXMainWindow, GUIDialog_ChooserAbstractMap, ARRAYNUMBER(GUIDialog_ChooserAbstractMap))
63 
64 
65 // ===========================================================================
66 // method definitions
67 // ===========================================================================
69  FXIcon* icon, const FXString& title, const std::vector<GUIGlID>& ids, GUIGlObjectStorage& /*glStorage*/) :
70  FXMainWindow(windowsParent->getApp(), title, icon, nullptr, GUIDesignChooserDialog),
71  GUIPersistentWindowPos(this, "LOCATOR", true, 20, 40, 300, 350),
72  myWindowsParent(windowsParent),
73  myMessageId(messageId),
74  myLocateByName(false),
75  myHaveFilteredSubstring(false) {
76  FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);
77  // build the list
78  FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);
79  myTextEntry = new FXTextField(layoutLeft, 0, this, MID_CHOOSER_TEXT, TEXTFIELD_ENTER_ONLY | GUIDesignChooserTextField);
80  FXVerticalFrame* layoutList = new FXVerticalFrame(layoutLeft, GUIDesignChooserLayoutList);
81  myList = new FXList(layoutList, this, MID_CHOOSER_LIST, GUIDesignChooserListSingle);
82  // build the buttons
83  FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);
86  // only enable Track Button if we're locating vehicles
87  if (title.text() != std::string(TL("Vehicle Chooser"))) {
88  myTrackButton->disable();
89  myTrackButton->hide();
90  }
91  new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
93  GUIDesigns::buildFXButton(layoutRight, TL("By &Name"), TL("Locate item by name"), "", nullptr, this, MID_CHOOSEN_NAME, GUIDesignChooserButtons);
94  GUIDesigns::buildFXButton(layoutRight, TL("&Select/deselect"), "", TL("Select/deselect current object"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_INVERT, GUIDesignChooserButtons);
95  GUIDesigns::buildFXButton(layoutRight, TL("&Filter substring"), "", "", nullptr, this, MID_CHOOSER_FILTER_SUBSTR, GUIDesignChooserButtons);
96  GUIDesigns::buildFXButton(layoutRight, TL("Select &all"), "", TL("Select all items in list"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_SELECT, GUIDesignChooserButtons);
97  GUIDesigns::buildFXButton(layoutRight, TL("&Deselect all"), "", TL("Deselect all items in list"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);
98  GUIDesigns::buildFXButton(layoutRight, TL("&Update"), "", TL("Reload all ids"), GUIIconSubSys::getIcon(GUIIcon::RELOAD), this, MID_UPDATE, GUIDesignChooserButtons);
99  new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
101  myCountLabel = new FXLabel(layoutRight, "placeholder", nullptr, LAYOUT_BOTTOM | LAYOUT_FILL_X | JUSTIFY_LEFT);
102  myCaseSensitive = new FXCheckButton(layoutRight, TL("case-sensitive search"));
103  myCaseSensitive->setCheck(getApp()->reg().readIntEntry("LOCATOR", "caseSensitive", 0) == 1);
104  myInstantCenter = new FXCheckButton(layoutRight, TL("auto-center"));
105  myInstantCenter->setCheck(getApp()->reg().readIntEntry("LOCATOR", "autoCenter", 0) == 1);
106  refreshList(ids);
107  // add child in windowsParent
108  myWindowsParent->getGUIMainWindowParent()->addChild(this);
109  loadWindowPos();
110  // create and show dialog
111  create();
112  show();
113 }
114 
115 
117  // remove child from windowsParent
119  getApp()->reg().writeIntEntry("LOCATOR", "autoCenter", myInstantCenter->getCheck());
120  getApp()->reg().writeIntEntry("LOCATOR", "caseSensitive", myCaseSensitive->getCheck());
121 }
122 
123 
126  return static_cast<GUIGlObject*>(mySelected);
127 }
128 
129 
130 void
132  FXMainWindow::show();
133  myTextEntry->setFocus();
134 }
135 
136 
137 long
138 GUIDialog_ChooserAbstract::onCmdCenter(FXObject*, FXSelector, void*) {
139  int selected = myList->getCurrentItem();
140  if (selected >= 0) {
142  myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));
143  }
144  return 1;
145 }
146 
147 
148 long
149 GUIDialog_ChooserAbstract::onCmdTrack(FXObject*, FXSelector, void*) {
150  int selected = myList->getCurrentItem();
151  if (selected >= 0) {
152  myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));
153  GUIGlID id = *static_cast<GUIGlID*>(myList->getItemData(selected));
155  if (o->getType() == GLO_VEHICLE) {
157  }
159  }
160  return 1;
161 }
162 
163 
164 long
165 GUIDialog_ChooserAbstract::onCmdClose(FXObject*, FXSelector, void*) {
166  close(true);
167  return 1;
168 }
169 
170 long
171 GUIDialog_ChooserAbstract::onChgList(FXObject*, FXSelector, void*) {
172  // mouse-click toggles item selection but changked current item with
173  // keyboard does not affect select
174  // Enabling the line blow toggles the behavior (which must be fixed via onChgListSel)
175  myList->selectItem(myList->getCurrentItem());
176  if (myInstantCenter->getCheck()) {
177  onCmdCenter(nullptr, 0, nullptr);
178  }
179  return 1;
180 }
181 
182 long
183 GUIDialog_ChooserAbstract::onChgListSel(FXObject*, FXSelector, void*) {
184  myList->selectItem(myList->getCurrentItem());
185  return 1;
186 }
187 
188 long
189 GUIDialog_ChooserAbstract::onChgText(FXObject*, FXSelector, void*) {
190  const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;
191  int id = -1;
193  // findItem does not support substring search
194  const int numItems = myList->getNumItems();
195  FXString t = myTextEntry->getText();
196  if (!caseSensitive) {
197  t = t.lower();
198  }
199  for (int i = 0; i < numItems; i++) {
200  FXString t2 = myList->getItemText(i);
201  if (!caseSensitive) {
202  t2 = t2.lower();
203  }
204  if (t2.find(t) >= 0) {
205  id = i;
206  break;
207  }
208  }
209  } else {
210  const int caseOpt = caseSensitive ? 0 : SEARCH_IGNORECASE;
211  id = myList->findItem(myTextEntry->getText(), -1, SEARCH_PREFIX | caseOpt);
212  }
213  if (id < 0) {
214  if (myList->getNumItems() > 0) {
215  myList->deselectItem(myList->getCurrentItem());
216  }
217  myCenterButton->disable();
218  myTrackButton->disable();
219  return 1;
220  }
221  myList->deselectItem(myList->getCurrentItem());
222  myList->makeItemVisible(id);
223  myList->selectItem(id);
224  myList->setCurrentItem(id, true);
225  myCenterButton->enable();
226  myTrackButton->enable();
227  return 1;
228 }
229 
230 
231 long
232 GUIDialog_ChooserAbstract::onCmdText(FXObject*, FXSelector, void*) {
233  int current = myList->getCurrentItem();
234  if (current >= 0 && myList->isItemSelected(current)) {
235  myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(current)));
236  }
237  return 1;
238 }
239 
240 
241 
242 long
243 GUIDialog_ChooserAbstract::onListKeyPress(FXObject*, FXSelector, void* ptr) {
244  FXEvent* event = (FXEvent*)ptr;
245  if (event->code == KEY_Return) {
246  onCmdText(nullptr, 0, nullptr);
247  if ((event->state & CONTROLMASK) != 0) {
248  close(true);
249  }
250  return 1;
251  } else if (event->code == KEY_Left || (event->code == KEY_Up && myList->getCurrentItem() == 0)) {
252  myTextEntry->setFocus();
253  return 1;
254  }
255  // let other elements handle the keypress
256  return 0;
257 }
258 
259 
260 long
261 GUIDialog_ChooserAbstract::onCmdFilter(FXObject*, FXSelector, void*) {
262  FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);
263  std::vector<GUIGlID> selectedGlIDs;
264  const int numItems = myList->getNumItems();
265  for (int i = 0; i < numItems; i++) {
266  const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
267  if (myList->getItemIcon(i) == flag) {
268  selectedGlIDs.push_back(glID);
269  }
270  }
271  refreshList(selectedGlIDs);
272  return 1;
273 }
274 
275 
276 long
277 GUIDialog_ChooserAbstract::onCmdFilterSubstr(FXObject*, FXSelector, void*) {
278  const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;
279  std::vector<GUIGlID> selectedGlIDs;
280  const int numItems = myList->getNumItems();
281  FXString t = myTextEntry->getText();
282  if (!caseSensitive) {
283  t = t.lower();
284  }
285  for (int i = 0; i < numItems; i++) {
286  FXString t2 = myList->getItemText(i);
287  if (!caseSensitive) {
288  t2 = t2.lower();
289  }
290  if (t2.find(t) >= 0) {
291  const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
292  selectedGlIDs.push_back(glID);
293  }
294  }
295  refreshList(selectedGlIDs);
296  // filter ACs in netedit
297  filterACs(selectedGlIDs);
299  onChgText(nullptr, 0, nullptr);
300  return 1;
301 }
302 
303 
304 std::string
306  if (myLocateByName) {
307  return o->getOptionalName();
308  } else {
309  return o->getMicrosimID();
310  }
311 }
312 
313 void
314 GUIDialog_ChooserAbstract::refreshList(const std::vector<GUIGlID>& ids) {
315  myList->clearItems();
316  for (auto i : ids) {
318  if (o == nullptr) {
319  continue;
320  }
321  const std::string& name = getObjectName(o);
322  const bool selected = myWindowsParent->isSelected(o);
323  FXIcon* const ico = selected ? GUIIconSubSys::getIcon(GUIIcon::FLAG) : nullptr;
324  myIDs.insert(o->getGlID());
325  myList->appendItem(name.c_str(), ico, (void*) & (*myIDs.find(o->getGlID())));
327  }
328  myList->update();
329  myCountLabel->setText(TLF("% objects", toString(ids.size())).c_str());
330 }
331 
332 
333 long
334 GUIDialog_ChooserAbstract::onCmdToggleSelection(FXObject*, FXSelector, void*) {
335  FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);
336  int i = myList->getCurrentItem();
337  if (i >= 0) {
338  toggleSelection(i);
339  if (myList->getItemIcon(i) == flag) {
340  myList->setItemIcon(i, nullptr);
341  } else {
342  myList->setItemIcon(i, flag);
343  }
344  }
345  myList->update();
346  myWindowsParent->getView()->update();
347  return 1;
348 }
349 
350 
351 long
353  FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);
354  const int numItems = myList->getNumItems();
355  for (int i = 0; i < numItems; i++) {
356  select(i);
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  deselect(i);
370  myList->setItemIcon(i, nullptr);
371  }
372  myList->update();
373  myWindowsParent->getView()->update();
374  return 1;
375 }
376 
377 
378 long
379 GUIDialog_ChooserAbstract::onCmdLocateByName(FXObject*, FXSelector, void*) {
380  std::vector<std::pair<std::string, GUIGlID> > namesAndIDs;
381  myLocateByName = true;
382  const int numItems = myList->getNumItems();
383  for (int i = 0; i < numItems; i++) {
384  GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
386  if (o != 0) {
387  const std::string& name = getObjectName(o);
388  if (name != "") {
389  namesAndIDs.push_back(std::make_pair(name, glID));
390  }
391  }
393  }
394  std::sort(namesAndIDs.begin(), namesAndIDs.end());
395  std::vector<GUIGlID> selectedGlIDs;
396  for (const auto& item : namesAndIDs) {
397  selectedGlIDs.push_back(item.second);
398  }
399  refreshList(selectedGlIDs);
400  myTextEntry->setFocus();
401  return 1;
402 }
403 
404 long
405 GUIDialog_ChooserAbstract::onCmdUpdate(FXObject*, FXSelector, void*) {
407  return 1;
408 }
409 
410 void
412  GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
413  gSelected.toggleSelection(*glID);
414 }
415 
416 void
418  GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
419  gSelected.select(*glID);
420 }
421 
422 void
424  GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
425  gSelected.deselect(*glID);
426 }
427 
428 
429 void
430 GUIDialog_ChooserAbstract::filterACs(const std::vector<GUIGlID>& /*GLIDs*/) {
431  // overrided in GNEDialogACChooser
432 }
433 
434 /****************************************************************************/
@ MID_CHOOSER_TRACK
Track object.
Definition: GUIAppEnum.h:577
@ MID_CANCEL
Cancel-button pressed.
Definition: GUIAppEnum.h:306
@ MID_CHOOSER_TEXT
Text entry.
Definition: GUIAppEnum.h:579
@ MID_UPDATE
Update-button pressed.
Definition: GUIAppEnum.h:308
@ MID_CHOOSEN_INVERT
Deselect selected items.
Definition: GUIAppEnum.h:611
@ MID_CHOOSEN_SELECT
select all items
Definition: GUIAppEnum.h:607
@ MID_CHOOSER_LIST
Object list.
Definition: GUIAppEnum.h:581
@ MID_CHOOSEN_NAME
Deselect selected items.
Definition: GUIAppEnum.h:613
@ MID_CHOOSER_FILTER_SUBSTR
Filter list by substring.
Definition: GUIAppEnum.h:585
@ MID_CHOOSEN_CLEAR
Clear set.
Definition: GUIAppEnum.h:601
@ MID_CHOOSER_FILTER
Filter selected.
Definition: GUIAppEnum.h:583
@ MID_CHOOSER_CENTER
Center object.
Definition: GUIAppEnum.h:575
#define GUIDesignChooserTextField
design for Chooser TextField
Definition: GUIDesigns.h:654
#define GUIDesignChooserListSingle
design for Chooser List
Definition: GUIDesigns.h:657
#define GUIDesignChooserButtons
design for Chooser buttons
Definition: GUIDesigns.h:651
#define GUIDesignChooserLayoutLeft
design for Chooser Layout left
Definition: GUIDesigns.h:666
#define GUIDesignChooserLayoutRight
design for Chooser Layout right
Definition: GUIDesigns.h:669
#define GUIDesignHorizontalSeparator
Definition: GUIDesigns.h:466
#define GUIDesignChooserLayoutList
design for Chooser Layout list
Definition: GUIDesigns.h:672
#define GUIDesignAuxiliarFrame
design for auxiliar (Without borders) frame extended in all directions
Definition: GUIDesigns.h:396
#define GUIDesignChooserDialog
Definition: GUIDesigns.h:648
FXDEFMAP(GUIDialog_ChooserAbstract) GUIDialog_ChooserAbstractMap[]
unsigned int GUIGlID
Definition: GUIGlObject.h:43
@ GLO_VEHICLE
a vehicle
GUISelectedStorage gSelected
A global holder of selected objects.
@ RECENTERVIEW
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
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
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.
virtual void deselect(int listIndex)
unset selection (handled differently in netedit)
virtual void select(int listIndex)
set selection (handled differently in netedit)
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 * getGUIMainWindowParent()
Returns the GUIMainWindow parent.
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.
Definition: GUIGlObject.h:156
const std::string & getMicrosimID() const
Returns the id of the object as known to microsim.
Definition: GUIGlObject.h:143
GUIGlID getGlID() const
Returns the numerical id of the object.
Definition: GUIGlObject.h:104
A storage for of displayed objects via their numerical id.
void unblockObject(GUIGlID id)
Marks an object as unblocked.
GUIGlObject * getObjectBlocking(GUIGlID id) const
Returns the object from the container locking it.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
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)
Persists window position in the registry.
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.
Definition: json.hpp:4471