SUMO - Simulation of Urban MObility
GNEInspector.cpp
Go to the documentation of this file.
1 /****************************************************************************/
7 // The Widget for modifying network-element attributes (i.e. lane speed)
8 /****************************************************************************/
9 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
10 // Copyright (C) 2001-2015 DLR (http://www.dlr.de/) and contributors
11 /****************************************************************************/
12 //
13 // This file is part of SUMO.
14 // SUMO is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #ifdef _MSC_VER
26 #include <windows_config.h>
27 #else
28 #include <config.h>
29 #endif
30 
31 #ifdef HAVE_VERSION_H
32 #include <version.h>
33 #endif
34 
35 #include <cmath>
36 #include <cassert>
37 #include <iostream>
40 #include "GNEInspector.h"
41 #include "GNEUndoList.h"
42 #include "GNEEdge.h"
43 #include "GNEAttributeCarrier.h"
44 
45 #ifdef CHECK_MEMORY_LEAKS
46 #include <foreign/nvwa/debug_new.h>
47 #endif // CHECK_MEMORY_LEAKS
48 
49 
50 // ===========================================================================
51 // FOX callback mapping
52 // ===========================================================================
53 FXDEFMAP(GNEInspector) GNEInspectorMap[] = {
57 };
58 
59 /*
60 FXDEFMAP(GNEInspector::AttrPanel) AttrPanelMap[]= {
61  FXMAPFUNC(SEL_COMMAND, MID_GNE_COPY_TEMPLATE, GNEInspector::AttrPanelMap::onCmdCopyTemplate),
62  FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_TEMPLATE, GNEInspector::AttrPanelMap::onCmdSetTemplate)
63 };
64 */
65 
66 FXDEFMAP(GNEInspector::AttrInput) AttrInputMap[] = {
69 };
70 
71 // Object implementation
72 FXIMPLEMENT(GNEInspector, FXScrollWindow, GNEInspectorMap, ARRAYNUMBER(GNEInspectorMap))
73 // FXIMPLEMENT(GNEInspector::AttrPanel, FXVerticalFrame, AttrPanelMap, ARRAYNUMBER(AttrPanelMap))
74 FXIMPLEMENT(GNEInspector::AttrInput, FXHorizontalFrame, AttrInputMap, ARRAYNUMBER(AttrInputMap))
75 
76 // ===========================================================================
77 // static members
78 // ===========================================================================
79 const int GNEInspector::WIDTH = 140;
80 
81 // ===========================================================================
82 // method definitions
83 // ===========================================================================
84 GNEInspector::GNEInspector(FXComposite* parent, GNEUndoList* undoList):
85  FXScrollWindow(parent, LAYOUT_FILL_Y | LAYOUT_FIX_WIDTH, 0, 0, WIDTH, 0),
86  myUndoList(undoList),
87  myHeaderFont(new FXFont(getApp(), "Arial", 18, FXFont::Bold)),
88  myPanel(0),
89  myEdgeTemplate(0) {
90  myPanel = new AttrPanel(this, myACs, undoList);
91 }
92 
93 
94 void
96  FXScrollWindow::create();
97  myHeaderFont->create();
98  myPanel->create();
99 }
100 
101 
103  delete myPanel;
104  delete myHeaderFont;
105  if (myEdgeTemplate) {
106  myEdgeTemplate->decRef("GNEInspector::~GNEInspector");
107  if (myEdgeTemplate->unreferenced()) {
108  delete myEdgeTemplate;
109  }
110  }
111 }
112 
113 
114 void
115 GNEInspector::inspect(const std::vector<GNEAttributeCarrier*>& ACs) {
116  delete myPanel;
117  myACs = ACs;
118  myPanel = new AttrPanel(this, myACs, myUndoList);
119  myPanel->create();
120  recalc();
121 }
122 
123 
124 void
126  inspect(myACs);
127 }
128 
129 void
131  if (myEdgeTemplate) {
132  myEdgeTemplate->decRef("GNEInspector::setEdgeTemplate");
133  if (myEdgeTemplate->unreferenced()) {
134  delete myEdgeTemplate;
135  }
136  }
137  myEdgeTemplate = tpl;
138  myEdgeTemplate->incRef("GNEInspector::setEdgeTemplate");
139 }
140 
141 
142 long
143 GNEInspector::onCmdCopyTemplate(FXObject*, FXSelector, void*) {
144  for (std::vector<GNEAttributeCarrier*>::iterator it = myACs.begin(); it != myACs.end(); it++) {
145  GNEEdge* edge = dynamic_cast<GNEEdge*>(*it);
146  assert(edge);
148  }
149  return 1;
150 }
151 
152 
153 long
154 GNEInspector::onCmdSetTemplate(FXObject*, FXSelector, void*) {
155  assert(myACs.size() == 1);
156  GNEEdge* edge = dynamic_cast<GNEEdge*>(myACs[0]);
157  assert(edge);
158  setEdgeTemplate(edge);
159  myPanel->update();
160  return 1;
161 }
162 
163 
164 long
165 GNEInspector::onUpdCopyTemplate(FXObject* sender, FXSelector, void*) {
166  FXString caption;
167  if (myEdgeTemplate) {
168  caption = ("Copy '" + myEdgeTemplate->getMicrosimID() + "'").c_str();
169  sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
170  } else {
171  caption = "No Template Set";
172  sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), NULL);
173  }
174  sender->handle(this, FXSEL(SEL_COMMAND, FXLabel::ID_SETSTRINGVALUE), (void*)&caption);
175  return 1;
176 }
177 
178 
179 // ===========================================================================
180 // AttrPanel method definitions
181 // ===========================================================================
182 
183 GNEInspector::AttrPanel::AttrPanel(GNEInspector* parent, const std::vector<GNEAttributeCarrier*>& ACs, GNEUndoList* undoList) :
184  FXVerticalFrame(parent, LAYOUT_FILL_Y | LAYOUT_FIX_WIDTH, 0, 0, WIDTH, 0, 2, 0, 0, 0, 0, 0) {
185  FXLabel* header;
186  if (ACs.size() > 0) {
187  std::string headerString = toString(ACs[0]->getTag());
188  if (ACs.size() > 1) {
189  headerString = toString(ACs.size()) + " " + headerString + "s";
190  }
191  header = new FXLabel(this, headerString.c_str());
192  new FXHorizontalSeparator(this, SEPARATOR_GROOVE | LAYOUT_FILL_X, 0, 0, 0, 2, 2, 2, 4, 4);
193 
194  const std::vector<SumoXMLAttr>& attrs = ACs[0]->getAttrs();
195  for (std::vector<SumoXMLAttr>::const_iterator it = attrs.begin(); it != attrs.end(); it++) {
196  if (ACs.size() > 1 && GNEAttributeCarrier::isUnique(*it)) {
197  // disable editing for some attributes in case of multi-selection
198  // even displaying is problematic because of string rendering restrictions
199  continue;
200  }
201  std::set<std::string> occuringValues;
202  for (std::vector<GNEAttributeCarrier*>::const_iterator it_ac = ACs.begin(); it_ac != ACs.end(); it_ac++) {
203  occuringValues.insert((*it_ac)->getAttribute(*it));
204  }
205  std::ostringstream oss;
206  for (std::set<std::string>::iterator it_val = occuringValues.begin(); it_val != occuringValues.end(); it_val++) {
207  if (it_val != occuringValues.begin()) {
208  oss << " ";
209  }
210  oss << *it_val;
211  }
212  new AttrInput(this, ACs, *it, oss.str(), undoList);
213  }
214 
215  if (dynamic_cast<GNEEdge*>(ACs[0])) {
216  new FXHorizontalSeparator(this, SEPARATOR_GROOVE | LAYOUT_FILL_X, 0, 0, 0, 2, 2, 2, 4, 4);
217  // "Copy Template" (caption supplied via onUpdate)
218  new FXButton(this, "", 0, parent, MID_GNE_COPY_TEMPLATE,
219  ICON_BEFORE_TEXT | LAYOUT_FILL_X | FRAME_THICK | FRAME_RAISED,
220  0, 0, 0, 0, 4, 4, 3, 3);
221 
222  if (ACs.size() == 1) {
223  // "Set As Template"
224  new FXButton(this, "Set as Template\t\t", 0, parent, MID_GNE_SET_TEMPLATE,
225  ICON_BEFORE_TEXT | LAYOUT_FILL_X | FRAME_THICK | FRAME_RAISED,
226  0, 0, 0, 0, 4, 4, 3, 3);
227  }
228  };
229  } else {
230  header = new FXLabel(this, "No Object\nselected", 0, JUSTIFY_LEFT);
231  }
232  header->setFont(parent->getHeaderFont());
233 
234 }
235 
236 
237 // ===========================================================================
238 // AttrInput method definitions
239 //
240 // ===========================================================================
242  FXComposite* parent,
243  const std::vector<GNEAttributeCarrier*>& ACs, SumoXMLAttr attr, std::string initialValue,
244  GNEUndoList* undoList) :
245  FXHorizontalFrame(parent, LAYOUT_FILL_X, 0, 0, WIDTH, 0, 0, 0, 0, 2),
246  myTag(ACs[0]->getTag()),
247  myAttr(attr),
248  myACs(&ACs),
249  myUndoList(undoList),
250  myTextField(0),
251  myChoicesCombo(0) {
252  const std::vector<std::string>& choices = GNEAttributeCarrier::discreteChoices(myTag, myAttr);
253  const bool combinableChoices = choices.size() > 0 && GNEAttributeCarrier::discreteCombinableChoices(myTag, myAttr);
254  FXuint opts;
255  std::string label;
256  if (combinableChoices) {
257  opts = BUTTON_NORMAL;
258  label = toString(attr) + "\t\tOpen edit dialog for attribute '" + toString(attr) + "'";
259  } else {
260  opts = 0;
261  label = toString(attr);
262  }
263  FXButton* but = new FXButton(this, label.c_str(), 0, this, MID_GNE_OPEN_ATTRIBUTE_EDITOR,
264  opts, 0, 0, 0, 0, DEFAULT_PAD, DEFAULT_PAD, 1, 1);
265  int cols = (WIDTH - but->getDefaultWidth() - 6) / 9;
266  if (choices.size() == 0 || combinableChoices) {
267  // rudimentary input restriction
268  unsigned int numerical = GNEAttributeCarrier::isNumerical(attr) ? TEXTFIELD_REAL : 0;
269  myTextField = new FXTextField(this, cols,
270  this, MID_GNE_SET_ATTRIBUTE, TEXTFIELD_NORMAL | LAYOUT_RIGHT | numerical, 0, 0, 0, 0, 4, 2, 0, 2);
271  myTextField->setText(initialValue.c_str());
272  } else {
273  myChoicesCombo = new FXComboBox(this, 12, this, MID_GNE_SET_ATTRIBUTE,
274  FRAME_SUNKEN | LAYOUT_LEFT | LAYOUT_TOP | COMBOBOX_STATIC | LAYOUT_CENTER_Y);
275  for (std::vector<std::string>::const_iterator it = choices.begin(); it != choices.end(); ++it) {
276  myChoicesCombo->appendItem(it->c_str());
277  }
278  myChoicesCombo->setNumVisible((int)choices.size());
279  myChoicesCombo->setCurrentItem(myChoicesCombo->findItem(initialValue.c_str()));
280  }
281 }
282 
283 
284 long
286  FXDialogBox* editor = new FXDialogBox(getApp(),
287  ("Select " + toString(myAttr) + "ed").c_str(),
288  DECOR_CLOSE | DECOR_TITLE);
289  FXMatrix* m1 = new FXMatrix(editor, 2, MATRIX_BY_COLUMNS);
290  const std::vector<std::string>& choices = GNEAttributeCarrier::discreteChoices(myTag, myAttr);
291  std::vector<FXCheckButton*> vClassButtons;
292  const std::string oldValue(myTextField->getText().text());
293  for (std::vector<std::string>::const_iterator it = choices.begin(); it != choices.end(); ++it) {
294  vClassButtons.push_back(new FXCheckButton(m1, (*it).c_str()));
295  if (oldValue.find(*it) != std::string::npos) {
296  vClassButtons.back()->setCheck(true);
297  }
298  }
299  // buttons
300  new FXHorizontalSeparator(m1, SEPARATOR_GROOVE | LAYOUT_FILL_X, 0, 0, 0, 2, 2, 2, 4, 4);
301  new FXHorizontalSeparator(m1, SEPARATOR_GROOVE | LAYOUT_FILL_X, 0, 0, 0, 2, 2, 2, 4, 4);
302  // "Cancel"
303  new FXButton(m1, "Cancel\t\tDiscard modifications", 0, editor, FXDialogBox::ID_CANCEL,
304  ICON_BEFORE_TEXT | LAYOUT_FILL_X | FRAME_THICK | FRAME_RAISED,
305  0, 0, 0, 0, 4, 4, 3, 3);
306  // "OK"
307  new FXButton(m1, "OK\t\tSave modifications", 0, editor, FXDialogBox::ID_ACCEPT,
308  ICON_BEFORE_TEXT | LAYOUT_FILL_X | FRAME_THICK | FRAME_RAISED,
309  0, 0, 0, 0, 4, 4, 3, 3);
310  editor->create();
311  if (editor->execute()) {
312  std::vector<std::string> vClasses;
313  for (std::vector<FXCheckButton*>::const_iterator it = vClassButtons.begin(); it != vClassButtons.end(); ++it) {
314  if ((*it)->getCheck()) {
315  vClasses.push_back(std::string((*it)->getText().text()));
316  }
317  }
318  myTextField->setText(joinToString(vClasses, " ").c_str());
319  onCmdSetAttribute(0, 0, 0);
320  }
321  return 1;
322 }
323 
324 
325 long
326 GNEInspector::AttrInput::onCmdSetAttribute(FXObject*, FXSelector, void* data) {
327  std::string newVal(myTextField != 0 ? myTextField->getText().text() : (char*) data);
328  const std::vector<GNEAttributeCarrier*>& ACs = *myACs;
329  if (ACs[0]->isValid(myAttr, newVal)) {
330  // if its valid for the first AC than its valid for all (of the same type)
331  if (ACs.size() > 1) {
332  myUndoList->p_begin("Change multiple attributes");
333  }
334  for (std::vector<GNEAttributeCarrier*>::const_iterator it_ac = ACs.begin(); it_ac != ACs.end(); it_ac++) {
335  (*it_ac)->setAttribute(myAttr, newVal, myUndoList);
336  }
337  if (ACs.size() > 1) {
338  myUndoList->p_end();
339  }
340  if (myTextField != 0) {
341  myTextField->setTextColor(FXRGB(0, 0, 0));
342  myTextField->killFocus();
343  }
344  } else {
345  if (myTextField != 0) {
346  myTextField->setTextColor(FXRGB(255, 0, 0));
347  }
348  }
349  return 1;
350 }
351 
352 
353 /****************************************************************************/
void copyTemplate(GNEEdge *tpl, GNEUndoList *undolist)
copy edge attributes from tpl
Definition: GNEEdge.cpp:369
AttrPanel()
FOX needs this.
Definition: GNEInspector.h:68
std::vector< GNEAttributeCarrier * > myACs
the multi-selection currently being inspected
Definition: GNEInspector.h:160
static bool isNumerical(SumoXMLAttr attr)
whether an attribute is numerical
void inspect(const std::vector< GNEAttributeCarrier * > &ACs)
Inspect the given multi-selection.
long onUpdCopyTemplate(FXObject *, FXSelector, void *)
update the copy button with the name of the template
FXFont * myHeaderFont
Font for the widget.
Definition: GNEInspector.h:152
void create()
Creates the widget.
~GNEInspector()
Destructor.
FXTextField * myTextField
Definition: GNEInspector.h:97
long onCmdCopyTemplate(FXObject *, FXSelector, void *)
copy edge attributes from edge template
const std::string & getMicrosimID() const
Returns the id of the object as known to microsim.
Definition: GUIGlObject.h:154
void p_begin(const std::string &description)
Definition: GNEUndoList.cpp:75
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
void setEdgeTemplate(GNEEdge *tpl)
GNEUndoList * myUndoList
Definition: GNEInspector.h:96
long onCmdSetTemplate(FXObject *, FXSelector, void *)
set current edge as new template
static const std::vector< std::string > & discreteChoices(SumoXMLTag tag, SumoXMLAttr attr)
return a list of discrete choices for this attribute or an empty vector
GNEEdge * myEdgeTemplate
the edge template
Definition: GNEInspector.h:157
#define new
Definition: debug_new.h:121
FXFont * getHeaderFont()
Definition: GNEInspector.h:123
void p_end()
Definition: GNEUndoList.cpp:82
void update()
update the widget
FXDEFMAP(GNEInspector) GNEInspectorMap[]
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:53
long onCmdOpenAttributeEditor(FXObject *, FXSelector, void *)
open model dialog for more comfortable attribute editing
void incRef(const std::string &debugMsg="")
void decRef(const std::string &debugMsg="")
AttrPanel * myPanel
Definition: GNEInspector.h:154
A road/street connecting two junctions (netedit-version)
Definition: GNEEdge.h:61
static bool discreteCombinableChoices(SumoXMLTag tag, SumoXMLAttr attr)
return whether the given attribute allows for a combination of discrete values
const std::vector< GNEAttributeCarrier * > * myACs
Definition: GNEInspector.h:95
FXComboBox * myChoicesCombo
Definition: GNEInspector.h:98
long onCmdSetAttribute(FXObject *, FXSelector, void *)
try to set new attribute value
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:159
GNEUndoList * myUndoList
Definition: GNEInspector.h:149
static bool isUnique(SumoXMLAttr attr)
whether an attribute is unique (may not be edited for a multi-selection)
AttrInput()
FOX needs this.
Definition: GNEInspector.h:90
static const int WIDTH
Definition: GNEInspector.h:162