Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/frames/GNEElementTree.cpp
169678 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 GNEElementTree.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Mar 2022
17
///
18
// Frame for show hierarchical elements
19
/****************************************************************************/
20
21
#include <netedit/GNEApplicationWindow.h>
22
#include <netedit/GNENet.h>
23
#include <netedit/GNETagProperties.h>
24
#include <netedit/GNEUndoList.h>
25
#include <netedit/GNEViewNet.h>
26
#include <netedit/GNEViewParent.h>
27
#include <netedit/changes/GNEChange_Children.h>
28
#include <netedit/elements/data/GNEDataInterval.h>
29
#include <netedit/elements/network/GNEConnection.h>
30
#include <netedit/elements/network/GNECrossing.h>
31
#include <netedit/frames/common/GNEInspectorFrame.h>
32
#include <utils/foxtools/MFXMenuHeader.h>
33
#include <utils/gui/div/GUIDesigns.h>
34
#include <utils/gui/windows/GUIAppEnum.h>
35
36
#include "GNEElementTree.h"
37
38
// ===========================================================================
39
// FOX callback mapping
40
// ===========================================================================
41
42
FXDEFMAP(GNEElementTree) HierarchicalElementTreeMap[] = {
43
FXMAPFUNC(SEL_COMMAND, MID_GNE_CENTER, GNEElementTree::onCmdCenterItem),
44
FXMAPFUNC(SEL_COMMAND, MID_GNE_INSPECT, GNEElementTree::onCmdInspectItem),
45
FXMAPFUNC(SEL_COMMAND, MID_GNE_DELETE, GNEElementTree::onCmdDeleteItem),
46
FXMAPFUNC(SEL_COMMAND, MID_GNE_ACHIERARCHY_MOVEUP, GNEElementTree::onCmdMoveItemUp),
47
FXMAPFUNC(SEL_COMMAND, MID_GNE_ACHIERARCHY_MOVEDOWN, GNEElementTree::onCmdMoveItemDown),
48
FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, MID_GNE_ACHIERARCHY_SHOWCHILDMENU, GNEElementTree::onCmdShowChildMenu)
49
};
50
51
52
// Object implementation
53
FXIMPLEMENT(GNEElementTree, MFXGroupBoxModule, HierarchicalElementTreeMap, ARRAYNUMBER(HierarchicalElementTreeMap))
54
55
// ===========================================================================
56
// method definitions
57
// ===========================================================================
58
59
GNEElementTree::GNEElementTree(GNEFrame* frameParent) :
60
MFXGroupBoxModule(frameParent, TL("Hierarchy")),
61
myFrameParent(frameParent) {
62
// Create tree list with fixed height
63
myTreeListDynamic = new MFXTreeListDynamic(getCollapsableFrame(), this, MID_GNE_ACHIERARCHY_SHOWCHILDMENU, GUIDesignTreeListFixedHeight);
64
hide();
65
}
66
67
68
GNEElementTree::~GNEElementTree() {}
69
70
71
void
72
GNEElementTree::showHierarchicalElementTree(GNEAttributeCarrier* AC) {
73
myHierarchicalElement = AC;
74
// show GNEElementTree and refresh GNEElementTree
75
if (myHierarchicalElement) {
76
// refresh GNEElementTree
77
refreshHierarchicalElementTree();
78
// show myTreeListDynamic
79
myTreeListDynamic->show();
80
// show module
81
show();
82
}
83
}
84
85
86
void
87
GNEElementTree::hideHierarchicalElementTree() {
88
// set all pointers null
89
myHierarchicalElement = nullptr;
90
myClickedAC = nullptr;
91
myClickedJunction = nullptr;
92
myClickedEdge = nullptr;
93
myClickedLane = nullptr;
94
myClickedCrossing = nullptr;
95
myClickedConnection = nullptr;
96
myClickedAdditional = nullptr;
97
myClickedTAZSourceSink = nullptr;
98
myClickedDemandElement = nullptr;
99
myClickedDataSet = nullptr;
100
myClickedDataInterval = nullptr;
101
myClickedGenericData = nullptr;
102
// hide myTreeListDynamic
103
myTreeListDynamic->hide();
104
// hide module
105
hide();
106
}
107
108
109
void
110
GNEElementTree::refreshHierarchicalElementTree() {
111
// clear items
112
myTreeListDynamic->clearItems();
113
myTreeItemToACMap.clear();
114
myTreeItemsConnections.clear();
115
// show children of myHE
116
if (myHierarchicalElement) {
117
showHierarchicalElementChildren(myHierarchicalElement, showAttributeCarrierParents());
118
}
119
}
120
121
122
void
123
GNEElementTree::removeCurrentEditedAttributeCarrier(const GNEAttributeCarrier* AC) {
124
// simply check if AC is the same of myHE
125
if (AC == myHierarchicalElement) {
126
myHierarchicalElement = nullptr;
127
}
128
}
129
130
131
long
132
GNEElementTree::onCmdShowChildMenu(FXObject*, FXSelector, void* eventData) {
133
// obtain event
134
FXEvent* e = (FXEvent*)eventData;
135
// obtain FXTreeItem in the given position
136
FXTreeItem* item = myTreeListDynamic->getItemAt(e->win_x, e->win_y);
137
// open Pop-up if FXTreeItem has a Attribute Carrier vinculated
138
if (item && (myTreeItemsConnections.find(item) == myTreeItemsConnections.end())) {
139
createPopUpMenu(e->root_x, e->root_y, myTreeItemToACMap[item]);
140
}
141
return 1;
142
}
143
144
145
long
146
GNEElementTree::onCmdCenterItem(FXObject*, FXSelector, void*) {
147
// Center item
148
if (myClickedJunction) {
149
myFrameParent->getViewNet()->centerTo(myClickedJunction->getGlID(), true, -1);
150
} else if (myClickedEdge) {
151
myFrameParent->getViewNet()->centerTo(myClickedEdge->getGlID(), true, -1);
152
} else if (myClickedLane) {
153
myFrameParent->getViewNet()->centerTo(myClickedLane->getGlID(), true, -1);
154
} else if (myClickedCrossing) {
155
myFrameParent->getViewNet()->centerTo(myClickedCrossing->getGlID(), true, -1);
156
} else if (myClickedConnection) {
157
myFrameParent->getViewNet()->centerTo(myClickedConnection->getGlID(), true, -1);
158
} else if (myClickedAdditional) {
159
myFrameParent->getViewNet()->centerTo(myClickedAdditional->getGlID(), true, -1);
160
} else if (myClickedTAZSourceSink) {
161
myFrameParent->getViewNet()->centerTo(myClickedTAZSourceSink->getParentEdges().front()->getGlID(), true, -1);
162
} else if (myClickedDemandElement) {
163
myFrameParent->getViewNet()->centerTo(myClickedDemandElement->getGlID(), true, -1);
164
} else if (myClickedGenericData) {
165
myFrameParent->getViewNet()->centerTo(myClickedGenericData->getGlID(), true, -1);
166
}
167
// update view after centering
168
myFrameParent->getViewNet()->updateViewNet();
169
return 1;
170
}
171
172
173
long
174
GNEElementTree::onCmdInspectItem(FXObject*, FXSelector, void*) {
175
myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->inspectElement(myClickedAC, myHierarchicalElement);
176
return 1;
177
}
178
179
180
long
181
GNEElementTree::onCmdDeleteItem(FXObject*, FXSelector, void*) {
182
const auto& inspectedElements = myFrameParent->getViewNet()->getInspectedElements();
183
// Remove Attribute Carrier
184
if (myClickedJunction) {
185
myFrameParent->getViewNet()->getNet()->deleteJunction(myClickedJunction, myFrameParent->getViewNet()->getUndoList());
186
} else if (myClickedEdge) {
187
myFrameParent->getViewNet()->getNet()->deleteEdge(myClickedEdge, myFrameParent->getViewNet()->getUndoList(), false);
188
} else if (myClickedLane) {
189
myFrameParent->getViewNet()->getNet()->deleteLane(myClickedLane, myFrameParent->getViewNet()->getUndoList(), false);
190
} else if (myClickedCrossing) {
191
myFrameParent->getViewNet()->getNet()->deleteCrossing(myClickedCrossing, myFrameParent->getViewNet()->getUndoList());
192
} else if (myClickedConnection) {
193
myFrameParent->getViewNet()->getNet()->deleteConnection(myClickedConnection, myFrameParent->getViewNet()->getUndoList());
194
} else if (myClickedAdditional) {
195
myFrameParent->getViewNet()->getNet()->deleteAdditional(myClickedAdditional, myFrameParent->getViewNet()->getUndoList());
196
} else if (myClickedTAZSourceSink) {
197
myFrameParent->getViewNet()->getNet()->deleteTAZSourceSink(myClickedTAZSourceSink, myFrameParent->getViewNet()->getUndoList());
198
} else if (myClickedDemandElement) {
199
// check that default VTypes aren't removed
200
if ((myClickedDemandElement->getTagProperty()->getTag() == SUMO_TAG_VTYPE) && (GNEAttributeCarrier::parse<bool>(myClickedDemandElement->getAttribute(GNE_ATTR_DEFAULT_VTYPE)))) {
201
WRITE_WARNINGF(TL("Default Vehicle Type '%' cannot be removed"), myClickedDemandElement->getAttribute(SUMO_ATTR_ID));
202
return 1;
203
} else if (myClickedDemandElement->getTagProperty()->isPlan()) {
204
// we need to check if we're removing the last person plan of a person.
205
auto planParent = myClickedDemandElement->getParentDemandElements().front();
206
if (planParent->getChildDemandElements().size() == 1) {
207
myFrameParent->getViewNet()->getNet()->deleteDemandElement(planParent, myFrameParent->getViewNet()->getUndoList());
208
} else {
209
myFrameParent->getViewNet()->getNet()->deleteDemandElement(myClickedDemandElement, myFrameParent->getViewNet()->getUndoList());
210
}
211
}
212
} else if (myClickedDataSet) {
213
myFrameParent->getViewNet()->getNet()->deleteDataSet(myClickedDataSet, myFrameParent->getViewNet()->getUndoList());
214
} else if (myClickedDataInterval) {
215
// check if we have to remove data Set
216
if (myClickedDataInterval->getDataSetParent()->getDataIntervalChildren().size() == 1) {
217
myFrameParent->getViewNet()->getNet()->deleteDataSet(myClickedDataInterval->getDataSetParent(), myFrameParent->getViewNet()->getUndoList());
218
} else {
219
myFrameParent->getViewNet()->getNet()->deleteDataInterval(myClickedDataInterval, myFrameParent->getViewNet()->getUndoList());
220
}
221
} else if (myClickedGenericData) {
222
// check if we have to remove interval
223
if (myClickedGenericData->getDataIntervalParent()->getGenericDataChildren().size() == 1) {
224
// check if we have to remove data Set
225
if (myClickedGenericData->getDataIntervalParent()->getDataSetParent()->getDataIntervalChildren().size() == 1) {
226
myFrameParent->getViewNet()->getNet()->deleteDataSet(myClickedGenericData->getDataIntervalParent()->getDataSetParent(), myFrameParent->getViewNet()->getUndoList());
227
} else {
228
myFrameParent->getViewNet()->getNet()->deleteDataInterval(myClickedGenericData->getDataIntervalParent(), myFrameParent->getViewNet()->getUndoList());
229
}
230
} else {
231
myFrameParent->getViewNet()->getNet()->deleteGenericData(myClickedGenericData, myFrameParent->getViewNet()->getUndoList());
232
}
233
}
234
// refresh AC Hierarchy
235
refreshHierarchicalElementTree();
236
// check if inspector frame has to be shown again
237
if (inspectedElements.isInspectingSingleElement()) {
238
if (inspectedElements.getFirstAC() != myClickedAC) {
239
myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->inspectElement(inspectedElements.getFirstAC());
240
} else {
241
// inspect a nullptr element to reset inspector frame
242
myFrameParent->getViewNet()->getViewParent()->getInspectorFrame()->clearInspection();
243
}
244
}
245
return 1;
246
}
247
248
249
long
250
GNEElementTree::onCmdMoveItemUp(FXObject*, FXSelector, void*) {
251
// currently only children of demand elements can be moved
252
if (myClickedDemandElement) {
253
myFrameParent->getViewNet()->getUndoList()->begin(myClickedDemandElement, ("moving up " + myClickedDemandElement->getTagStr()).c_str());
254
// move element one position back
255
myFrameParent->getViewNet()->getUndoList()->add(new GNEChange_Children(myClickedDemandElement->getParentDemandElements().at(0), myClickedDemandElement,
256
GNEChange_Children::Operation::MOVE_BACK), true);
257
myFrameParent->getViewNet()->getUndoList()->end();
258
}
259
// refresh after moving child
260
refreshHierarchicalElementTree();
261
return 1;
262
}
263
264
265
long
266
GNEElementTree::onCmdMoveItemDown(FXObject*, FXSelector, void*) {
267
// currently only children of demand elements can be moved
268
if (myClickedDemandElement) {
269
myFrameParent->getViewNet()->getUndoList()->begin(myClickedDemandElement, ("moving down " + myClickedDemandElement->getTagStr()).c_str());
270
// move element one position front
271
myFrameParent->getViewNet()->getUndoList()->add(new GNEChange_Children(myClickedDemandElement->getParentDemandElements().at(0), myClickedDemandElement,
272
GNEChange_Children::Operation::MOVE_FRONT), true);
273
myFrameParent->getViewNet()->getUndoList()->end();
274
}
275
// refresh after moving child
276
refreshHierarchicalElementTree();
277
return 1;
278
}
279
280
281
void
282
GNEElementTree::createPopUpMenu(int X, int Y, GNEAttributeCarrier* clickedAC) {
283
// get attributeCarriers
284
const auto& attributeCarriers = myFrameParent->getViewNet()->getNet()->getAttributeCarriers();
285
// first check that AC exist
286
if (clickedAC) {
287
// set current clicked AC
288
myClickedAC = clickedAC;
289
// cast all elements
290
myClickedJunction = attributeCarriers->retrieveJunction(clickedAC->getID(), false);
291
myClickedEdge = attributeCarriers->retrieveEdge(clickedAC->getID(), false);
292
myClickedLane = attributeCarriers->retrieveLane(clickedAC->getGUIGlObject(), false);
293
myClickedCrossing = attributeCarriers->retrieveCrossing(clickedAC->getGUIGlObject(), false);
294
myClickedConnection = attributeCarriers->retrieveConnection(clickedAC->getGUIGlObject(), false);
295
myClickedAdditional = attributeCarriers->retrieveAdditional(clickedAC->getGUIGlObject(), false);
296
myClickedTAZSourceSink = attributeCarriers->retrieveTAZSourceSink(clickedAC, false);
297
myClickedDemandElement = attributeCarriers->retrieveDemandElement(clickedAC->getGUIGlObject(), false);
298
myClickedDataSet = attributeCarriers->retrieveDataSet(clickedAC->getID(), false);
299
myClickedDataInterval = attributeCarriers->retrieveDataInterval(clickedAC, false);
300
myClickedGenericData = attributeCarriers->retrieveGenericData(clickedAC->getGUIGlObject(), false);
301
// create FXMenuPane
302
FXMenuPane* pane = new FXMenuPane(myTreeListDynamic->getFXWindow());
303
// set item name and icon
304
new MFXMenuHeader(pane, myFrameParent->getViewNet()->getViewParent()->getGUIMainWindow()->getBoldFont(), myClickedAC->getPopUpID().c_str(), myClickedAC->getACIcon());
305
// add extra info for TAZ Source Sinks
306
if (myClickedTAZSourceSink) {
307
new FXMenuSeparator(pane);
308
GUIDesigns::buildFXMenuCommand(pane, TLF("Edge: %", myClickedTAZSourceSink->getParentEdges().front()->getID()), nullptr, nullptr, 0);
309
}
310
// insert separator
311
new FXMenuSeparator(pane);
312
// create center menu command
313
FXMenuCommand* centerMenuCommand = GUIDesigns::buildFXMenuCommand(pane, TL("Center"), GUIIconSubSys::getIcon(GUIIcon::RECENTERVIEW), this, MID_GNE_CENTER);
314
// disable Centering for Vehicle Types, data sets and data intervals
315
if (myClickedAC->getTagProperty()->isType() || (myClickedAC->getTagProperty()->getTag() == SUMO_TAG_DATASET) ||
316
(myClickedAC->getTagProperty()->getTag() == SUMO_TAG_DATAINTERVAL)) {
317
centerMenuCommand->disable();
318
}
319
// create inspect and delete menu commands
320
FXMenuCommand* inspectMenuCommand = GUIDesigns::buildFXMenuCommand(pane, TL("Inspect"), GUIIconSubSys::getIcon(GUIIcon::MODEINSPECT), this, MID_GNE_INSPECT);
321
FXMenuCommand* deleteMenuCommand = GUIDesigns::buildFXMenuCommand(pane, TL("Delete"), GUIIconSubSys::getIcon(GUIIcon::MODEDELETE), this, MID_GNE_DELETE);
322
// check if inspect and delete menu commands has to be disabled
323
if (!isSupermodeValid(myClickedAC)) {
324
inspectMenuCommand->disable();
325
deleteMenuCommand->disable();
326
}
327
// now check if given AC support manually moving of their item up and down (Currently only for certain demand elements)
328
/* if (myClickedDemandElement && myClickedAC->getTagProperty()->canBeSortedManually()) {
329
// insert separator
330
new FXMenuSeparator(pane);
331
// create both moving menu commands
332
FXMenuCommand* moveUpMenuCommand = GUIDesigns::buildFXMenuCommand(pane, "Move up", GUIIconSubSys::getIcon(GUIIcon::ARROW_UP), this, MID_GNE_ACHIERARCHY_MOVEUP);
333
FXMenuCommand* moveDownMenuCommand = GUIDesigns::buildFXMenuCommand(pane, "Move down", GUIIconSubSys::getIcon(GUIIcon::ARROW_DOWN), this, MID_GNE_ACHIERARCHY_MOVEDOWN);
334
// check if both commands has to be disabled
335
if (myClickedDemandElement->getTagProperty()->isPlanStopPerson()) {
336
moveUpMenuCommand->setText(TL("Move up (Stops cannot be moved)"));
337
moveDownMenuCommand->setText(TL("Move down (Stops cannot be moved)"));
338
moveUpMenuCommand->disable();
339
moveDownMenuCommand->disable();
340
} else {
341
// check if moveUpMenuCommand has to be disabled
342
if (myClickedDemandElement->getParentDemandElements().front()->getChildDemandElements().front() == myClickedDemandElement) {
343
moveUpMenuCommand->setText(TL("Move up (It's already the first element)"));
344
moveUpMenuCommand->disable();
345
} else if (myClickedDemandElement->getParentDemandElements().front()->getPreviousChildDemandElement(myClickedDemandElement)->getTagProperty()->isPlanStopPerson()) {
346
moveUpMenuCommand->setText(TL("Move up (Previous element is a Stop)"));
347
moveUpMenuCommand->disable();
348
}
349
// check if moveDownMenuCommand has to be disabled
350
if (myClickedDemandElement->getParentDemandElements().front()->getChildDemandElements().back() == myClickedDemandElement) {
351
moveDownMenuCommand->setText(TL("Move down (It's already the last element)"));
352
moveDownMenuCommand->disable();
353
} else if (myClickedDemandElement->getParentDemandElements().front()->getNextChildDemandElement(myClickedDemandElement)->getTagProperty()->isPlanStopPerson()) {
354
moveDownMenuCommand->setText(TL("Move down (Next element is a Stop)"));
355
moveDownMenuCommand->disable();
356
}
357
}
358
} */
359
// Center in the mouse position and create pane
360
pane->setX(X);
361
pane->setY(Y);
362
pane->create();
363
pane->show();
364
} else {
365
// set all clicked elements to null
366
myClickedAC = nullptr;
367
myClickedJunction = nullptr;
368
myClickedEdge = nullptr;
369
myClickedLane = nullptr;
370
myClickedCrossing = nullptr;
371
myClickedConnection = nullptr;
372
myClickedAdditional = nullptr;
373
myClickedTAZSourceSink = nullptr;
374
myClickedDemandElement = nullptr;
375
myClickedDataSet = nullptr;
376
myClickedDataInterval = nullptr;
377
myClickedGenericData = nullptr;
378
}
379
}
380
381
382
FXTreeItem*
383
GNEElementTree::showAttributeCarrierParents() {
384
// get attributeCarriers
385
const auto& attributeCarriers = myFrameParent->getViewNet()->getNet()->getAttributeCarriers();
386
// check tags
387
if (myHierarchicalElement->getTagProperty()->isNetworkElement()) {
388
// check demand element type
389
switch (myHierarchicalElement->getTagProperty()->getTag()) {
390
case SUMO_TAG_EDGE: {
391
// obtain Edge
392
GNEEdge* edge = attributeCarriers->retrieveEdge(myHierarchicalElement->getID(), false);
393
if (edge == nullptr) {
394
return nullptr;
395
} else {
396
// insert Junctions of edge in tree (Parallel because an edge has always two Junctions)
397
FXTreeItem* junctionSourceItem = myTreeListDynamic->appendItem(nullptr, (edge->getFromJunction()->getHierarchyName() + TL(" origin")).c_str(), edge->getFromJunction()->getACIcon());
398
FXTreeItem* junctionDestinationItem = myTreeListDynamic->appendItem(nullptr, (edge->getFromJunction()->getHierarchyName() + TL(" destination")).c_str(), edge->getFromJunction()->getACIcon());
399
junctionDestinationItem->setExpanded(true);
400
// Save items in myTreeItemToACMap
401
myTreeItemToACMap[junctionSourceItem] = edge->getFromJunction();
402
myTreeItemToACMap[junctionDestinationItem] = edge->getToJunction();
403
// return junction destination Item
404
return junctionDestinationItem;
405
}
406
}
407
case SUMO_TAG_LANE: {
408
// obtain lane
409
GNELane* lane = attributeCarriers->retrieveLane(myHierarchicalElement->getID(), false);
410
if (lane == nullptr) {
411
return nullptr;
412
} else {
413
// obtain parent edge
414
GNEEdge* edge = attributeCarriers->retrieveEdge(lane->getParentEdge()->getID());
415
//insert Junctions of lane of edge in tree (Parallel because an edge has always two Junctions)
416
FXTreeItem* junctionSourceItem = myTreeListDynamic->appendItem(nullptr, (edge->getFromJunction()->getHierarchyName() + TL(" origin")).c_str(), edge->getFromJunction()->getACIcon());
417
FXTreeItem* junctionDestinationItem = myTreeListDynamic->appendItem(nullptr, (edge->getFromJunction()->getHierarchyName() + TL(" destination")).c_str(), edge->getFromJunction()->getACIcon());
418
junctionDestinationItem->setExpanded(true);
419
// Create edge item
420
FXTreeItem* edgeItem = myTreeListDynamic->appendItem(junctionDestinationItem, edge->getHierarchyName().c_str(), edge->getACIcon());
421
edgeItem->setExpanded(true);
422
// Save items in myTreeItemToACMap
423
myTreeItemToACMap[junctionSourceItem] = edge->getFromJunction();
424
myTreeItemToACMap[junctionDestinationItem] = edge->getToJunction();
425
myTreeItemToACMap[edgeItem] = edge;
426
// return edge item
427
return edgeItem;
428
}
429
}
430
case SUMO_TAG_CROSSING: {
431
// obtain crossing parent junction
432
auto crossing = attributeCarriers->retrieveCrossing(myHierarchicalElement->getGUIGlObject(), false);
433
if (crossing == nullptr) {
434
return nullptr;
435
} else {
436
GNEJunction* junction = crossing->getParentJunctions().front();
437
// create junction item
438
FXTreeItem* junctionItem = myTreeListDynamic->appendItem(nullptr, junction->getHierarchyName().c_str(), junction->getACIcon());
439
junctionItem->setExpanded(true);
440
// Save items in myTreeItemToACMap
441
myTreeItemToACMap[junctionItem] = junction;
442
// return junction Item
443
return junctionItem;
444
}
445
}
446
case SUMO_TAG_CONNECTION: {
447
// obtain Connection
448
GNEConnection* connection = attributeCarriers->retrieveConnection(myHierarchicalElement->getID(), false);
449
if (connection == nullptr) {
450
return nullptr;
451
} else {
452
// create edge from item
453
FXTreeItem* edgeFromItem = myTreeListDynamic->appendItem(nullptr, connection->getEdgeFrom()->getHierarchyName().c_str(), connection->getEdgeFrom()->getACIcon());
454
edgeFromItem->setExpanded(true);
455
// create edge to item
456
FXTreeItem* edgeToItem = myTreeListDynamic->appendItem(nullptr, connection->getEdgeTo()->getHierarchyName().c_str(), connection->getEdgeTo()->getACIcon());
457
edgeToItem->setExpanded(true);
458
// create connection item
459
FXTreeItem* connectionItem = myTreeListDynamic->appendItem(edgeToItem, connection->getHierarchyName().c_str(), connection->getACIcon());
460
connectionItem->setExpanded(true);
461
// Save items in myTreeItemToACMap
462
myTreeItemToACMap[edgeFromItem] = connection->getEdgeFrom();
463
myTreeItemToACMap[edgeToItem] = connection->getEdgeTo();
464
myTreeItemToACMap[connectionItem] = connection;
465
// return connection item
466
return connectionItem;
467
}
468
}
469
default:
470
break;
471
}
472
} else if (myHierarchicalElement->getTagProperty()->getTag() == GNE_TAG_POILANE) {
473
// Obtain POILane
474
const auto* POILane = attributeCarriers->retrieveAdditional(myHierarchicalElement->getGUIGlObject(), false);
475
if (POILane == nullptr) {
476
return nullptr;
477
} else {
478
// obtain parent lane
479
GNELane* lane = attributeCarriers->retrieveLane(POILane->getParentLanes().at(0)->getID());
480
// obtain parent edge
481
GNEEdge* edge = attributeCarriers->retrieveEdge(lane->getParentEdge()->getID());
482
//insert Junctions of lane of edge in tree (Parallel because an edge has always two Junctions)
483
FXTreeItem* junctionSourceItem = myTreeListDynamic->appendItem(nullptr, (edge->getFromJunction()->getHierarchyName() + TL(" origin")).c_str(), edge->getFromJunction()->getACIcon());
484
FXTreeItem* junctionDestinationItem = myTreeListDynamic->appendItem(nullptr, (edge->getFromJunction()->getHierarchyName() + TL(" destination")).c_str(), edge->getFromJunction()->getACIcon());
485
junctionDestinationItem->setExpanded(true);
486
// Create edge item
487
FXTreeItem* edgeItem = myTreeListDynamic->appendItem(junctionDestinationItem, edge->getHierarchyName().c_str(), edge->getACIcon());
488
edgeItem->setExpanded(true);
489
// Create lane item
490
FXTreeItem* laneItem = myTreeListDynamic->appendItem(edgeItem, lane->getHierarchyName().c_str(), lane->getACIcon());
491
laneItem->setExpanded(true);
492
// Save items in myTreeItemToACMap
493
myTreeItemToACMap[junctionSourceItem] = edge->getFromJunction();
494
myTreeItemToACMap[junctionDestinationItem] = edge->getToJunction();
495
myTreeItemToACMap[edgeItem] = edge;
496
myTreeItemToACMap[laneItem] = lane;
497
// return Lane item
498
return laneItem;
499
}
500
} else if (myHierarchicalElement->getTagProperty()->isAdditionalElement()) {
501
// Obtain Additional
502
const GNEAdditional* additional = attributeCarriers->retrieveAdditional(myHierarchicalElement->getGUIGlObject(), false);
503
if (additional == nullptr) {
504
return nullptr;
505
} else {
506
// declare auxiliary FXTreeItem, due a demand element can have multiple "roots"
507
FXTreeItem* root = nullptr;
508
// check if there is demand elements parents
509
if (additional->getParentAdditionals().size() > 0) {
510
// check if we have more than one edge
511
if (additional->getParentAdditionals().size() > 1) {
512
// insert first item
513
addListItem(additional->getParentAdditionals().front());
514
// insert "spacer"
515
if (additional->getParentAdditionals().size() > 2) {
516
addListItem(nullptr, ("..." + toString((int)additional->getParentAdditionals().size() - 2) + TL(" additionals...")).c_str(), 0, false);
517
}
518
}
519
// return last inserted item
520
root = addListItem(additional->getParentAdditionals().back());
521
}
522
// check if there is parent demand elements
523
if (additional->getParentDemandElements().size() > 0) {
524
// check if we have more than one demand element
525
if (additional->getParentDemandElements().size() > 1) {
526
// insert first item
527
addListItem(additional->getParentDemandElements().front());
528
// insert "spacer"
529
if (additional->getParentDemandElements().size() > 2) {
530
addListItem(nullptr, ("..." + toString((int)additional->getParentDemandElements().size() - 2) + TL(" demand elements...")).c_str(), 0, false);
531
}
532
}
533
// return last inserted item
534
root = addListItem(additional->getParentDemandElements().back());
535
}
536
// check if there is parent edges
537
if (additional->getParentEdges().size() > 0) {
538
// check if we have more than one edge
539
if (additional->getParentEdges().size() > 1) {
540
// insert first item
541
addListItem(additional->getParentEdges().front());
542
// insert "spacer"
543
if (additional->getParentEdges().size() > 2) {
544
addListItem(nullptr, ("..." + toString((int)additional->getParentEdges().size() - 2) + TL(" edges...")).c_str(), 0, false);
545
}
546
}
547
// return last inserted item
548
root = addListItem(additional->getParentEdges().back());
549
}
550
// check if there is parent lanes
551
if (additional->getParentLanes().size() > 0) {
552
// check if we have more than one parent lane
553
if (additional->getParentLanes().size() > 1) {
554
// insert first item
555
addListItem(additional->getParentLanes().front());
556
// insert "spacer"
557
if (additional->getParentLanes().size() > 2) {
558
addListItem(nullptr, ("..." + toString((int)additional->getParentLanes().size() - 2) + TL(" lanes...")).c_str(), 0, false);
559
}
560
}
561
// return last inserted item
562
root = addListItem(additional->getParentLanes().back());
563
}
564
// return last inserted list item
565
return root;
566
}
567
} else if (myHierarchicalElement->getTagProperty()->isTAZElement()) {
568
// Obtain TAZElement
569
const GNEAdditional* TAZElement = attributeCarriers->retrieveAdditional(myHierarchicalElement->getGUIGlObject(), false);
570
if (TAZElement == nullptr) {
571
return nullptr;
572
} else {
573
// declare auxiliary FXTreeItem, due a demand element can have multiple "roots"
574
FXTreeItem* root = nullptr;
575
// check if there is demand elements parents
576
if (TAZElement->getParentAdditionals().size() > 0) {
577
// check if we have more than one edge
578
if (TAZElement->getParentAdditionals().size() > 1) {
579
// insert first item
580
addListItem(TAZElement->getParentAdditionals().front());
581
// insert "spacer"
582
if (TAZElement->getParentAdditionals().size() > 2) {
583
addListItem(nullptr, ("..." + toString((int)TAZElement->getParentAdditionals().size() - 2) + TL(" TAZElements...")).c_str(), 0, false);
584
}
585
}
586
// return last inserted item
587
root = addListItem(TAZElement->getParentAdditionals().back());
588
}
589
// check if there is parent demand elements
590
if (TAZElement->getParentDemandElements().size() > 0) {
591
// check if we have more than one demand element
592
if (TAZElement->getParentDemandElements().size() > 1) {
593
// insert first item
594
addListItem(TAZElement->getParentDemandElements().front());
595
// insert "spacer"
596
if (TAZElement->getParentDemandElements().size() > 2) {
597
addListItem(nullptr, ("..." + toString((int)TAZElement->getParentDemandElements().size() - 2) + TL(" demand elements...")).c_str(), 0, false);
598
}
599
}
600
// return last inserted item
601
root = addListItem(TAZElement->getParentDemandElements().back());
602
}
603
// check if there is parent edges
604
if (TAZElement->getParentEdges().size() > 0) {
605
// check if we have more than one edge
606
if (TAZElement->getParentEdges().size() > 1) {
607
// insert first item
608
addListItem(TAZElement->getParentEdges().front());
609
// insert "spacer"
610
if (TAZElement->getParentEdges().size() > 2) {
611
addListItem(nullptr, ("..." + toString((int)TAZElement->getParentEdges().size() - 2) + TL(" edges...")).c_str(), 0, false);
612
}
613
}
614
// return last inserted item
615
root = addListItem(TAZElement->getParentEdges().back());
616
}
617
// check if there is parent lanes
618
if (TAZElement->getParentLanes().size() > 0) {
619
// check if we have more than one parent lane
620
if (TAZElement->getParentLanes().size() > 1) {
621
// insert first item
622
addListItem(TAZElement->getParentLanes().front());
623
// insert "spacer"
624
if (TAZElement->getParentLanes().size() > 2) {
625
addListItem(nullptr, ("..." + toString((int)TAZElement->getParentLanes().size() - 2) + TL(" lanes...")).c_str(), 0, false);
626
}
627
}
628
// return last inserted item
629
root = addListItem(TAZElement->getParentLanes().back());
630
}
631
// return last inserted list item
632
return root;
633
}
634
} else if (myHierarchicalElement->getTagProperty()->isDemandElement()) {
635
// Obtain DemandElement
636
GNEDemandElement* demandElement = attributeCarriers->retrieveDemandElement(myHierarchicalElement->getGUIGlObject(), false);
637
if (demandElement == nullptr) {
638
return nullptr;
639
} else {
640
// declare auxiliar FXTreeItem, due a demand element can have multiple "roots"
641
FXTreeItem* root = nullptr;
642
// check if there are demand element parents
643
if (demandElement->getParentAdditionals().size() > 0) {
644
// check if we have more than one edge
645
if (demandElement->getParentAdditionals().size() > 1) {
646
// insert first item
647
addListItem(demandElement->getParentAdditionals().front());
648
// insert "spacer"
649
if (demandElement->getParentAdditionals().size() > 2) {
650
addListItem(nullptr, ("..." + toString((int)demandElement->getParentAdditionals().size() - 2) + TL(" additionals...")).c_str(), 0, false);
651
}
652
}
653
// return last inserted item
654
root = addListItem(demandElement->getParentAdditionals().back());
655
}
656
// check if there is parent demand elements
657
if (demandElement->getParentDemandElements().size() > 0) {
658
// check if we have more than one demand element
659
if (demandElement->getParentDemandElements().size() > 1) {
660
// insert first item
661
addListItem(demandElement->getParentDemandElements().front());
662
// insert "spacer"
663
if (demandElement->getParentDemandElements().size() > 2) {
664
addListItem(nullptr, ("..." + toString((int)demandElement->getParentDemandElements().size() - 2) + TL(" demand elements...")).c_str(), 0, false);
665
}
666
}
667
// return last inserted item
668
root = addListItem(demandElement->getParentDemandElements().back());
669
}
670
// check if there is parent edges
671
if (demandElement->getParentEdges().size() > 0) {
672
// check if we have more than one edge
673
if (demandElement->getParentEdges().size() > 1) {
674
// insert first item
675
addListItem(demandElement->getParentEdges().front());
676
// insert "spacer"
677
if (demandElement->getParentEdges().size() > 2) {
678
addListItem(nullptr, ("..." + toString((int)demandElement->getParentEdges().size() - 2) + TL(" edges...")).c_str(), 0, false);
679
}
680
}
681
// return last inserted item
682
root = addListItem(demandElement->getParentEdges().back());
683
}
684
// check if there is parent lanes
685
if (demandElement->getParentLanes().size() > 0) {
686
// check if we have more than one parent lane
687
if (demandElement->getParentLanes().size() > 1) {
688
// insert first item
689
addListItem(demandElement->getParentLanes().front());
690
// insert "spacer"
691
if (demandElement->getParentLanes().size() > 2) {
692
addListItem(nullptr, ("..." + toString((int)demandElement->getParentLanes().size() - 2) + TL(" lanes...")).c_str(), 0, false);
693
}
694
}
695
// return last inserted item
696
root = addListItem(demandElement->getParentLanes().back());
697
}
698
// return last inserted list item
699
return root;
700
}
701
} else if (myHierarchicalElement->getTagProperty()->isDataElement()) {
702
// check if is a GNEDataInterval or a GNEGenericData
703
if (myHierarchicalElement->getTagProperty()->getTag() == SUMO_TAG_DATASET) {
704
return nullptr;
705
} else if (myHierarchicalElement->getTagProperty()->getTag() == SUMO_TAG_DATAINTERVAL) {
706
auto dataInterval = attributeCarriers->retrieveDataInterval(myHierarchicalElement, false);
707
if (dataInterval == nullptr) {
708
return nullptr;
709
} else {
710
return addListItem(dataInterval);
711
}
712
} else {
713
// Obtain DataElement
714
GNEGenericData* dataElement = dynamic_cast<GNEGenericData*>(myHierarchicalElement);
715
if (dataElement == nullptr) {
716
return nullptr;
717
} else {
718
// declare auxiliary FXTreeItem, due a data element can have multiple "roots"
719
FXTreeItem* root = nullptr;
720
// set dataset
721
addListItem(dataElement->getDataIntervalParent()->getDataSetParent());
722
// set data interval
723
addListItem(dataElement->getDataIntervalParent());
724
// check if there is data elements parents
725
if (dataElement->getParentAdditionals().size() > 0) {
726
// check if we have more than one edge
727
if (dataElement->getParentAdditionals().size() > 1) {
728
// insert first item
729
addListItem(dataElement->getParentAdditionals().front());
730
// insert "spacer"
731
if (dataElement->getParentAdditionals().size() > 2) {
732
addListItem(nullptr, ("..." + toString((int)dataElement->getParentAdditionals().size() - 2) + TL(" additionals...")).c_str(), 0, false);
733
}
734
}
735
// return last inserted item
736
root = addListItem(dataElement->getParentAdditionals().back());
737
}
738
// check if there is parent demand elements
739
if (dataElement->getParentDemandElements().size() > 0) {
740
// check if we have more than one demand element
741
if (dataElement->getParentDemandElements().size() > 1) {
742
// insert first item
743
addListItem(dataElement->getParentDemandElements().front());
744
// insert "spacer"
745
if (dataElement->getParentDemandElements().size() > 2) {
746
addListItem(nullptr, ("..." + toString((int)dataElement->getParentDemandElements().size() - 2) + TL(" demand elements...")).c_str(), 0, false);
747
}
748
}
749
// return last inserted item
750
root = addListItem(dataElement->getParentDemandElements().back());
751
}
752
// check if there is parent edges
753
if (dataElement->getParentEdges().size() > 0) {
754
// check if we have more than one edge
755
if (dataElement->getParentEdges().size() > 1) {
756
// insert first ege
757
if (dataElement->getTagProperty()->getTag() == SUMO_TAG_EDGEREL) {
758
addListItem(dataElement->getParentEdges().front(), nullptr, "from ");
759
} else {
760
addListItem(dataElement->getParentEdges().front());
761
}
762
// insert "spacer"
763
if (dataElement->getParentEdges().size() > 2) {
764
addListItem(nullptr, ("..." + toString((int)dataElement->getParentEdges().size() - 2) + TL(" edges...")).c_str(), 0, false);
765
}
766
}
767
// insert last ege
768
if (dataElement->getTagProperty()->getTag() == SUMO_TAG_EDGEREL) {
769
addListItem(dataElement->getParentEdges().back(), nullptr, "to ");
770
} else {
771
addListItem(dataElement->getParentEdges().back());
772
}
773
}
774
// check if there is parent lanes
775
if (dataElement->getParentLanes().size() > 0) {
776
// check if we have more than one parent lane
777
if (dataElement->getParentLanes().size() > 1) {
778
// insert first item
779
addListItem(dataElement->getParentLanes().front());
780
// insert "spacer"
781
if (dataElement->getParentLanes().size() > 2) {
782
addListItem(nullptr, ("..." + toString((int)dataElement->getParentLanes().size() - 2) + TL(" lanes...")).c_str(), 0, false);
783
}
784
}
785
// return last inserted item
786
root = addListItem(dataElement->getParentLanes().back());
787
}
788
// return last inserted list item
789
return root;
790
}
791
}
792
}
793
// no parents
794
return nullptr;
795
}
796
797
798
void
799
GNEElementTree::showHierarchicalElementChildren(GNEAttributeCarrier* hierarchicalElement, FXTreeItem* itemParent) {
800
// get attributeCarriers
801
const auto& attributeCarriers = myFrameParent->getViewNet()->getNet()->getAttributeCarriers();
802
// create item
803
FXTreeItem* item = addListItem(hierarchicalElement, itemParent);
804
// junctions
805
for (const auto& junction : hierarchicalElement->getHierarchicalElement()->getChildJunctions()) {
806
showHierarchicalElementChildren(junction, item);
807
}
808
// edges
809
for (const auto& edge : hierarchicalElement->getHierarchicalElement()->getChildEdges()) {
810
showHierarchicalElementChildren(edge, item);
811
}
812
// lanes
813
for (const auto& lane : hierarchicalElement->getHierarchicalElement()->getChildLanes()) {
814
showHierarchicalElementChildren(lane, item);
815
}
816
// crossings
817
if (hierarchicalElement->getTagProperty()->getTag() == SUMO_TAG_JUNCTION) {
818
// retrieve junction
819
GNEJunction* junction = attributeCarriers->retrieveJunction(hierarchicalElement->getID(), false);
820
if (junction) {
821
// insert crossings
822
for (const auto& crossing : junction->getGNECrossings()) {
823
showHierarchicalElementChildren(crossing, item);
824
}
825
}
826
}
827
// connections
828
if (hierarchicalElement->getTagProperty()->getTag() == SUMO_TAG_LANE) {
829
// retrieve lane
830
GNELane* lane = attributeCarriers->retrieveLane(hierarchicalElement->getID(), false);
831
if (lane) {
832
// insert incoming connections of lanes (by default isn't expanded)
833
if (lane->getGNEIncomingConnections().size() > 0) {
834
std::vector<GNEConnection*> incomingLaneConnections = lane->getGNEIncomingConnections();
835
// insert intermediate list item
836
FXTreeItem* incomingConnections = addListItem(item, TL("Incomings"), incomingLaneConnections.front()->getACIcon(), false);
837
// insert incoming connections
838
for (const auto& connection : incomingLaneConnections) {
839
showHierarchicalElementChildren(connection, incomingConnections);
840
}
841
}
842
// insert outcoming connections of lanes (by default isn't expanded)
843
if (lane->getGNEOutcomingConnections().size() > 0) {
844
std::vector<GNEConnection*> outcomingLaneConnections = lane->getGNEOutcomingConnections();
845
// insert intermediate list item
846
FXTreeItem* outgoingConnections = addListItem(item, TL("Outgoing"), outcomingLaneConnections.front()->getACIcon(), false);
847
// insert outcoming connections
848
for (const auto& connection : outcomingLaneConnections) {
849
showHierarchicalElementChildren(connection, outgoingConnections);
850
}
851
}
852
}
853
}
854
// additionals
855
for (const auto& additional : hierarchicalElement->getHierarchicalElement()->getChildAdditionals()) {
856
if (!additional->getTagProperty()->isSymbol()) {
857
showHierarchicalElementChildren(additional, item);
858
}
859
}
860
// additionals symbols
861
for (const auto& additional : hierarchicalElement->getHierarchicalElement()->getChildAdditionals()) {
862
if (additional->getTagProperty()->isSymbol()) {
863
showHierarchicalElementChildren(additional, item);
864
}
865
}
866
// TAZ SourceSinks (avoiding show a high number)
867
if (hierarchicalElement->getHierarchicalElement()->getChildTAZSourceSinks().size() > 20) {
868
addListItem(item, TLF("SourceSinks (%)", toString(hierarchicalElement->getHierarchicalElement()->getChildTAZSourceSinks().size())), GUIIconSubSys::getIcon(GUIIcon::TAZ), false);
869
} else {
870
// show source and sinks separated
871
for (const auto& TAZSource : hierarchicalElement->getHierarchicalElement()->getChildTAZSourceSinks()) {
872
if (TAZSource->getTagProperty()->getTag() == SUMO_TAG_TAZSOURCE) {
873
showHierarchicalElementChildren(TAZSource, item);
874
}
875
}
876
for (const auto& TAZSink : hierarchicalElement->getHierarchicalElement()->getChildTAZSourceSinks()) {
877
if (TAZSink->getTagProperty()->getTag() == SUMO_TAG_TAZSINK) {
878
showHierarchicalElementChildren(TAZSink, item);
879
}
880
}
881
}
882
// insert child demand elements
883
for (const auto& demandElement : hierarchicalElement->getHierarchicalElement()->getChildDemandElements()) {
884
showHierarchicalElementChildren(demandElement, item);
885
}
886
// insert child data elements
887
if (hierarchicalElement->getHierarchicalElement()->getChildGenericDatas().size() > 0) {
888
// insert intermediate list item
889
FXTreeItem* dataElements = addListItem(item, TL("Data elements"), GUIIconSubSys::getIcon(GUIIcon::SUPERMODEDATA), false);
890
for (const auto& genericDatas : hierarchicalElement->getHierarchicalElement()->getChildGenericDatas()) {
891
showHierarchicalElementChildren(genericDatas, dataElements);
892
}
893
}
894
// data sets
895
if (hierarchicalElement->getTagProperty()->getTag() == SUMO_TAG_DATASET) {
896
GNEDataSet* dataSet = attributeCarriers->retrieveDataSet(hierarchicalElement->getID(), false);
897
if (dataSet) {
898
// iterate over intervals
899
for (const auto& interval : dataSet->getDataIntervalChildren()) {
900
showHierarchicalElementChildren(interval.second, item);
901
}
902
}
903
}
904
// data interval
905
if (hierarchicalElement->getTagProperty()->getTag() == SUMO_TAG_DATAINTERVAL) {
906
auto dataInterval = attributeCarriers->retrieveDataInterval(hierarchicalElement, false);
907
if (dataInterval) {
908
// iterate over generic datas
909
for (const auto& genericData : dataInterval->getGenericDataChildren()) {
910
showHierarchicalElementChildren(genericData, item);
911
}
912
}
913
} else if (hierarchicalElement->getHierarchicalElement()->getChildGenericDatas().size() > 0) {
914
// insert intermediate list item
915
FXTreeItem* dataElements = addListItem(item, TL("Data elements"), GUIIconSubSys::getIcon(GUIIcon::SUPERMODEDATA), false);
916
for (const auto& genericDatas : hierarchicalElement->getHierarchicalElement()->getChildGenericDatas()) {
917
showHierarchicalElementChildren(genericDatas, dataElements);
918
}
919
}
920
}
921
922
923
FXTreeItem*
924
GNEElementTree::addListItem(GNEAttributeCarrier* AC, FXTreeItem* itemParent, std::string prefix, std::string sufix) {
925
if (AC) {
926
// insert item in Tree list
927
FXTreeItem* item = myTreeListDynamic->appendItem(itemParent, (prefix + AC->getHierarchyName() + sufix).c_str(), AC->getACIcon());
928
// insert item in map
929
myTreeItemToACMap[item] = AC;
930
// by default item is expanded
931
item->setExpanded(true);
932
// return created FXTreeItem
933
return item;
934
} else {
935
return nullptr;
936
}
937
}
938
939
940
FXTreeItem*
941
GNEElementTree::addListItem(FXTreeItem* itemParent, const std::string& text, FXIcon* icon, bool expanded) {
942
if (itemParent) {
943
// insert item in Tree list
944
FXTreeItem* item = myTreeListDynamic->appendItem(itemParent, text.c_str(), icon);
945
// expand item depending of flag expanded
946
item->setExpanded(expanded);
947
// return created FXTreeItem
948
return item;
949
} else {
950
return nullptr;
951
}
952
}
953
954
955
bool
956
GNEElementTree::isSupermodeValid(const GNEAttributeCarrier* AC) const {
957
const auto& editModes = myFrameParent->getViewNet()->getEditModes();
958
const auto tagProperty = AC->getTagProperty();
959
if (editModes.isCurrentSupermodeNetwork()) {
960
if (tagProperty->isNetworkElement() || tagProperty->isAdditionalElement()) {
961
return true;
962
} else if ((tagProperty->getTag() == SUMO_TAG_TAZSOURCE) || (tagProperty->getTag() == SUMO_TAG_TAZSINK)) {
963
return true;
964
} else {
965
return false;
966
}
967
} else if (editModes.isCurrentSupermodeDemand() &&
968
tagProperty->isDemandElement()) {
969
return true;
970
} else if (editModes.isCurrentSupermodeData() &&
971
(tagProperty->isDataElement() || tagProperty->isMeanData())) {
972
return true;
973
} else {
974
return false;
975
}
976
}
977
978
/****************************************************************************/
979
980