1""" 2@package vnet.dialogs 3 4@brief Dialogs for vector network analysis front-end 5 6Classes: 7 - dialogs::VNETDialog 8 - dialogs::PtsList 9 - dialogs::SettingsDialog 10 - dialogs::CreateTtbDialog 11 - dialogs::OutputVectorDialog 12 - dialogs::VnetStatusbar 13 - dialogs::DefIntesectionTurnCostDialog 14 - dialogs::DefGlobalTurnsDialog 15 - dialogs::TurnAnglesList 16 17(C) 2012-2013 by the GRASS Development Team 18 19This program is free software under the GNU General Public License 20(>=v2). Read the file COPYING that comes with GRASS for details. 21 22@author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa) 23@author Lukas Bocan <silent_bob centrum.cz> (turn costs support) 24@author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support) 25""" 26 27import os 28import sys 29import types 30import six 31 32if sys.version_info.major >= 3: 33 unicode = str 34 35from copy import copy 36from grass.script import core as grass 37 38import wx 39import wx.aui 40try: 41 import wx.lib.agw.flatnotebook as FN 42except ImportError: 43 import wx.lib.flatnotebook as FN 44import wx.lib.colourselect as csel 45import wx.lib.mixins.listctrl as listmix 46import wx.lib.scrolledpanel as scrolled 47 48from core import globalvar, utils 49from core.gcmd import RunCommand, GMessage 50from core.settings import UserSettings 51 52from dbmgr.base import DbMgrBase 53from dbmgr.vinfo import VectorDBInfo 54 55from gui_core.widgets import GNotebook 56from gui_core.goutput import GConsoleWindow 57from gui_core.gselect import Select, LayerSelect, ColumnSelect 58from gui_core.wrap import ( 59 BitmapButton, BitmapFromImage, Button, CheckBox, ComboBox, ListCtrl, 60 Panel, ScrolledPanel, SpinCtrl, StaticBox, StaticText, TextCtrl 61) 62 63from vnet.widgets import PointsList 64from vnet.toolbars import MainToolbar, PointListToolbar, AnalysisToolbar 65from vnet.vnet_core import VNETManager 66from vnet.vnet_utils import DegreesToRadians, RadiansToDegrees, GetNearestNodeCat, ParseMapStr 67 68# Main TODOs 69# - when layer tree of is changed, tmp result map is removed from render list 70# - optimization of map drawing 71# - tmp maps - add number of process 72 73 74class VNETDialog(wx.Dialog): 75 76 def __init__(self, parent, giface, id=wx.ID_ANY, 77 title=_("GRASS GIS Vector Network Analysis Tool"), 78 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs): 79 """Dialog for vector network analysis""" 80 81 wx.Dialog.__init__( 82 self, 83 parent, 84 id, 85 style=style, 86 title=title, 87 **kwargs) 88 self.SetIcon( 89 wx.Icon( 90 os.path.join( 91 globalvar.ICONDIR, 92 'grass.ico'), 93 wx.BITMAP_TYPE_ICO)) 94 95 self.parent = parent 96 self.mapWin = giface.GetMapWindow() 97 self.giface = giface 98 99 # contains current analysis result (do not have to be last one, when history is browsed), 100 # it is instance of VectMap class 101 self.tmp_result = None 102 103 self.defIsecTurnsHndlrReg = False 104 105 # get attribute table columns only with numbers (for cost columns in 106 # vnet analysis) 107 self.columnTypes = ['integer', 'double precision'] 108 109 self.vnet_mgr = VNETManager(self, giface) 110 111 self.vnet_mgr.analysisDone.connect(self.AnalysisDone) 112 self.vnet_mgr.ttbCreated.connect(self.TtbCreated) 113 self.vnet_mgr.snapping.connect(self.Snapping) 114 self.vnet_mgr.pointsChanged.connect(self.PointsChanged) 115 116 self.currAnModule, valid = self.vnet_mgr.GetParam("analysis") 117 118 # toobars 119 self.toolbars = {} 120 self.toolbars['mainToolbar'] = MainToolbar( 121 parent=self, vnet_mgr=self.vnet_mgr) 122 self.toolbars['analysisToolbar'] = AnalysisToolbar( 123 parent=self, vnet_mgr=self.vnet_mgr) 124 # 125 # Fancy gui 126 # 127 self._mgr = wx.aui.AuiManager(self) 128 129 self.mainPanel = Panel(parent=self) 130 self.notebook = GNotebook(parent=self.mainPanel, 131 style=globalvar.FNPageDStyle) 132 133 # statusbar 134 self.stPriorities = {'important': 5, 'iformation': 1} 135 self.stBar = VnetStatusbar(parent=self.mainPanel, style=0) 136 self.stBar.SetFieldsCount(number=1) 137 138 self.def_isec_turns = None 139 140 # Create tabs 141 142 # Stores widgets which sets some of analysis parameters (e. g. v.ne.iso 143 # -> iso lines) 144 self.anSettings = {} 145 146 self._createPointsPage() 147 148 # stores widgets which are shown on parameters page 149 # they set data, on which analysis will be done 150 self.inputData = {} 151 self._createParametersPage() 152 153 # Output console for analysis 154 self._createOutputPage() 155 156 # Stores data which are needed for attribute table browser of analysis 157 # input map layers 158 self.inpDbMgrData = {} 159 self._checkSelectedVectorMap() 160 161 # Stores data which are need for attribute table browser of analysis 162 # result map layers 163 self.resultDbMgrData = {} 164 if self.tmp_result: 165 self.resultDbMgrData['input'] = self.tmp_result.GetVectMapName() 166 else: 167 self.resultDbMgrData['input'] = None 168 169 self.notebook.Bind( 170 FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, 171 self.OnPageChanged) 172 self.Bind(wx.EVT_CLOSE, self.OnCloseDialog) 173 174 self._addPanes() 175 self._doVnetDialogLayout() 176 self._mgr.Update() 177 178 self.SetSize((370, 550)) 179 self.SetMinSize((370, 420)) 180 181 # fix goutput's pane size (required for Mac OSX) 182 if self.gwindow: 183 self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75)) 184 185 self.OnAnalysisChanged(None) 186 self.notebook.SetSelectionByName("parameters") 187 self.toolbars['analysisToolbar'].SetMinSize( 188 (-1, self.toolbars['mainToolbar'].GetSize()[1])) 189 190 self.toolbars['mainToolbar'].UpdateUndoRedo(0, 0) 191 192 def _addPanes(self): 193 """Adds toolbar pane and pane with tabs""" 194 self._mgr.AddPane(self.toolbars['mainToolbar'], 195 wx.aui.AuiPaneInfo(). 196 Name("pointlisttools").Caption(_("Point list toolbar")). 197 ToolbarPane().Top().Row(0). 198 Dockable(False). 199 CloseButton(False).Layer(0)) 200 201 self._mgr.AddPane(self.toolbars['analysisToolbar'], 202 wx.aui.AuiPaneInfo(). 203 Name("analysisTools").Caption(_("Analysis toolbar")). 204 ToolbarPane().Top().Row(1). 205 Dockable(False). 206 CloseButton(False).Layer(0)) 207 208 self._mgr.AddPane(self.mainPanel, 209 wx.aui.AuiPaneInfo(). 210 Name("tabs").CaptionVisible(visible=False). 211 Center(). 212 Dockable(False). 213 CloseButton(False).Layer(0)) 214 215 def _doVnetDialogLayout(self): 216 217 sizer = wx.BoxSizer(wx.VERTICAL) 218 219 sizer.Add(self.notebook, proportion=1, 220 flag=wx.EXPAND) 221 222 sizer.Add(self.stBar, proportion=0, flag=wx.EXPAND) 223 224 self.mainPanel.SetSizer(sizer) 225 226 sizer.Fit(self) 227 self.Layout() 228 229 def _createPointsPage(self): 230 """Tab with points list and analysis settings""" 231 pointsPanel = Panel(parent=self) 232 anSettingsPanel = Panel(parent=pointsPanel) 233 maxDistPanel = Panel(parent=anSettingsPanel) 234 maxValue = 1e8 235 236 listBox = StaticBox(parent=pointsPanel, id=wx.ID_ANY, 237 label=" %s " % _("Points for analysis:")) 238 listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL) 239 anSettingsBox = StaticBox(parent=anSettingsPanel, id=wx.ID_ANY, 240 label=" %s " % _("Analysis settings:")) 241 anSettingsSizer = wx.StaticBoxSizer(anSettingsBox, wx.VERTICAL) 242 243 self.notebook.AddPage(page=pointsPanel, 244 text=_('Points'), 245 name='points') 246 247 self.list = PtsList(parent=pointsPanel, vnet_mgr=self.vnet_mgr) 248 toolSwitcher = self.giface.GetMapDisplay().GetToolSwitcher() 249 self.toolbars['pointsList'] = PointListToolbar( 250 parent=pointsPanel, 251 toolSwitcher=toolSwitcher, 252 dialog=self, 253 vnet_mgr=self.vnet_mgr) 254 255 maxDistLabel = StaticText( 256 parent=maxDistPanel, id=wx.ID_ANY, 257 label=_("Maximum distance of point to the network:")) 258 self.anSettings["max_dist"] = SpinCtrl( 259 parent=maxDistPanel, id=wx.ID_ANY, min=0, max=maxValue, 260 size=(150, -1), 261 ) 262 self.anSettings["max_dist"].Bind( 263 wx.EVT_SPINCTRL, lambda event: self.MaxDist()) 264 self.anSettings["max_dist"].SetValue(100000) # TODO init val 265 self.MaxDist() 266 267 #showCutPanel = Panel(parent = anSettingsPanel) 268 # self.anSettings["show_cut"] = CheckBox(parent = showCutPanel, id=wx.ID_ANY, 269 # label = _("Show minimal cut")) 270 #self.anSettings["show_cut"].Bind(wx.EVT_CHECKBOX, self.OnShowCut) 271 272 isoLinesPanel = Panel(parent=anSettingsPanel) 273 isoLineslabel = StaticText( 274 parent=isoLinesPanel, 275 id=wx.ID_ANY, 276 label=_("Iso lines:")) 277 self.anSettings["iso_lines"] = TextCtrl( 278 parent=isoLinesPanel, id=wx.ID_ANY) 279 self.anSettings["iso_lines"].Bind( 280 wx.EVT_TEXT, lambda event: self.IsoLines()) 281 self.anSettings["iso_lines"].SetValue("1000,2000,3000") 282 self.IsoLines() 283 284 # Layout 285 AnalysisSizer = wx.BoxSizer(wx.VERTICAL) 286 287 listSizer.Add(self.toolbars['pointsList'], proportion=0) 288 listSizer.Add(self.list, proportion=1, flag=wx.EXPAND) 289 290 maxDistSizer = wx.BoxSizer(wx.HORIZONTAL) 291 maxDistSizer.Add( 292 maxDistLabel, 293 flag=wx.ALIGN_CENTER_VERTICAL, 294 proportion=1) 295 maxDistSizer.Add(self.anSettings["max_dist"], 296 flag=wx.EXPAND | wx.ALL, border=5, proportion=0) 297 maxDistPanel.SetSizer(maxDistSizer) 298 anSettingsSizer.Add(maxDistPanel, proportion=1, flag=wx.EXPAND) 299 300 #showCutSizer = wx.BoxSizer(wx.HORIZONTAL) 301 # showCutPanel.SetSizer(showCutSizer) 302 # showCutSizer.Add(item = self.anSettings["show_cut"], 303 # flag = wx.EXPAND | wx.ALL, border = 5, proportion = 0) 304 #anSettingsSizer.Add(item = showCutPanel, proportion = 1, flag = wx.EXPAND) 305 306 isoLinesSizer = wx.BoxSizer(wx.HORIZONTAL) 307 isoLinesSizer.Add( 308 isoLineslabel, 309 flag=wx.ALIGN_CENTER_VERTICAL, 310 proportion=1) 311 isoLinesSizer.Add(self.anSettings["iso_lines"], 312 flag=wx.EXPAND | wx.ALL, border=5, proportion=1) 313 isoLinesPanel.SetSizer(isoLinesSizer) 314 anSettingsSizer.Add(isoLinesPanel, proportion=1, flag=wx.EXPAND) 315 316 AnalysisSizer.Add( 317 listSizer, 318 proportion=1, 319 flag=wx.EXPAND | wx.ALL, 320 border=5) 321 AnalysisSizer.Add( 322 anSettingsPanel, 323 proportion=0, 324 flag=wx.EXPAND | wx.RIGHT | wx.LEFT | wx.BOTTOM, 325 border=5) 326 327 anSettingsPanel.SetSizer(anSettingsSizer) 328 pointsPanel.SetSizer(AnalysisSizer) 329 330 def MaxDist(self): 331 val = self.anSettings["max_dist"].GetValue() 332 self.vnet_mgr.SetParams({"max_dist": val}, {}) 333 334 def IsoLines(self): 335 val = self.anSettings["iso_lines"].GetValue() 336 self.vnet_mgr.SetParams({"iso_lines": val}, {}) 337 338 def OnShowCut(self, event): 339 """Shows vector map with minimal cut (v.net.flow) - not yet implemented""" 340 val = event.IsChecked() 341 if val and self.tmp_result: 342 self.tmp_result.DeleteRenderLayer() 343 cmd = self.GetLayerStyle() 344 self.vnetFlowTmpCut.AddRenderLayer(cmd) 345 else: 346 self.vnetFlowTmpCut.DeleteRenderLayer() 347 cmd = self.GetLayerStyle() 348 self.tmp_result.AddRenderLayer(cmd) 349 350 self.giface.updateMap.emit(render=True, renderVector=True) 351 352 def _createOutputPage(self): 353 """Tab with output console""" 354 outputPanel = Panel(parent=self) 355 self.notebook.AddPage(page=outputPanel, 356 text=_("Output"), 357 name='output') 358 359 goutput = self.vnet_mgr.goutput # TODO make interface 360 self.gwindow = GConsoleWindow(parent=outputPanel, gconsole=goutput) 361 362 # Layout 363 outputSizer = wx.BoxSizer(wx.VERTICAL) 364 outputSizer.Add(self.gwindow, proportion=1, flag=wx.EXPAND) 365 self.gwindow.SetMinSize((-1, -1)) 366 367 outputPanel.SetSizer(outputSizer) 368 369 def _createParametersPage(self): 370 """Tab for selection of data for analysis""" 371 dataPanel = ScrolledPanel(parent=self) 372 self.notebook.AddPage(page=dataPanel, 373 text=_('Parameters'), 374 name='parameters') 375 label = {} 376 dataSelects = [ 377 ['input', "Choose vector map for analysis:", Select], 378 ['arc_layer', "Arc layer number or name:", LayerSelect], 379 ['node_layer', "Node layer number or name:", LayerSelect], 380 #['turn_layer', "Layer with turntable:", LayerSelect], 381 #['turn_cat_layer', "Layer with unique categories for turntable:", LayerSelect], 382 ['arc_column', "", ColumnSelect], 383 ['arc_backward_column', "", ColumnSelect], 384 ['node_column', "", ColumnSelect], 385 ] 386 387 # self.useTurns = CheckBox(parent = dataPanel, id=wx.ID_ANY, 388 # label = _('Use turns')) 389 390 box = StaticBox(dataPanel, -1, "Vector map and layers for analysis") 391 bsizer = wx.StaticBoxSizer(box, wx.VERTICAL) 392 box2 = StaticBox(dataPanel, -1, "Costs") 393 bsizer2 = wx.StaticBoxSizer(box2, wx.VERTICAL) 394 selPanels = {} 395 396 for dataSel in dataSelects: 397 selPanels[dataSel[0]] = Panel(parent=dataPanel) 398 if dataSel[0] == 'input': 399 self.inputData[ 400 dataSel[0]] = dataSel[2]( 401 parent=selPanels[dataSel[0]], 402 size=(-1, -1), 403 type='vector') 404 icon = wx.Image( 405 os.path.join( 406 globalvar.ICONDIR, 407 "grass", 408 "layer-vector-add.png")) 409 icon.Rescale(18, 18) 410 icon = BitmapFromImage(icon) 411 self.addToTreeBtn = BitmapButton( 412 parent=selPanels[dataSel[0]], 413 bitmap=icon, size=globalvar.DIALOG_COLOR_SIZE) 414 self.addToTreeBtn.SetToolTip( 415 _("Add vector map into layer tree")) 416 self.addToTreeBtn.Disable() 417 self.addToTreeBtn.Bind(wx.EVT_BUTTON, self.OnToTreeBtn) 418 elif dataSel[0] != 'input': 419 # if dataSel[0] == "turn_layer": 420 # self.createTtbBtn = wx.Button(parent = selPanels[dataSel[0]], 421 # label = _("Create turntable")) 422 # self.createTtbBtn.Bind(wx.EVT_BUTTON, self.OnCreateTtbBtn) 423 424 self.inputData[dataSel[0]] = dataSel[2]( 425 parent=selPanels[dataSel[0]], size=(-1, -1)) 426 label[dataSel[0]] = StaticText(parent=selPanels[dataSel[0]], 427 name=dataSel[0]) 428 label[dataSel[0]].SetLabel(dataSel[1]) 429 430 self.inputData['input'].Bind(wx.EVT_TEXT, self.OnVectSel) 431 self.inputData['arc_layer'].Bind(wx.EVT_TEXT, self.OnALayerSel) 432 self.inputData['node_layer'].Bind(wx.EVT_TEXT, self.OnNLayerSel) 433 434 # , "turn_layer", "turn_cat_layer"]: 435 for params in ["arc_column", "arc_backward_column", "node_column"]: 436 self.inputData[params].Bind( 437 wx.EVT_TEXT, lambda event: self._setInputData()) 438 439 # self.useTurns.Bind(wx.EVT_CHECKBOX, 440 # lambda event: self.UseTurns()) 441 # self.UseTurns() 442 443 # Layout 444 mainSizer = wx.BoxSizer(wx.VERTICAL) 445 446 mainSizer.Add(bsizer, proportion=0, 447 flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=5) 448 449 # , 'turn_layer', 'turn_cat_layer']: 450 for sel in ['input', 'arc_layer', 'node_layer']: 451 if sel == 'input': 452 btn = self.addToTreeBtn 453 # elif sel == "turn_layer": 454 # btn = self.createTtbBtn 455 else: 456 btn = None 457 # if sel == 'turn_layer': 458 # bsizer.Add(item = self.useTurns, proportion = 0, 459 # flag = wx.TOP | wx.LEFT | wx.RIGHT, border = 5) 460 461 selPanels[sel].SetSizer(self._doSelLayout(title=label[sel], 462 sel=self.inputData[sel], 463 btn=btn)) 464 bsizer.Add(selPanels[sel], proportion=0, 465 flag=wx.EXPAND) 466 467 mainSizer.Add(bsizer2, proportion=0, 468 flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=5) 469 470 for sel in ['arc_column', 'arc_backward_column', 'node_column']: 471 selPanels[sel].SetSizer( 472 self._doSelLayout( 473 title=label[sel], 474 sel=self.inputData[sel])) 475 bsizer2.Add(selPanels[sel], proportion=0, 476 flag=wx.EXPAND) 477 478 dataPanel.SetSizer(mainSizer) 479 dataPanel.SetupScrolling() 480 481 dataPanel.SetAutoLayout(1) 482 483 def _doSelLayout(self, title, sel, btn=None): 484 # helper function for layout of self.inputData widgets initialized in 485 # _createParametersPage 486 selSizer = wx.BoxSizer(orient=wx.VERTICAL) 487 488 selTitleSizer = wx.BoxSizer(wx.HORIZONTAL) 489 selTitleSizer.Add(title, proportion=1, 490 flag=wx.LEFT | wx.TOP | wx.EXPAND, border=5) 491 492 selSizer.Add(selTitleSizer, proportion=0, 493 flag=wx.EXPAND) 494 495 if btn: 496 selFiledSizer = wx.BoxSizer(orient=wx.HORIZONTAL) 497 selFiledSizer.Add(sel, proportion=1, 498 flag=wx.EXPAND | wx.ALL) 499 500 selFiledSizer.Add(btn, proportion=0, 501 flag=wx.EXPAND | wx.ALL) 502 503 selSizer.Add(selFiledSizer, proportion=0, 504 flag=wx.EXPAND | wx.ALL, 505 border=5) 506 else: 507 selSizer.Add(sel, proportion=1, 508 flag=wx.EXPAND | wx.ALL, 509 border=5) 510 return selSizer 511 512 def _checkSelectedVectorMap(self): 513 """Check selected vector map""" 514 selMapName = None 515 # if selected vector map is in layer tree then set it 516 layer = self.giface.GetLayerList().GetSelectedLayer() 517 if layer is not None and layer.type == 'vector': 518 selMapName = layer.maplayer.name 519 self._createInputDbMgrPage() 520 521 self.inpDbMgrData['input'] = None 522 if selMapName: 523 self.inputData['input'].SetValue(selMapName) 524 self.OnVectSel(None) 525 526 def _createInputDbMgrPage(self): 527 """Tab with attribute tables of analysis input layers""" 528 self.inpDbMgrData['dbMgr'] = DbMgrBase() 529 530 self.inpDbMgrData['browse'] = self.inpDbMgrData[ 531 'dbMgr'].CreateDbMgrPage(parent=self.notebook, pageName='browse') 532 self.inpDbMgrData['browse'].SetTabAreaColour(globalvar.FNPageColor) 533 534 def _updateInputDbMgrPage(self, show): 535 """Show or hide input tables tab""" 536 if show and self.notebook.GetPageIndexByName('inputDbMgr') == -1: 537 self.notebook.AddPage(page=self.inpDbMgrData['browse'], 538 text=_('Input tables'), 539 name='inputDbMgr') 540 elif not show: 541 self.notebook.RemovePage(page=self.notebook.GetPageIndexByName('inputDbMgr')) 542 543 def _createResultDbMgrPage(self): 544 """Tab with attribute tables of analysis result layers""" 545 self.resultDbMgrData['dbMgr'] = DbMgrBase() 546 self.resultDbMgrData['browse'] = self.resultDbMgrData[ 547 'dbMgr'].CreateDbMgrPage(parent=self.notebook, pageName='browse') 548 self.resultDbMgrData['browse'].SetTabAreaColour(globalvar.FNPageColor) 549 550 def _updateResultDbMgrPage(self): 551 """Show or Hide Result tables tab""" 552 # analysis, which created result 553 analysis = self.resultDbMgrData['analysis'] 554 # TODO maybe no need to store this information, just check it has 555 # attribute table, if so show it 556 haveDbMgr = self.vnet_mgr.GetAnalysisProperties( 557 analysis)["resultProps"]["dbMgr"] 558 559 if haveDbMgr and self.notebook.GetPageIndexByName('resultDbMgr') == -1: 560 self._createResultDbMgrPage() 561 self.notebook.AddPage(page=self.resultDbMgrData['browse'], 562 text=_('Result tables'), 563 name='resultDbMgr') 564 elif not haveDbMgr: 565 page = self.notebook.GetPageIndexByName("resultDbMgr") 566 if page != -1: 567 self.notebook.RemovePage(page=page) 568 569 def OnPageChanged(self, event): 570 """Tab switched""" 571 if event.GetEventObject() == self.notebook: 572 dbMgrIndxs = [] 573 dbMgrIndxs.append(self.notebook.GetPageIndexByName('inputDbMgr')) 574 dbMgrIndxs.append(self.notebook.GetPageIndexByName('resultDbMgr')) 575 if self.notebook.GetSelection() in dbMgrIndxs: 576 self.stBar.AddStatusItem( 577 text=_('Loading tables...'), 578 key='dbMgr', 579 priority=self.stPriorities['important']) 580 self._updateDbMgrData() 581 self.stBar.RemoveStatusItem(key='dbMgr') 582 # update columns (when some is added in input tables browser), TODO 583 # needs optimization 584 elif self.notebook.GetSelection() == self.notebook.GetPageIndexByName('parameters'): 585 self.OnALayerSel(None) 586 self.OnNLayerSel(None) 587 588 self.Layout() 589 590 def _updateDbMgrData(self): 591 """Updates input/result tables page """ 592 if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('inputDbMgr'): 593 self._updateInputDbMgrData() 594 elif self.notebook.GetSelection() == self.notebook.GetPageIndexByName('resultDbMgr'): 595 self._updateResultDbMgrData() 596 else: 597 self.stBar.RemoveStatusItem('manager') 598 599 def _updateInputDbMgrData(self): 600 """Loads data according to selected layers in Parameters tab""" 601 inpSel = self.inputData['input'].GetValue().strip() 602 # changed vector map 603 if self.inpDbMgrData['input'] != inpSel: 604 wx.BeginBusyCursor() 605 self.inpDbMgrData['dbMgr'].ChangeVectorMap(vectorName=inpSel) 606 self.inpDbMgrData['input'] = inpSel 607 for layerName in ['arc_layer', 'node_layer']: 608 try: 609 layer = int(self.inputData[layerName].GetValue()) 610 except ValueError: 611 continue 612 self.inpDbMgrData['browse'].AddLayer(layer) 613 wx.EndBusyCursor() 614 # same vector map 615 else: 616 needLayers = [] 617 browseLayers = self.inpDbMgrData['browse'].GetAddedLayers() 618 for layerName in ['arc_layer', 'node_layer']: 619 try: 620 inpLayer = int(self.inputData[layerName].GetValue()) 621 except ValueError: 622 continue 623 624 if inpLayer in browseLayers: 625 needLayers.append(inpLayer) 626 continue 627 else: 628 wx.BeginBusyCursor() 629 self.inpDbMgrData['browse'].AddLayer(inpLayer) 630 wx.EndBusyCursor() 631 needLayers.append(inpLayer) 632 633 for layer in browseLayers: 634 if layer not in needLayers: 635 self.inpDbMgrData['browse'].DeletePage(layer) 636 637 def _updateResultDbMgrData(self): 638 """Loads data from analysis result map""" 639 if not self.tmp_result: 640 return 641 vectName = self.tmp_result.GetVectMapName() 642 643 if self.resultDbMgrData['input'] != vectName: 644 wx.BeginBusyCursor() 645 dbMgr = self.resultDbMgrData['dbMgr'] 646 dbMgr.ChangeVectorMap(vectorName=vectName) 647 648 for layer in dbMgr.GetVectorLayers(): 649 self.resultDbMgrData['browse'].AddLayer(layer) 650 651 self.resultDbMgrData['input'] = vectName 652 wx.EndBusyCursor() 653 654 def OnToTreeBtn(self, event): 655 """Add vector map into layer tree""" 656 vectorMap = self.inputData['input'].GetValue() 657 vectMapName, mapSet = ParseMapStr(vectorMap) 658 vectorMap = vectMapName + '@' + mapSet 659 existsMap = grass.find_file(name=vectMapName, 660 element='vector', 661 mapset=mapSet) 662 if not existsMap["name"]: 663 return 664 665 cmd = ['d.vect', 666 'map=' + vectorMap] 667 668 if True: 669 self.giface.GetLayerList().AddLayer(ltype="vector", 670 cmd=cmd, 671 name=vectorMap, 672 checked=True) 673 # d.mon case is not need giface implementation should solve it for us 674 675 def UseTurns(self): 676 if self.useTurns.IsChecked(): 677 self.inputData["turn_layer"].GetParent().Show() 678 self.inputData["turn_cat_layer"].GetParent().Show() 679 680 self.vnet_mgr.SetParams(params={}, flags={"t": True}) 681 else: 682 self.inputData["turn_layer"].GetParent().Hide() 683 self.inputData["turn_cat_layer"].GetParent().Hide() 684 685 self.vnet_mgr.SetParams(params={}, flags={"t": False}) 686 687 self.Layout() 688 689 def PointsChanged(self, method, kwargs): 690 691 if method == "EditMode" and not kwargs["activated"]: 692 ptListToolbar = self.toolbars['pointsList'] 693 if ptListToolbar: 694 ptListToolbar.ToggleTool( 695 ptListToolbar.GetToolId("insertPoint"), False) 696 697 if method == "EditMode" and kwargs["activated"]: 698 ptListToolbar = self.toolbars['pointsList'] 699 if ptListToolbar: 700 ptListToolbar.ToggleTool( 701 ptListToolbar.GetToolId("insertPoint"), True) 702 703 if method == "SetPointData" and ( 704 "e" in kwargs.keys() or "n" in kwargs.keys()): 705 self.notebook.SetSelectionByName("points") 706 707 def OnCreateTtbBtn(self, event): 708 709 params, err_params, flags = self.vnet_mgr.GetParams() 710 dlg = CreateTtbDialog(parent=self, init_data=params) 711 712 if dlg.ShowModal() == wx.ID_OK: 713 self.stBar.AddStatusItem(text=_('Creating turntable...'), 714 key='ttb', 715 priority=self.stPriorities['important']) 716 717 params = dlg.GetData() 718 if not self.vnet_mgr.CreateTttb(params): 719 self.stBar.RemoveStatusItem('ttb') 720 dlg.Destroy() 721 722 def TtbCreated(self): 723 724 params, err_params, flags = self.vnet_mgr.GetParams() 725 self._updateParamsTab(params, flags) 726 727 self.stBar.RemoveStatusItem('ttb') 728 729 def OnVectSel(self, event): 730 """When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)""" 731 if self.vnet_mgr.IsSnappingActive(): # TODO should be in vnet_mgr 732 self.vnet_mgr.Snapping(activate=True) 733 734 vectMapName, mapSet = self._parseMapStr( 735 self.inputData['input'].GetValue()) 736 vectorMap = vectMapName + '@' + mapSet 737 738 # , 'turn_layer', 'turn_cat_layer']: 739 for sel in ['arc_layer', 'node_layer']: 740 self.inputData[sel].Clear() 741 self.inputData[sel].InsertLayers(vector=vectorMap) 742 743 items = self.inputData['arc_layer'].GetItems() 744 itemsLen = len(items) 745 if itemsLen < 1: 746 self.addToTreeBtn.Disable() 747 if hasattr(self, 'inpDbMgrData'): 748 self._updateInputDbMgrPage(show=False) 749 self.inputData['arc_layer'].SetValue("") 750 self.inputData['node_layer'].SetValue("") 751 for sel in ['arc_column', 'arc_backward_column', 'node_column']: 752 self.inputData[sel].SetValue("") 753 return 754 elif itemsLen == 1: 755 self.inputData['arc_layer'].SetSelection(0) 756 self.inputData['node_layer'].SetSelection(0) 757 elif itemsLen >= 1: 758 if unicode("1") in items: 759 iItem = items.index(unicode("1")) 760 self.inputData['arc_layer'].SetSelection(iItem) 761 if unicode("2") in items: 762 iItem = items.index(unicode("2")) 763 self.inputData['node_layer'].SetSelection(iItem) 764 765 self.addToTreeBtn.Enable() 766 if 'browse' in self.inpDbMgrData: 767 self._updateInputDbMgrPage(show=True) 768 else: 769 self._createInputDbMgrPage() 770 self._updateInputDbMgrPage(show=True) 771 772 self.OnALayerSel(event) 773 self.OnNLayerSel(event) 774 775 self._setInputData() 776 777 def _updateParamsTab(self, params, flags): 778 # TODO flag 779 780 #'turn_layer', 'turn_cat_layer', 781 for k in ['input', 'arc_layer', 'node_layer', 782 'arc_column', 'arc_backward_column', 'node_column']: 783 self.inputData[k].SetValue(params[k]) 784 785 def OnALayerSel(self, event): 786 """When arc layer from vector map is selected, populates corespondent columns selects""" 787 self.inputData['arc_column'].InsertColumns( 788 vector=self.inputData['input'].GetValue(), 789 layer=self.inputData['arc_layer'].GetValue(), 790 type=self.columnTypes) 791 self.inputData['arc_backward_column'].InsertColumns( 792 vector=self.inputData['input'].GetValue(), 793 layer=self.inputData['arc_layer'].GetValue(), 794 type=self.columnTypes) 795 796 self._setInputData() 797 798 def OnNLayerSel(self, event): 799 """When node layer from vector map is selected, populates corespondent column select""" 800 if self.vnet_mgr.IsSnappingActive(): 801 self.vnet_mgr.Snapping(activate=True) 802 803 self.inputData['node_column'].InsertColumns( 804 vector=self.inputData['input'].GetValue(), 805 layer=self.inputData['node_layer'].GetValue(), 806 type=self.columnTypes) 807 808 self._setInputData() 809 810 def _setInputData(self): 811 params = {} 812 for k, v in six.iteritems(self.inputData): 813 params[k] = v.GetValue() 814 flags = {} 815 self.vnet_mgr.SetParams(params, flags) 816 817 def _parseMapStr(self, vectMapStr): 818 """Create full map name (add current mapset if it is not present in name)""" 819 mapValSpl = vectMapStr.strip().split("@") 820 if len(mapValSpl) > 1: 821 mapSet = mapValSpl[1] 822 else: 823 mapSet = grass.gisenv()['MAPSET'] 824 mapName = mapValSpl[0] 825 826 return mapName, mapSet 827 828 def OnCloseDialog(self, event=None): 829 """Cancel dialog""" 830 self.vnet_mgr.CleanUp() 831 self._mgr.UnInit() 832 toolSwitcher = self.giface.GetMapDisplay().GetToolSwitcher() 833 toolSwitcher.RemoveToolbarFromGroup( 834 'mouseUse', self.toolbars['pointsList']) 835 self.parent.dialogs['vnet'] = None 836 self.Destroy() 837 838 def OnDefIsecTurnCosts(self, event): 839 """Registers/unregisters mouse handler into map window""" 840 if self.defIsecTurnsHndlrReg == False: 841 self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN, 842 self.OnDefIsecTurnCost, 843 'cross') 844 self.defIsecTurnsHndlrReg = True 845 else: 846 self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, 847 self.OnDefIsecTurnCost) 848 849 self.defIsecTurnsHndlrReg = False 850 851 def OnDefGlobalTurnCosts(self, event): 852 853 dialog = DefGlobalTurnsDialog( 854 self, data=self.vnet_mgr.GetGlobalTurnsData()) 855 dialog.Show() 856 857 def OnDefIsecTurnCost(self, event): # TODO move to vnet mgr? 858 """Take coordinates from map window""" 859 if event == 'unregistered': 860 ptListToolbar = self.toolbars['pointsList'] 861 if ptListToolbar: 862 ptListToolbar.ToggleTool( 863 id=ptListToolbar.GetToolId("isec_turn_edit"), toggle=False) 864 self.handlerRegistered = False 865 return 866 867 e, n = self.mapWin.GetLastEN() 868 869 # compute threshold 870 snapTreshPix = int(UserSettings.Get(group='vnet', 871 key='other', 872 subkey='snap_tresh')) 873 res = max( 874 self.mapWin.Map.region['nsres'], 875 self.mapWin.Map.region['ewres']) 876 snapTreshDist = snapTreshPix * res 877 878 params, err_params, flags = self.vnet_mgr.GetParams() 879 880 if "input" in err_params: 881 GMessage(parent=self, 882 message=_("Input vector map does not exist.")) 883 884 if ["turn_layer", "turn_cat_layer"] in err_params: 885 GMessage( 886 parent=self, 887 message="Please choose existing turntable layer and unique categories layer in Parameters tab.") 888 889 cat = GetNearestNodeCat( 890 e, n, int(params['turn_cat_layer']), 891 snapTreshDist, params["input"]) 892 893 if not self.def_isec_turns: 894 self.def_isec_turns = DefIntesectionTurnCostDialog( 895 self, self.parent) 896 self.def_isec_turns.SetSize((500, 400)) 897 898 self.def_isec_turns.SetData(params["input"], params["turn_layer"]) 899 self.def_isec_turns.SetIntersection(cat) 900 self.def_isec_turns.Show() 901 902 def OnAnalyze(self, event): 903 """Called when network analysis is started""" 904 905 self.stBar.AddStatusItem(text=_('Analysing...'), 906 key='analyze', 907 priority=self.stPriorities['important']) 908 909 ret = self.vnet_mgr.RunAnalysis() 910 911 # TODO 912 self.resultDbMgrData['analysis'] = self.currAnModule 913 914 if ret < 0: 915 self.stBar.RemoveStatusItem(key='analyze') 916 if ret == -2: 917 self.notebook.SetSelectionByName("parameters") 918 919 def AnalysisDone(self): 920 921 curr_step, steps_num = self.vnet_mgr.GetHistStep() 922 self.toolbars['mainToolbar'].UpdateUndoRedo(curr_step, steps_num) 923 924 self.tmp_result = self.vnet_mgr.GetResults() 925 926 mainToolbar = self.toolbars['mainToolbar'] 927 id = vars(mainToolbar)['showResult'] 928 mainToolbar.ToggleTool(id, True) 929 930 self.stBar.RemoveStatusItem(key='analyze') 931 932 self._updateResultDbMgrPage() 933 self._updateDbMgrData() 934 935 self.giface.updateMap.emit(render=True, renderVector=True) 936 937 def OnShowResult(self, event): 938 """Show/hide analysis result""" 939 mainToolbar = self.toolbars['mainToolbar'] 940 id = vars(mainToolbar)['showResult'] 941 toggleState = mainToolbar.GetToolState(id) 942 943 if not self.tmp_result: 944 mainToolbar.ToggleTool(id, False) 945 elif toggleState: 946 self.vnet_mgr.ShowResult(True) 947 else: 948 self.vnet_mgr.ShowResult(False) 949 950 def OnSaveTmpLayer(self, event): 951 dlg = OutputVectorDialog(parent=self) 952 dlg.ShowModal() 953 self.vnet_mgr.SaveTmpLayer(dlg.vectSel.GetValue()) 954 dlg.Destroy() 955 956 def OnSettings(self, event): 957 """Displays vnet settings dialog""" 958 dlg = SettingsDialog(parent=self, id=wx.ID_ANY, 959 title=_('Settings'), vnet_mgr=self.vnet_mgr) 960 961 dlg.ShowModal() 962 dlg.Destroy() 963 964 def OnAnalysisChanged(self, event): 965 """Updates dialog when analysis is changed""" 966 # set chosen analysis 967 iAn = self.toolbars['analysisToolbar'].anChoice.GetSelection() 968 self.currAnModule = self.vnet_mgr.GetAnalyses()[iAn] 969 self.vnet_mgr.SetParams({"analysis": self.currAnModule}, {}) 970 971 # update dialog for particular analysis 972 if self.currAnModule == "v.net.iso": 973 self.anSettings['iso_lines'].GetParent().Show() 974 else: 975 self.anSettings['iso_lines'].GetParent().Hide() 976 977 # if self.currAnModule == "v.net.flow": TODO not implemented 978 # self.anSettings['show_cut'].GetParent().Show() 979 # else: 980 # self.anSettings['show_cut'].GetParent().Hide() 981 982 # show only corresponding selects for chosen v.net module 983 skip = [] 984 985 an_props = self.vnet_mgr.GetAnalysisProperties() 986 987 used_cols = [] 988 attrCols = an_props["cmdParams"]["cols"] 989 990 for col in six.iterkeys(attrCols): 991 992 if "inputField" in attrCols[col]: 993 colInptF = attrCols[col]["inputField"] 994 else: 995 colInptF = col 996 997 if col in skip: 998 continue 999 1000 inputPanel = self.inputData[colInptF].GetParent() 1001 inputPanel.Show() 1002 inputPanel.FindWindowByName( 1003 colInptF).SetLabel(attrCols[col]["label"]) 1004 1005 if col != colInptF: 1006 skip.append(colInptF) 1007 used_cols.append(colInptF) 1008 1009 for col in ["arc_backward_column", "arc_column", "node_column"]: 1010 if col not in used_cols: 1011 inputPanel = self.inputData[colInptF].GetParent() 1012 inputPanel.Hide() 1013 1014 self.Layout() 1015 1016 def Snapping(self, evt): 1017 """Start/stop snapping mode""" 1018 1019 if evt == "deactivated": 1020 self.stBar.RemoveStatusItem(key='snap') 1021 ptListToolbar = self.toolbars['pointsList'] 1022 ptListToolbar.ToggleTool(ptListToolbar.GetToolId("snapping"), False) 1023 1024 elif evt == "computing_points": 1025 self.stBar.AddStatusItem(text=_('Computing nodes...'), 1026 key='snap', 1027 priority=self.stPriorities['important']) 1028 1029 elif evt == "computing_points_done": 1030 self.stBar.RemoveStatusItem(key='snap') 1031 1032 def SnapPointsDone(self): 1033 """Update map window, when map with nodes to snap is created""" 1034 self.stBar.RemoveStatusItem(key='snap') 1035 1036 def OnUndo(self, event): 1037 """Step back in history""" 1038 1039 curr_step, steps_num = self.vnet_mgr.Undo() 1040 self._updateDialog() 1041 self.toolbars['mainToolbar'].UpdateUndoRedo(curr_step, steps_num) 1042 1043 def OnRedo(self, event): 1044 """Step forward in history""" 1045 1046 curr_step, steps_num = self.vnet_mgr.Redo() 1047 self._updateDialog() 1048 self.toolbars['mainToolbar'].UpdateUndoRedo(curr_step, steps_num) 1049 1050 def _updateDialog(self): 1051 params, err_params, flags = self.vnet_mgr.GetParams() 1052 self._updateParamsTab(params, flags) 1053 1054 anChoice = self.toolbars['analysisToolbar'].anChoice 1055 anChoice.SetSelection( 1056 self.vnet_mgr.GetAnalyses().index( 1057 params["analysis"])) 1058 self.currAnModule = params["analysis"] 1059 self.resultDbMgrData['analysis'] = params["analysis"] 1060 1061 # set analysis combobox 1062 anChoice = self.toolbars['analysisToolbar'].anChoice 1063 anChoice.SetSelection( 1064 self.vnet_mgr.GetAnalyses().index( 1065 params["analysis"])) 1066 1067 self._updateResultDbMgrPage() 1068 self._updateDbMgrData() 1069 1070 self.OnAnalysisChanged(None) 1071 1072 1073class PtsList(PointsList): 1074 1075 def __init__(self, parent, vnet_mgr, id=wx.ID_ANY): 1076 """ List with points for analysis""" 1077 self.updateMap = True 1078 self.vnet_mgr = vnet_mgr 1079 self.pts_data = self.vnet_mgr.GetPointsManager() 1080 1081 pts_data_cols = self.pts_data.GetColumns(only_relevant=False) 1082 1083 cols = [] 1084 for i_col, name in enumerate(pts_data_cols["name"]): 1085 if i_col == 0: 1086 continue 1087 cols.append([name, pts_data_cols["label"][i_col], pts_data_cols[ 1088 "type"][i_col], pts_data_cols["def_vals"][i_col]]) 1089 1090 PointsList.__init__(self, parent=parent, cols=cols, id=id) 1091 1092 self.vnet_mgr.pointsChanged.connect(self.PointsChanged) 1093 self.vnet_mgr.parametersChanged.connect(self.ParametersChanged) 1094 1095 analysis, valid = self.vnet_mgr.GetParam("analysis") 1096 1097 self.AnalysisChanged(analysis) 1098 1099 for iPt in range(self.pts_data.GetPointsCount()): 1100 self.AddItem() 1101 pt_dt = self.pts_data.GetPointData(iPt) 1102 self.SetData(iPt, pt_dt) 1103 self.Select(self.pts_data.GetSelected()) 1104 1105 def AnalysisChanged(self, analysis): 1106 active_cols = self.pts_data.GetColumns() 1107 if 'type' in active_cols["name"]: 1108 if not self.IsShown('type'): 1109 self.ShowColumn('type', 1) 1110 1111 type_idx = active_cols["name"].index("type") 1112 type_labels = active_cols["type"][type_idx] 1113 1114 self.ChangeColEditable('type', type_labels) 1115 colNum = self._getColumnNum('type') 1116 1117 for iItem, item in enumerate(self.itemDataMap): 1118 self.EditCellKey(iItem, 'type', self.selIdxs[iItem][colNum]) 1119 1120 if not item[1]: 1121 self.CheckItem(iItem, False) 1122 1123 else: 1124 if self.IsShown('type'): 1125 self.HideColumn('type') 1126 1127 def ParametersChanged(self, method, kwargs): 1128 if "analysis" in kwargs["changed_params"].keys(): 1129 self.AnalysisChanged(analysis=kwargs["changed_params"]["analysis"]) 1130 1131 def OnItemActivated(self, event): 1132 changed, key = PointsList.OnItemActivated(self, event) 1133 1134 if not changed: 1135 return 1136 1137 dt_dict = {} 1138 active_cols = self.pts_data.GetColumns() 1139 for col in active_cols["name"]: 1140 if col == "use": 1141 continue 1142 dt_dict[col] = self.GetCellValue(key, col) 1143 1144 self.pts_data.SetPointData(key, dt_dict) 1145 1146 def PointsChanged(self, method, kwargs): 1147 if method == "AddPoint": 1148 self.AddItem() 1149 1150 elif method == "DeletePoint": 1151 self.DeleteItem() 1152 1153 elif method == "SetPointData": 1154 self.SetData(kwargs["pt_id"], kwargs["data"]) 1155 1156 elif method == "SetPoints": 1157 while self.GetSelected() != wx.NOT_FOUND: 1158 self.DeleteItem() 1159 1160 for iPt, pt_dt in enumerate(kwargs["pts_data"]): 1161 self.AddItem() 1162 self.SetData(iPt, pt_dt) 1163 1164 elif method == "SetSelected": 1165 self.Select(self._findIndex(kwargs["pt_id"])) 1166 1167 def SetData(self, key, data): 1168 1169 idx = self._findIndex(key) 1170 for k, v in six.iteritems(data): 1171 if k == "use": 1172 1173 if v and not self.IsItemChecked(idx): 1174 self.CheckItem(idx, True) 1175 elif not v and self.IsItemChecked(idx): 1176 self.CheckItem(idx, False) 1177 else: 1178 found = 0 1179 for col in self.colsData: 1180 if k == col[0]: 1181 found = 1 1182 break 1183 1184 if found: 1185 self.EditCellKey(key, k, v) 1186 1187 def OnItemSelected(self, event): 1188 """Item selected""" 1189 PointsList.OnItemSelected(self, event) 1190 self.selectedkey = self.GetItemData(self.selected) 1191 1192 if self.selectedkey == self.pts_data.GetSelected(): 1193 return 1194 1195 if self.selectedkey == wx.NOT_FOUND: 1196 self.pts_data.SetSelected(None) 1197 else: 1198 self.pts_data.SetSelected(self.selectedkey) 1199 1200 def OnCheckItem(self, index, flag): 1201 "flag is True if the item was checked, False if unchecked" 1202 key = self.GetItemData(index) 1203 if self.pts_data.GetPointData(key)["use"] != flag: 1204 self.pts_data.SetPointData(key, {"use": flag}) 1205 1206 1207class SettingsDialog(wx.Dialog): 1208 1209 def __init__( 1210 self, parent, id, title, vnet_mgr, pos=wx.DefaultPosition, 1211 size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE): 1212 """Settings dialog""" 1213 wx.Dialog.__init__(self, parent, id, title, pos, size, style) 1214 1215 self.vnet_mgr = vnet_mgr 1216 1217 maxValue = 1e8 1218 self.parent = parent 1219 self.settings = {} 1220 1221 # create all staticboxes before creating widgets, needed for Mac 1222 otherBox = StaticBox(parent=self, id=wx.ID_ANY, 1223 label=" %s " % _("Other settings")) 1224 otherBoxSizer = wx.StaticBoxSizer(otherBox, wx.VERTICAL) 1225 ptsStyleBox = StaticBox(parent=self, id=wx.ID_ANY, 1226 label=" %s " % _("Point style:")) 1227 ptsStyleBoxSizer = wx.StaticBoxSizer(ptsStyleBox, wx.VERTICAL) 1228 styleBox = StaticBox(parent=self, id=wx.ID_ANY, 1229 label=" %s " % _("Analysis result style:")) 1230 styleBoxSizer = wx.StaticBoxSizer(styleBox, wx.VERTICAL) 1231 1232 rules = RunCommand('v.colors', 1233 read=True, 1234 flags='l') 1235 1236 settsLabels = {} 1237 1238 settsLabels['color_table'] = StaticText( 1239 parent=self, 1240 id=wx.ID_ANY, 1241 label=_('Color table style %s:') % 1242 '(v.net.flow)') 1243 self.settings['color_table'] = ComboBox( 1244 parent=self, id=wx.ID_ANY, choices=rules.split(), 1245 style=wx.CB_READONLY, size=(180, -1)) 1246 1247 setStyle = UserSettings.Get( 1248 group='vnet', 1249 key="res_style", 1250 subkey="color_table") 1251 i = self.settings['color_table'].FindString(setStyle) 1252 if i != wx.NOT_FOUND: 1253 self.settings['color_table'].Select(i) 1254 1255 self.settings["invert_colors"] = CheckBox( 1256 parent=self, 1257 id=wx.ID_ANY, 1258 label=_('Invert colors %s:') % 1259 '(v.net.flow)') 1260 setInvert = UserSettings.Get( 1261 group='vnet', 1262 key="res_style", 1263 subkey="invert_colors") 1264 self.settings["invert_colors"].SetValue(setInvert) 1265 1266 self.colorsSetts = { 1267 "line_color": [ 1268 "res_style", 1269 _("Line color:")], 1270 "unused": [ 1271 "point_colors", 1272 _("Color for unused point:")], 1273 "used1cat": [ 1274 "point_colors", 1275 _("Color for Start/From/Source/Used point:")], 1276 "used2cat": [ 1277 "point_colors", 1278 _("Color for End/To/Sink point:")], 1279 "selected": [ 1280 "point_colors", 1281 _("Color for selected point:")]} 1282 1283 for settKey, sett in six.iteritems(self.colorsSetts): 1284 settsLabels[settKey] = StaticText( 1285 parent=self, id=wx.ID_ANY, label=sett[1]) 1286 col = UserSettings.Get(group='vnet', key=sett[0], subkey=settKey) 1287 self.settings[settKey] = csel.ColourSelect( 1288 parent=self, id=wx.ID_ANY, colour=wx.Colour( 1289 col[0], col[1], col[2], 255)) 1290 1291 self.sizeSetts = { 1292 "line_width": ["res_style", _("Line width:")], 1293 "point_size": ["point_symbol", _("Point size:")], 1294 "point_width": ["point_symbol", _("Point width:")], 1295 "snap_tresh": ["other", _("Snapping threshold in pixels:")], 1296 "max_hist_steps": ["other", _("Maximum number of results in history:")] 1297 } 1298 1299 for settKey, sett in six.iteritems(self.sizeSetts): 1300 settsLabels[settKey] = StaticText( 1301 parent=self, id=wx.ID_ANY, label=sett[1]) 1302 self.settings[settKey] = SpinCtrl( 1303 parent=self, id=wx.ID_ANY, min=1, max=50) 1304 size = int( 1305 UserSettings.Get( 1306 group='vnet', 1307 key=sett[0], 1308 subkey=settKey)) 1309 self.settings[settKey].SetValue(size) 1310 1311 # buttons 1312 self.btnSave = Button(self, wx.ID_SAVE) 1313 self.btnApply = Button(self, wx.ID_APPLY) 1314 self.btnClose = Button(self, wx.ID_CLOSE) 1315 self.btnApply.SetDefault() 1316 1317 # bindings 1318 self.btnApply.Bind(wx.EVT_BUTTON, self.OnApply) 1319 self.btnApply.SetToolTip( 1320 _("Apply changes for the current session")) 1321 self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave) 1322 self.btnSave.SetToolTip( 1323 _("Apply and save changes to user settings file (default for next sessions)")) 1324 self.btnClose.Bind(wx.EVT_BUTTON, self.OnClose) 1325 self.btnClose.SetToolTip(_("Close dialog")) 1326 1327 # Layout 1328 1329 # Analysis result style layout 1330 self.SetMinSize(self.GetBestSize()) 1331 1332 sizer = wx.BoxSizer(wx.VERTICAL) 1333 1334 gridSizer = wx.GridBagSizer(vgap=1, hgap=1) 1335 1336 row = 0 1337 gridSizer.Add( 1338 settsLabels["line_color"], 1339 flag=wx.ALIGN_CENTER_VERTICAL, 1340 pos=( 1341 row, 1342 0)) 1343 gridSizer.Add(self.settings["line_color"], 1344 flag=wx.ALIGN_RIGHT | wx.ALL, border=5, 1345 pos=(row, 1)) 1346 1347 row += 1 1348 gridSizer.Add( 1349 settsLabels["line_width"], 1350 flag=wx.ALIGN_CENTER_VERTICAL, 1351 pos=( 1352 row, 1353 0)) 1354 gridSizer.Add(self.settings["line_width"], 1355 flag=wx.ALIGN_RIGHT | wx.ALL, border=5, 1356 pos=(row, 1)) 1357 row += 1 1358 gridSizer.Add( 1359 settsLabels['color_table'], 1360 flag=wx.ALIGN_CENTER_VERTICAL, 1361 pos=( 1362 row, 1363 0)) 1364 gridSizer.Add(self.settings['color_table'], 1365 flag=wx.ALIGN_RIGHT | wx.ALL, border=5, 1366 pos=(row, 1)) 1367 1368 row += 1 1369 gridSizer.Add( 1370 self.settings["invert_colors"], 1371 flag=wx.ALIGN_CENTER_VERTICAL, 1372 pos=( 1373 row, 1374 0)) 1375 1376 gridSizer.AddGrowableCol(1) 1377 styleBoxSizer.Add(gridSizer, flag=wx.EXPAND) 1378 1379 # Point style layout 1380 gridSizer = wx.GridBagSizer(vgap=1, hgap=1) 1381 1382 row = 0 1383 setts = {**self.colorsSetts, **self.sizeSetts} 1384 1385 settsOrder = [ 1386 "selected", 1387 "used1cat", 1388 "used2cat", 1389 "unused", 1390 "point_size", 1391 "point_width"] 1392 for settKey in settsOrder: 1393 sett = setts[settKey] 1394 gridSizer.Add( 1395 settsLabels[settKey], 1396 flag=wx.ALIGN_CENTER_VERTICAL, 1397 pos=( 1398 row, 1399 0)) 1400 gridSizer.Add(self.settings[settKey], 1401 flag=wx.ALIGN_RIGHT | wx.ALL, border=5, 1402 pos=(row, 1)) 1403 row += 1 1404 1405 gridSizer.AddGrowableCol(1) 1406 ptsStyleBoxSizer.Add(gridSizer, flag=wx.EXPAND) 1407 1408 # Other settings layout 1409 gridSizer = wx.GridBagSizer(vgap=1, hgap=1) 1410 1411 row = 0 1412 for otherSettName in ["snap_tresh", "max_hist_steps"]: 1413 gridSizer.Add( 1414 settsLabels[otherSettName], 1415 flag=wx.ALIGN_CENTER_VERTICAL, 1416 pos=( 1417 row, 1418 0)) 1419 gridSizer.Add(self.settings[otherSettName], 1420 flag=wx.ALIGN_RIGHT | wx.ALL, border=5, 1421 pos=(row, 1)) 1422 row += 1 1423 1424 gridSizer.AddGrowableCol(1) 1425 otherBoxSizer.Add(gridSizer, flag=wx.EXPAND) 1426 1427 btnSizer = wx.BoxSizer(wx.HORIZONTAL) 1428 btnSizer.Add(self.btnApply, flag=wx.LEFT | wx.RIGHT, border=5) 1429 btnSizer.Add(self.btnSave, flag=wx.LEFT | wx.RIGHT, border=5) 1430 btnSizer.Add(self.btnClose, flag=wx.LEFT | wx.RIGHT, border=5) 1431 1432 sizer.Add(styleBoxSizer, flag=wx.EXPAND | wx.ALL, border=5) 1433 sizer.Add(ptsStyleBoxSizer, flag=wx.EXPAND | wx.ALL, border=5) 1434 sizer.Add(otherBoxSizer, flag=wx.EXPAND | wx.ALL, border=5) 1435 sizer.Add( 1436 btnSizer, 1437 flag=wx.EXPAND | wx.ALL, 1438 border=5, 1439 proportion=0) 1440 1441 self.SetSizer(sizer) 1442 sizer.Fit(self) 1443 1444 def OnSave(self, event): 1445 """Button 'Save' pressed""" 1446 self.UpdateSettings() 1447 1448 fileSettings = {} 1449 UserSettings.ReadSettingsFile(settings=fileSettings) 1450 fileSettings['vnet'] = UserSettings.Get(group='vnet') 1451 UserSettings.SaveToFile(fileSettings) 1452 1453 self.Close() 1454 1455 def UpdateSettings(self): 1456 UserSettings.Set(group='vnet', key="res_style", subkey='line_width', 1457 value=self.settings["line_width"].GetValue()) 1458 1459 for settKey, sett in six.iteritems(self.colorsSetts): 1460 col = tuple(self.settings[settKey].GetColour()) 1461 UserSettings.Set(group='vnet', 1462 key=sett[0], 1463 subkey=settKey, 1464 value=col) 1465 1466 for settKey, sett in six.iteritems(self.sizeSetts): 1467 UserSettings.Set(group='vnet', key=sett[0], subkey=settKey, 1468 value=self.settings[settKey].GetValue()) 1469 1470 UserSettings.Set( 1471 group='vnet', 1472 key='res_style', 1473 subkey='color_table', 1474 value=self.settings['color_table'].GetStringSelection()) 1475 1476 UserSettings.Set(group='vnet', key='res_style', subkey='invert_colors', 1477 value=self.settings['invert_colors'].IsChecked()) 1478 1479 self.vnet_mgr.SettingsUpdated() 1480 1481 def OnApply(self, event): 1482 """Button 'Apply' pressed""" 1483 self.UpdateSettings() 1484 # self.Close() 1485 1486 def OnClose(self, event): 1487 """Button 'Cancel' pressed""" 1488 self.Close() 1489 1490 1491class CreateTtbDialog(wx.Dialog): 1492 1493 def __init__(self, parent, init_data, id=wx.ID_ANY, 1494 title=_("New vector map with turntable"), 1495 style=wx.DEFAULT_DIALOG_STYLE): 1496 """Create turntable dialog.""" 1497 wx.Dialog.__init__(self, parent, id, title=_(title), style=style) 1498 1499 box = StaticBox(self, -1, "Vector map and layers for analysis") 1500 bsizer = wx.StaticBoxSizer(box, wx.VERTICAL) 1501 label = {} 1502 dataSelects = [ 1503 ['input', "Choose vector map for analysis:", Select], 1504 ['output', "Name of vector map with turntable:", Select], 1505 ['arc_layer', "Arc layer which will be expanded by turntable:", LayerSelect], 1506 ['turn_layer', "Layer with turntable:", LayerSelect], 1507 ['turn_cat_layer', "Layer with unique categories for turntable:", LayerSelect], 1508 ] 1509 1510 self.inputData = {} 1511 1512 selPanels = {} 1513 1514 for dataSel in dataSelects: 1515 selPanels[dataSel[0]] = Panel(parent=self) 1516 if dataSel[0] in ['input', 'output']: 1517 self.inputData[ 1518 dataSel[0]] = dataSel[2]( 1519 parent=selPanels[dataSel[0]], 1520 size=(-1, -1), 1521 type='vector') 1522 elif dataSel[0] != 'input': 1523 self.inputData[dataSel[0]] = dataSel[2]( 1524 parent=selPanels[dataSel[0]], size=(-1, -1)) 1525 1526 label[dataSel[0]] = StaticText(parent=selPanels[dataSel[0]], 1527 name=dataSel[0]) 1528 label[dataSel[0]].SetLabel(dataSel[1]) 1529 1530 self.inputData['input'].Bind(wx.EVT_TEXT, lambda event: self.InputSel) 1531 1532 # buttons 1533 self.btnCancel = Button(self, wx.ID_CANCEL) 1534 self.btnOk = Button(self, wx.ID_OK) 1535 self.btnOk.SetDefault() 1536 1537 # Layout 1538 mainSizer = wx.BoxSizer(wx.VERTICAL) 1539 1540 mainSizer.Add(bsizer, proportion=0, 1541 flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=5) 1542 1543 btn = None 1544 for sel in ['input', 'output', 'arc_layer', 1545 'turn_layer', 'turn_cat_layer']: 1546 1547 selPanels[sel].SetSizer(self._doSelLayout(title=label[sel], 1548 sel=self.inputData[sel], 1549 btn=btn)) 1550 bsizer.Add(selPanels[sel], proportion=0, 1551 flag=wx.EXPAND) 1552 1553 for k, v in six.iteritems(init_data): 1554 if k in self.inputData: 1555 self.inputData[k].SetValue(v) 1556 1557 inp_vect_map = self.inputData["input"].GetValue().split("@")[0] 1558 self.inputData['output'].SetValue(inp_vect_map + "_ttb") 1559 1560 btnSizer = wx.StdDialogButtonSizer() 1561 btnSizer.AddButton(self.btnCancel) 1562 btnSizer.AddButton(self.btnOk) 1563 btnSizer.Realize() 1564 1565 mainSizer.Add(btnSizer, proportion=0, 1566 flag=wx.ALIGN_RIGHT | wx.ALL, border=5) 1567 1568 self.SetSizer(mainSizer) 1569 self.Fit() 1570 1571 def _doSelLayout(self, title, sel, btn=None): 1572 # helper function for layout of self.inputData widgets initialized in 1573 # _createParametersPage 1574 selSizer = wx.BoxSizer(orient=wx.VERTICAL) 1575 1576 selTitleSizer = wx.BoxSizer(wx.HORIZONTAL) 1577 selTitleSizer.Add(title, proportion=1, 1578 flag=wx.LEFT | wx.TOP | wx.EXPAND, border=5) 1579 1580 selSizer.Add(selTitleSizer, proportion=0, 1581 flag=wx.EXPAND) 1582 1583 if btn: 1584 selFiledSizer = wx.BoxSizer(orient=wx.HORIZONTAL) 1585 selFiledSizer.Add(sel, proportion=1, 1586 flag=wx.EXPAND | wx.ALL) 1587 1588 selFiledSizer.Add(btn, proportion=0, 1589 flag=wx.EXPAND | wx.ALL) 1590 1591 selSizer.Add(selFiledSizer, proportion=0, 1592 flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1593 border=5) 1594 else: 1595 selSizer.Add(sel, proportion=1, 1596 flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1597 border=5) 1598 return selSizer 1599 1600 def InputSel(self): 1601 """When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)""" 1602 vectMapName, mapSet = self._parseMapStr( 1603 self.inputData['input'].GetValue()) 1604 vectorMap = vectMapName + '@' + mapSet 1605 1606 for sel in ['arc_layer', 'turn_layer', 'turn_cat_layer']: 1607 self.inputData[sel].Clear() 1608 self.inputData[sel].InsertLayers(vector=vectorMap) 1609 1610 items = self.inputData['arc_layer'].GetItems() 1611 itemsLen = len(items) 1612 if itemsLen < 1: 1613 self.addToTreeBtn.Disable() 1614 if hasattr(self, 'inpDbMgrData'): 1615 self._updateInputDbMgrPage(show=False) 1616 self.inputData['arc_layer'].SetValue("") 1617 return 1618 elif itemsLen == 1: 1619 self.inputData['arc_layer'].SetSelection(0) 1620 elif itemsLen >= 1: 1621 if unicode("1") in items: 1622 iItem = items.index(unicode("1")) 1623 self.inputData['arc_layer'].SetSelection(iItem) 1624 self.addToTreeBtn.Enable() 1625 if hasattr(self, 'inpDbMgrData'): 1626 self._updateInputDbMgrPage(show=True) 1627 1628 def GetData(self): 1629 1630 params = {} 1631 for param, sel in six.iteritems(self.inputData): 1632 params[param] = sel.GetValue() 1633 1634 return params 1635 1636 1637class OutputVectorDialog(wx.Dialog): 1638 1639 def __init__(self, parent, id=wx.ID_ANY, title=_( 1640 "Save analysis result"), style=wx.DEFAULT_DIALOG_STYLE): 1641 """Save analysis result""" 1642 wx.Dialog.__init__(self, parent, id, title=_(title), style=style) 1643 1644 self.panel = Panel(parent=self) 1645 box = StaticBox(parent=self.panel, id=wx.ID_ANY, 1646 label="Vector map") 1647 1648 self.boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL) 1649 1650 # text fields and it's captions 1651 self.vectSel = Select( 1652 parent=self.panel, type='vector', 1653 mapsets=[grass.gisenv()['MAPSET']], 1654 size=(-1, -1)) 1655 self.vectSellabel = StaticText(parent=self.panel, id=wx.ID_ANY, 1656 label=_("Name:")) 1657 1658 # buttons 1659 self.btnCancel = Button(self.panel, wx.ID_CANCEL) 1660 self.btnOk = Button(self.panel, wx.ID_OK) 1661 self.btnOk.SetDefault() 1662 1663 self.SetInitialSize((400, -1)) 1664 self._layout() 1665 1666 def _layout(self): 1667 1668 sizer = wx.BoxSizer(wx.VERTICAL) 1669 1670 self.boxSizer.Add(self.vectSellabel, 1671 flag=wx.ALIGN_CENTER_VERTICAL, 1672 proportion=0) 1673 1674 self.boxSizer.Add(self.vectSel, proportion=1, 1675 flag=wx.EXPAND | wx.ALL, border=5) 1676 1677 sizer.Add(self.boxSizer, proportion=1, 1678 flag=wx.EXPAND | wx.ALL, border=5) 1679 1680 btnSizer = wx.StdDialogButtonSizer() 1681 btnSizer.AddButton(self.btnCancel) 1682 btnSizer.AddButton(self.btnOk) 1683 btnSizer.Realize() 1684 1685 sizer.Add(btnSizer, proportion=0, 1686 flag=wx.ALIGN_RIGHT | wx.ALL, border=5) 1687 1688 self.panel.SetSizer(sizer) 1689 sizer.Fit(self) 1690 1691 1692class VnetStatusbar(wx.StatusBar): 1693 """Extends wx.StatusBar class with functionality to show multiple messages with the highest priority""" 1694 1695 def __init__(self, parent, style, id=wx.ID_ANY, **kwargs): 1696 1697 wx.StatusBar.__init__(self, parent, id, style, **kwargs) 1698 1699 self.maxPriority = 0 1700 self.statusItems = [] 1701 1702 def AddStatusItem(self, text, key, priority): 1703 """Add new item to show 1704 1705 :param text: string to show 1706 :param key: item identifier, if already contains 1707 item with same identifier, overwrites this item 1708 :param priority: only items with highest priority are showed 1709 """ 1710 statusTextItem = { 1711 'text': text, 1712 'key': key, 1713 'priority': priority 1714 } 1715 1716 for item in self.statusItems: 1717 if item['key'] == statusTextItem['key']: 1718 self.statusItems.remove(item) 1719 self.statusItems.append(statusTextItem) 1720 if self.maxPriority < statusTextItem['priority']: 1721 self.maxPriority = statusTextItem['priority'] 1722 self._updateStatus() 1723 1724 def _updateStatus(self): 1725 1726 currStatusText = '' 1727 for item in reversed(self.statusItems): 1728 if item['priority'] == self.maxPriority: 1729 if currStatusText: 1730 currStatusText += '; ' 1731 currStatusText += item['text'] 1732 wx.StatusBar.SetStatusText(self, currStatusText) 1733 1734 def RemoveStatusItem(self, key): 1735 """Remove item 1736 1737 :param key: item identifier 1738 """ 1739 update = False 1740 for iItem, item in enumerate(self.statusItems): 1741 if item['key'] == key: 1742 if item['priority'] == self.maxPriority: 1743 update = True 1744 self.statusItems.pop(iItem) 1745 if update: 1746 for item in self.statusItems: 1747 self.maxPriority = 0 1748 if self.maxPriority < item['priority']: 1749 self.maxPriority = item['priority'] 1750 self._updateStatus() 1751 1752 1753class DefIntesectionTurnCostDialog(wx.Dialog): 1754 1755 def __init__(self, parent, mapWin, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, 1756 id=wx.ID_ANY, title=_("Edit intersection turns costs"), **kwargs): 1757 wx.Dialog.__init__( 1758 self, 1759 parent, 1760 id, 1761 style=style, 1762 title=title, 1763 **kwargs) 1764 1765 self.dbMgr = DbMgrBase(mapdisplay=mapWin) 1766 self.browsePage = self.dbMgr.CreateDbMgrPage( 1767 parent=self, pageName='browse') 1768 1769 def layout(self): 1770 sizer = wx.BoxSizer(wx.VERTICAL) 1771 1772 sizer.Add(self.browsePage, proportion=1, 1773 flag=wx.EXPAND) 1774 1775 self.SetSizer(sizer) 1776 1777 def SetData(self, vectMapName, layer): 1778 if vectMapName != self.dbMgr.GetVectorName(): 1779 self.dbMgr.ChangeVectorMap(vectorName=vectMapName) 1780 else: 1781 self.browsePage.DeleteAllPages() 1782 1783 self.browsePage.AddLayer(int(layer)) 1784 self.layer = int(layer) 1785 1786 # TODO HACK!!! 1787 self.browsePage.FindWindowById( 1788 self.browsePage.layerPage[int(layer)] 1789 ['sqlNtb']).GetParent().Hide() 1790 1791 def SetIntersection(self, isec): 1792 1793 self.browsePage.LoadData(self.layer, where="isec = %d" % (isec)) 1794 1795 1796class DefGlobalTurnsDialog(wx.Dialog): 1797 1798 def __init__(self, parent, data, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, 1799 id=wx.ID_ANY, title=_("Define Global Turn Costs"), **kwargs): # v Gassu dopln preklad 1800 1801 wx.Dialog.__init__(self, parent, id, title, style=style, **kwargs) 1802 1803 self.data = data 1804 1805 self.angle_list = TurnAnglesList(parent=self, data=self.data) 1806 1807 self.btnAdd = Button(parent=self, id=wx.ID_ANY, label="Add") 1808 self.btnRemove = Button(parent=self, id=wx.ID_ANY, label="Remove") 1809 self.btnClose = Button(parent=self, id=wx.ID_CLOSE) 1810 self.useUTurns = CheckBox( 1811 parent=self, id=wx.ID_ANY, label="Use U-turns") 1812 1813 self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAddButtonClick) 1814 self.btnRemove.Bind(wx.EVT_BUTTON, self.OnRemoveButtonClick) 1815 self.Bind(wx.EVT_CLOSE, self.OnCloseDialog) 1816 self.useUTurns.Bind(wx.EVT_CHECKBOX, self.OnCheckedUTurns) 1817 1818 self.btnClose.SetDefault() 1819 self.useUTurns.SetValue(True) 1820 self.OnCheckedUTurns(None) 1821 self.layout() 1822 self.SetInitialSize((500, 200)) 1823 1824 def layout(self): 1825 sizer = wx.BoxSizer(wx.VERTICAL) 1826 labelSizer = wx.BoxSizer(wx.HORIZONTAL) 1827 addRemoveSizer = wx.BoxSizer(wx.VERTICAL) 1828 closeSizer = wx.BoxSizer(wx.HORIZONTAL) 1829 1830 addRemoveSizer.Add( 1831 self.btnAdd, 1832 proportion=0, 1833 flag=wx.ALIGN_RIGHT, 1834 border=10) 1835 addRemoveSizer.Add( 1836 self.btnRemove, 1837 proportion=0, 1838 flag=wx.ALIGN_RIGHT, 1839 border=10) 1840 1841 labelSizer.Add( 1842 self.angle_list, 1843 proportion=1, 1844 flag=wx.EXPAND, 1845 border=10) 1846 labelSizer.Add( 1847 addRemoveSizer, 1848 proportion=0, 1849 flag=wx.ALIGN_RIGHT, 1850 border=10) 1851 1852 closeSizer.Add( 1853 self.useUTurns, 1854 proportion=1, 1855 flag=wx.ALIGN_LEFT, 1856 border=10) 1857 closeSizer.Add( 1858 self.btnClose, 1859 proportion=0, 1860 flag=wx.ALIGN_RIGHT, 1861 border=10) 1862 1863 sizer.Add(labelSizer, proportion=1, flag=wx.EXPAND) 1864 sizer.Add(closeSizer, proportion=0, flag=wx.EXPAND) 1865 1866 self.SetSizer(sizer) 1867 1868 def OnAddButtonClick(self, event): 1869 """Add new direction over selected row""" 1870 selected_indices = self.angle_list.GetSelectedIndices() 1871 1872 if not selected_indices: 1873 from_value = self.turn_data.GetValue( 1874 self.turn_data.GetLinesCount() - 1, 2) 1875 to_value = self.turn_data.GetValue(0, 1) 1876 default_row = ["new", from_value, to_value, 0.0] 1877 self.angle_list.AppendRow(default_row) 1878 1879 # If no row is selected, new direction is added to the end of table 1880 i_addition = 0 1881 for i in selected_indices: 1882 i += i_addition 1883 from_value = self.turn_data.GetValue(i - 1, 2) 1884 to_value = self.turn_data.GetValue(i, 1) 1885 default_row = ["new", from_value, to_value, 0.0] 1886 self.angle_list.InsertRow(i, default_row) 1887 i_addition += 1 1888 1889 def OnRemoveButtonClick(self, event): 1890 """Delete one or more selected directions""" 1891 selected_indices = self.angle_list.GetSelectedIndices() 1892 1893 i_reduction = 0 1894 for i in selected_indices: 1895 i -= i_reduction 1896 self.angle_list.DeleteRow(i) 1897 i_reduction += 1 1898 1899 def OnCloseDialog(self, event): 1900 """Close dialog""" 1901 self.Close() 1902 1903 def OnCheckedUTurns(self, event): 1904 """Use U-turns in analyse""" 1905 self.data.SetUTurns(self.useUTurns.GetValue()) 1906 1907 def SetData(self, data): 1908 self.angle_list.SetData(data) 1909 self.data = data 1910 1911 1912class TurnAnglesList( 1913 ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.TextEditMixin): 1914 """Virtual editable table with global turns""" 1915 1916 def __init__(self, parent, data, id=wx.ID_ANY, 1917 style=wx.LC_REPORT | wx.LC_VIRTUAL, **kwargs): 1918 ListCtrl.__init__(self, parent, id, style=style, **kwargs) 1919 listmix.ListCtrlAutoWidthMixin.__init__(self) 1920 listmix.TextEditMixin.__init__(self) 1921 1922 self.Populate() 1923 self.data = data 1924 self.SetItemCount(self.data.GetLinesCount()) 1925 1926 def Populate(self): 1927 """Columns definition""" 1928 self.InsertColumn( 1929 col=0, 1930 heading="Direction", 1931 format=wx.LIST_FORMAT_LEFT) # v Gassu dopln preklad 1932 self.InsertColumn( 1933 col=1, 1934 heading="From Angle", 1935 format=wx.LIST_FORMAT_RIGHT) 1936 self.InsertColumn( 1937 col=2, 1938 heading="To Angle", 1939 format=wx.LIST_FORMAT_RIGHT) 1940 self.InsertColumn(col=3, heading="Cost", format=wx.LIST_FORMAT_RIGHT) 1941 1942 def OnGetItemText(self, item, col): 1943 val = self.data.GetValue(item, col) 1944 if col in [1, 2]: 1945 val = RadiansToDegrees(val) 1946 return str(val) 1947 1948 def SetVirtualData(self, row, column, text): 1949 """Set data to table""" 1950 if column in [1, 2, 3]: 1951 try: 1952 text = float(text) 1953 except: 1954 return 1955 if column in [1, 2]: 1956 text = DegreesToRadians(text) 1957 1958 # Tested allowed range of values 1959 if text > math.pi: 1960 text = 0.0 1961 elif text < -math.pi: 1962 text = 0.0 1963 1964 self.data.SetValue(text, row, column) 1965 1966 self.edited_row = row 1967 self.RefreshItems(0, self.data.GetLinesCount() - 1) 1968 1969 def AppendRow(self, values): 1970 self.data.AppendRow(values) 1971 self.SetItemCount(self.data.GetLinesCount()) 1972 1973 def InsertRow(self, line, values): 1974 self.data.InsertRow(line, values) 1975 self.SetItemCount(self.data.GetLinesCount()) 1976 1977 def DeleteRow(self, row): 1978 self.data.PopRow(row) 1979 self.SetItemCount(self.data.GetLinesCount()) 1980 1981 def SetData(self, data): 1982 self.data = data 1983 self.SetItemCount(self.data.GetLinesCount()) 1984 self.RefreshItems(0, self.data.GetLinesCount() - 1) 1985 1986 def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): 1987 """Get numbers of selected rows""" 1988 indices = [] 1989 lastFound = -1 1990 while True: 1991 index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) 1992 if index == -1: 1993 break 1994 else: 1995 lastFound = index 1996 indices.append(index) 1997 return indices 1998