dialogs.py 68 KB

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