Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/gui/windows/GUIDialog_ChooserAbstract.cpp
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
14
/// @file GUIDialog_ChooserAbstract.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Sept 2002
19
///
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>
27
#include <utils/common/MsgHandler.h>
28
#include <utils/gui/windows/GUIAppEnum.h>
29
#include <utils/gui/windows/GUIGlChildWindow.h>
30
#include <utils/gui/windows/GUIMainWindow.h>
31
#include <utils/gui/globjects/GUIGlObject.h>
32
#include <utils/gui/globjects/GUIGlObjectStorage.h>
33
#include <utils/gui/images/GUIIconSubSys.h>
34
#include <utils/gui/div/GUIGlobalSelection.h>
35
#include <utils/gui/div/GUIDesigns.h>
36
#include <utils/gui/globjects/GUIGlObject_AbstractAdd.h>
37
38
#include "GUIDialog_ChooserAbstract.h"
39
40
41
// ===========================================================================
42
// FOX callback mapping
43
// ===========================================================================
44
FXDEFMAP(GUIDialog_ChooserAbstract) GUIDialog_ChooserAbstractMap[] = {
45
FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_CENTER, GUIDialog_ChooserAbstract::onCmdCenter),
46
FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_TRACK, GUIDialog_ChooserAbstract::onCmdTrack),
47
FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GUIDialog_ChooserAbstract::onCmdClose),
48
FXMAPFUNC(SEL_CHANGED, MID_CHOOSER_TEXT, GUIDialog_ChooserAbstract::onChgText),
49
FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_TEXT, GUIDialog_ChooserAbstract::onCmdText),
50
FXMAPFUNC(SEL_KEYPRESS, 0, GUIDialog_ChooserAbstract::onKeyPress),
51
FXMAPFUNC(SEL_CHANGED, MID_CHOOSER_LIST, GUIDialog_ChooserAbstract::onChgList),
52
FXMAPFUNC(SEL_DESELECTED, MID_CHOOSER_LIST, GUIDialog_ChooserAbstract::onChgListSel),
53
FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_FILTER, GUIDialog_ChooserAbstract::onCmdFilter),
54
FXMAPFUNC(SEL_COMMAND, MID_CHOOSER_FILTER_SUBSTR, GUIDialog_ChooserAbstract::onCmdFilterSubstr),
55
FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_INVERT, GUIDialog_ChooserAbstract::onCmdToggleSelection),
56
FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SELECT, GUIDialog_ChooserAbstract::onCmdAddListSelection),
57
FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GUIDialog_ChooserAbstract::onCmdClearListSelection),
58
FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_NAME, GUIDialog_ChooserAbstract::onCmdLocateByName),
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
// ===========================================================================
68
#ifdef _MSC_VER
69
#pragma warning(push)
70
#pragma warning(disable: 4355) // mask warning about "this" in initializers
71
#endif
72
GUIDialog_ChooserAbstract::GUIDialog_ChooserAbstract(GUIGlChildWindow* windowsParent, int messageId,
73
FXIcon* icon, const FXString& title, const std::vector<GUIGlID>& ids, GUIGlObjectStorage& /*glStorage*/) :
74
FXMainWindow(windowsParent->getApp(), title, icon, nullptr, GUIDesignChooserDialog),
75
GUIPersistentWindowPos(this, "LOCATOR", true, 20, 40, 300, 350),
76
myWindowsParent(windowsParent),
77
myMessageId(messageId),
78
myLocateByName(false),
79
myHaveFilteredSubstring(false) {
80
FXHorizontalFrame* hbox = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);
81
// build the list
82
FXVerticalFrame* layoutLeft = new FXVerticalFrame(hbox, GUIDesignChooserLayoutLeft);
83
myTextEntry = new FXTextField(layoutLeft, 0, this, MID_CHOOSER_TEXT, TEXTFIELD_ENTER_ONLY | GUIDesignChooserTextField);
84
FXVerticalFrame* layoutList = new FXVerticalFrame(layoutLeft, GUIDesignChooserLayoutList);
85
myList = new FXList(layoutList, this, MID_CHOOSER_LIST, GUIDesignChooserListSingle);
86
// build the buttons
87
FXVerticalFrame* layoutRight = new FXVerticalFrame(hbox, GUIDesignChooserLayoutRight);
88
myCenterButton = GUIDesigns::buildFXButton(layoutRight, TL("Center"), "", "", GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_CHOOSER_CENTER, GUIDesignChooserButtons);
89
myTrackButton = GUIDesigns::buildFXButton(layoutRight, TL("Track"), "", "", GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_CHOOSER_TRACK, GUIDesignChooserButtons);
90
// only enable Track Button if we're locating vehicles
91
if (title.text() != std::string(TL("Vehicle Chooser"))) {
92
myTrackButton->disable();
93
myTrackButton->hide();
94
}
95
new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
96
GUIDesigns::buildFXButton(layoutRight, TL("&Hide Unselected"), "", "", GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSER_FILTER, GUIDesignChooserButtons);
97
GUIDesigns::buildFXButton(layoutRight, TL("By &Name"), TL("Locate item by name"), "", nullptr, this, MID_CHOOSEN_NAME, GUIDesignChooserButtons);
98
GUIDesigns::buildFXButton(layoutRight, TL("&Select/deselect"), "", TL("Select/deselect current object"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_INVERT, GUIDesignChooserButtons);
99
GUIDesigns::buildFXButton(layoutRight, TL("&Filter substring"), "", "", nullptr, this, MID_CHOOSER_FILTER_SUBSTR, GUIDesignChooserButtons);
100
GUIDesigns::buildFXButton(layoutRight, TL("Select &all"), "", TL("Select all items in list"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_SELECT, GUIDesignChooserButtons);
101
GUIDesigns::buildFXButton(layoutRight, TL("&Deselect all"), "", TL("Deselect all items in list"), GUIIconSubSys::getIcon(GUIIcon::FLAG), this, MID_CHOOSEN_CLEAR, GUIDesignChooserButtons);
102
GUIDesigns::buildFXButton(layoutRight, TL("&Update"), "", TL("Reload all ids"), GUIIconSubSys::getIcon(GUIIcon::RELOAD), this, MID_UPDATE, GUIDesignChooserButtons);
103
new FXHorizontalSeparator(layoutRight, GUIDesignHorizontalSeparator);
104
GUIDesigns::buildFXButton(layoutRight, TL("&Close"), "", "", GUIIconSubSys::getIcon(GUIIcon::NO), this, MID_CANCEL, GUIDesignChooserButtons);
105
myCountLabel = new FXLabel(layoutRight, "placeholder", nullptr, LAYOUT_BOTTOM | LAYOUT_FILL_X | JUSTIFY_LEFT);
106
myCaseSensitive = new FXCheckButton(layoutRight, TL("case-sensitive search"));
107
myCaseSensitive->setCheck(getApp()->reg().readIntEntry("LOCATOR", "caseSensitive", 0) == 1);
108
myInstantCenter = new FXCheckButton(layoutRight, TL("auto-center"));
109
myInstantCenter->setCheck(getApp()->reg().readIntEntry("LOCATOR", "autoCenter", 0) == 1);
110
refreshList(ids);
111
// add child in windowsParent
112
myWindowsParent->getGUIMainWindowParent()->addChild(this);
113
loadWindowPos();
114
// create and show dialog
115
create();
116
show();
117
}
118
#ifdef _MSC_VER
119
#pragma warning(pop)
120
#endif
121
122
123
GUIDialog_ChooserAbstract::~GUIDialog_ChooserAbstract() {
124
// remove child from windowsParent
125
myWindowsParent->getGUIMainWindowParent()->removeChild(this);
126
getApp()->reg().writeIntEntry("LOCATOR", "autoCenter", myInstantCenter->getCheck());
127
getApp()->reg().writeIntEntry("LOCATOR", "caseSensitive", myCaseSensitive->getCheck());
128
}
129
130
131
GUIGlObject*
132
GUIDialog_ChooserAbstract::getObject() const {
133
return static_cast<GUIGlObject*>(mySelected);
134
}
135
136
137
void
138
GUIDialog_ChooserAbstract::show() {
139
FXMainWindow::show();
140
myTextEntry->setFocus();
141
}
142
143
144
long
145
GUIDialog_ChooserAbstract::onCmdCenter(FXObject*, FXSelector, void*) {
146
int selected = myList->getCurrentItem();
147
if (selected >= 0) {
148
myWindowsParent->getView()->stopTrack();
149
myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));
150
}
151
return 1;
152
}
153
154
155
long
156
GUIDialog_ChooserAbstract::onCmdTrack(FXObject*, FXSelector, void*) {
157
int selected = myList->getCurrentItem();
158
if (selected >= 0) {
159
myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(selected)));
160
GUIGlID id = *static_cast<GUIGlID*>(myList->getItemData(selected));
161
GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
162
if (o->getType() == GLO_VEHICLE) {
163
myWindowsParent->getView()->startTrack(o->getGlID());
164
}
165
GUIGlObjectStorage::gIDStorage.unblockObject(id);
166
}
167
return 1;
168
}
169
170
171
long
172
GUIDialog_ChooserAbstract::onCmdClose(FXObject*, FXSelector, void*) {
173
close(true);
174
return 1;
175
}
176
177
long
178
GUIDialog_ChooserAbstract::onChgList(FXObject*, FXSelector, void*) {
179
// mouse-click toggles item selection but changked current item with
180
// keyboard does not affect select
181
// Enabling the line blow toggles the behavior (which must be fixed via onChgListSel)
182
myList->selectItem(myList->getCurrentItem());
183
if (myInstantCenter->getCheck()) {
184
onCmdCenter(nullptr, 0, nullptr);
185
}
186
return 1;
187
}
188
189
long
190
GUIDialog_ChooserAbstract::onChgListSel(FXObject*, FXSelector, void*) {
191
myList->selectItem(myList->getCurrentItem());
192
return 1;
193
}
194
195
long
196
GUIDialog_ChooserAbstract::onChgText(FXObject*, FXSelector, void*) {
197
const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;
198
int id = -1;
199
if (myLocateByName || myHaveFilteredSubstring) {
200
// findItem does not support substring search
201
const int numItems = myList->getNumItems();
202
FXString t = myTextEntry->getText();
203
if (!caseSensitive) {
204
t = t.lower();
205
}
206
for (int i = 0; i < numItems; i++) {
207
FXString t2 = myList->getItemText(i);
208
if (!caseSensitive) {
209
t2 = t2.lower();
210
}
211
if (t2.find(t) >= 0) {
212
id = i;
213
break;
214
}
215
}
216
} else {
217
const int caseOpt = caseSensitive ? 0 : SEARCH_IGNORECASE;
218
id = myList->findItem(myTextEntry->getText(), -1, SEARCH_PREFIX | caseOpt);
219
}
220
if (id < 0) {
221
if (myList->getNumItems() > 0) {
222
myList->deselectItem(myList->getCurrentItem());
223
}
224
myCenterButton->disable();
225
myTrackButton->disable();
226
return 1;
227
}
228
myList->deselectItem(myList->getCurrentItem());
229
myList->makeItemVisible(id);
230
myList->selectItem(id);
231
myList->setCurrentItem(id, true);
232
myCenterButton->enable();
233
myTrackButton->enable();
234
return 1;
235
}
236
237
238
long
239
GUIDialog_ChooserAbstract::onCmdText(FXObject*, FXSelector, void*) {
240
int current = myList->getCurrentItem();
241
if (current >= 0 && myList->isItemSelected(current)) {
242
myWindowsParent->setView(*static_cast<GUIGlID*>(myList->getItemData(current)));
243
}
244
return 1;
245
}
246
247
248
249
long
250
GUIDialog_ChooserAbstract::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
251
FXEvent* event = (FXEvent*)ptr;
252
if (event->code == KEY_Return) {
253
onCmdText(nullptr, 0, nullptr);
254
if ((event->state & CONTROLMASK) != 0) {
255
close(true);
256
}
257
return 1;
258
} else if (event->code == KEY_Left || (event->code == KEY_Up && myList->getCurrentItem() == 0)) {
259
myTextEntry->setFocus();
260
return 1;
261
} else if (event->code == KEY_Escape) {
262
close(true);
263
return 1;
264
}
265
return FXMainWindow::onKeyPress(o, sel, ptr);
266
}
267
268
269
long
270
GUIDialog_ChooserAbstract::onCmdFilter(FXObject*, FXSelector, void*) {
271
FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);
272
std::vector<GUIGlID> selectedGlIDs;
273
const int numItems = myList->getNumItems();
274
for (int i = 0; i < numItems; i++) {
275
const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
276
if (myList->getItemIcon(i) == flag) {
277
selectedGlIDs.push_back(glID);
278
}
279
}
280
refreshList(selectedGlIDs);
281
return 1;
282
}
283
284
285
long
286
GUIDialog_ChooserAbstract::onCmdFilterSubstr(FXObject*, FXSelector, void*) {
287
const bool caseSensitive = myCaseSensitive->getCheck() == TRUE;
288
std::vector<GUIGlID> selectedGlIDs;
289
const int numItems = myList->getNumItems();
290
FXString t = myTextEntry->getText();
291
if (!caseSensitive) {
292
t = t.lower();
293
}
294
for (int i = 0; i < numItems; i++) {
295
FXString t2 = myList->getItemText(i);
296
if (!caseSensitive) {
297
t2 = t2.lower();
298
}
299
if (t2.find(t) >= 0) {
300
const GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
301
selectedGlIDs.push_back(glID);
302
}
303
}
304
refreshList(selectedGlIDs);
305
// filter ACs in netedit
306
filterACs(selectedGlIDs);
307
myHaveFilteredSubstring = true;
308
onChgText(nullptr, 0, nullptr);
309
return 1;
310
}
311
312
313
std::string
314
GUIDialog_ChooserAbstract::getObjectName(GUIGlObject* o) const {
315
if (myLocateByName) {
316
return o->getOptionalName();
317
} else {
318
return o->getMicrosimID();
319
}
320
}
321
322
void
323
GUIDialog_ChooserAbstract::refreshList(const std::vector<GUIGlID>& ids) {
324
myList->clearItems();
325
for (auto i : ids) {
326
GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
327
if (o == nullptr) {
328
continue;
329
}
330
const std::string& name = getObjectName(o);
331
const bool selected = myWindowsParent->isSelected(o);
332
FXIcon* const ico = selected ? GUIIconSubSys::getIcon(GUIIcon::FLAG) : nullptr;
333
myIDs.insert(o->getGlID());
334
myList->appendItem(name.c_str(), ico, (void*) & (*myIDs.find(o->getGlID())));
335
GUIGlObjectStorage::gIDStorage.unblockObject(i);
336
}
337
myList->update();
338
myCountLabel->setText(TLF("% objects", toString(ids.size())).c_str());
339
}
340
341
342
long
343
GUIDialog_ChooserAbstract::onCmdToggleSelection(FXObject*, FXSelector, void*) {
344
FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);
345
int i = myList->getCurrentItem();
346
if (i >= 0) {
347
toggleSelection(i);
348
if (myList->getItemIcon(i) == flag) {
349
myList->setItemIcon(i, nullptr);
350
} else {
351
myList->setItemIcon(i, flag);
352
}
353
}
354
myList->update();
355
myWindowsParent->getView()->update();
356
return 1;
357
}
358
359
360
long
361
GUIDialog_ChooserAbstract::onCmdAddListSelection(FXObject*, FXSelector, void*) {
362
FXIcon* flag = GUIIconSubSys::getIcon(GUIIcon::FLAG);
363
const int numItems = myList->getNumItems();
364
for (int i = 0; i < numItems; i++) {
365
select(i);
366
myList->setItemIcon(i, flag);
367
}
368
myList->update();
369
myWindowsParent->getView()->update();
370
return 1;
371
}
372
373
374
long
375
GUIDialog_ChooserAbstract::onCmdClearListSelection(FXObject*, FXSelector, void*) {
376
const int numItems = myList->getNumItems();
377
for (int i = 0; i < numItems; i++) {
378
deselect(i);
379
myList->setItemIcon(i, nullptr);
380
}
381
myList->update();
382
myWindowsParent->getView()->update();
383
return 1;
384
}
385
386
387
long
388
GUIDialog_ChooserAbstract::onCmdLocateByName(FXObject*, FXSelector, void*) {
389
std::vector<std::pair<std::string, GUIGlID> > namesAndIDs;
390
myLocateByName = true;
391
const int numItems = myList->getNumItems();
392
for (int i = 0; i < numItems; i++) {
393
GUIGlID glID = *static_cast<GUIGlID*>(myList->getItemData(i));
394
GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(glID);
395
if (o != 0) {
396
const std::string& name = getObjectName(o);
397
if (name != "") {
398
namesAndIDs.push_back(std::make_pair(name, glID));
399
}
400
}
401
GUIGlObjectStorage::gIDStorage.unblockObject(glID);
402
}
403
std::sort(namesAndIDs.begin(), namesAndIDs.end());
404
std::vector<GUIGlID> selectedGlIDs;
405
for (const auto& item : namesAndIDs) {
406
selectedGlIDs.push_back(item.second);
407
}
408
refreshList(selectedGlIDs);
409
myTextEntry->setFocus();
410
return 1;
411
}
412
413
long
414
GUIDialog_ChooserAbstract::onCmdUpdate(FXObject*, FXSelector, void*) {
415
refreshList(myWindowsParent->getObjectIDs(myMessageId));
416
return 1;
417
}
418
419
void
420
GUIDialog_ChooserAbstract::toggleSelection(int listIndex) {
421
GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
422
gSelected.toggleSelection(*glID);
423
}
424
425
void
426
GUIDialog_ChooserAbstract::select(int listIndex) {
427
GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
428
gSelected.select(*glID);
429
}
430
431
void
432
GUIDialog_ChooserAbstract::deselect(int listIndex) {
433
GUIGlID* glID = static_cast<GUIGlID*>(myList->getItemData(listIndex));
434
gSelected.deselect(*glID);
435
}
436
437
438
void
439
GUIDialog_ChooserAbstract::filterACs(const std::vector<GUIGlID>& /*GLIDs*/) {
440
// overrided in GNEACChooserDialog
441
}
442
443
/****************************************************************************/
444
445