Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/frames/common/GNEInspectorFrame.cpp
169685 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 GNEInspectorFrame.cpp
15
/// @author Jakob Erdmann
16
/// @author Pablo Alvarez Lopez
17
/// @date Mar 2011
18
///
19
// The Widget for modifying network-element attributes (i.e. lane speed)
20
/****************************************************************************/
21
22
#include <netedit/GNEApplicationWindow.h>
23
#include <netedit/GNENet.h>
24
#include <netedit/GNETagProperties.h>
25
#include <netedit/GNEUndoList.h>
26
#include <netedit/GNEViewParent.h>
27
#include <netedit/elements/network/GNEEdgeTemplate.h>
28
#include <netedit/frames/GNEAttributesEditor.h>
29
#include <netedit/frames/GNEElementTree.h>
30
#include <netedit/frames/GNEOverlappedInspection.h>
31
#include <netedit/frames/network/GNECreateEdgeFrame.h>
32
#include <utils/gui/div/GUIDesigns.h>
33
34
#include "GNEInspectorFrame.h"
35
36
// ===========================================================================
37
// FOX callback mapping
38
// ===========================================================================
39
40
FXDEFMAP(GNEInspectorFrame) GNEInspectorFrameMap[] = {
41
FXMAPFUNC(SEL_COMMAND, MID_GNE_INSPECTORFRAME_INSPECTPREVIOUSELEMENT, GNEInspectorFrame::onCmdInspectPreviousElement)
42
};
43
44
FXDEFMAP(GNEInspectorFrame::TemplateEditor) TemplateEditorMap[] = {
45
FXMAPFUNC(SEL_COMMAND, MID_HOTKEY_SHIFT_F1_TEMPLATE_SET, GNEInspectorFrame::TemplateEditor::onCmdSetTemplate),
46
FXMAPFUNC(SEL_COMMAND, MID_HOTKEY_SHIFT_F2_TEMPLATE_COPY, GNEInspectorFrame::TemplateEditor::onCmdCopyTemplate),
47
FXMAPFUNC(SEL_COMMAND, MID_HOTKEY_SHIFT_F3_TEMPLATE_CLEAR, GNEInspectorFrame::TemplateEditor::onCmdClearTemplate),
48
};
49
50
// Object implementation
51
FXIMPLEMENT(GNEInspectorFrame, FXVerticalFrame, GNEInspectorFrameMap, ARRAYNUMBER(GNEInspectorFrameMap))
52
FXIMPLEMENT(GNEInspectorFrame::TemplateEditor, MFXGroupBoxModule, TemplateEditorMap, ARRAYNUMBER(TemplateEditorMap))
53
54
55
// ===========================================================================
56
// method definitions
57
// ===========================================================================
58
59
// ---------------------------------------------------------------------------
60
// GNEInspectorFrame::TemplateEditor - methods
61
// ---------------------------------------------------------------------------
62
63
GNEInspectorFrame::TemplateEditor::TemplateEditor(GNEInspectorFrame* inspectorFrameParent) :
64
MFXGroupBoxModule(inspectorFrameParent, TL("Templates")),
65
myInspectorFrameParent(inspectorFrameParent),
66
myEdgeTemplate(nullptr) {
67
// Create set template button
68
mySetTemplateButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Set as Template"), "", "", nullptr, this, MID_HOTKEY_SHIFT_F1_TEMPLATE_SET, GUIDesignButton);
69
// Create copy template button
70
myCopyTemplateButton = GUIDesigns::buildFXButton(getCollapsableFrame(), "", "", "", nullptr, this, MID_HOTKEY_SHIFT_F2_TEMPLATE_COPY, GUIDesignButton);
71
// Create copy template button
72
myClearTemplateButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("clear Edge Template"), "", "", nullptr, this, MID_HOTKEY_SHIFT_F3_TEMPLATE_CLEAR, GUIDesignButton);
73
}
74
75
76
GNEInspectorFrame::TemplateEditor::~TemplateEditor() {
77
}
78
79
80
bool
81
GNEInspectorFrame::TemplateEditor::showTemplateEditor() {
82
// show template editor only if we're editing an edge in Network mode AND we have at least one inspected edge
83
if (myInspectorFrameParent->myViewNet->getEditModes().isCurrentSupermodeNetwork()) {
84
for (const auto& AC : myInspectorFrameParent->getViewNet()->getInspectedElements().getACs()) {
85
if (AC->getTagProperty()->getTag() == SUMO_TAG_EDGE) {
86
// update buttons and show module
87
updateButtons();
88
show();
89
return true;
90
}
91
}
92
}
93
return false;
94
}
95
96
97
void
98
GNEInspectorFrame::TemplateEditor::hideTemplateEditor() {
99
// hide template editor
100
hide();
101
}
102
103
104
GNEEdgeTemplate*
105
GNEInspectorFrame::TemplateEditor::getEdgeTemplate() const {
106
return myEdgeTemplate;
107
}
108
109
110
void
111
GNEInspectorFrame::TemplateEditor::setEdgeTemplate(const GNEEdge* edge) {
112
// delete previous template edge
113
if (myEdgeTemplate) {
114
delete myEdgeTemplate;
115
myEdgeTemplate = nullptr;
116
}
117
// update edge template
118
if (edge) {
119
myEdgeTemplate = new GNEEdgeTemplate(edge);
120
// use template by default
121
myInspectorFrameParent->myViewNet->getViewParent()->getCreateEdgeFrame()->setUseEdgeTemplate();
122
}
123
}
124
125
126
void
127
GNEInspectorFrame::TemplateEditor::updateEdgeTemplate() {
128
if (myEdgeTemplate) {
129
myEdgeTemplate->updateLaneTemplates();
130
// use template by default
131
myInspectorFrameParent->myViewNet->getViewParent()->getCreateEdgeFrame()->setUseEdgeTemplate();
132
}
133
}
134
135
void
136
GNEInspectorFrame::TemplateEditor::setTemplate() {
137
// check if template editor AND mySetTemplateButton is enabled
138
if (shown() && mySetTemplateButton->isEnabled()) {
139
onCmdSetTemplate(nullptr, 0, nullptr);
140
}
141
}
142
143
144
void
145
GNEInspectorFrame::TemplateEditor::copyTemplate() {
146
// check if template editor AND myCopyTemplateButton is enabled
147
if (shown() && myCopyTemplateButton->isEnabled()) {
148
onCmdCopyTemplate(nullptr, 0, nullptr);
149
}
150
}
151
152
153
void
154
GNEInspectorFrame::TemplateEditor::clearTemplate() {
155
// check if template editor AND myClearTemplateButton is enabled
156
if (shown() && myClearTemplateButton->isEnabled()) {
157
onCmdClearTemplate(nullptr, 0, nullptr);
158
}
159
}
160
161
162
long
163
GNEInspectorFrame::TemplateEditor::onCmdSetTemplate(FXObject*, FXSelector, void*) {
164
// apply to all selected edges
165
for (const auto& AC : myInspectorFrameParent->myViewNet->getInspectedElements().getACs()) {
166
if (AC->getTagProperty()->getTag() == SUMO_TAG_EDGE) {
167
// set template
168
setEdgeTemplate(myInspectorFrameParent->myViewNet->getNet()->getAttributeCarriers()->retrieveEdge(AC->getID()));
169
// update buttons
170
updateButtons();
171
}
172
}
173
return 1;
174
}
175
176
177
long
178
GNEInspectorFrame::TemplateEditor::onCmdCopyTemplate(FXObject*, FXSelector, void*) {
179
// first check
180
if (myEdgeTemplate) {
181
// begin copy template
182
myInspectorFrameParent->myViewNet->getUndoList()->begin(myEdgeTemplate, "copy edge template");
183
// iterate over inspected ACs
184
for (const auto& AC : myInspectorFrameParent->myViewNet->getInspectedElements().getACs()) {
185
// avoid copy template in the same edge
186
if (AC->getID() != myEdgeTemplate->getID()) {
187
// retrieve edge ID (and throw exception if edge doesn't exist)
188
myInspectorFrameParent->myViewNet->getNet()->getAttributeCarriers()->retrieveEdge(AC->getID())->copyTemplate(myEdgeTemplate, myInspectorFrameParent->myViewNet->getUndoList());
189
}
190
}
191
// end copy template
192
myInspectorFrameParent->myViewNet->getUndoList()->end();
193
// refresh inspector parent
194
myInspectorFrameParent->myAttributesEditor->refreshAttributesEditor();
195
}
196
return 1;
197
}
198
199
200
long
201
GNEInspectorFrame::TemplateEditor::onCmdClearTemplate(FXObject*, FXSelector, void*) {
202
// set null edge
203
setEdgeTemplate(nullptr);
204
// update buttons
205
updateButtons();
206
return 1;
207
}
208
209
210
void
211
GNEInspectorFrame::TemplateEditor::updateButtons() {
212
const auto& inspectedElements = myInspectorFrameParent->getViewNet()->getInspectedElements();
213
// only show set template button if we have exactly one inspected edge
214
if (inspectedElements.isInspectingSingleElement() && (inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_EDGE)) {
215
mySetTemplateButton->setText((TLF("Set edge '%' as Template", inspectedElements.getFirstAC()->getID())).c_str());
216
mySetTemplateButton->show();
217
} else {
218
mySetTemplateButton->hide();
219
}
220
// enable or disable clear buttons depending of myEdgeTemplate
221
if (myEdgeTemplate) {
222
// update caption of copy button
223
if (inspectedElements.isInspectingSingleElement()) {
224
myCopyTemplateButton->setText(("Copy '" + myEdgeTemplate->getID() + "' into edge '" + inspectedElements.getFirstAC()->getID() + "'").c_str());
225
} else {
226
myCopyTemplateButton->setText(("Copy '" + myEdgeTemplate->getID() + "' into " + toString(inspectedElements.getACs().size()) + " selected edges").c_str());
227
}
228
// enable set and clear buttons
229
myCopyTemplateButton->enable();
230
myClearTemplateButton->enable();
231
} else {
232
// update caption of copy button
233
myCopyTemplateButton->setText(TL("No edge Template Set"));
234
// disable set and clear buttons
235
myCopyTemplateButton->disable();
236
myClearTemplateButton->disable();
237
}
238
}
239
240
// ---------------------------------------------------------------------------
241
// GNEInspectorFrame - methods
242
// ---------------------------------------------------------------------------
243
244
GNEInspectorFrame::GNEInspectorFrame(GNEViewParent* viewParent, GNEViewNet* viewNet) :
245
GNEFrame(viewParent, viewNet, "Inspector") {
246
247
// Create back button
248
myBackButton = GUIDesigns::buildFXButton(myHeaderLeftFrame, "", "", "", GUIIconSubSys::getIcon(GUIIcon::BIGARROWLEFT),
249
this, MID_GNE_INSPECTORFRAME_INSPECTPREVIOUSELEMENT, GUIDesignButtonRectangular);
250
myHeaderLeftFrame->hide();
251
myBackButton->hide();
252
253
// Create Overlapped Inspection module
254
myOverlappedInspection = new GNEOverlappedInspection(this, false);
255
256
// Create Attributes Editor module
257
myAttributesEditor = new GNEAttributesEditor(this, GNEAttributesEditorType::EditorType::EDITOR);
258
259
// Create Template editor module
260
myTemplateEditor = new TemplateEditor(this);
261
262
// Create GNEElementTree module
263
myHierarchicalElementTree = new GNEElementTree(this);
264
}
265
266
267
GNEInspectorFrame::~GNEInspectorFrame() {}
268
269
270
void
271
GNEInspectorFrame::show() {
272
refreshInspection();
273
// stop reparenting
274
myAttributesEditor->abortReparenting();
275
// show
276
GNEFrame::show();
277
}
278
279
280
void
281
GNEInspectorFrame::hide() {
282
myViewNet->getInspectedElements().inspectACs({});
283
GNEFrame::hide();
284
}
285
286
287
bool
288
GNEInspectorFrame::inspectClickedElements(GNEViewNetHelper::ViewObjectsSelector& viewObjects,
289
const Position& clickedPosition, const bool shiftKeyPressed) {
290
// get unlocked attribute carrier front
291
auto AC = viewObjects.getAttributeCarrierFront();
292
// first check if we have clicked over an Attribute Carrier
293
if (AC) {
294
// if Control key is Pressed, select instead inspect element
295
if (myViewNet->getMouseButtonKeyPressed().controlKeyPressed()) {
296
// toggle networkElement selection
297
if (AC->isAttributeCarrierSelected()) {
298
AC->unselectAttributeCarrier();
299
} else {
300
AC->selectAttributeCarrier();
301
}
302
} else {
303
// show Overlapped Inspection module
304
myOverlappedInspection->showOverlappedInspection(viewObjects, clickedPosition, shiftKeyPressed);
305
// focus upper element of inspector frame
306
focusUpperElement();
307
}
308
return true;
309
} else {
310
return false;
311
}
312
}
313
314
315
void
316
GNEInspectorFrame::inspectElement(GNEAttributeCarrier* AC, GNEAttributeCarrier* previousInspectedAC) {
317
std::vector<GNEAttributeCarrier*> itemsToInspect;
318
// Use the implementation of inspect for multiple AttributeCarriers to avoid repetition of code
319
if (AC) {
320
if (AC->isAttributeCarrierSelected() && !myViewNet->getMouseButtonKeyPressed().altKeyPressed()) {
321
// obtain selected ACs depending of current supermode
322
const auto selectedACs = myViewNet->getNet()->getAttributeCarriers()->getSelectedAttributeCarriers(false);
323
// reserve space
324
itemsToInspect.reserve(selectedACs.size());
325
// iterate over selected ACs
326
for (const auto& selectedAC : selectedACs) {
327
// filter ACs to inspect using Tag as criterion
328
if (selectedAC->getTagProperty()->getTag() == AC->getTagProperty()->getTag()) {
329
itemsToInspect.push_back(selectedAC);
330
}
331
}
332
} else {
333
itemsToInspect.push_back(AC);
334
}
335
}
336
inspectElements(itemsToInspect, previousInspectedAC);
337
}
338
339
void
340
GNEInspectorFrame::inspectElements(const std::vector<GNEAttributeCarrier*>& ACs, GNEAttributeCarrier* previousInspectedAC) {
341
myViewNet->getInspectedElements().inspectACs(ACs);
342
myPreviousInspectedAC = previousInspectedAC;
343
refreshInspection();
344
}
345
346
347
void
348
GNEInspectorFrame::clearInspection() {
349
// simply clear overlapped inspection (it refresh inspector frame)
350
myOverlappedInspection->clearOverlappedInspection();
351
}
352
353
354
void
355
GNEInspectorFrame::refreshInspection() {
356
const auto& inspectedElements = myViewNet->getInspectedElements();
357
// check if show back button
358
if (myPreviousInspectedAC) {
359
myHeaderLeftFrame->show();
360
myBackButton->show();
361
} else {
362
myHeaderLeftFrame->hide();
363
myBackButton->hide();
364
}
365
// Show all attribute editors (will be automatically hidden if there are no elements to inspect)
366
myAttributesEditor->showAttributesEditor(inspectedElements.getACs(), true);
367
// Hide other moduls
368
myTemplateEditor->hideTemplateEditor();
369
myHierarchicalElementTree->hideHierarchicalElementTree();
370
// If vector of attribute Carriers contain data
371
if (inspectedElements.isInspectingElements()) {
372
// Set header
373
std::string headerString;
374
if (inspectedElements.getFirstAC()->getTagProperty()->isNetworkElement()) {
375
headerString = "Net: ";
376
} else if (inspectedElements.getFirstAC()->getTagProperty()->isAdditionalElement()) {
377
headerString = "Additional: ";
378
} else if (inspectedElements.getFirstAC()->getTagProperty()->isShapeElement()) {
379
headerString = "Shape: ";
380
} else if (inspectedElements.getFirstAC()->getTagProperty()->isTAZElement()) {
381
headerString = "TAZ: ";
382
} else if (inspectedElements.getFirstAC()->getTagProperty()->isWireElement()) {
383
headerString = "WIRE: ";
384
} else if (inspectedElements.getFirstAC()->getTagProperty()->isVehicle()) {
385
headerString = "Vehicle: ";
386
} else if (inspectedElements.getFirstAC()->getTagProperty()->isRoute()) {
387
headerString = "Route: ";
388
} else if (inspectedElements.getFirstAC()->getTagProperty()->isPerson()) {
389
headerString = "Person: ";
390
} else if (inspectedElements.getFirstAC()->getTagProperty()->isPlanPerson()) {
391
headerString = "PersonPlan: ";
392
} else if (inspectedElements.getFirstAC()->getTagProperty()->isContainer()) {
393
headerString = "Container: ";
394
} else if (inspectedElements.getFirstAC()->getTagProperty()->isPlanContainer()) {
395
headerString = "ContainerPlan: ";
396
} else if (inspectedElements.getFirstAC()->getTagProperty()->isVehicleStop()) {
397
headerString = "Stop: ";
398
} else if (inspectedElements.getFirstAC()->getTagProperty()->isDataElement()) {
399
headerString = "Data: ";
400
}
401
if (myViewNet->getInspectedElements().isInspectingMultipleElements()) {
402
headerString += toString(inspectedElements.getACs().size()) + " ";
403
}
404
headerString += inspectedElements.getFirstAC()->getTagStr();
405
if (myViewNet->getInspectedElements().isInspectingMultipleElements()) {
406
headerString += "s";
407
}
408
// Set headerString into header label
409
getFrameHeaderLabel()->setText(headerString.c_str());
410
411
// If attributes correspond to an Edge and we aren't in demand mode, show template editor
412
myTemplateEditor->showTemplateEditor();
413
414
// if we inspect a single Attribute carrier vector, show their children
415
if (inspectedElements.isInspectingSingleElement()) {
416
myHierarchicalElementTree->showHierarchicalElementTree(inspectedElements.getFirstAC());
417
}
418
} else {
419
getFrameHeaderLabel()->setText(TL("Inspect"));
420
myOverlappedInspection->hiderOverlappedInspection();
421
}
422
// update frame width
423
setFrameWidth(myViewNet->getViewParent()->getFrameAreaWidth());
424
// update viewNet
425
myViewNet->update();
426
}
427
428
429
GNEAttributesEditor*
430
GNEInspectorFrame::getAttributesEditor() const {
431
return myAttributesEditor;
432
}
433
434
435
GNEInspectorFrame::TemplateEditor*
436
GNEInspectorFrame::getTemplateEditor() const {
437
return myTemplateEditor;
438
}
439
440
441
GNEOverlappedInspection*
442
GNEInspectorFrame::getOverlappedInspection() const {
443
return myOverlappedInspection;
444
}
445
446
447
GNEElementTree*
448
GNEInspectorFrame::getHierarchicalElementTree() const {
449
return myHierarchicalElementTree;
450
}
451
452
453
long
454
GNEInspectorFrame::onCmdInspectPreviousElement(FXObject*, FXSelector, void*) {
455
inspectElement(myPreviousInspectedAC, nullptr);
456
return 1;
457
}
458
459
460
void
461
GNEInspectorFrame::updateFrameAfterUndoRedo() {
462
refreshInspection();
463
}
464
465
466
void
467
GNEInspectorFrame::selectedOverlappedElement(GNEAttributeCarrier* AC) {
468
inspectElement(AC);
469
// update view (due dotted contour)
470
myViewNet->updateViewNet();
471
}
472
473
/****************************************************************************/
474
475