1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file GNESelectorFrame.cpp
11 /// @author Jakob Erdmann
12 /// @date Mar 2011
13 /// @version $Id$
14 ///
15 // The Widget for modifying selections of network-elements
16 // (some elements adapted from GUIDialog_GLChosenEditor)
17 /****************************************************************************/
18
19
20 // ===========================================================================
21 // included modules
22 // ===========================================================================
23 #include <config.h>
24
25 #include <utils/foxtools/MFXUtils.h>
26 #include <utils/gui/windows/GUIAppEnum.h>
27 #include <utils/gui/div/GUIDesigns.h>
28 #include <utils/gui/images/GUIIconSubSys.h>
29 #include <netedit/GNENet.h>
30 #include <netedit/GNEViewNet.h>
31 #include <netedit/netelements/GNEJunction.h>
32 #include <netedit/netelements/GNEEdge.h>
33 #include <netedit/netelements/GNELane.h>
34 #include <netedit/netelements/GNEConnection.h>
35 #include <netedit/netelements/GNECrossing.h>
36 #include <netedit/additionals/GNEAdditional.h>
37 #include <netedit/additionals/GNEPoly.h>
38 #include <netedit/additionals/GNEPOI.h>
39 #include <netedit/GNEUndoList.h>
40 #include <utils/gui/globjects/GUIGlObjectStorage.h>
41
42 #include "GNESelectorFrame.h"
43
44
45 // ===========================================================================
46 // FOX callback mapping
47 // ===========================================================================
48 FXDEFMAP(GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry) ObjectTypeEntryMap[] = {
49 FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE, GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::onCmdSetCheckBox)
50 };
51
52 FXDEFMAP(GNESelectorFrame::ModificationMode) ModificationModeMap[] = {
53 FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_OPERATION, GNESelectorFrame::ModificationMode::onCmdSelectModificationMode)
54 };
55
56 FXDEFMAP(GNESelectorFrame::ElementSet) ElementSetMap[] = {
57 FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_ELEMENTS, GNESelectorFrame::ElementSet::onCmdSelectElementSet)
58 };
59
60 FXDEFMAP(GNESelectorFrame::MatchAttribute) MatchAttributeMap[] = {
61 FXMAPFUNC(SEL_COMMAND, MID_GNE_SELECTORFRAME_SELECTTAG, GNESelectorFrame::MatchAttribute::onCmdSelMBTag),
62 FXMAPFUNC(SEL_COMMAND, MID_GNE_SELECTORFRAME_SELECTATTRIBUTE, GNESelectorFrame::MatchAttribute::onCmdSelMBAttribute),
63 FXMAPFUNC(SEL_COMMAND, MID_GNE_SELECTORFRAME_PROCESSSTRING, GNESelectorFrame::MatchAttribute::onCmdSelMBString),
64 FXMAPFUNC(SEL_COMMAND, MID_HELP, GNESelectorFrame::MatchAttribute::onCmdHelp)
65 };
66
67 FXDEFMAP(GNESelectorFrame::VisualScaling) VisualScalingMap[] = {
68 FXMAPFUNC(SEL_COMMAND, MID_GNE_SELECTORFRAME_SELECTSCALE, GNESelectorFrame::VisualScaling::onCmdScaleSelection)
69 };
70
71 FXDEFMAP(GNESelectorFrame::SelectionOperation) SelectionOperationMap[] = {
72 FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_LOAD, GNESelectorFrame::SelectionOperation::onCmdLoad),
73 FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SAVE, GNESelectorFrame::SelectionOperation::onCmdSave),
74 FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_INVERT, GNESelectorFrame::SelectionOperation::onCmdInvert),
75 FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GNESelectorFrame::SelectionOperation::onCmdClear)
76 };
77
78 // Object implementation
FXIMPLEMENT(GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry,FXObject,ObjectTypeEntryMap,ARRAYNUMBER (ObjectTypeEntryMap))79 FXIMPLEMENT(GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry, FXObject, ObjectTypeEntryMap, ARRAYNUMBER(ObjectTypeEntryMap))
80 FXIMPLEMENT(GNESelectorFrame::ModificationMode, FXGroupBox, ModificationModeMap, ARRAYNUMBER(ModificationModeMap))
81 FXIMPLEMENT(GNESelectorFrame::ElementSet, FXGroupBox, ElementSetMap, ARRAYNUMBER(ElementSetMap))
82 FXIMPLEMENT(GNESelectorFrame::MatchAttribute, FXGroupBox, MatchAttributeMap, ARRAYNUMBER(MatchAttributeMap))
83 FXIMPLEMENT(GNESelectorFrame::VisualScaling, FXGroupBox, VisualScalingMap, ARRAYNUMBER(VisualScalingMap))
84 FXIMPLEMENT(GNESelectorFrame::SelectionOperation, FXGroupBox, SelectionOperationMap, ARRAYNUMBER(SelectionOperationMap))
85
86 // ===========================================================================
87 // method definitions
88 // ===========================================================================
89
90 GNESelectorFrame::GNESelectorFrame(FXHorizontalFrame* horizontalFrameParent, GNEViewNet* viewNet):
91 GNEFrame(horizontalFrameParent, viewNet, "Selection") {
92 // create selectedItems modul
93 myLockGLObjectTypes = new LockGLObjectTypes(this);
94 // create Modification Mode modul
95 myModificationMode = new ModificationMode(this);
96 // create ElementSet modul
97 myElementSet = new ElementSet(this);
98 // create MatchAttribute modul
99 myMatchAttribute = new MatchAttribute(this);
100 // create VisualScaling modul
101 myVisualScaling = new VisualScaling(this);
102 // create SelectionOperation modul
103 mySelectionOperation = new SelectionOperation(this);
104 // Create groupbox for information about selections
105 FXGroupBox* selectionHintGroupBox = new FXGroupBox(myContentFrame, "Information", GUIDesignGroupBoxFrame);
106 // Create Selection Hint
107 new FXLabel(selectionHintGroupBox, " - Hold <SHIFT> for \n rectangle selection.\n - Press <DEL> to\n delete selected items.", nullptr, GUIDesignLabelFrameInformation);
108
109 }
110
111
~GNESelectorFrame()112 GNESelectorFrame::~GNESelectorFrame() {}
113
114
115 void
show()116 GNESelectorFrame::show() {
117 // show Type Entries depending of current supermode
118 myLockGLObjectTypes->showTypeEntries();
119 // refresh element set
120 myElementSet->refreshElementSet();
121 // Show frame
122 GNEFrame::show();
123 }
124
125
126 void
hide()127 GNESelectorFrame::hide() {
128 // hide frame
129 GNEFrame::hide();
130 }
131
132
133 void
clearCurrentSelection() const134 GNESelectorFrame::clearCurrentSelection() const {
135 // for clear selection, simply change all GNE_ATTR_SELECTED attribute of current selected elements
136 myViewNet->getUndoList()->p_begin("clear selection");
137 // obtain selected ACs depending of current supermode
138 std::vector<GNEAttributeCarrier*> selectedAC = myViewNet->getNet()->getSelectedAttributeCarriers(false);
139 // change attribute GNE_ATTR_SELECTED of all selected items to false
140 for (auto i : selectedAC) {
141 i->setAttribute(GNE_ATTR_SELECTED, "false", myViewNet->getUndoList());
142 }
143 // finish clear selection
144 myViewNet->getUndoList()->p_end();
145 // update view
146 myViewNet->update();
147 }
148
149
150 void
handleIDs(const std::vector<GNEAttributeCarrier * > & ACs,ModificationMode::SetOperation setop)151 GNESelectorFrame::handleIDs(const std::vector<GNEAttributeCarrier*>& ACs, ModificationMode::SetOperation setop) {
152 const ModificationMode::SetOperation setOperation = ((setop == ModificationMode::SET_DEFAULT) ? myModificationMode->getModificationMode() : setop);
153 // declare two sets of attribute carriers, one for select and another for unselect
154 std::set<std::pair<std::string, GNEAttributeCarrier*> > ACToSelect;
155 std::set<std::pair<std::string, GNEAttributeCarrier*> > ACToUnselect;
156 // in restrict AND replace mode all current selected attribute carriers will be unselected
157 if ((setOperation == ModificationMode::SET_REPLACE) || (setOperation == ModificationMode::SET_RESTRICT)) {
158 // obtain selected ACs depending of current supermode
159 std::vector<GNEAttributeCarrier*> selectedAC = myViewNet->getNet()->getSelectedAttributeCarriers(false);
160 // add id into ACs to unselect
161 for (auto i : selectedAC) {
162 ACToUnselect.insert(std::pair<std::string, GNEAttributeCarrier*>(i->getID(), i));
163 }
164 }
165 // handle ids
166 for (auto i : ACs) {
167 // iterate over AtributeCarriers an place it in ACToSelect or ACToUnselect
168 switch (setOperation) {
169 case GNESelectorFrame::ModificationMode::SET_SUB:
170 ACToUnselect.insert(std::pair<std::string, GNEAttributeCarrier*>(i->getID(), i));
171 break;
172 case GNESelectorFrame::ModificationMode::SET_RESTRICT:
173 if (ACToUnselect.find(std::pair<std::string, GNEAttributeCarrier*>(i->getID(), i)) != ACToUnselect.end()) {
174 ACToSelect.insert(std::pair<std::string, GNEAttributeCarrier*>(i->getID(), i));
175 }
176 break;
177 default:
178 ACToSelect.insert(std::pair<std::string, GNEAttributeCarrier*>(i->getID(), i));
179 break;
180 }
181 }
182 // select junctions and their connections if Auto select junctions is enabled (note: only for "add mode")
183 if (myViewNet->autoSelectNodes() && GNESelectorFrame::ModificationMode::SET_ADD) {
184 std::vector<GNEEdge*> edgesToSelect;
185 // iterate over ACToSelect and extract edges
186 for (auto i : ACToSelect) {
187 if (i.second->getTagProperty().getTag() == SUMO_TAG_EDGE) {
188 edgesToSelect.push_back(dynamic_cast<GNEEdge*>(i.second));
189 }
190 }
191 // iterate over extracted edges
192 for (auto i : edgesToSelect) {
193 // select junction source and all their connections and crossings
194 ACToSelect.insert(std::make_pair(i->getGNEJunctionSource()->getID(), i->getGNEJunctionSource()));
195 for (auto j : i->getGNEJunctionSource()->getGNEConnections()) {
196 ACToSelect.insert(std::make_pair(j->getID(), j));
197 }
198 for (auto j : i->getGNEJunctionSource()->getGNECrossings()) {
199 ACToSelect.insert(std::make_pair(j->getID(), j));
200 }
201 // select junction destiny and all their connections crossings
202 ACToSelect.insert(std::make_pair(i->getGNEJunctionDestiny()->getID(), i->getGNEJunctionDestiny()));
203 for (auto j : i->getGNEJunctionDestiny()->getGNEConnections()) {
204 ACToSelect.insert(std::make_pair(j->getID(), j));
205 }
206 for (auto j : i->getGNEJunctionDestiny()->getGNECrossings()) {
207 ACToSelect.insert(std::make_pair(j->getID(), j));
208 }
209 }
210 }
211 // only continue if there is ACs to select or unselect
212 if ((ACToSelect.size() + ACToUnselect.size()) > 0) {
213 // first unselect AC of ACToUnselect and then selects AC of ACToSelect
214 myViewNet->getUndoList()->p_begin("selection using rectangle");
215 for (auto i : ACToUnselect) {
216 if (i.second->getTagProperty().isSelectable()) {
217 i.second->setAttribute(GNE_ATTR_SELECTED, "false", myViewNet->getUndoList());
218 }
219 }
220 for (auto i : ACToSelect) {
221 if (i.second->getTagProperty().isSelectable()) {
222 i.second->setAttribute(GNE_ATTR_SELECTED, "true", myViewNet->getUndoList());
223 }
224 }
225 // finish operation
226 myViewNet->getUndoList()->p_end();
227 }
228 // update view
229 myViewNet->update();
230 }
231
232
233 GNESelectorFrame::ModificationMode*
getModificationModeModul() const234 GNESelectorFrame::getModificationModeModul() const {
235 return myModificationMode;
236 }
237
238
239 GNESelectorFrame::LockGLObjectTypes*
getLockGLObjectTypes() const240 GNESelectorFrame::getLockGLObjectTypes() const {
241 return myLockGLObjectTypes;
242 }
243
244
245 std::vector<GNEAttributeCarrier*>
getMatches(SumoXMLTag ACTag,SumoXMLAttr ACAttr,char compOp,double val,const std::string & expr)246 GNESelectorFrame::getMatches(SumoXMLTag ACTag, SumoXMLAttr ACAttr, char compOp, double val, const std::string& expr) {
247 std::vector<GNEAttributeCarrier*> result;
248 std::vector<GNEAttributeCarrier*> allACbyTag = myViewNet->getNet()->retrieveAttributeCarriers(ACTag);
249 const auto& tagValue = GNEAttributeCarrier::getTagProperties(ACTag);
250 for (auto it : allACbyTag) {
251 if (expr == "") {
252 result.push_back(it);
253 } else if (tagValue.hasAttribute(ACAttr) && tagValue.getAttributeProperties(ACAttr).isNumerical()) {
254 double acVal;
255 std::istringstream buf(it->getAttribute(ACAttr));
256 buf >> acVal;
257 switch (compOp) {
258 case '<':
259 if (acVal < val) {
260 result.push_back(it);
261 }
262 break;
263 case '>':
264 if (acVal > val) {
265 result.push_back(it);
266 }
267 break;
268 case '=':
269 if (acVal == val) {
270 result.push_back(it);
271 }
272 break;
273 }
274 } else {
275 // string match
276 std::string acVal = it->getAttributeForSelection(ACAttr);
277 switch (compOp) {
278 case '@':
279 if (acVal.find(expr) != std::string::npos) {
280 result.push_back(it);
281 }
282 break;
283 case '!':
284 if (acVal.find(expr) == std::string::npos) {
285 result.push_back(it);
286 }
287 break;
288 case '=':
289 if (acVal == expr) {
290 result.push_back(it);
291 }
292 break;
293 case '^':
294 if (acVal != expr) {
295 result.push_back(it);
296 }
297 break;
298 }
299 }
300 }
301 return result;
302 }
303
304 // ---------------------------------------------------------------------------
305 // ModificationMode::LockGLObjectTypes - methods
306 // ---------------------------------------------------------------------------
307
LockGLObjectTypes(GNESelectorFrame * selectorFrameParent)308 GNESelectorFrame::LockGLObjectTypes::LockGLObjectTypes(GNESelectorFrame* selectorFrameParent) :
309 FXGroupBox(selectorFrameParent->myContentFrame, "Locked selected items", GUIDesignGroupBoxFrame),
310 mySelectorFrameParent(selectorFrameParent) {
311 // create a matrix for TypeEntries
312 FXMatrix* matrixLockGLObjectTypes = new FXMatrix(this, 3, GUIDesignMatrixLockGLTypes);
313 // create typeEntries for the different Network elements
314 myTypeEntries[GLO_JUNCTION] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Junctions"));
315 myTypeEntries[GLO_EDGE] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Edges"));
316 myTypeEntries[GLO_LANE] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Lanes"));
317 myTypeEntries[GLO_CONNECTION] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Connections"));
318 myTypeEntries[GLO_ADDITIONAL] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Additionals"));
319 myTypeEntries[GLO_CROSSING] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Crossings"));
320 myTypeEntries[GLO_POLYGON] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "Polygons"));
321 myTypeEntries[GLO_POI] = std::make_pair(Supermode::GNE_SUPERMODE_NETWORK, new ObjectTypeEntry(matrixLockGLObjectTypes, "POIs"));
322 // create typeEntries for the different Demand elements
323 myTypeEntries[GLO_ROUTE] = std::make_pair(Supermode::GNE_SUPERMODE_DEMAND, new ObjectTypeEntry(matrixLockGLObjectTypes, "Routes"));
324 myTypeEntries[GLO_VEHICLE] = std::make_pair(Supermode::GNE_SUPERMODE_DEMAND, new ObjectTypeEntry(matrixLockGLObjectTypes, "Vehicles"));
325 myTypeEntries[GLO_FLOW] = std::make_pair(Supermode::GNE_SUPERMODE_DEMAND, new ObjectTypeEntry(matrixLockGLObjectTypes, "Flows"));
326 myTypeEntries[GLO_TRIP] = std::make_pair(Supermode::GNE_SUPERMODE_DEMAND, new ObjectTypeEntry(matrixLockGLObjectTypes, "Trips"));
327 }
328
329
~LockGLObjectTypes()330 GNESelectorFrame::LockGLObjectTypes::~LockGLObjectTypes() {
331 // remove all type entries
332 for (const auto& i : myTypeEntries) {
333 delete i.second.second;
334 }
335 }
336
337
338 void
addedLockedObject(const GUIGlObjectType type)339 GNESelectorFrame::LockGLObjectTypes::addedLockedObject(const GUIGlObjectType type) {
340 myTypeEntries.at(type).second->counterUp();
341 }
342
343
344 void
removeLockedObject(const GUIGlObjectType type)345 GNESelectorFrame::LockGLObjectTypes::removeLockedObject(const GUIGlObjectType type) {
346 myTypeEntries.at(type).second->counterDown();
347 }
348
349
350 bool
IsObjectTypeLocked(const GUIGlObjectType type) const351 GNESelectorFrame::LockGLObjectTypes::IsObjectTypeLocked(const GUIGlObjectType type) const {
352 if ((type >= 100) && (type < 199)) {
353 return myTypeEntries.at(GLO_ADDITIONAL).second->isGLTypeLocked();
354 } else {
355 return myTypeEntries.at(type).second->isGLTypeLocked();
356 }
357 }
358
359
360 void
showTypeEntries()361 GNESelectorFrame::LockGLObjectTypes::showTypeEntries() {
362 for (const auto& i : myTypeEntries) {
363 // showr or hidde type entries depending of current supermode
364 if (i.second.first == mySelectorFrameParent->getViewNet()->getEditModes().currentSupermode) {
365 i.second.second->showObjectTypeEntry();
366 } else {
367 i.second.second->hideObjectTypeEntry();
368 }
369 }
370 // recalc frame parent
371 recalc();
372 }
373
374
ObjectTypeEntry(FXMatrix * matrixParent,const std::string & label)375 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::ObjectTypeEntry(FXMatrix* matrixParent, const std::string& label) :
376 FXObject(),
377 myCounter(0) {
378 // create elements
379 myLabelCounter = new FXLabel(matrixParent, "0", nullptr, GUIDesignLabelLeft);
380 myLabelTypeName = new FXLabel(matrixParent, (label + " ").c_str(), nullptr, GUIDesignLabelLeft);
381 myCheckBoxLocked = new FXCheckButton(matrixParent, "unlocked", this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButtonLeft);
382 }
383
384
385 void
showObjectTypeEntry()386 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::showObjectTypeEntry() {
387 myLabelCounter->show();
388 myLabelTypeName->show();
389 myCheckBoxLocked->show();
390 }
391
392
393 void
hideObjectTypeEntry()394 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::hideObjectTypeEntry() {
395 myLabelCounter->hide();
396 myLabelTypeName->hide();
397 myCheckBoxLocked->hide();
398 }
399
400
401 void
counterUp()402 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::counterUp() {
403 myCounter++;
404 myLabelCounter->setText(toString(myCounter).c_str());
405 }
406
407
408 void
counterDown()409 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::counterDown() {
410 myCounter--;
411 myLabelCounter->setText(toString(myCounter).c_str());
412 }
413
414
415 bool
isGLTypeLocked() const416 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::isGLTypeLocked() const {
417 return (myCheckBoxLocked->getCheck() == TRUE);
418 }
419
420
421 long
onCmdSetCheckBox(FXObject *,FXSelector,void *)422 GNESelectorFrame::LockGLObjectTypes::ObjectTypeEntry::onCmdSetCheckBox(FXObject*, FXSelector, void*) {
423 if (myCheckBoxLocked->getCheck() == TRUE) {
424 myCheckBoxLocked->setText("locked");
425 } else {
426 myCheckBoxLocked->setText("unlocked");
427 }
428 return 1;
429 }
430
431 // ---------------------------------------------------------------------------
432 // ModificationMode::ModificationMode - methods
433 // ---------------------------------------------------------------------------
434
ModificationMode(GNESelectorFrame * selectorFrameParent)435 GNESelectorFrame::ModificationMode::ModificationMode(GNESelectorFrame* selectorFrameParent) :
436 FXGroupBox(selectorFrameParent->myContentFrame, "Modification Mode", GUIDesignGroupBoxFrame),
437 mySelectorFrameParent(selectorFrameParent),
438 myModificationModeType(SET_ADD) {
439 // Create all options buttons
440 myAddRadioButton = new FXRadioButton(this, "add\t\tSelected objects are added to the previous selection",
441 this, MID_CHOOSEN_OPERATION, GUIDesignRadioButton);
442 myRemoveRadioButton = new FXRadioButton(this, "remove\t\tSelected objects are removed from the previous selection",
443 this, MID_CHOOSEN_OPERATION, GUIDesignRadioButton);
444 myKeepRadioButton = new FXRadioButton(this, "keep\t\tRestrict previous selection by the current selection",
445 this, MID_CHOOSEN_OPERATION, GUIDesignRadioButton);
446 myReplaceRadioButton = new FXRadioButton(this, "replace\t\tReplace previous selection by the current selection",
447 this, MID_CHOOSEN_OPERATION, GUIDesignRadioButton);
448 myAddRadioButton->setCheck(true);
449 }
450
451
~ModificationMode()452 GNESelectorFrame::ModificationMode::~ModificationMode() {}
453
454
455 GNESelectorFrame::ModificationMode::SetOperation
getModificationMode() const456 GNESelectorFrame::ModificationMode::getModificationMode() const {
457 return myModificationModeType;
458 }
459
460
461 long
onCmdSelectModificationMode(FXObject * obj,FXSelector,void *)462 GNESelectorFrame::ModificationMode::onCmdSelectModificationMode(FXObject* obj, FXSelector, void*) {
463 if (obj == myAddRadioButton) {
464 myModificationModeType = SET_ADD;
465 myAddRadioButton->setCheck(true);
466 myRemoveRadioButton->setCheck(false);
467 myKeepRadioButton->setCheck(false);
468 myReplaceRadioButton->setCheck(false);
469 return 1;
470 } else if (obj == myRemoveRadioButton) {
471 myModificationModeType = SET_SUB;
472 myAddRadioButton->setCheck(false);
473 myRemoveRadioButton->setCheck(true);
474 myKeepRadioButton->setCheck(false);
475 myReplaceRadioButton->setCheck(false);
476 return 1;
477 } else if (obj == myKeepRadioButton) {
478 myModificationModeType = SET_RESTRICT;
479 myAddRadioButton->setCheck(false);
480 myRemoveRadioButton->setCheck(false);
481 myKeepRadioButton->setCheck(true);
482 myReplaceRadioButton->setCheck(false);
483 return 1;
484 } else if (obj == myReplaceRadioButton) {
485 myModificationModeType = SET_REPLACE;
486 myAddRadioButton->setCheck(false);
487 myRemoveRadioButton->setCheck(false);
488 myKeepRadioButton->setCheck(false);
489 myReplaceRadioButton->setCheck(true);
490 return 1;
491 } else {
492 return 0;
493 }
494 }
495
496 // ---------------------------------------------------------------------------
497 // ModificationMode::ElementSet - methods
498 // ---------------------------------------------------------------------------
499
ElementSet(GNESelectorFrame * selectorFrameParent)500 GNESelectorFrame::ElementSet::ElementSet(GNESelectorFrame* selectorFrameParent) :
501 FXGroupBox(selectorFrameParent->myContentFrame, "Element Set", GUIDesignGroupBoxFrame),
502 mySelectorFrameParent(selectorFrameParent),
503 myCurrentElementSet(ELEMENTSET_NETELEMENT) {
504 // Create MatchTagBox for tags and fill it
505 mySetComboBox = new FXComboBox(this, GUIDesignComboBoxNCol, this, MID_CHOOSEN_ELEMENTS, GUIDesignComboBox);
506 }
507
508
~ElementSet()509 GNESelectorFrame::ElementSet::~ElementSet() {}
510
511
512 GNESelectorFrame::ElementSet::ElementSetType
getElementSet() const513 GNESelectorFrame::ElementSet::getElementSet() const {
514 return myCurrentElementSet;
515 }
516
517
518 void
refreshElementSet()519 GNESelectorFrame::ElementSet::refreshElementSet() {
520 // first clear item
521 mySetComboBox->clearItems();
522 // now fill elements depending of supermode
523 if (mySelectorFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) {
524 mySetComboBox->appendItem("Net Element");
525 mySetComboBox->appendItem("Additional");
526 mySetComboBox->appendItem("Shape");
527 } else {
528 mySetComboBox->appendItem("Demand Element");
529 }
530 mySetComboBox->setNumVisible(mySetComboBox->getNumItems());
531 // update rest of elements
532 onCmdSelectElementSet(0, 0, 0);
533 }
534
535
536 long
onCmdSelectElementSet(FXObject *,FXSelector,void *)537 GNESelectorFrame::ElementSet::onCmdSelectElementSet(FXObject*, FXSelector, void*) {
538 // check depending of current supermode
539 if (mySelectorFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) {
540 if (mySetComboBox->getText() == "Net Element") {
541 myCurrentElementSet = ELEMENTSET_NETELEMENT;
542 mySetComboBox->setTextColor(FXRGB(0, 0, 0));
543 // enable match attribute
544 mySelectorFrameParent->myMatchAttribute->enableMatchAttribute();
545 } else if (mySetComboBox->getText() == "Additional") {
546 myCurrentElementSet = ELEMENTSET_ADDITIONAL;
547 mySetComboBox->setTextColor(FXRGB(0, 0, 0));
548 // enable match attribute
549 mySelectorFrameParent->myMatchAttribute->enableMatchAttribute();
550 } else if (mySetComboBox->getText() == "Shape") {
551 myCurrentElementSet = ELEMENTSET_SHAPE;
552 mySetComboBox->setTextColor(FXRGB(0, 0, 0));
553 // enable match attribute
554 mySelectorFrameParent->myMatchAttribute->enableMatchAttribute();
555 } else {
556 myCurrentElementSet = ELEMENTSET_INVALID;
557 mySetComboBox->setTextColor(FXRGB(255, 0, 0));
558 // disable match attribute
559 mySelectorFrameParent->myMatchAttribute->disableMatchAttribute();
560 }
561 } else {
562 if (mySetComboBox->getText() == "Demand Element") {
563 myCurrentElementSet = ELEMENTSET_DEMANDELEMENT;
564 mySetComboBox->setTextColor(FXRGB(0, 0, 0));
565 // enable match attribute
566 mySelectorFrameParent->myMatchAttribute->enableMatchAttribute();
567 } else {
568 myCurrentElementSet = ELEMENTSET_INVALID;
569 mySetComboBox->setTextColor(FXRGB(255, 0, 0));
570 // disable match attribute
571 mySelectorFrameParent->myMatchAttribute->disableMatchAttribute();
572 }
573 }
574 return 1;
575 }
576
577 // ---------------------------------------------------------------------------
578 // ModificationMode::MatchAttribute - methods
579 // ---------------------------------------------------------------------------
580
MatchAttribute(GNESelectorFrame * selectorFrameParent)581 GNESelectorFrame::MatchAttribute::MatchAttribute(GNESelectorFrame* selectorFrameParent) :
582 FXGroupBox(selectorFrameParent->myContentFrame, "Match Attribute", GUIDesignGroupBoxFrame),
583 mySelectorFrameParent(selectorFrameParent),
584 myCurrentTag(SUMO_TAG_EDGE),
585 myCurrentAttribute(SUMO_ATTR_ID) {
586 // Create MatchTagBox for tags
587 myMatchTagComboBox = new FXComboBox(this, GUIDesignComboBoxNCol, this, MID_GNE_SELECTORFRAME_SELECTTAG, GUIDesignComboBox);
588 // Create listBox for Attributes
589 myMatchAttrComboBox = new FXComboBox(this, GUIDesignComboBoxNCol, this, MID_GNE_SELECTORFRAME_SELECTATTRIBUTE, GUIDesignComboBox);
590 // Create TextField for Match string
591 myMatchString = new FXTextField(this, GUIDesignTextFieldNCol, this, MID_GNE_SELECTORFRAME_PROCESSSTRING, GUIDesignTextField);
592 // Create help button
593 new FXButton(this, "Help", nullptr, this, MID_HELP, GUIDesignButtonRectangular);
594 // Fill list of sub-items (first element will be "edge")
595 enableMatchAttribute();
596 // Set speed of edge as default attribute
597 myMatchAttrComboBox->setText("speed");
598 myCurrentAttribute = SUMO_ATTR_SPEED;
599 // Set default value for Match string
600 myMatchString->setText(">10.0");
601 }
602
603
~MatchAttribute()604 GNESelectorFrame::MatchAttribute::~MatchAttribute() {}
605
606
607 void
enableMatchAttribute()608 GNESelectorFrame::MatchAttribute::enableMatchAttribute() {
609 // enable comboboxes and text field
610 myMatchTagComboBox->enable();
611 myMatchAttrComboBox->enable();
612 myMatchString->enable();
613 // Clear items of myMatchTagComboBox
614 myMatchTagComboBox->clearItems();
615 // Set items depending of current item set
616 std::vector<SumoXMLTag> listOfTags;
617 if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_NETELEMENT) {
618 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_NETELEMENT, true);
619 } else if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_ADDITIONAL) {
620 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL | GNEAttributeCarrier::TagType::TAGTYPE_TAZ, true);
621 } else if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_SHAPE) {
622 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_SHAPE, true);
623 } else if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_DEMANDELEMENT) {
624 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_DEMANDELEMENT | GNEAttributeCarrier::TagType::TAGTYPE_STOP, true);
625 } else {
626 throw ProcessError("Invalid element set");
627 }
628 // fill combo box
629 for (auto i : listOfTags) {
630 myMatchTagComboBox->appendItem(toString(i).c_str());
631 }
632 // set first item as current item
633 myMatchTagComboBox->setCurrentItem(0);
634 myMatchTagComboBox->setNumVisible(myMatchTagComboBox->getNumItems());
635 // Fill attributes with the current element type
636 onCmdSelMBTag(nullptr, 0, nullptr);
637 }
638
639
640 void
disableMatchAttribute()641 GNESelectorFrame::MatchAttribute::disableMatchAttribute() {
642 // disable comboboxes and text field
643 myMatchTagComboBox->disable();
644 myMatchAttrComboBox->disable();
645 myMatchString->disable();
646 // change colors to black (even if there are invalid values)
647 myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
648 myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
649 myMatchString->setTextColor(FXRGB(0, 0, 0));
650 }
651
652
653 long
onCmdSelMBTag(FXObject *,FXSelector,void *)654 GNESelectorFrame::MatchAttribute::onCmdSelMBTag(FXObject*, FXSelector, void*) {
655 // First check what type of elementes is being selected
656 myCurrentTag = SUMO_TAG_NOTHING;
657 // find current element tag
658 std::vector<SumoXMLTag> listOfTags;
659 if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_NETELEMENT) {
660 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_NETELEMENT, true);
661 } else if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_ADDITIONAL) {
662 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_ADDITIONAL | GNEAttributeCarrier::TagType::TAGTYPE_TAZ, true);
663 } else if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_SHAPE) {
664 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_SHAPE, true);
665 } else if (mySelectorFrameParent->myElementSet->getElementSet() == ElementSet::ELEMENTSET_DEMANDELEMENT) {
666 listOfTags = GNEAttributeCarrier::allowedTagsByCategory(GNEAttributeCarrier::TagType::TAGTYPE_DEMANDELEMENT | GNEAttributeCarrier::TagType::TAGTYPE_STOP, true);
667 } else {
668 throw ProcessError("Unkown set");
669 }
670 // fill myMatchTagComboBox
671 for (auto i : listOfTags) {
672 if (toString(i) == myMatchTagComboBox->getText().text()) {
673 myCurrentTag = i;
674 }
675 }
676 // check that typed-by-user value is correct
677 if (myCurrentTag != SUMO_TAG_NOTHING) {
678 // obtain tag property (only for improve code legibility)
679 const auto& tagValue = GNEAttributeCarrier::getTagProperties(myCurrentTag);
680 // set color and enable items
681 myMatchTagComboBox->setTextColor(FXRGB(0, 0, 0));
682 myMatchAttrComboBox->enable();
683 myMatchString->enable();
684 myMatchAttrComboBox->clearItems();
685 // fill attribute combo box
686 for (auto it : tagValue) {
687 myMatchAttrComboBox->appendItem(toString(it.first).c_str());
688 }
689 // Add extra attribute "generic"
690 myMatchAttrComboBox->appendItem(toString(GNE_ATTR_GENERIC).c_str());
691 // check if item can block movement
692 if (tagValue.canBlockMovement()) {
693 myMatchAttrComboBox->appendItem(toString(GNE_ATTR_BLOCK_MOVEMENT).c_str());
694 }
695 // check if item can block shape
696 if (tagValue.canBlockShape()) {
697 myMatchAttrComboBox->appendItem(toString(GNE_ATTR_BLOCK_SHAPE).c_str());
698 }
699 // check if item can close shape
700 if (tagValue.canCloseShape()) {
701 myMatchAttrComboBox->appendItem(toString(GNE_ATTR_CLOSE_SHAPE).c_str());
702 }
703 // check if item can have parent
704 if (tagValue.hasParent()) {
705 myMatchAttrComboBox->appendItem(toString(GNE_ATTR_PARENT).c_str());
706 }
707 // @ToDo: Here can be placed a button to set the default value
708 myMatchAttrComboBox->setNumVisible(myMatchAttrComboBox->getNumItems());
709 onCmdSelMBAttribute(nullptr, 0, nullptr);
710 } else {
711 // change color to red and disable items
712 myMatchTagComboBox->setTextColor(FXRGB(255, 0, 0));
713 myMatchAttrComboBox->disable();
714 myMatchString->disable();
715 }
716 update();
717 return 1;
718 }
719
720
721 long
onCmdSelMBAttribute(FXObject *,FXSelector,void *)722 GNESelectorFrame::MatchAttribute::onCmdSelMBAttribute(FXObject*, FXSelector, void*) {
723 // first obtain a copy of item attributes vinculated with current tag
724 auto tagPropertiesCopy = GNEAttributeCarrier::getTagProperties(myCurrentTag);
725 // obtain tag property (only for improve code legibility)
726 const auto& tagValue = GNEAttributeCarrier::getTagProperties(myCurrentTag);
727 // add an extra AttributeValues to allow select ACs using as criterium "generic parameters"
728 GNEAttributeCarrier::AttributeProperties extraAttrProperty;
729 extraAttrProperty = GNEAttributeCarrier::AttributeProperties(GNE_ATTR_GENERIC,
730 GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_STRING,
731 "Generic Parameters");
732 tagPropertiesCopy.addAttribute(extraAttrProperty);
733 // add extra attribute if item can block movement
734 if (tagValue.canBlockMovement()) {
735 // add an extra AttributeValues to allow select ACs using as criterium "block movement"
736 extraAttrProperty = GNEAttributeCarrier::AttributeProperties(GNE_ATTR_BLOCK_MOVEMENT,
737 GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_BOOL | GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_DEFAULTVALUE,
738 "Block movement",
739 "false");
740 tagPropertiesCopy.addAttribute(extraAttrProperty);
741 }
742 // add extra attribute if item can block shape
743 if (tagValue.canBlockShape()) {
744 // add an extra AttributeValues to allow select ACs using as criterium "block shape"
745 extraAttrProperty = GNEAttributeCarrier::AttributeProperties(GNE_ATTR_BLOCK_SHAPE,
746 GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_BOOL | GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_DEFAULTVALUE,
747 "Block shape",
748 "false");
749 tagPropertiesCopy.addAttribute(extraAttrProperty);
750 }
751 // add extra attribute if item can close shape
752 if (tagValue.canCloseShape()) {
753 // add an extra AttributeValues to allow select ACs using as criterium "close shape"
754 extraAttrProperty = GNEAttributeCarrier::AttributeProperties(GNE_ATTR_CLOSE_SHAPE,
755 GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_BOOL | GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_DEFAULTVALUE,
756 "Close shape",
757 "true");
758 tagPropertiesCopy.addAttribute(extraAttrProperty);
759 }
760 // add extra attribute if item can have parent
761 if (tagValue.hasParent()) {
762 // add an extra AttributeValues to allow select ACs using as criterium "parent"
763 extraAttrProperty = GNEAttributeCarrier::AttributeProperties(GNE_ATTR_PARENT,
764 GNEAttributeCarrier::AttrProperty::ATTRPROPERTY_STRING,
765 "Parent element");
766 tagPropertiesCopy.addAttribute(extraAttrProperty);
767 }
768 // set current selected attribute
769 myCurrentAttribute = SUMO_ATTR_NOTHING;
770 for (auto i : tagPropertiesCopy) {
771 if (toString(i.first) == myMatchAttrComboBox->getText().text()) {
772 myCurrentAttribute = i.first;
773 }
774 }
775 // check if selected attribute is valid
776 if (myCurrentAttribute != SUMO_ATTR_NOTHING) {
777 myMatchAttrComboBox->setTextColor(FXRGB(0, 0, 0));
778 myMatchString->enable();
779 } else {
780 myMatchAttrComboBox->setTextColor(FXRGB(255, 0, 0));
781 myMatchString->disable();
782 }
783 return 1;
784 }
785
786
787 long
onCmdSelMBString(FXObject *,FXSelector,void *)788 GNESelectorFrame::MatchAttribute::onCmdSelMBString(FXObject*, FXSelector, void*) {
789 // obtain expresion
790 std::string expr(myMatchString->getText().text());
791 const auto& tagValue = GNEAttributeCarrier::getTagProperties(myCurrentTag);
792 bool valid = true;
793 if (expr == "") {
794 // the empty expression matches all objects
795 mySelectorFrameParent->handleIDs(mySelectorFrameParent->getMatches(myCurrentTag, myCurrentAttribute, '@', 0, expr));
796 } else if (tagValue.hasAttribute(myCurrentAttribute) && tagValue.getAttributeProperties(myCurrentAttribute).isNumerical()) {
797 // The expression must have the form
798 // <val matches if attr < val
799 // >val matches if attr > val
800 // =val matches if attr = val
801 // val matches if attr = val
802 char compOp = expr[0];
803 if (compOp == '<' || compOp == '>' || compOp == '=') {
804 expr = expr.substr(1);
805 } else {
806 compOp = '=';
807 }
808 // check if value can be parsed to double
809 if (GNEAttributeCarrier::canParse<double>(expr.c_str())) {
810 mySelectorFrameParent->handleIDs(mySelectorFrameParent->getMatches(myCurrentTag, myCurrentAttribute, compOp, GNEAttributeCarrier::parse<double>(expr.c_str()), expr));
811 } else {
812 valid = false;
813 }
814 } else {
815 // The expression must have the form
816 // =str: matches if <str> is an exact match
817 // !str: matches if <str> is not a substring
818 // ^str: matches if <str> is not an exact match
819 // str: matches if <str> is a substring (sends compOp '@')
820 // Alternatively, if the expression is empty it matches all objects
821 char compOp = expr[0];
822 if (compOp == '=' || compOp == '!' || compOp == '^') {
823 expr = expr.substr(1);
824 } else {
825 compOp = '@';
826 }
827 mySelectorFrameParent->handleIDs(mySelectorFrameParent->getMatches(myCurrentTag, myCurrentAttribute, compOp, 0, expr));
828 }
829 if (valid) {
830 myMatchString->setTextColor(FXRGB(0, 0, 0));
831 myMatchString->killFocus();
832 } else {
833 myMatchString->setTextColor(FXRGB(255, 0, 0));
834 }
835 return 1;
836 }
837
838
839 long
onCmdHelp(FXObject *,FXSelector,void *)840 GNESelectorFrame::MatchAttribute::onCmdHelp(FXObject*, FXSelector, void*) {
841 // Create dialog box
842 FXDialogBox* additionalNeteditAttributesHelpDialog = new FXDialogBox(this, "Netedit Parameters Help", GUIDesignDialogBox);
843 additionalNeteditAttributesHelpDialog->setIcon(GUIIconSubSys::getIcon(ICON_MODEADDITIONAL));
844 // set help text
845 std::ostringstream help;
846 help
847 << "- The 'Match Attribute' controls allow to specify a set of objects which are then applied to the current selection\n"
848 << " according to the current 'Modification Mode'.\n"
849 << " 1. Select an object type from the first input box\n"
850 << " 2. Select an attribute from the second input box\n"
851 << " 3. Enter a 'match expression' in the third input box and press <return>\n"
852 << "\n"
853 << "- The empty expression matches all objects\n"
854 << "- For numerical attributes the match expression must consist of a comparison operator ('<', '>', '=') and a number.\n"
855 << "- An object matches if the comparison between its attribute and the given number by the given operator evaluates to 'true'\n"
856 << "\n"
857 << "- For string attributes the match expression must consist of a comparison operator ('', '=', '!', '^') and a string.\n"
858 << " '' (no operator) matches if string is a substring of that object'ts attribute.\n"
859 << " '=' matches if string is an exact match.\n"
860 << " '!' matches if string is not a substring.\n"
861 << " '^' matches if string is not an exact match.\n"
862 << "\n"
863 << "- Examples:\n"
864 << " junction; id; 'foo' -> match all junctions that have 'foo' in their id\n"
865 << " junction; type; '=priority' -> match all junctions of type 'priority', but not of type 'priority_stop'\n"
866 << " edge; speed; '>10' -> match all edges with a speed above 10\n";
867 // Create label with the help text
868 new FXLabel(additionalNeteditAttributesHelpDialog, help.str().c_str(), nullptr, GUIDesignLabelFrameInformation);
869 // Create horizontal separator
870 new FXHorizontalSeparator(additionalNeteditAttributesHelpDialog, GUIDesignHorizontalSeparator);
871 // Create frame for OK Button
872 FXHorizontalFrame* myHorizontalFrameOKButton = new FXHorizontalFrame(additionalNeteditAttributesHelpDialog, GUIDesignAuxiliarHorizontalFrame);
873 // Create Button Close (And two more horizontal frames to center it)
874 new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
875 new FXButton(myHorizontalFrameOKButton, "OK\t\tclose", GUIIconSubSys::getIcon(ICON_ACCEPT), additionalNeteditAttributesHelpDialog, FXDialogBox::ID_ACCEPT, GUIDesignButtonOK);
876 new FXHorizontalFrame(myHorizontalFrameOKButton, GUIDesignAuxiliarHorizontalFrame);
877 // Write Warning in console if we're in testing mode
878 WRITE_DEBUG("Opening help dialog of selector frame");
879 // create Dialog
880 additionalNeteditAttributesHelpDialog->create();
881 // show in the given position
882 additionalNeteditAttributesHelpDialog->show(PLACEMENT_CURSOR);
883 // refresh APP
884 getApp()->refresh();
885 // open as modal dialog (will block all windows until stop() or stopModal() is called)
886 getApp()->runModalFor(additionalNeteditAttributesHelpDialog);
887 // Write Warning in console if we're in testing mode
888 WRITE_DEBUG("Close help dialog of selector frame");
889 return 1;
890 }
891
892 // ---------------------------------------------------------------------------
893 // ModificationMode::VisualScaling - methods
894 // ---------------------------------------------------------------------------
895
VisualScaling(GNESelectorFrame * selectorFrameParent)896 GNESelectorFrame::VisualScaling::VisualScaling(GNESelectorFrame* selectorFrameParent) :
897 FXGroupBox(selectorFrameParent->myContentFrame, "Visual Scaling", GUIDesignGroupBoxFrame),
898 mySelectorFrameParent(selectorFrameParent) {
899 // Create spin button and configure it
900 mySelectionScaling = new FXRealSpinner(this, 7, this, MID_GNE_SELECTORFRAME_SELECTSCALE, GUIDesignSpinDial);
901 //mySelectionScaling->setNumberFormat(1);
902 //mySelectionScaling->setIncrements(0.1, .5, 1);
903 mySelectionScaling->setIncrement(0.5);
904 mySelectionScaling->setRange(1, 100000);
905 mySelectionScaling->setValue(1);
906 mySelectionScaling->setHelpText("Enlarge selected objects");
907 }
908
909
~VisualScaling()910 GNESelectorFrame::VisualScaling::~VisualScaling() {}
911
912
913 long
onCmdScaleSelection(FXObject *,FXSelector,void *)914 GNESelectorFrame::VisualScaling::onCmdScaleSelection(FXObject*, FXSelector, void*) {
915 // set scale in viewnet
916 mySelectorFrameParent->getViewNet()->setSelectionScaling(mySelectionScaling->getValue());
917 mySelectorFrameParent->getViewNet()->update();
918 return 1;
919 }
920
921 // ---------------------------------------------------------------------------
922 // ModificationMode::SelectionOperation - methods
923 // ---------------------------------------------------------------------------
924
SelectionOperation(GNESelectorFrame * selectorFrameParent)925 GNESelectorFrame::SelectionOperation::SelectionOperation(GNESelectorFrame* selectorFrameParent) :
926 FXGroupBox(selectorFrameParent->myContentFrame, "Operations for selections", GUIDesignGroupBoxFrame),
927 mySelectorFrameParent(selectorFrameParent) {
928 // Create "Clear List" Button
929 new FXButton(this, "Clear\t\t", nullptr, this, MID_CHOOSEN_CLEAR, GUIDesignButton);
930 // Create "Invert" Button
931 new FXButton(this, "Invert\t\t", nullptr, this, MID_CHOOSEN_INVERT, GUIDesignButton);
932 // Create "Save" Button
933 new FXButton(this, "Save\t\tSave ids of currently selected objects to a file.", nullptr, this, MID_CHOOSEN_SAVE, GUIDesignButton);
934 // Create "Load" Button
935 new FXButton(this, "Load\t\tLoad ids from a file according to the current modfication mode.", nullptr, this, MID_CHOOSEN_LOAD, GUIDesignButton);
936 }
937
938
~SelectionOperation()939 GNESelectorFrame::SelectionOperation::~SelectionOperation() {}
940
941
942 long
onCmdLoad(FXObject *,FXSelector,void *)943 GNESelectorFrame::SelectionOperation::onCmdLoad(FXObject*, FXSelector, void*) {
944 // get the new file name
945 FXFileDialog opendialog(this, "Open List of Selected Items");
946 opendialog.setIcon(GUIIconSubSys::getIcon(ICON_EMPTY));
947 opendialog.setSelectMode(SELECTFILE_EXISTING);
948 opendialog.setPatternList("Selection files (*.txt)\nAll files (*)");
949 if (gCurrentFolder.length() != 0) {
950 opendialog.setDirectory(gCurrentFolder);
951 }
952 if (opendialog.execute()) {
953 std::vector<GNEAttributeCarrier*> loadedACs;
954 gCurrentFolder = opendialog.getDirectory();
955 std::string file = opendialog.getFilename().text();
956 std::ostringstream msg;
957 std::ifstream strm(file.c_str());
958 // check if file can be opened
959 if (!strm.good()) {
960 WRITE_ERROR("Could not open '" + file + "'.");
961 return 0;
962 }
963 while (strm.good()) {
964 std::string line;
965 strm >> line;
966 // check if line isn't empty
967 if (line.length() != 0) {
968 // obtain GLObject
969 GUIGlObject* object = GUIGlObjectStorage::gIDStorage.getObjectBlocking(line);
970 // check if GUIGlObject exist and their their GL type isn't blocked
971 if ((object != nullptr) && !mySelectorFrameParent->myLockGLObjectTypes->IsObjectTypeLocked(object->getType())) {
972 // obtain GNEAttributeCarrier
973 GNEAttributeCarrier* AC = mySelectorFrameParent->getViewNet()->getNet()->retrieveAttributeCarrier(object->getGlID(), false);
974 // check if AC exist and if is selectable
975 if (AC && AC->getTagProperty().isSelectable())
976 // now check if we're in the correct supermode to load this element
977 if (((mySelectorFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_NETWORK) && !AC->getTagProperty().isDemandElement()) ||
978 ((mySelectorFrameParent->getViewNet()->getEditModes().currentSupermode == GNE_SUPERMODE_DEMAND) && AC->getTagProperty().isDemandElement())) {
979 loadedACs.push_back(AC);
980 }
981 }
982 }
983 }
984 // change selected attribute in loaded ACs allowing undo/redo
985 if (loadedACs.size() > 0) {
986 mySelectorFrameParent->getViewNet()->getUndoList()->p_begin("load selection");
987 mySelectorFrameParent->handleIDs(loadedACs);
988 mySelectorFrameParent->getViewNet()->getUndoList()->p_end();
989 }
990 }
991 mySelectorFrameParent->getViewNet()->update();
992 return 1;
993 }
994
995
996 long
onCmdSave(FXObject *,FXSelector,void *)997 GNESelectorFrame::SelectionOperation::onCmdSave(FXObject*, FXSelector, void*) {
998 FXString file = MFXUtils::getFilename2Write(
999 this, "Save List of selected Items", ".txt", GUIIconSubSys::getIcon(ICON_EMPTY), gCurrentFolder);
1000 if (file == "") {
1001 return 1;
1002 }
1003 try {
1004 OutputDevice& dev = OutputDevice::getDevice(file.text());
1005 for (auto i : mySelectorFrameParent->myViewNet->getNet()->getSelectedAttributeCarriers(false)) {
1006 GUIGlObject* object = dynamic_cast<GUIGlObject*>(i);
1007 if (object) {
1008 dev << GUIGlObject::TypeNames.getString(object->getType()) << ":" << i->getID() << "\n";
1009 }
1010 }
1011 dev.close();
1012 } catch (IOError& e) {
1013 // write warning if netedit is running in testing mode
1014 WRITE_DEBUG("Opening FXMessageBox 'error storing selection'");
1015 // open message box error
1016 FXMessageBox::error(this, MBOX_OK, "Storing Selection failed", "%s", e.what());
1017 // write warning if netedit is running in testing mode
1018 WRITE_DEBUG("Closed FXMessageBox 'error storing selection' with 'OK'");
1019 }
1020 return 1;
1021 }
1022
1023
1024 long
onCmdClear(FXObject *,FXSelector,void *)1025 GNESelectorFrame::SelectionOperation::onCmdClear(FXObject*, FXSelector, void*) {
1026 // clear current selection
1027 mySelectorFrameParent->clearCurrentSelection();
1028 return 1;
1029 }
1030
1031
1032 long
onCmdInvert(FXObject *,FXSelector,void *)1033 GNESelectorFrame::SelectionOperation::onCmdInvert(FXObject*, FXSelector, void*) {
1034 // first make a copy of current selected elements
1035 std::vector<GNEAttributeCarrier*> copyOfSelectedAC = mySelectorFrameParent->getViewNet()->getNet()->getSelectedAttributeCarriers(false);
1036 // for invert selection, first clean current selection and next select elements of set "unselectedElements"
1037 mySelectorFrameParent->getViewNet()->getUndoList()->p_begin("invert selection");
1038 // select junctions, edges, lanes connections and crossings
1039 std::vector<GNEJunction*> junctions = mySelectorFrameParent->getViewNet()->getNet()->retrieveJunctions();
1040 for (auto i : junctions) {
1041 i->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1042 // due we iterate over all junctions, only it's neccesary iterate over incoming edges
1043 for (auto j : i->getGNEIncomingEdges()) {
1044 // only select edges if "select edges" flag is enabled. In other case, select only lanes
1045 if (mySelectorFrameParent->getViewNet()->getViewOptions().selectEdges()) {
1046 j->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1047 } else {
1048 for (auto k : j->getLanes()) {
1049 k->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1050 }
1051 }
1052 // select connections
1053 for (auto k : j->getGNEConnections()) {
1054 k->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1055 }
1056 }
1057 // select crossings
1058 for (auto j : i->getGNECrossings()) {
1059 j->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1060 }
1061 }
1062 // select additionals
1063 std::vector<GNEAdditional*> additionals = mySelectorFrameParent->getViewNet()->getNet()->retrieveAdditionals();
1064 for (auto i : additionals) {
1065 if (i->getTagProperty().isSelectable()) {
1066 i->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1067 }
1068 }
1069 // select polygons
1070 for (auto i : mySelectorFrameParent->getViewNet()->getNet()->getPolygons()) {
1071 dynamic_cast<GNEPoly*>(i.second)->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1072 }
1073 // select POIs
1074 for (auto i : mySelectorFrameParent->getViewNet()->getNet()->getPOIs()) {
1075 dynamic_cast<GNEPOI*>(i.second)->setAttribute(GNE_ATTR_SELECTED, "true", mySelectorFrameParent->getViewNet()->getUndoList());
1076 }
1077 // now iterate over all elements of "copyOfSelectedAC" and undselect it
1078 for (auto i : copyOfSelectedAC) {
1079 i->setAttribute(GNE_ATTR_SELECTED, "false", mySelectorFrameParent->getViewNet()->getUndoList());
1080 }
1081 // finish selection operation
1082 mySelectorFrameParent->getViewNet()->getUndoList()->p_end();
1083 // update view
1084 mySelectorFrameParent->getViewNet()->update();
1085 return 1;
1086 }
1087
1088
1089 /****************************************************************************/
1090