dialogs.py 118 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860
  1. """!
  2. @package vnet.dialogs
  3. @brief Dialog for vector network analysis front-end
  4. Classes:
  5. - dialogs::VNETDialog
  6. - dialogs::PtsList
  7. - dialogs::SettingsDialog
  8. - dialogs::AddLayerDialog
  9. - dialogs::VnetTmpVectMaps
  10. - dialogs::VectMap
  11. - dialogs::History
  12. - dialogs::VnetStatusbar
  13. (C) 2012 by the GRASS Development Team
  14. This program is free software under the GNU General Public License
  15. (>=v2). Read the file COPYING that comes with GRASS for details.
  16. @author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
  17. """
  18. import os
  19. import sys
  20. import types
  21. try:
  22. import grass.lib.vector as vectlib
  23. from ctypes import pointer, byref, c_char_p, c_int, c_double
  24. haveCtypes = True
  25. except ImportError:
  26. haveCtypes = False
  27. from copy import copy
  28. from grass.script import core as grass
  29. import wx
  30. import wx.aui
  31. import wx.lib.flatnotebook as FN
  32. import wx.lib.colourselect as csel
  33. from core import globalvar, utils
  34. from core.gcmd import RunCommand, GMessage
  35. from core.events import gUpdateMap
  36. from core.settings import UserSettings
  37. from dbmgr.base import DbMgrBase
  38. from gui_core.widgets import GNotebook
  39. from gui_core.goutput import GConsoleWindow
  40. from core.gconsole import CmdThread, EVT_CMD_DONE, GConsole
  41. from gui_core.gselect import Select, LayerSelect, ColumnSelect
  42. from vnet.widgets import PointsList
  43. from vnet.toolbars import MainToolbar, PointListToolbar, AnalysisToolbar
  44. #Main TODOs
  45. # - when layer tree of is changed, tmp result map is removed from render list
  46. # - optimization of map drawing
  47. # - tmp maps - add number of process
  48. # - destructor problem - when GRASS GIS is closed with open VNETDialog,
  49. # it's destructor is not called
  50. class VNETDialog(wx.Dialog):
  51. def __init__(self, parent,
  52. id = wx.ID_ANY, title = _("GRASS GIS Vector Network Analysis Tool"),
  53. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
  54. """!Dialog for vector network analysis"""
  55. wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
  56. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  57. self.parent = parent # mapdisp.frame MapFrame class
  58. self.mapWin = parent.MapWindow
  59. # contains current analysis result (do not have to be last one, when history is browsed),
  60. # it is instance of VectMap class
  61. self.tmp_result = None
  62. # initialization of History class used for saving and reading data from file
  63. # it is used for browsing analysis results
  64. self.history = History(self)
  65. # variable, which appends unique number to every name of map, which is saved into history
  66. self.histTmpVectMapNum = 0
  67. # list of maps, which will be saved into history
  68. self.tmpVectMapsToHist = []
  69. # this class instance manages all temporary vector maps created during life of VNETDialog
  70. self.tmpMaps = VnetTmpVectMaps(parent = self)
  71. # setting initialization
  72. self._initSettings()
  73. # registration graphics for drawing
  74. self.pointsToDraw = self.mapWin.RegisterGraphicsToDraw(graphicsType = "point",
  75. setStatusFunc = self.SetPointStatus)
  76. self.SetPointDrawSettings()
  77. # information, whether mouse event handler is registered in map window
  78. self.handlerRegistered = False
  79. # get attribute table columns only with numbers (for cost columns in vnet analysis)
  80. self.columnTypes = ['integer', 'double precision']
  81. # initialization of v.net.* analysis parameters (data which characterizes particular analysis)
  82. self._initVnetParams()
  83. # toobars
  84. self.toolbars = {}
  85. self.toolbars['mainToolbar'] = MainToolbar(parent = self)
  86. self.toolbars['analysisToolbar'] = AnalysisToolbar(parent = self)
  87. #
  88. # Fancy gui
  89. #
  90. self._mgr = wx.aui.AuiManager(self)
  91. # Columns in points list
  92. # TODO init dynamically, not hard typed v.net.path
  93. self.cols = [
  94. ['type', _('type'), [_(""), _("Start point"), _("End point")], 0],
  95. ['topology', _('topology'), None, ""]
  96. ]
  97. self.mainPanel = wx.Panel(parent=self)
  98. self.notebook = GNotebook(parent = self.mainPanel,
  99. style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
  100. FN.FNB_NO_X_BUTTON)
  101. # statusbar
  102. self.stPriorities = {'important' : 5, 'iformation' : 1}
  103. self.stBar = VnetStatusbar(parent = self.mainPanel, style = 0)
  104. self.stBar.SetFieldsCount(number = 1)
  105. # Create tabs
  106. # Stores all data related to snapping
  107. self.snapData = {}
  108. self.snapData['snap_mode'] = False
  109. # Stores widgets which sets some of analysis parameters (e. g. v.ne.iso -> iso lines)
  110. self.anSettings = {}
  111. self._createPointsPage()
  112. # stores widgets which are shown on parameters page
  113. # they set data, on which analysis will be done
  114. self.inputData = {}
  115. self._createParametersPage()
  116. # Output console for analysis
  117. self._createOutputPage()
  118. # Stores data which are needed for attribute table browser of analysis input map layers
  119. self.inpDbMgrData = {}
  120. self._createInputDbMgrPage()
  121. # Stores data which are need for attribute table browser of analysis result map layers
  122. self.resultDbMgrData = {}
  123. self._createResultDbMgrPage()
  124. self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
  125. self.Bind(wx.EVT_CLOSE, self.OnCloseDialog)
  126. self._addPanes()
  127. self._doVnetDialogLayout()
  128. self._mgr.Update()
  129. # adds 2 points into list
  130. for i in range(2):
  131. self.list.AddItem()
  132. self.list.EditCellIndex(i, 'type', i + 1)
  133. self.list.CheckItem(i, True)
  134. # selects first point
  135. self.list.selected = 0
  136. self.list.Select(self.list.selected)
  137. dlgSize = (420, 560)
  138. self.SetMinSize(dlgSize)
  139. self.SetInitialSize(dlgSize)
  140. #fix goutput's pane size (required for Mac OSX)
  141. if self.gwindow:
  142. self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
  143. self.OnAnalysisChanged(None)
  144. self.notebook.SetSelectionByName("parameters")
  145. self.toolbars['analysisToolbar'].SetMinSize((-1, self.toolbars['mainToolbar'].GetSize()[1]))
  146. def __del__(self):
  147. """!Removes temp layers, unregisters handlers and graphics"""
  148. update = self.tmpMaps.DeleteAllTmpMaps()
  149. self.mapWin.UnregisterGraphicsToDraw(self.pointsToDraw)
  150. if self.handlerRegistered:
  151. self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
  152. self.OnMapClickHandler)
  153. if update:
  154. up_map_evt = gUpdateMap(render = True, renderVector = True)
  155. wx.PostEvent(self.mapWin, up_map_evt)
  156. else:
  157. up_map_evt = gUpdateMap(render = True, renderVector = True)
  158. wx.PostEvent(self.mapWin, up_map_evt)
  159. def _addPanes(self):
  160. """!Adds toolbar pane and pane with tabs"""
  161. self._mgr.AddPane(self.toolbars['mainToolbar'],
  162. wx.aui.AuiPaneInfo().
  163. Name("pointlisttools").Caption(_("Point list toolbar")).
  164. ToolbarPane().Top().Row(0).
  165. Dockable(False).
  166. CloseButton(False).Layer(0))
  167. self._mgr.AddPane(self.toolbars['analysisToolbar'],
  168. wx.aui.AuiPaneInfo().
  169. Name("pointlisttools").Caption(_("Point list toolbar")).
  170. ToolbarPane().Top().Row(1).
  171. Dockable(False).
  172. CloseButton(False).Layer(0))
  173. self._mgr.AddPane(self.mainPanel,
  174. wx.aui.AuiPaneInfo().
  175. Name("tabs").CaptionVisible(visible = False).
  176. Center().
  177. Dockable(False).
  178. CloseButton(False).Layer(0))
  179. def _doVnetDialogLayout(self):
  180. sizer = wx.BoxSizer(wx.VERTICAL)
  181. sizer.Add(item = self.notebook, proportion = 1,
  182. flag = wx.EXPAND)
  183. sizer.Add(item = self.stBar, proportion = 0)
  184. self.mainPanel.SetSizer(sizer)
  185. sizer.Fit(self)
  186. self.Layout()
  187. def _createPointsPage(self):
  188. """!Tab with points list and analysis settings"""
  189. pointsPanel = wx.Panel(parent = self)
  190. maxValue = 1e8
  191. listBox = wx.StaticBox(parent = pointsPanel, id = wx.ID_ANY,
  192. label =" %s " % _("Points for analysis:"))
  193. self.notebook.AddPage(page = pointsPanel,
  194. text=_('Points'),
  195. name = 'points')
  196. self.list = PtsList(parent = pointsPanel, dialog = self, cols = self.cols)
  197. self.toolbars['pointsList'] = PointListToolbar(parent = pointsPanel, list = self.list)
  198. anSettingsPanel = wx.Panel(parent = pointsPanel)
  199. anSettingsBox = wx.StaticBox(parent = anSettingsPanel, id = wx.ID_ANY,
  200. label =" %s " % _("Analysis settings:"))
  201. maxDistPanel = wx.Panel(parent = anSettingsPanel)
  202. maxDistLabel = wx.StaticText(parent = maxDistPanel, id = wx.ID_ANY, label = _("Maximum distance of point to the network:"))
  203. self.anSettings["max_dist"] = wx.SpinCtrl(parent = maxDistPanel, id = wx.ID_ANY, min = 0, max = maxValue)
  204. self.anSettings["max_dist"].SetValue(100000) #TODO init val
  205. #showCutPanel = wx.Panel(parent = anSettingsPanel)
  206. #self.anSettings["show_cut"] = wx.CheckBox(parent = showCutPanel, id=wx.ID_ANY,
  207. # label = _("Show minimal cut"))
  208. #self.anSettings["show_cut"].Bind(wx.EVT_CHECKBOX, self.OnShowCut)
  209. isoLinesPanel = wx.Panel(parent = anSettingsPanel)
  210. isoLineslabel = wx.StaticText(parent = isoLinesPanel, id = wx.ID_ANY, label = _("Iso lines:"))
  211. self.anSettings["iso_lines"] = wx.TextCtrl(parent = isoLinesPanel, id = wx.ID_ANY)
  212. self.anSettings["iso_lines"].SetValue("1000,2000,3000")
  213. # Layout
  214. AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
  215. listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL)
  216. listSizer.Add(item = self.toolbars['pointsList'], proportion = 0)
  217. listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND)
  218. anSettingsSizer = wx.StaticBoxSizer(anSettingsBox, wx.VERTICAL)
  219. maxDistSizer = wx.BoxSizer(wx.HORIZONTAL)
  220. maxDistSizer.Add(item = maxDistLabel, flag = wx.ALIGN_CENTER_VERTICAL, proportion = 1)
  221. maxDistSizer.Add(item = self.anSettings["max_dist"],
  222. flag = wx.EXPAND | wx.ALL, border = 5, proportion = 0)
  223. maxDistPanel.SetSizer(maxDistSizer)
  224. anSettingsSizer.Add(item = maxDistPanel, proportion = 1, flag = wx.EXPAND)
  225. #showCutSizer = wx.BoxSizer(wx.HORIZONTAL)
  226. #showCutPanel.SetSizer(showCutSizer)
  227. #showCutSizer.Add(item = self.anSettings["show_cut"],
  228. # flag = wx.EXPAND | wx.ALL, border = 5, proportion = 0)
  229. #anSettingsSizer.Add(item = showCutPanel, proportion = 1, flag = wx.EXPAND)
  230. isoLinesSizer = wx.BoxSizer(wx.HORIZONTAL)
  231. isoLinesSizer.Add(item = isoLineslabel, flag = wx.ALIGN_CENTER_VERTICAL, proportion = 1)
  232. isoLinesSizer.Add(item = self.anSettings["iso_lines"],
  233. flag = wx.EXPAND | wx.ALL, border = 5, proportion = 1)
  234. isoLinesPanel.SetSizer(isoLinesSizer)
  235. anSettingsSizer.Add(item = isoLinesPanel, proportion = 1, flag = wx.EXPAND)
  236. AnalysisSizer.Add(item = listSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
  237. AnalysisSizer.Add(item = anSettingsPanel, proportion = 0, flag = wx.EXPAND | wx.RIGHT | wx.LEFT | wx.BOTTOM, border = 5)
  238. anSettingsPanel.SetSizer(anSettingsSizer)
  239. pointsPanel.SetSizer(AnalysisSizer)
  240. def OnShowCut(self, event):
  241. """!Shows vector map with minimal cut (v.net.flow) - not yet implemented"""
  242. val = event.IsChecked()
  243. if val and self.tmp_result:
  244. self.tmp_result.DeleteRenderLayer()
  245. cmd = self.GetLayerStyle()
  246. self.vnetFlowTmpCut.AddRenderLayer(cmd)
  247. else:
  248. self.vnetFlowTmpCut.DeleteRenderLayer()
  249. cmd = self.GetLayerStyle()
  250. self.tmp_result.AddRenderLayer(cmd)
  251. up_map_evt = gUpdateMap(render = True, renderVector = True)
  252. wx.PostEvent(self.mapWin, up_map_evt)
  253. def _createOutputPage(self):
  254. """!Tab with output console"""
  255. outputPanel = wx.Panel(parent = self)
  256. self.notebook.AddPage(page = outputPanel,
  257. text = _("Output"),
  258. name = 'output')
  259. self.goutput = GConsole(guiparent = self)
  260. self.gwindow = GConsoleWindow(parent = outputPanel, gconsole = self.goutput)
  261. #Layout
  262. outputSizer = wx.BoxSizer(wx.VERTICAL)
  263. outputSizer.Add(item = self.gwindow, proportion = 1, flag = wx.EXPAND)
  264. self.gwindow.SetMinSize((-1,-1))
  265. outputPanel.SetSizer(outputSizer)
  266. def _createParametersPage(self):
  267. """!Tab for selection of data for analysis"""
  268. dataPanel = wx.Panel(parent=self)
  269. self.notebook.AddPage(page = dataPanel,
  270. text=_('Parameters'),
  271. name = 'parameters')
  272. label = {}
  273. dataSelects = [
  274. ['input', "Choose vector map for analysis:", Select],
  275. ['alayer', "Arc layer number or name:", LayerSelect],
  276. ['nlayer', "Node layer number or name:", LayerSelect],
  277. ['afcolumn', self.attrCols['afcolumn']['label'], ColumnSelect],
  278. ['abcolumn', self.attrCols['abcolumn']['label'], ColumnSelect],
  279. ['ncolumn', self.attrCols['ncolumn']['label'], ColumnSelect],
  280. ]
  281. selPanels = {}
  282. for dataSel in dataSelects:
  283. selPanels[dataSel[0]] = wx.Panel(parent = dataPanel)
  284. if dataSel[0] == 'input':
  285. self.inputData[dataSel[0]] = dataSel[2](parent = selPanels[dataSel[0]],
  286. size = (-1, -1),
  287. type = 'vector')
  288. icon = wx.Image(os.path.join(globalvar.ETCICONDIR, "grass", "layer-vector-add.png"))
  289. icon.Rescale(18, 18)
  290. icon = wx.BitmapFromImage(icon)
  291. self.addToTreeBtn = wx.BitmapButton(parent = selPanels[dataSel[0]],
  292. bitmap = icon,
  293. size = globalvar.DIALOG_COLOR_SIZE)
  294. self.addToTreeBtn.SetToolTipString(_("Add vector map into layer tree"))
  295. self.addToTreeBtn.Disable()
  296. self.addToTreeBtn.Bind(wx.EVT_BUTTON, self.OnToTreeBtn)
  297. elif dataSel[0] != 'input':
  298. self.inputData[dataSel[0]] = dataSel[2](parent = selPanels[dataSel[0]],
  299. size = (-1, -1))
  300. label[dataSel[0]] = wx.StaticText(parent = selPanels[dataSel[0]],
  301. name = dataSel[0])
  302. label[dataSel[0]].SetLabel(dataSel[1])
  303. self.inputData['input'].Bind(wx.EVT_TEXT, self.OnVectSel)
  304. self.inputData['alayer'].Bind(wx.EVT_TEXT, self.OnALayerSel)
  305. self.inputData['nlayer'].Bind(wx.EVT_TEXT, self.OnNLayerSel)
  306. # Layout
  307. mainSizer = wx.BoxSizer(wx.VERTICAL)
  308. box = wx.StaticBox(dataPanel, -1, "Vector map and layers for analysis")
  309. bsizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  310. mainSizer.Add(item = bsizer, proportion = 0,
  311. flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
  312. for sel in ['input', 'alayer', 'nlayer']:
  313. if sel== 'input':
  314. btn = self.addToTreeBtn
  315. else:
  316. btn = None
  317. selPanels[sel].SetSizer(self._doSelLayout(title = label[sel],
  318. sel = self.inputData[sel],
  319. btn = btn))
  320. bsizer.Add(item = selPanels[sel], proportion = 1,
  321. flag = wx.EXPAND)
  322. box = wx.StaticBox(dataPanel, -1, "Costs")
  323. bsizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  324. mainSizer.Add(item = bsizer, proportion = 0,
  325. flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
  326. for sel in ['afcolumn', 'abcolumn', 'ncolumn']:
  327. selPanels[sel].SetSizer(self._doSelLayout(title = label[sel], sel = self.inputData[sel]))
  328. bsizer.Add(item = selPanels[sel], proportion = 0,
  329. flag = wx.EXPAND)
  330. dataPanel.SetSizer(mainSizer)
  331. def _doSelLayout(self, title, sel, btn = None):
  332. # helper function for layout of self.inputData widgets initialized in _createParametersPage
  333. selSizer = wx.BoxSizer(orient = wx.VERTICAL)
  334. selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
  335. selTitleSizer.Add(item = title, proportion = 1,
  336. flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
  337. selSizer.Add(item = selTitleSizer, proportion = 0,
  338. flag = wx.EXPAND)
  339. if btn:
  340. selFiledSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
  341. selFiledSizer.Add(item = sel, proportion = 1,
  342. flag = wx.EXPAND | wx.ALL)
  343. selFiledSizer.Add(item = btn, proportion = 0,
  344. flag = wx.EXPAND | wx.ALL)
  345. selSizer.Add(item = selFiledSizer, proportion = 0,
  346. flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
  347. border = 5)
  348. else:
  349. selSizer.Add(item = sel, proportion = 1,
  350. flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
  351. border = 5)
  352. return selSizer
  353. def _createInputDbMgrPage(self):
  354. """!Tab with attribute tables of analysis input layers"""
  355. self.inpDbMgrData['dbMgr'] = DbMgrBase()
  356. selMapName = None
  357. # if selected vector map is in layer tree then set it
  358. if self.mapWin.tree and self.mapWin.tree.layer_selected:
  359. selMapData = self.mapWin.tree.GetPyData(self.mapWin.tree.layer_selected)[0]
  360. if selMapData['type'] == 'vector': # wrap somehow in LayerTree
  361. selMapName = selMapData['maplayer'].name
  362. self.inpDbMgrData['browse'] = self.inpDbMgrData['dbMgr'].CreateDbMgrPage(parent = self.notebook,
  363. pageName = 'browse')
  364. self.inpDbMgrData['browse'].SetTabAreaColour(globalvar.FNPageColor)
  365. self.inpDbMgrData['input'] = None
  366. if selMapName:
  367. self.inputData['input'].SetValue(selMapName)
  368. self.OnVectSel(None)
  369. def _updateInputDbMgrPage(self, show):
  370. """!Show or hide input tables tab"""
  371. if show and self.notebook.GetPageIndexByName('inputDbMgr') == -1:
  372. self.notebook.AddPage(page = self.inpDbMgrData['browse'],
  373. text=_('Input tables'),
  374. name = 'inputDbMgr')
  375. elif not show:
  376. self.notebook.RemovePage(page = 'inputDbMgr')
  377. def _createResultDbMgrPage(self):
  378. """!Tab with attribute tables of analysis result layers"""
  379. self.resultDbMgrData['dbMgr'] = DbMgrBase()
  380. self.resultDbMgrData['browse'] = self.resultDbMgrData['dbMgr'].CreateDbMgrPage(parent = self.notebook,
  381. pageName = 'browse')
  382. self.resultDbMgrData['browse'].SetTabAreaColour(globalvar.FNPageColor)
  383. if self.tmp_result:
  384. self.resultDbMgrData['input'] = self.tmp_result.GetVectMapName()
  385. else:
  386. self.resultDbMgrData['input'] = None
  387. def _updateResultDbMgrPage(self):
  388. """!Show or Hide Result tables tab"""
  389. # analysis, which created result
  390. analysis = self.resultDbMgrData['analysis']
  391. #TODO maybe no need to store this information, just check it has attribute table, if so show it
  392. haveDbMgr = self.vnetParams[analysis]["resultProps"]["dbMgr"]
  393. if haveDbMgr and self.notebook.GetPageIndexByName('resultDbMgr') == -1:
  394. self.notebook.AddPage(page = self.resultDbMgrData['browse'],
  395. text=_('Result tables'),
  396. name = 'resultDbMgr')
  397. elif not haveDbMgr:
  398. self.notebook.RemovePage(page = 'resultDbMgr')
  399. def OnPageChanged(self, event):
  400. """!Tab switched"""
  401. if event.GetEventObject() == self.notebook:
  402. dbMgrIndxs = []
  403. dbMgrIndxs.append(self.notebook.GetPageIndexByName('inputDbMgr'))
  404. dbMgrIndxs.append(self.notebook.GetPageIndexByName('resultDbMgr'))
  405. if self.notebook.GetSelection() in dbMgrIndxs:
  406. self.stBar.AddStatusItem(text = _('Loading tables...'),
  407. key = 'dbMgr',
  408. priority = self.stPriorities['important'])
  409. self._updateDbMgrData()
  410. self.stBar.RemoveStatusItem(key = 'dbMgr')
  411. # update columns (when some is added in input tables browser), TODO needs optimization
  412. elif self.notebook.GetSelection() == self.notebook.GetPageIndexByName('parameters'):
  413. self.OnALayerSel(None)
  414. self.OnNLayerSel(None)
  415. def _updateDbMgrData(self):
  416. """!Updates input/result tables page """
  417. if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('inputDbMgr'):
  418. self._updateInputDbMgrData()
  419. elif self.notebook.GetSelection() == self.notebook.GetPageIndexByName('resultDbMgr'):
  420. self._updateResultDbMgrData()
  421. else:
  422. self.stBar.RemoveStatusItem('manager')
  423. def _updateInputDbMgrData(self):
  424. """!Loads data according to selected layers in Parameters tab"""
  425. inpSel = self.inputData['input'].GetValue().strip()
  426. # changed vector map
  427. if self.inpDbMgrData['input'] != inpSel:
  428. wx.BeginBusyCursor()
  429. self.inpDbMgrData['dbMgr'].ChangeVectorMap(vectorName = inpSel)
  430. self.inpDbMgrData['input'] = inpSel
  431. for layerName in ['alayer', 'nlayer']:
  432. try:
  433. layer = int(self.inputData[layerName].GetValue())
  434. except ValueError:
  435. continue
  436. self.inpDbMgrData['browse'].AddLayer(layer)
  437. wx.EndBusyCursor()
  438. # same vector map
  439. else:
  440. needLayers = []
  441. browseLayers = self.inpDbMgrData['browse'].GetAddedLayers()
  442. for layerName in ['alayer', 'nlayer']:
  443. try:
  444. inpLayer = int(self.inputData[layerName].GetValue())
  445. except ValueError:
  446. continue
  447. if inpLayer in browseLayers:
  448. needLayers.append(inpLayer)
  449. continue
  450. else:
  451. wx.BeginBusyCursor()
  452. self.inpDbMgrData['browse'].AddLayer(inpLayer)
  453. wx.EndBusyCursor()
  454. needLayers.append(inpLayer)
  455. for layer in browseLayers:
  456. if layer not in needLayers:
  457. self.inpDbMgrData['browse'].DeletePage(layer)
  458. def _updateResultDbMgrData(self):
  459. """!Loads data from analysis result map"""
  460. if not self.tmp_result:
  461. return
  462. vectName = self.tmp_result.GetVectMapName()
  463. if self.resultDbMgrData['input'] != vectName:
  464. wx.BeginBusyCursor()
  465. dbMgr = self.resultDbMgrData['dbMgr']
  466. dbMgr.ChangeVectorMap(vectorName = vectName)
  467. for layer in dbMgr.GetVectorLayers():
  468. self.resultDbMgrData['browse'].AddLayer(layer)
  469. self.resultDbMgrData['input'] = vectName
  470. wx.EndBusyCursor()
  471. def OnToTreeBtn(self, event):
  472. """!Add vector map into layer tree"""
  473. vectorMap = self.inputData['input'].GetValue()
  474. vectMapName, mapSet = self._parseMapStr(vectorMap)
  475. vectorMap = vectMapName + '@' + mapSet
  476. existsMap = grass.find_file(name = vectMapName,
  477. element = 'vector',
  478. mapset = mapSet)
  479. if not existsMap["name"]:
  480. return
  481. cmd = ['d.vect',
  482. 'map=' + vectorMap]
  483. if self.mapWin.tree and \
  484. self.mapWin.tree.FindItemByData(key = 'name', value = vectorMap) is None:
  485. self.mapWin.tree.AddLayer(ltype = "vector",
  486. lcmd = cmd,
  487. lname =vectorMap,
  488. lchecked = True)
  489. #d.mon case
  490. else:
  491. self.renderLayer = self.mapWin.Map.AddLayer(ltype = "vector", command = cmd,
  492. name = vectorMap, active = True,
  493. opacity = 1.0, render = True,
  494. pos = -1)
  495. up_map_evt = gUpdateMap(render = True, renderVector = True)
  496. wx.PostEvent(self.mapWin, up_map_evt)
  497. def OnVectSel(self, event):
  498. """!When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)"""
  499. if self.snapData['snap_mode']:
  500. self.OnSnapping(event = None)
  501. vectMapName, mapSet = self._parseMapStr(self.inputData['input'].GetValue())
  502. vectorMap = vectMapName + '@' + mapSet
  503. cd .
  504. self.inputData['alayer'].Clear()
  505. self.inputData['nlayer'].Clear()
  506. self.inputData['alayer'].InsertLayers(vector = vectorMap)
  507. self.inputData['nlayer'].InsertLayers(vector = vectorMap)
  508. items = self.inputData['alayer'].GetItems()
  509. itemsLen = len(items)
  510. if itemsLen < 1:
  511. self.addToTreeBtn.Disable()
  512. if hasattr(self, 'inpDbMgrData'):
  513. self._updateInputDbMgrPage(show = False)
  514. self.inputData['alayer'].SetValue("")
  515. self.inputData['nlayer'].SetValue("")
  516. for sel in ['afcolumn', 'abcolumn', 'ncolumn']:
  517. self.inputData[sel].Clear()
  518. self.inputData[sel].SetValue("")
  519. return
  520. elif itemsLen == 1:
  521. self.inputData['alayer'].SetSelection(0)
  522. self.inputData['nlayer'].SetSelection(0)
  523. elif itemsLen >= 1:
  524. if unicode("1") in items:
  525. iItem = items.index(unicode("1"))
  526. self.inputData['alayer'].SetSelection(iItem)
  527. if unicode("2") in items:
  528. iItem = items.index(unicode("2"))
  529. self.inputData['nlayer'].SetSelection(iItem)
  530. self.addToTreeBtn.Enable()
  531. if hasattr(self, 'inpDbMgrData'):
  532. self._updateInputDbMgrPage(show = True)
  533. self.OnALayerSel(event)
  534. self.OnNLayerSel(event)
  535. def OnALayerSel(self, event):
  536. """!When arc layer from vector map is selected, populates corespondent columns selects"""
  537. self.inputData['afcolumn'].InsertColumns(vector = self.inputData['input'].GetValue(),
  538. layer = self.inputData['alayer'].GetValue(),
  539. type = self.columnTypes)
  540. self.inputData['abcolumn'].InsertColumns(vector = self.inputData['input'].GetValue(),
  541. layer = self.inputData['alayer'].GetValue(),
  542. type = self.columnTypes)
  543. def OnNLayerSel(self, event):
  544. """!When node layer from vector map is selected, populates corespondent column select"""
  545. if self.snapData['snap_mode']:
  546. self.OnSnapping(event = None)
  547. self.inputData['ncolumn'].InsertColumns(vector = self.inputData['input'].GetValue(),
  548. layer = self.inputData['nlayer'].GetValue(),
  549. type = self.columnTypes)
  550. def _getInvalidInputs(self, inpToTest):
  551. """!Check of analysis input data for invalid values (Parameters tab)"""
  552. # dict of invalid values {key from self.itemData (comboboxes from Parameters tab) : invalid value}
  553. errInput = {}
  554. mapVal = self.inputData['input'].GetValue()
  555. mapName, mapSet = self._parseMapStr(mapVal)
  556. vectMaps = grass.list_grouped('vect')[mapSet]
  557. # check of vector map
  558. if not inpToTest or "input" in inpToTest:
  559. if mapName not in vectMaps:
  560. errInput['input'] = mapVal
  561. # check of arc/node layer
  562. for layerSelName in ['alayer', 'nlayer'] :
  563. if not inpToTest or layerSelName in inpToTest:
  564. layerItems = self.inputData[layerSelName].GetItems()
  565. layerVal = self.inputData[layerSelName].GetValue().strip()
  566. if layerVal not in layerItems:
  567. errInput[layerSelName] = layerVal
  568. # check of costs columns
  569. currModCols = self.vnetParams[self.currAnModule]["cmdParams"]["cols"]
  570. for col, colData in self.attrCols.iteritems():
  571. if not inpToTest or col in inpToTest:
  572. if col not in currModCols:
  573. continue
  574. if "inputField" in self.attrCols[col]:
  575. colInptF = self.attrCols[col]["inputField"]
  576. else:
  577. colInptF = col
  578. if not self.inputData[colInptF].IsShown():
  579. continue
  580. colVal = self.inputData[colInptF].GetValue().strip()
  581. if not colVal:
  582. continue
  583. if colVal not in self.inputData[colInptF].GetItems():
  584. errInput[col] = colVal
  585. return errInput
  586. def _parseMapStr(self, vectMapStr):
  587. """!Create full map name (add current mapset if it is not present in name)"""
  588. mapValSpl = vectMapStr.strip().split("@")
  589. if len(mapValSpl) > 1:
  590. mapSet = mapValSpl[1]
  591. else:
  592. mapSet = grass.gisenv()['MAPSET']
  593. mapName = mapValSpl[0]
  594. return mapName, mapSet
  595. def InputsErrorMsgs(self, msg, inpToTest = None):
  596. """!Checks input data in Parameters tab and shows messages if some value is not valid
  597. @param msg (str) - message added to start of message string
  598. @param inpToTest (list) - list of keys from self.itemData map, which says which input data should be checked,
  599. if is empty or None, all input data are checked
  600. @return True - if checked inputs are OK
  601. @return False - if some of checked inputs is not ok
  602. """
  603. errInput = self._getInvalidInputs(inpToTest)
  604. errMapStr = ""
  605. if errInput.has_key('input'):
  606. self.notebook.SetSelectionByName("parameters")
  607. if errInput['input']:
  608. errMapStr = _("Vector map '%s' does not exist.") % (errInput['input'])
  609. else:
  610. errMapStr = _("Vector map was not chosen.")
  611. if errMapStr:
  612. GMessage(parent = self,
  613. message = msg + "\n" + errMapStr)
  614. return False
  615. errLayerStr = ""
  616. for layer, layerLabel in {'alayer' : _("arc layer"),
  617. 'nlayer' : _("node layer")}.iteritems():
  618. if errInput.has_key(layer):
  619. if errInput[layer]:
  620. errLayerStr += _("Chosen %s '%s' does not exist in vector map '%s'.\n") % \
  621. (layerLabel, self.inputData[layer].GetValue(), self.inputData['input'].GetValue())
  622. else:
  623. errLayerStr += _("Choose existing %s.\n") % \
  624. (layerLabel)
  625. if errLayerStr:
  626. GMessage(parent = self,
  627. message = msg + "\n" + errLayerStr)
  628. return False
  629. errColStr = ""
  630. for col, colData in self.attrCols.iteritems():
  631. if col in errInput.iterkeys():
  632. errColStr += _("Chosen column '%s' does not exist in attribute table of layer '%s' of vector map '%s'.\n") % \
  633. (errInput[col], self.inputData[layer].GetValue(), self.inputData['input'].GetValue())
  634. if errColStr:
  635. self.notebook.SetSelectionByName("parameters")
  636. GMessage(parent = self,
  637. message = msg + "\n" + errColStr)
  638. return False
  639. return True
  640. def OnCloseDialog(self, event):
  641. """!Cancel dialog"""
  642. self.parent.dialogs['vnet'] = None
  643. self.Destroy()
  644. def SetPointStatus(self, item, itemIndex):
  645. """!Before point is drawn, decides properties of drawing style"""
  646. key = self.list.GetItemData(itemIndex)
  647. cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
  648. if key == self.list.selected:
  649. wxPen = "selected"
  650. elif not self.list.IsChecked(key):
  651. wxPen = "unused"
  652. item.hide = False
  653. elif len(cats) > 1:
  654. idx = self.list.GetCellSelIdx(key, 'type')
  655. if idx == 2: #End/To/Sink point
  656. wxPen = "used2cat"
  657. else:
  658. wxPen = "used1cat"
  659. else:
  660. wxPen = "used1cat"
  661. item.SetPropertyVal('label', str(itemIndex + 1))
  662. item.SetPropertyVal('penName', wxPen)
  663. def OnMapClickHandler(self, event):
  664. """!Take coordinates from map window"""
  665. if event == 'unregistered':
  666. ptListToolbar = self.toolbars['pointsList']
  667. if ptListToolbar:
  668. ptListToolbar.ToggleTool( id = ptListToolbar.GetToolId("insertPoint"),
  669. toggle = False)
  670. self.handlerRegistered = False
  671. return
  672. self.notebook.SetSelectionByName("points")
  673. if not self.list.itemDataMap:
  674. self.list.AddItem(None)
  675. e, n = self.mapWin.GetLastEN()
  676. index = self.list.selected
  677. key = self.list.GetItemData(index)
  678. if self.snapData['snap_mode']:
  679. coords = [e, n]
  680. if self._snapPoint(coords):
  681. msg = ("snapped to node")
  682. else:
  683. msg = _("new point")
  684. e = coords[0]
  685. n = coords[1]
  686. else:
  687. msg = _("new point")
  688. self.list.EditCellKey(key = self.list.selected ,
  689. colName = 'topology',
  690. cellData = msg)
  691. self.pointsToDraw.GetItem(key).SetCoords([e, n])
  692. if self.list.selected == self.list.GetItemCount() - 1:
  693. self.list.selected = 0
  694. else:
  695. self.list.selected += 1
  696. self.list.Select(self.list.selected)
  697. def _snapPoint(self, coords):
  698. """!Find nearest node to click coordinates (within given threshold)"""
  699. e = coords[0]
  700. n = coords[1]
  701. # compute threshold
  702. snapTreshPix = int(UserSettings.Get(group ='vnet',
  703. key = 'other',
  704. subkey = 'snap_tresh'))
  705. res = max(self.mapWin.Map.region['nsres'], self.mapWin.Map.region['ewres'])
  706. snapTreshDist = snapTreshPix * res
  707. vectorMap = self.inputData['input'].GetValue()
  708. vectMapName, mapSet = self._parseMapStr(vectorMap)
  709. inpMapExists = grass.find_file(name = vectMapName,
  710. element = 'vector',
  711. mapset = mapSet)
  712. if not inpMapExists['name']:
  713. return False
  714. openedMap = pointer(vectlib.Map_info())
  715. ret = vectlib.Vect_open_old2(openedMap,
  716. c_char_p(vectMapName),
  717. c_char_p(mapSet),
  718. c_char_p(self.inputData['alayer'].GetValue()))
  719. if ret == 1:
  720. vectlib.Vect_close(openedMap)
  721. if ret != 2:
  722. return False
  723. nodeNum = vectlib.Vect_find_node(openedMap,
  724. c_double(e),
  725. c_double(n),
  726. c_double(0),
  727. c_double(snapTreshDist),
  728. vectlib.WITHOUT_Z)
  729. if nodeNum > 0:
  730. e = c_double(0)
  731. n = c_double(0)
  732. vectlib.Vect_get_node_coor(openedMap,
  733. nodeNum,
  734. byref(e),
  735. byref(n),
  736. None); # z
  737. e = e.value
  738. n = n.value
  739. else:
  740. vectlib.Vect_close(openedMap)
  741. return False
  742. coords[0] = e
  743. coords[1] = n
  744. return True
  745. def OnAnalyze(self, event):
  746. """!Called when network analysis is started"""
  747. # Check of parameters for analysis
  748. if not self.InputsErrorMsgs(msg = _("Analysis can not be done.")):
  749. return
  750. if self.tmp_result:
  751. self.tmp_result.DeleteRenderLayer()
  752. # history - delete data in buffer for hist step
  753. self.history.DeleteNewHistStepData()
  754. # empty list for maps to be saved to history
  755. self.tmpVectMapsToHist= []
  756. # create new map (included to history) for result of analysis
  757. self.tmp_result = self.NewTmpVectMapToHist('vnet_tmp_result')
  758. if not self.tmp_result:
  759. return
  760. self.stBar.AddStatusItem(text = _('Analysing...'),
  761. key = 'analyze',
  762. priority = self.stPriorities['important'])
  763. # for case there is some map with same name
  764. # (when analysis does not produce any map, this map would have been shown as result)
  765. RunCommand('g.remove',
  766. vect = self.tmp_result.GetVectMapName())
  767. # save data from
  768. self._saveAnInputToHist()
  769. self.resultDbMgrData['analysis'] = self.currAnModule
  770. # Creates part of cmd fro analysis
  771. cmdParams = [self.currAnModule]
  772. cmdParams.extend(self._getInputParams())
  773. cmdParams.append("output=" + self.tmp_result.GetVectMapName())
  774. catPts = self._getPtByCat()
  775. if self.currAnModule == "v.net.path":
  776. self._vnetPathRunAn(cmdParams, catPts)
  777. else:
  778. self._runAn(cmdParams, catPts)
  779. def _vnetPathRunAn(self, cmdParams, catPts):
  780. """!Called when analysis is run for v.net.path module"""
  781. if len(self.pointsToDraw.GetAllItems()) < 1:
  782. return
  783. cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
  784. cmdPts = []
  785. for cat in cats:
  786. if len(catPts[cat[0]]) < 1:
  787. GMessage(parent = self,
  788. message=_("Please choose '%s' and '%s' point.") % (cats[0][1], cats[1][1]))
  789. return
  790. cmdPts.append(catPts[cat[0]][0])
  791. resId = 1
  792. inpPoints = str(resId) + " " + str(cmdPts[0][0]) + " " + str(cmdPts[0][1]) + \
  793. " " + str(cmdPts[1][0]) + " " + str(cmdPts[1][1])
  794. self.coordsTmpFile = grass.tempfile()
  795. coordsTmpFileOpened = open(self.coordsTmpFile, 'w')
  796. coordsTmpFileOpened.write(inpPoints)
  797. coordsTmpFileOpened.close()
  798. cmdParams.append("file=" + self.coordsTmpFile)
  799. cmdParams.append("dmax=" + str(self.anSettings["max_dist"].GetValue()))
  800. cmdParams.append("input=" + self.inputData['input'].GetValue())
  801. cmdParams.append("--overwrite")
  802. self._prepareCmd(cmd = cmdParams)
  803. self.goutput.RunCmd(command = cmdParams, onDone = self._vnetPathRunAnDone)
  804. def _vnetPathRunAnDone(self, cmd, returncode):
  805. """!Called when v.net.path analysis is done"""
  806. grass.try_remove(self.coordsTmpFile)
  807. self._saveHistStep()
  808. self.tmp_result.SaveVectMapState()
  809. self._updateResultDbMgrPage()
  810. self._updateDbMgrData()
  811. cmd = self.GetLayerStyle()
  812. self.tmp_result.AddRenderLayer(cmd)
  813. up_map_evt = gUpdateMap(render = True, renderVector = True)
  814. wx.PostEvent(self.mapWin, up_map_evt)
  815. mainToolbar = self.toolbars['mainToolbar']
  816. id = vars(mainToolbar)['showResult']
  817. mainToolbar.ToggleTool(id =id,
  818. toggle = True)
  819. self.stBar.RemoveStatusItem(key = 'analyze')
  820. def _runAn(self, cmdParams, catPts):
  821. """!Called for all v.net.* analysis (except v.net.path)"""
  822. cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
  823. if len(cats) > 1:
  824. for cat in cats:
  825. if len(catPts[cat[0]]) < 1:
  826. GMessage(parent = self,
  827. message = _("Please choose '%s' and '%s' point.") \
  828. % (cats[0][1], cats[1][1]))
  829. return
  830. else:
  831. for cat in cats:
  832. if len(catPts[cat[0]]) < 2:
  833. GMessage(parent = self,
  834. message = _("Please choose at least two points."))
  835. return
  836. # TODO add also to thread for analysis?
  837. vcatResult = RunCommand("v.category",
  838. input = self.inputData['input'].GetValue(),
  839. option = "report",
  840. flags = "g",
  841. read = True)
  842. vcatResult = vcatResult.splitlines()
  843. for cat in vcatResult:#TODO
  844. cat = cat.split()
  845. if "all" in cat:
  846. maxCat = int(cat[4])
  847. break
  848. layerNum = self.inputData["nlayer"].GetValue().strip()
  849. pt_ascii, catsNums = self._getAsciiPts (catPts = catPts,
  850. maxCat = maxCat,
  851. layerNum = layerNum)
  852. self.tmpPtsAsciiFile = grass.tempfile()#TODO better tmp files cleanup (make class for managing tmp files)
  853. tmpPtsAsciiFileOpened = open(self.tmpPtsAsciiFile, 'w')
  854. tmpPtsAsciiFileOpened.write(pt_ascii)
  855. tmpPtsAsciiFileOpened.close()
  856. self.tmpInPts = self._addTmpMapAnalysisMsg("vnet_tmp_in_pts")
  857. if not self.tmpInPts:
  858. return
  859. self.tmpInPtsConnected = self._addTmpMapAnalysisMsg("vnet_tmp_in_pts_connected")
  860. if not self.tmpInPtsConnected:
  861. return
  862. cmdParams.append("input=" + self.tmpInPtsConnected.GetVectMapName())
  863. cmdParams.append("--overwrite")
  864. # append parameters needed for particular analysis
  865. if self.currAnModule == "v.net.distance":
  866. cmdParams.append("from_layer=1")
  867. cmdParams.append("to_layer=1")
  868. elif self.currAnModule == "v.net.flow":
  869. self.vnetFlowTmpCut = self.NewTmpVectMapToHist('vnet_tmp_flow_cut')
  870. if not self.vnetFlowTmpCut:
  871. return
  872. cmdParams.append("cut=" + self.vnetFlowTmpCut.GetVectMapName())
  873. elif self.currAnModule == "v.net.iso":
  874. costs = self.anSettings["iso_lines"].GetValue()
  875. cmdParams.append("costs=" + costs)
  876. for catName, catNum in catsNums.iteritems():
  877. if catNum[0] == catNum[1]:
  878. cmdParams.append(catName + "=" + str(catNum[0]))
  879. else:
  880. cmdParams.append(catName + "=" + str(catNum[0]) + "-" + str(catNum[1]))
  881. # create and run commands which goes to analysis thread
  882. cmdVEdit = [
  883. "v.edit",
  884. "map=" + self.tmpInPts.GetVectMapName(),
  885. "input=" + self.tmpPtsAsciiFile,
  886. "tool=create",
  887. "--overwrite",
  888. "-n"
  889. ]
  890. self._prepareCmd(cmdVEdit)
  891. self.goutput.RunCmd(command = cmdVEdit)
  892. cmdVNet = [
  893. "v.net",
  894. "points=" + self.tmpInPts.GetVectMapName(),
  895. "input=" + self.inputData['input'].GetValue(),
  896. "output=" + self.tmpInPtsConnected.GetVectMapName(),
  897. "alayer=" + self.inputData["alayer"].GetValue().strip(),
  898. "nlayer=" + self.inputData["nlayer"].GetValue().strip(),
  899. "operation=connect",
  900. "thresh=" + str(self.anSettings["max_dist"].GetValue()),
  901. "--overwrite"
  902. ] #TODO snapping to nodes optimization
  903. self._prepareCmd(cmdVNet)
  904. self.goutput.RunCmd(command = cmdVNet)
  905. self._prepareCmd(cmdParams)
  906. self.goutput.RunCmd(command = cmdParams, onDone = self._runAnDone)
  907. def _runAnDone(self, cmd, returncode):
  908. """!Called when analysis is done"""
  909. self.tmpMaps.DeleteTmpMap(self.tmpInPts) #TODO remove earlier (OnDone lambda?)
  910. self.tmpMaps.DeleteTmpMap(self.tmpInPtsConnected)
  911. grass.try_remove(self.tmpPtsAsciiFile)
  912. self._saveHistStep()
  913. self.tmp_result.SaveVectMapState()
  914. if self.currAnModule == "v.net.flow":
  915. self.vnetFlowTmpCut.SaveVectMapState()
  916. self._updateResultDbMgrPage()
  917. self._updateDbMgrData()
  918. cmd = self.GetLayerStyle()
  919. self.tmp_result.AddRenderLayer(cmd)
  920. up_map_evt = gUpdateMap(render = True, renderVector = True)
  921. wx.PostEvent(self.mapWin, up_map_evt)
  922. mainToolbar = self.toolbars['mainToolbar']
  923. id = vars(mainToolbar)['showResult']
  924. mainToolbar.ToggleTool(id =id,
  925. toggle = True)
  926. self.stBar.RemoveStatusItem(key = 'analyze')
  927. def _getInputParams(self):
  928. """!Return list of chosen values (vector map, layers) from Parameters tab.
  929. The list items are in form to be used in command for analysis e.g. 'alayer=1'.
  930. """
  931. inParams = []
  932. for col in self.vnetParams[self.currAnModule]["cmdParams"]["cols"]:
  933. if "inputField" in self.attrCols[col]:
  934. colInptF = self.attrCols[col]["inputField"]
  935. else:
  936. colInptF = col
  937. inParams.append(col + '=' + self.inputData[colInptF].GetValue())
  938. for layer in ['alayer', 'nlayer']:
  939. inParams.append(layer + "=" + self.inputData[layer].GetValue().strip())
  940. return inParams
  941. def _getPtByCat(self):
  942. """!Return points separated by theirs categories"""
  943. cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
  944. ptByCats = {}
  945. for cat in self.vnetParams[self.currAnModule]["cmdParams"]["cats"]:
  946. ptByCats[cat[0]] = []
  947. for i in range(len(self.list.itemDataMap)):
  948. key = self.list.GetItemData(i)
  949. if self.list.IsChecked(key):
  950. for cat in cats:
  951. if cat[1] == self.list.itemDataMap[key][1] or len(ptByCats) == 1:
  952. ptByCats[cat[0]].append(self.pointsToDraw.GetItem(key).GetCoords())
  953. continue
  954. return ptByCats
  955. def _getAsciiPts (self, catPts, maxCat, layerNum):
  956. """!Return points separated by categories in GRASS ASCII vector representation"""
  957. catsNums = {}
  958. pt_ascii = ""
  959. catNum = maxCat
  960. for catName, pts in catPts.iteritems():
  961. catsNums[catName] = [catNum + 1]
  962. for pt in pts:
  963. catNum += 1
  964. pt_ascii += "P 1 1\n"
  965. pt_ascii += str(pt[0]) + " " + str(pt[1]) + "\n"
  966. pt_ascii += str(layerNum) + " " + str(catNum) + "\n"
  967. catsNums[catName].append(catNum)
  968. return pt_ascii, catsNums
  969. def _prepareCmd(self, cmd):
  970. """!Helper function for preparation of cmd list into form for RunCmd method"""
  971. for c in cmd[:]:
  972. if c.find("=") == -1:
  973. continue
  974. v = c.split("=")
  975. if len(v) != 2:
  976. cmd.remove(c)
  977. elif not v[1].strip():
  978. cmd.remove(c)
  979. def GetLayerStyle(self):
  980. """!Returns cmd for d.vect, with set style for analysis result"""
  981. resProps = self.vnetParams[self.currAnModule]["resultProps"]
  982. width = UserSettings.Get(group='vnet', key='res_style', subkey= "line_width")
  983. layerStyleCmd = ["layer=1",'width=' + str(width)]
  984. if "catColor" in resProps:
  985. layerStyleCmd.append('flags=c')
  986. elif "singleColor" in resProps:
  987. col = UserSettings.Get(group='vnet', key='res_style', subkey= "line_color")
  988. layerStyleCmd.append('color=' + str(col[0]) + ':' + str(col[1]) + ':' + str(col[2]))
  989. if "attrColColor" in resProps:
  990. colorStyle = UserSettings.Get(group='vnet', key='res_style', subkey= "color_table")
  991. invert = UserSettings.Get(group='vnet', key='res_style', subkey= "invert_colors")
  992. layerStyleVnetColors = [
  993. "v.colors",
  994. "map=" + self.tmp_result.GetVectMapName(),
  995. "color=" + colorStyle,
  996. "column=" + resProps["attrColColor"],
  997. ]
  998. if invert:
  999. layerStyleVnetColors.append("-n")
  1000. layerStyleVnetColors = utils.CmdToTuple(layerStyleVnetColors)
  1001. RunCommand( layerStyleVnetColors[0],
  1002. **layerStyleVnetColors[1])
  1003. return layerStyleCmd
  1004. def OnShowResult(self, event):
  1005. """!Show/hide analysis result"""
  1006. mainToolbar = self.toolbars['mainToolbar']
  1007. id = vars(mainToolbar)['showResult']
  1008. toggleState = mainToolbar.GetToolState(id)
  1009. if not self.tmp_result:
  1010. mainToolbar.ToggleTool(id =id,
  1011. toggle = False)
  1012. elif toggleState:
  1013. self._checkResultMapChanged(self.tmp_result)
  1014. cmd = self.GetLayerStyle()
  1015. self.tmp_result.AddRenderLayer(cmd)
  1016. else:
  1017. cmd = self.GetLayerStyle()
  1018. self.tmp_result.DeleteRenderLayer()
  1019. up_map_evt = gUpdateMap(render = True, renderVector = True)
  1020. wx.PostEvent(self.mapWin, up_map_evt)
  1021. def OnInsertPoint(self, event):
  1022. """!Registers/unregisters mouse handler into map window"""
  1023. if self.handlerRegistered == False:
  1024. self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN,
  1025. self.OnMapClickHandler,
  1026. wx.StockCursor(wx.CURSOR_CROSS))
  1027. self.handlerRegistered = True
  1028. else:
  1029. self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
  1030. self.OnMapClickHandler)
  1031. self.handlerRegistered = False
  1032. def OnSaveTmpLayer(self, event):
  1033. """!Permanently saves temporary map of analysis result"""
  1034. dlg = AddLayerDialog(parent = self)
  1035. msg = _("Vector map with analysis result does not exist.")
  1036. if dlg.ShowModal() == wx.ID_OK:
  1037. if not hasattr(self.tmp_result, "GetVectMapName"):
  1038. GMessage(parent = self,
  1039. message = msg)
  1040. return
  1041. mapToAdd = self.tmp_result.GetVectMapName()
  1042. mapToAddEx = grass.find_file(name = mapToAdd,
  1043. element = 'vector',
  1044. mapset = grass.gisenv()['MAPSET'])
  1045. if not mapToAddEx["name"]:
  1046. GMessage(parent = self,
  1047. message = msg)
  1048. dlg.Destroy()
  1049. return
  1050. addedMap = dlg.vectSel.GetValue()
  1051. mapName, mapSet = self._parseMapStr(addedMap)
  1052. if mapSet != grass.gisenv()['MAPSET']:
  1053. GMessage(parent = self,
  1054. message = _("Map can be saved only to currently set mapset"))
  1055. return
  1056. existsMap = grass.find_file(name = mapName,
  1057. element = 'vector',
  1058. mapset = grass.gisenv()['MAPSET'])
  1059. dlg.Destroy()
  1060. if existsMap["name"]:
  1061. dlg = wx.MessageDialog(parent = self.parent.parent,
  1062. message = _("Vector map %s already exists. " +
  1063. "Do you want to overwrite it?") %
  1064. (existsMap["fullname"]),
  1065. caption = _("Overwrite map layer"),
  1066. style = wx.YES_NO | wx.NO_DEFAULT |
  1067. wx.ICON_QUESTION | wx.CENTRE)
  1068. ret = dlg.ShowModal()
  1069. if ret == wx.ID_NO:
  1070. dlg.Destroy()
  1071. return
  1072. dlg.Destroy()
  1073. RunCommand("g.copy",
  1074. overwrite = True,
  1075. vect = [self.tmp_result.GetVectMapName(), mapName])
  1076. cmd = self.GetLayerStyle()#TODO get rid of insert
  1077. cmd.insert(0, 'd.vect')
  1078. cmd.append('map=%s' % mapName)
  1079. if not self.mapWin.tree:
  1080. return
  1081. if self.mapWin.tree.FindItemByData(key = 'name', value = mapName) is None:
  1082. self.mapWin.tree.AddLayer(ltype = "vector",
  1083. lname = mapName,
  1084. lcmd = cmd,
  1085. lchecked = True)
  1086. else:
  1087. up_map_evt = gUpdateMap(render = True, renderVector = True)
  1088. wx.PostEvent(self.mapWin, up_map_evt)
  1089. def OnSettings(self, event):
  1090. """!Displays vnet settings dialog"""
  1091. dlg = SettingsDialog(parent=self, id=wx.ID_ANY, title=_('Settings'))
  1092. if dlg.ShowModal() == wx.ID_OK:
  1093. pass
  1094. dlg.Destroy()
  1095. def OnAnalysisChanged(self, event):
  1096. """!Updates dialog when analysis is changed"""
  1097. # set chosen analysis
  1098. iAn = self.toolbars['analysisToolbar'].anChoice.GetSelection()
  1099. self.currAnModule = self.vnetModulesOrder[iAn]
  1100. # update dialog for particular analysis
  1101. if self.currAnModule == "v.net.iso":
  1102. self.anSettings['iso_lines'].GetParent().Show()
  1103. else:
  1104. self.anSettings['iso_lines'].GetParent().Hide()
  1105. #if self.currAnModule == "v.net.flow": TODO not implemented
  1106. # self.anSettings['show_cut'].GetParent().Show()
  1107. #else:
  1108. # self.anSettings['show_cut'].GetParent().Hide()
  1109. # show only corresponding selects for chosen v.net module
  1110. skip = []
  1111. for col in self.attrCols.iterkeys():
  1112. if "inputField" in self.attrCols[col]:
  1113. colInptF = self.attrCols[col]["inputField"]
  1114. else:
  1115. colInptF = col
  1116. if col in skip:
  1117. continue
  1118. inputPanel = self.inputData[colInptF].GetParent()
  1119. if col in self.vnetParams[self.currAnModule]["cmdParams"]["cols"]:
  1120. inputPanel.Show()
  1121. inputPanel.FindWindowByName(colInptF).SetLabel(self.attrCols[col]["label"])
  1122. inputPanel.Layout()
  1123. if col != colInptF:
  1124. skip.append(colInptF)
  1125. else:
  1126. self.inputData[colInptF].GetParent().Hide()
  1127. self.Layout()
  1128. # if module has only one category -> hide type column in points list otherwise show it
  1129. if len(self.vnetParams[self.currAnModule]["cmdParams"]["cats"]) > 1:
  1130. if not self.list.IsShown('type'):
  1131. self.list.ShowColumn('type', 1)
  1132. currParamsCats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
  1133. self.list.AdaptPointsList(currParamsCats)
  1134. else:
  1135. if self.list.IsShown('type'):
  1136. self.list.HideColumn('type')
  1137. # for v.net.path just one 'Start point' and one 'End point' can be checked
  1138. if self.currAnModule == "v.net.path":
  1139. self.list.UpdateCheckedItems(index = None)
  1140. def OnSnapping(self, event):
  1141. """!Start/stop snapping mode"""
  1142. ptListToolbar = self.toolbars['pointsList']
  1143. if not haveCtypes:
  1144. ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
  1145. toggle = False)
  1146. GMessage(parent = self,
  1147. message = _("Unable to use ctypes. \n") + \
  1148. _("Snapping mode can not be activated."))
  1149. return
  1150. if not event or not event.IsChecked():
  1151. if not event:
  1152. ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
  1153. toggle = False)
  1154. if self.tmpMaps.HasTmpVectMap("vnet_snap_points"):
  1155. self.snapPts.DeleteRenderLayer()
  1156. up_map_evt = gUpdateMap(render = False, renderVector = False)
  1157. wx.PostEvent(self.mapWin, up_map_evt)
  1158. if self.snapData.has_key('cmdThread'):
  1159. self.snapData['cmdThread'].abort()
  1160. self.snapData['snap_mode'] = False
  1161. return
  1162. if not self.InputsErrorMsgs(msg = _("Snapping mode can not be activated."),
  1163. inpToTest = ["input", "nlayer"]):
  1164. ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
  1165. toggle = False)
  1166. return
  1167. if not self.tmpMaps.HasTmpVectMap("vnet_snap_points"):
  1168. endStr = _("Do you really want to activate snapping and overwrite it?")
  1169. self.snapPts = self.tmpMaps.AddTmpVectMap("vnet_snap_points", endStr)
  1170. if not self.snapPts:
  1171. ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
  1172. toggle = False)
  1173. return
  1174. elif self.snapPts.VectMapState() == 0:
  1175. dlg = wx.MessageDialog(parent = self.parent,
  1176. message = _("Temporary map '%s' was changed outside " +
  1177. "vector analysis tool.\n"
  1178. "Do you really want to activate " +
  1179. "snapping and overwrite it? ") % \
  1180. self.snapPts.GetVectMapName(),
  1181. caption = _("Overwrite map"),
  1182. style = wx.YES_NO | wx.NO_DEFAULT |
  1183. wx.ICON_QUESTION | wx.CENTRE)
  1184. ret = dlg.ShowModal()
  1185. dlg.Destroy()
  1186. if ret == wx.ID_NO:
  1187. self.tmpMaps.DeleteTmpMap(self.snapPts)
  1188. ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
  1189. toggle = False)
  1190. return
  1191. self.snapData['snap_mode'] = True
  1192. inpName = self.inputData['input'].GetValue()
  1193. inpName, mapSet = self._parseMapStr(inpName)
  1194. inpFullName = inpName + '@' + mapSet
  1195. computeNodes = True
  1196. if not self.snapData.has_key("inputMap"):
  1197. pass
  1198. elif inpFullName != self.snapData["inputMap"].GetVectMapName():
  1199. self.snapData["inputMap"] = VectMap(self, inpFullName)
  1200. elif self.snapData["inputMapNlayer"] == self.inputData["nlayer"].GetValue():
  1201. if self.snapData["inputMap"].VectMapState() == 1:
  1202. computeNodes = False
  1203. # new map need
  1204. if computeNodes:
  1205. self.stBar.AddStatusItem(text = _('Computing nodes...'),
  1206. key = 'snap',
  1207. priority = self.stPriorities['important'])
  1208. if not self.snapData.has_key('cmdThread'):
  1209. self.snapData['cmdThread'] = CmdThread(self)
  1210. cmd = ["v.to.points", "input=" + self.inputData['input'].GetValue(),
  1211. "output=" + self.snapPts.GetVectMapName(),
  1212. "llayer=" + self.inputData["nlayer"].GetValue(),
  1213. "-n", "--overwrite"]
  1214. # process GRASS command with argument
  1215. self.snapData["inputMap"] = VectMap(self, inpFullName)
  1216. self.snapData["inputMap"].SaveVectMapState()
  1217. self.Bind(EVT_CMD_DONE, self._onToPointsDone)
  1218. self.snapData['cmdThread'].RunCmd(cmd)
  1219. self.snapData["inputMapNlayer"] = self.inputData["nlayer"].GetValue()
  1220. # map is already created and up to date for input data
  1221. else:
  1222. self.snapPts.AddRenderLayer()
  1223. up_map_evt = gUpdateMap(render = True, renderVector = True)
  1224. wx.PostEvent(self.mapWin, up_map_evt)
  1225. def _onToPointsDone(self, event):
  1226. """!Update map window, when map with nodes to snap is created"""
  1227. self.stBar.RemoveStatusItem(key = 'snap')
  1228. if not event.aborted:
  1229. self.snapPts.SaveVectMapState()
  1230. self.snapPts.AddRenderLayer()
  1231. up_map_evt = gUpdateMap(render = True, renderVector = True)
  1232. wx.PostEvent(self.mapWin, up_map_evt)
  1233. def OnUndo(self, event):
  1234. """!Step back in history"""
  1235. histStepData = self.history.GetPrev()
  1236. self.toolbars['mainToolbar'].UpdateUndoRedo()
  1237. if histStepData:
  1238. self._updateHistStepData(histStepData)
  1239. def OnRedo(self, event):
  1240. """!Step forward in history"""
  1241. histStepData = self.history.GetNext()
  1242. self.toolbars['mainToolbar'].UpdateUndoRedo()
  1243. if histStepData:
  1244. self._updateHistStepData(histStepData)
  1245. def _saveAnInputToHist(self):
  1246. """!Save all data needed for analysis into history buffer"""
  1247. pts = self.pointsToDraw.GetAllItems()
  1248. for iPt, pt in enumerate(pts):
  1249. ptName = "pt" + str(iPt)
  1250. coords = pt.GetCoords()
  1251. self.history.Add(key = "points",
  1252. subkey = [ptName, "coords"],
  1253. value = coords)
  1254. # save type column
  1255. # if is shown
  1256. if len(self.vnetParams[self.currAnModule]["cmdParams"]["cats"]) > 1:
  1257. cat = self.list.GetCellSelIdx(iPt, 'type')
  1258. self.history.Add(key = "points",
  1259. subkey = [ptName, "catIdx"],
  1260. value = cat)
  1261. # if is hidden
  1262. else:
  1263. self.history.Add(key = 'points_hidden_cols',
  1264. subkey = 'type',
  1265. value = self.list.GetHiddenColSelIdxs('type'))
  1266. topology = self.list.GetCellValue(iPt, 'topology')
  1267. self.history.Add(key = "points",
  1268. subkey = [ptName, "topology"],
  1269. value = topology)
  1270. self.history.Add(key = "points",
  1271. subkey = [ptName, "checked"],
  1272. value = self.list.IsChecked(iPt))
  1273. for inpName, inp in self.inputData.iteritems():
  1274. if inpName == "input":
  1275. vectMapName, mapSet = self._parseMapStr(inp.GetValue())
  1276. inpMapFullName = vectMapName + '@' + mapSet
  1277. inpMap = VectMap(self, inpMapFullName)
  1278. self.history.Add(key = "other",
  1279. subkey = "input_modified",
  1280. value = inpMap.GetLastModified())
  1281. inpVal = inpMapFullName
  1282. else:
  1283. inpVal = inp.GetValue()
  1284. self.history.Add(key = "input_data",
  1285. subkey = inpName,
  1286. value = inpVal)
  1287. self.history.Add(key = "vnet_modules",
  1288. subkey = "curr_module",
  1289. value = self.currAnModule)
  1290. for settName, sett in self.anSettings.iteritems():
  1291. self.history.Add(key = "an_settings",
  1292. subkey = settName,
  1293. value = sett.GetValue())
  1294. def _saveHistStep(self):
  1295. """!Save new step into history"""
  1296. removedHistData = self.history.SaveHistStep()
  1297. self.toolbars['mainToolbar'].UpdateUndoRedo()
  1298. if not removedHistData:
  1299. return
  1300. # delete temporary maps in history steps which were deleted
  1301. for removedStep in removedHistData.itervalues():
  1302. mapsNames = removedStep["tmp_data"]["maps"]
  1303. for vectMapName in mapsNames:
  1304. tmpMap = self.tmpMaps.GetTmpVectMap(vectMapName)
  1305. self.tmpMaps.DeleteTmpMap(tmpMap)
  1306. def _updateHistStepData(self, histStepData):
  1307. """!Updates dialog according to chosen history step"""
  1308. # set analysis module
  1309. self.currAnModule = histStepData["vnet_modules"]["curr_module"]
  1310. # optimization -map is not re-rendered when change in points list is done
  1311. self.list.SetUpdateMap(updateMap = False)
  1312. # delete points list items
  1313. while self.list.GetSelected() != wx.NOT_FOUND:
  1314. self.list.DeleteItem()
  1315. # show/hide 'type' column according to particular analysis
  1316. if len(self.vnetParams[self.currAnModule]["cmdParams"]["cats"]) > 1:
  1317. hasType = True
  1318. self.list.ShowColumn('type', 1)
  1319. else:
  1320. hasType = False
  1321. self.list.HideColumn('type')
  1322. # add points to list
  1323. for iPt in range(len(histStepData["points"])):
  1324. ptData = histStepData["points"]["pt" + str(iPt)]
  1325. coords = ptData["coords"]
  1326. self.list.AddItem()
  1327. item = self.pointsToDraw.GetItem(iPt)
  1328. item.SetCoords(coords)
  1329. if hasType:
  1330. self.list.EditCellKey(iPt, 'type', int(ptData["catIdx"]))
  1331. self.list.EditCellKey(iPt, 'topology', ptData["topology"])
  1332. if ptData["checked"]:
  1333. self.list.CheckItem(iPt, True)
  1334. if hasType:
  1335. currParamsCats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
  1336. self.list.AdaptPointsList(currParamsCats)
  1337. else:
  1338. self.list.SetHiddenSelIdxs('type', histStepData["points_hidden_cols"]["type"])
  1339. # set analysis combobox
  1340. anChoice = self.toolbars['analysisToolbar'].anChoice
  1341. anChoice.SetSelection(self.vnetModulesOrder.index(self.currAnModule))
  1342. # update analysis result maps
  1343. mapsNames = histStepData["tmp_data"]["maps"]
  1344. for vectMapName in mapsNames:
  1345. if "vnet_tmp_result" in vectMapName:
  1346. self.tmp_result.DeleteRenderLayer()
  1347. self.tmp_result = self.tmpMaps.GetTmpVectMap(vectMapName)
  1348. self._checkResultMapChanged(self.tmp_result)
  1349. cmd = self.GetLayerStyle()
  1350. self.tmp_result.AddRenderLayer(cmd)
  1351. # update Parameters tab
  1352. histInputData = histStepData["input_data"]
  1353. for inpName, inp in histInputData.iteritems():
  1354. self.inputData[inpName].SetValue(str(inp))
  1355. if inpName == "input":
  1356. inpMap = inp
  1357. prevInpModTime = str(histStepData["other"]["input_modified"])
  1358. currInpModTime = VectMap(self, inpMap).GetLastModified()
  1359. if currInpModTime.strip()!= prevInpModTime.strip():
  1360. dlg = wx.MessageDialog(parent = self,
  1361. message = _("Input map '%s' for analysis was changed outside " +
  1362. "vector network analysis tool.\n" +
  1363. "Topology column may not " +
  1364. "correspond to changed situation.") %\
  1365. inpMap,
  1366. caption = _("Input changed outside"),
  1367. style = wx.ICON_INFORMATION| wx.CENTRE)
  1368. dlg.ShowModal()
  1369. dlg.Destroy()
  1370. # update Points tab (analysis settings)
  1371. histAnSettData = histStepData["an_settings"]
  1372. for settName, sett in histAnSettData.iteritems():
  1373. if settName == 'iso_lines':
  1374. sett = str(sett)
  1375. self.anSettings[settName].SetValue(sett)
  1376. self.resultDbMgrData['analysis'] = self.currAnModule
  1377. self._updateResultDbMgrPage()
  1378. self._updateDbMgrData()
  1379. self.OnAnalysisChanged(None)
  1380. self.list.SetUpdateMap(updateMap = True)
  1381. up_map_evt = gUpdateMap(render = True, renderVector = True)
  1382. wx.PostEvent(self.mapWin, up_map_evt)
  1383. def _checkResultMapChanged(self, resultVectMap):
  1384. """!Check if map was modified outside"""
  1385. if resultVectMap.VectMapState() == 0:
  1386. dlg = wx.MessageDialog(parent = self,
  1387. message = _("Temporary map '%s' with result " +
  1388. "was changed outside vector network analysis tool.\n" +
  1389. "Showed result may not correspond " +
  1390. "original analysis result.") %\
  1391. resultVectMap.GetVectMapName(),
  1392. caption = _("Result changed outside"),
  1393. style = wx.ICON_INFORMATION| wx.CENTRE)
  1394. dlg.ShowModal()
  1395. dlg.Destroy()
  1396. def NewTmpVectMapToHist(self, prefMapName):
  1397. """!Add new vector map, which will be saved into history step"""
  1398. mapName = prefMapName + str(self.histTmpVectMapNum)
  1399. self.histTmpVectMapNum += 1
  1400. tmpMap = self._addTmpMapAnalysisMsg(mapName)
  1401. if not tmpMap:
  1402. return tmpMap
  1403. self.tmpVectMapsToHist.append(tmpMap.GetVectMapName())
  1404. self.history.Add(key = "tmp_data",
  1405. subkey = "maps",
  1406. value = self.tmpVectMapsToHist)
  1407. return tmpMap
  1408. def _addTmpMapAnalysisMsg(self, mapName):
  1409. """!Wraped AddTmpVectMap"""
  1410. msg = _("Temporary map %s already exists.\n" +
  1411. "Do you want to continue in analysis and overwrite it?") \
  1412. % (mapName +'@' + grass.gisenv()['MAPSET'])
  1413. tmpMap = self.tmpMaps.AddTmpVectMap(mapName, msg)
  1414. return tmpMap
  1415. def _initVnetParams(self):
  1416. """!Initializes parameters for different v.net.* modules """
  1417. self.attrCols = {
  1418. 'afcolumn' : {
  1419. "label" : _("Arc forward/both direction(s) cost column:"),
  1420. "name" : _("arc forward/both")
  1421. },
  1422. 'abcolumn' : {
  1423. "label" : _("Arc backward direction cost column:"),
  1424. "name" : _("arc backward")
  1425. },
  1426. 'acolumn' : {
  1427. "label" : _("Arcs' cost column (for both directions):"),
  1428. "name" : _("arc"),
  1429. "inputField" : 'afcolumn',
  1430. },
  1431. 'ncolumn' : {
  1432. "label" : _("Node cost column:"),
  1433. "name" : _("node")
  1434. }
  1435. }
  1436. self.vnetParams = {
  1437. "v.net.path" : {
  1438. "label" : _("Shortest path %s") % "(v.net.path)",
  1439. "cmdParams" : {
  1440. "cats" : [
  1441. ["st_pt", _("Start point")],
  1442. ["end_pt", _("End point")]
  1443. ],
  1444. "cols" : [
  1445. 'afcolumn',
  1446. 'abcolumn',
  1447. 'ncolumn'
  1448. ],
  1449. },
  1450. "resultProps" : {
  1451. "singleColor" : None,
  1452. "dbMgr" : True
  1453. }
  1454. },
  1455. "v.net.salesman" : {
  1456. "label" : _("Traveling salesman %s") % "(v.net.salesman)",
  1457. "cmdParams" : {
  1458. "cats" : [["ccats", None]],
  1459. "cols" : [
  1460. 'afcolumn',
  1461. 'abcolumn'
  1462. ],
  1463. },
  1464. "resultProps" : {
  1465. "singleColor" : None,
  1466. "dbMgr" : False
  1467. }
  1468. },
  1469. "v.net.flow" : {
  1470. "label" : _("Maximum flow %s") % "(v.net.flow)",
  1471. "cmdParams" : {
  1472. "cats" : [
  1473. ["source_cats", _("Source point")],
  1474. ["sink_cats", _("Sink point")]
  1475. ],
  1476. "cols" : [
  1477. 'afcolumn',
  1478. 'abcolumn',
  1479. 'ncolumn'
  1480. ]
  1481. },
  1482. "resultProps" : {
  1483. "attrColColor": "flow",
  1484. "dbMgr" : True
  1485. }
  1486. },
  1487. "v.net.alloc" : {
  1488. "label" : _("Subnets for nearest centers %s") % "(v.net.alloc)",
  1489. "cmdParams" : {
  1490. "cats" : [["ccats", None]],
  1491. "cols" : [
  1492. 'afcolumn',
  1493. 'abcolumn',
  1494. 'ncolumn'
  1495. ]
  1496. },
  1497. "resultProps" : {
  1498. "catColor" : None,
  1499. "dbMgr" : False
  1500. }
  1501. },
  1502. "v.net.steiner" : {
  1503. "label" : _("Steiner tree for the network and given terminals %s") % "(v.net.steiner)",
  1504. "cmdParams" : {
  1505. "cats" : [["tcats", None]],
  1506. "cols" : [
  1507. 'acolumn',
  1508. ]
  1509. },
  1510. "resultProps" : {
  1511. "singleColor" : None,
  1512. "dbMgr" : False
  1513. }
  1514. },
  1515. "v.net.distance" : {
  1516. "label" : _("Shortest distance via the network %s") % "(v.net.distance)",
  1517. "cmdParams" : {
  1518. "cats" : [
  1519. ["from_cats", "From point"],
  1520. ["to_cats", "To point"]
  1521. ],
  1522. "cols" : [
  1523. 'afcolumn',
  1524. 'abcolumn',
  1525. 'ncolumn'
  1526. ],
  1527. },
  1528. "resultProps" : {
  1529. "catColor" : None,
  1530. "dbMgr" : True
  1531. }
  1532. },
  1533. "v.net.iso" : {
  1534. "label" : _("Cost isolines %s") % "(v.net.iso)",
  1535. "cmdParams" : {
  1536. "cats" : [["ccats", None]],
  1537. "cols" : [
  1538. 'afcolumn',
  1539. 'abcolumn',
  1540. 'ncolumn'
  1541. ]
  1542. },
  1543. "resultProps" : {
  1544. "catColor" : None,
  1545. "dbMgr" : False
  1546. }
  1547. }
  1548. }
  1549. # order in combobox for choose of analysis
  1550. self.vnetModulesOrder = ["v.net.path",
  1551. "v.net.salesman",
  1552. "v.net.flow",
  1553. "v.net.alloc",
  1554. "v.net.distance",
  1555. "v.net.iso",
  1556. #"v.net.steiner"
  1557. ]
  1558. self.currAnModule = self.vnetModulesOrder[0]
  1559. def _initSettings(self):
  1560. """!Initialization of settings (if not already defined)"""
  1561. # initializes default settings
  1562. initSettings = [
  1563. ['res_style', 'line_width', 5],
  1564. ['res_style', 'line_color', (192,0,0)],
  1565. ['res_style', 'color_table', 'byr'],
  1566. ['res_style', 'invert_colors', False],
  1567. ['point_symbol', 'point_size', 10],
  1568. ['point_symbol', 'point_width', 2],
  1569. ['point_colors', "unused", (131,139,139)],
  1570. ['point_colors', "used1cat", (192,0,0)],
  1571. ['point_colors', "used2cat", (0,0,255)],
  1572. ['point_colors', "selected", (9,249,17)],
  1573. ['other', "snap_tresh", 10],
  1574. ['other', "max_hist_steps", 5]
  1575. ]
  1576. for init in initSettings:
  1577. UserSettings.ReadSettingsFile()
  1578. UserSettings.Append(dict = UserSettings.userSettings,
  1579. group ='vnet',
  1580. key = init[0],
  1581. subkey =init[1],
  1582. value = init[2],
  1583. overwrite = False)
  1584. def SetPointDrawSettings(self):
  1585. """!Set settings for drawing of points"""
  1586. ptSize = int(UserSettings.Get(group='vnet', key='point_symbol', subkey = 'point_size'))
  1587. self.pointsToDraw.SetPropertyVal("size", ptSize)
  1588. colors = UserSettings.Get(group='vnet', key='point_colors')
  1589. ptWidth = int(UserSettings.Get(group='vnet', key='point_symbol', subkey = 'point_width'))
  1590. textProp = self.pointsToDraw.GetPropertyVal("text")
  1591. textProp["font"].SetPointSize(ptSize + 2)
  1592. for colKey, col in colors.iteritems():
  1593. pen = self.pointsToDraw.GetPen(colKey)
  1594. if pen:
  1595. pen.SetColour(wx.Colour(col[0], col[1], col[2], 255))
  1596. pen.SetWidth(ptWidth)
  1597. else:
  1598. self.pointsToDraw.AddPen(colKey, wx.Pen(colour = wx.Colour(col[0], col[1], col[2], 255), width = ptWidth))
  1599. class PtsList(PointsList):
  1600. def __init__(self, parent, dialog, cols, id=wx.ID_ANY):
  1601. """! List with points for analysis"""
  1602. self.updateMap = True
  1603. self.dialog = dialog # VNETDialog class
  1604. PointsList.__init__(self, parent = parent, cols = cols, id = id)
  1605. def AddItem(self, event = None, updateMap = True):
  1606. """!Append point to list"""
  1607. self.dialog.pointsToDraw.AddItem(coords = [0,0])
  1608. PointsList.AddItem(self, event)
  1609. self.EditCellKey(key = self.selected ,
  1610. colName = 'topology',
  1611. cellData = _("new point"))
  1612. def DeleteItem(self, event = None):
  1613. """!Delete selected point in list"""
  1614. key = self.GetItemData(self.selected)
  1615. if self.selected != wx.NOT_FOUND:
  1616. item = self.dialog.pointsToDraw.GetItem(key)
  1617. self.dialog.pointsToDraw.DeleteItem(item)
  1618. PointsList.DeleteItem(self, event)
  1619. def OnItemSelected(self, event):
  1620. """!Item selected"""
  1621. PointsList.OnItemSelected(self, event)
  1622. if self.updateMap:
  1623. up_map_evt = gUpdateMap(render = False, renderVector = False)
  1624. wx.PostEvent(self.dialog.mapWin, up_map_evt)
  1625. def AdaptPointsList(self, currParamsCats):
  1626. """Rename category values when module is changed. Expample: Start point -> Sink point"""
  1627. colValues = [""]
  1628. for ptCat in currParamsCats:
  1629. colValues.append(ptCat[1])
  1630. colNum = self._getColumnNum('type')
  1631. self.ChangeColEditable('type', colValues)
  1632. for iItem, item in enumerate(self.itemDataMap):
  1633. self.EditCellKey(iItem, 'type', self.selIdxs[iItem][colNum])
  1634. if not item[1]:
  1635. self.CheckItem(iItem, False)
  1636. def OnCheckItem(self, index, flag):
  1637. """!Item is checked/unchecked"""
  1638. key = self.GetItemData(index)
  1639. checkedVal = self.itemDataMap[key][1]
  1640. currModule = self.dialog.currAnModule #TODO public func
  1641. cats = self.dialog.vnetParams[currModule]["cmdParams"]["cats"]
  1642. if self.updateMap:
  1643. up_map_evt = gUpdateMap(render = False, renderVector = False)
  1644. wx.PostEvent(self.dialog.mapWin, up_map_evt)
  1645. if len(cats) <= 1:
  1646. return
  1647. if checkedVal == "":
  1648. self.CheckItem(key, False)
  1649. return
  1650. if currModule == "v.net.path" and flag:
  1651. self.UpdateCheckedItems(index)
  1652. def UpdateCheckedItems(self, index):
  1653. """!For v.net.path - max. just one checked 'Start point' and 'End point'"""
  1654. alreadyChecked = []
  1655. colNum = self._getColumnNum('type')
  1656. if colNum == -1:
  1657. return
  1658. if index:
  1659. checkedKey = self.GetItemData(index)
  1660. checkedVal = self.selIdxs[checkedKey][colNum]
  1661. alreadyChecked.append(checkedVal)
  1662. else:
  1663. checkedKey = -1
  1664. for iKey, idx in enumerate(self.selIdxs):
  1665. index = self._findIndex(iKey)
  1666. if (idx[colNum] in alreadyChecked and checkedKey != iKey) \
  1667. or idx[colNum] == 0:
  1668. self.CheckItem(index, False)
  1669. elif self.IsChecked(index):
  1670. alreadyChecked.append(idx[colNum])
  1671. def SetUpdateMap(self, updateMap):
  1672. """!Update/Not update map window when some change in list is made"""
  1673. self.updateMap = updateMap
  1674. def GetHiddenColSelIdxs(self, colName):
  1675. """!Get indexes of chosen values in hidden 'type' column"""
  1676. if self.hiddenCols.has_key(colName):
  1677. return self.hiddenCols[colName]['selIdxs']
  1678. return None
  1679. def SetHiddenSelIdxs(self, colName, selIdxs):
  1680. """!Set indexes of chosen values in hidden 'type' column and update text in it's cells"""
  1681. if self.hiddenCols.has_key(colName):
  1682. self.hiddenCols[colName]['selIdxs'] = map(int, selIdxs)
  1683. self.hiddenCols[colName]['itemDataMap'] = []
  1684. # update text in hidden column cells
  1685. for idx in self.hiddenCols[colName]['selIdxs']:
  1686. self.hiddenCols[colName]['itemDataMap'].append(self.hiddenCols[colName]['colsData'][2][idx])
  1687. return True
  1688. return False
  1689. class SettingsDialog(wx.Dialog):
  1690. def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
  1691. style=wx.DEFAULT_DIALOG_STYLE):
  1692. """!Settings dialog"""
  1693. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  1694. maxValue = 1e8
  1695. self.parent = parent
  1696. self.settings = {}
  1697. rules = RunCommand('v.colors',
  1698. read = True,
  1699. flags = 'l')
  1700. settsLabels = {}
  1701. settsLabels['color_table'] = wx.StaticText(parent = self, id = wx.ID_ANY,
  1702. label = _('Color table style %s:') % '(v.net.flow)')
  1703. self.settings['color_table'] = wx.ComboBox(parent = self, id = wx.ID_ANY,
  1704. choices = rules.split(),
  1705. style = wx.CB_READONLY, size = (180, -1))
  1706. setStyle = UserSettings.Get(group ='vnet', key = "res_style", subkey = "color_table")
  1707. i = self.settings['color_table'].FindString(setStyle)
  1708. if i != wx.NOT_FOUND:
  1709. self.settings['color_table'].Select(i)
  1710. self.settings["invert_colors"] = wx.CheckBox(parent = self, id=wx.ID_ANY,
  1711. label = _('Invert colors %s:') % '(v.net.flow)')
  1712. setInvert = UserSettings.Get(group ='vnet', key = "res_style", subkey = "invert_colors")
  1713. self.settings["invert_colors"].SetValue(setInvert)
  1714. self.colorsSetts = {
  1715. "line_color" : ["res_style", _("Line color:")],
  1716. "unused" : ["point_colors", _("Color for unused point:")],
  1717. "used1cat" : ["point_colors", _("Color for Start/From/Source/Used point:")],
  1718. "used2cat" : ["point_colors", _("Color for End/To/Sink point:")],
  1719. "selected" : ["point_colors", _("Color for selected point:")]
  1720. }
  1721. for settKey, sett in self.colorsSetts.iteritems():
  1722. settsLabels[settKey] = wx.StaticText(parent = self, id = wx.ID_ANY, label = sett[1])
  1723. col = UserSettings.Get(group ='vnet', key = sett[0], subkey = settKey)
  1724. self.settings[settKey] = csel.ColourSelect(parent = self, id = wx.ID_ANY,
  1725. colour = wx.Colour(col[0],
  1726. col[1],
  1727. col[2],
  1728. 255))
  1729. self.sizeSetts = {
  1730. "line_width" : ["res_style", _("Line width:")],
  1731. "point_size" : ["point_symbol", _("Point size:")],
  1732. "point_width" : ["point_symbol", _("Point width:")],
  1733. "snap_tresh" : ["other", _("Snapping treshold in pixels:")],
  1734. "max_hist_steps" : ["other", _("Maximum number of results in history:")]
  1735. }
  1736. for settKey, sett in self.sizeSetts.iteritems():
  1737. settsLabels[settKey] = wx.StaticText(parent = self, id = wx.ID_ANY, label = sett[1])
  1738. self.settings[settKey] = wx.SpinCtrl(parent = self, id = wx.ID_ANY, min = 1, max = 50)
  1739. size = int(UserSettings.Get(group = 'vnet', key = sett[0], subkey = settKey))
  1740. self.settings[settKey].SetValue(size)
  1741. # buttons
  1742. self.btnSave = wx.Button(self, wx.ID_SAVE)
  1743. self.btnApply = wx.Button(self, wx.ID_APPLY)
  1744. self.btnClose = wx.Button(self, wx.ID_CLOSE)
  1745. self.btnApply.SetDefault()
  1746. # bindings
  1747. self.btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1748. self.btnApply.SetToolTipString(_("Apply changes for the current session"))
  1749. self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1750. self.btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  1751. self.btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
  1752. self.btnClose.SetToolTipString(_("Close dialog"))
  1753. #Layout
  1754. # Analysis result style layout
  1755. self.SetMinSize(self.GetBestSize())
  1756. sizer = wx.BoxSizer(wx.VERTICAL)
  1757. styleBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  1758. label =" %s " % _("Analysis result style:"))
  1759. styleBoxSizer = wx.StaticBoxSizer(styleBox, wx.VERTICAL)
  1760. gridSizer = wx.GridBagSizer(vgap = 1, hgap = 1)
  1761. row = 0
  1762. gridSizer.Add(item = settsLabels["line_color"], flag = wx.ALIGN_CENTER_VERTICAL, pos =(row, 0))
  1763. gridSizer.Add(item = self.settings["line_color"],
  1764. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5,
  1765. pos =(row, 1))
  1766. row += 1
  1767. gridSizer.Add(item = settsLabels["line_width"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1768. gridSizer.Add(item = self.settings["line_width"],
  1769. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5,
  1770. pos = (row, 1))
  1771. row += 1
  1772. gridSizer.Add(item = settsLabels['color_table'], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1773. gridSizer.Add(item = self.settings['color_table'],
  1774. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5,
  1775. pos = (row, 1))
  1776. row += 1
  1777. gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1778. gridSizer.AddGrowableCol(1)
  1779. styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
  1780. # Point style layout
  1781. ptsStyleBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  1782. label =" %s " % _("Point style:"))
  1783. ptsStyleBoxSizer = wx.StaticBoxSizer(ptsStyleBox, wx.VERTICAL)
  1784. gridSizer = wx.GridBagSizer(vgap = 1, hgap = 1)
  1785. row = 0
  1786. setts = dict(self.colorsSetts.items() + self.sizeSetts.items())
  1787. settsOrder = ["selected", "used1cat", "used2cat", "unused", "point_size", "point_width"]
  1788. for settKey in settsOrder:
  1789. sett = setts[settKey]
  1790. gridSizer.Add(item = settsLabels[settKey], flag = wx.ALIGN_CENTER_VERTICAL, pos =(row, 0))
  1791. gridSizer.Add(item = self.settings[settKey],
  1792. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5,
  1793. pos =(row, 1))
  1794. row += 1
  1795. gridSizer.AddGrowableCol(1)
  1796. ptsStyleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
  1797. # Other settings layout
  1798. otherBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  1799. label =" %s " % _("Other settings"))
  1800. otherBoxSizer = wx.StaticBoxSizer(otherBox, wx.VERTICAL)
  1801. gridSizer = wx.GridBagSizer(vgap = 1, hgap = 1)
  1802. row = 0
  1803. for otherSettName in ["snap_tresh", "max_hist_steps"]:
  1804. gridSizer.Add(item = settsLabels[otherSettName], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1805. gridSizer.Add(item = self.settings[otherSettName],
  1806. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5,
  1807. pos = (row, 1))
  1808. row += 1
  1809. gridSizer.AddGrowableCol(1)
  1810. otherBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
  1811. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  1812. btnSizer.Add(self.btnApply, flag = wx.LEFT | wx.RIGHT, border = 5)
  1813. btnSizer.Add(self.btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
  1814. btnSizer.Add(self.btnClose, flag = wx.LEFT | wx.RIGHT, border = 5)
  1815. sizer.Add(item = styleBoxSizer, flag = wx.EXPAND | wx.ALL, border = 5)
  1816. sizer.Add(item = ptsStyleBoxSizer, flag = wx.EXPAND | wx.ALL, border = 5)
  1817. sizer.Add(item = otherBoxSizer, flag = wx.EXPAND | wx.ALL, border = 5)
  1818. sizer.Add(item = btnSizer, flag = wx.EXPAND | wx.ALL, border = 5, proportion = 0)
  1819. self.SetSizer(sizer)
  1820. sizer.Fit(self)
  1821. def OnSave(self, event):
  1822. """!Button 'Save' pressed"""
  1823. self.UpdateSettings()
  1824. fileSettings = {}
  1825. UserSettings.ReadSettingsFile(settings=fileSettings)
  1826. fileSettings['vnet'] = UserSettings.Get(group='vnet')
  1827. UserSettings.SaveToFile(fileSettings)
  1828. self.Close()
  1829. def UpdateSettings(self):
  1830. UserSettings.Set(group ='vnet', key = "res_style", subkey ='line_width',
  1831. value = self.settings["line_width"].GetValue())
  1832. for settKey, sett in self.colorsSetts.iteritems():
  1833. col = tuple(self.settings[settKey].GetColour())
  1834. UserSettings.Set(group = 'vnet',
  1835. key = sett[0],
  1836. subkey = settKey,
  1837. value = col)
  1838. for settKey, sett in self.sizeSetts.iteritems():
  1839. UserSettings.Set(group = 'vnet', key = sett[0], subkey = settKey,
  1840. value = self.settings[settKey].GetValue())
  1841. UserSettings.Set(group = 'vnet', key = 'res_style', subkey = 'color_table',
  1842. value = self.settings['color_table'].GetStringSelection())
  1843. UserSettings.Set(group = 'vnet', key = 'res_style', subkey = 'invert_colors',
  1844. value = self.settings['invert_colors'].IsChecked())
  1845. self.parent.SetPointDrawSettings()
  1846. if not self.parent.tmp_result or \
  1847. not self.parent.tmpMaps.HasTmpVectMap(self.parent.tmp_result.GetVectMapName()):
  1848. up_map_evt = gUpdateMap(render = False, renderVector = False)
  1849. wx.PostEvent(self.parent.mapWin, up_map_evt)
  1850. elif self.parent.tmp_result.GetRenderLayer():
  1851. cmd = self.parent.GetLayerStyle()
  1852. self.parent.tmp_result.AddRenderLayer(cmd)
  1853. up_map_evt = gUpdateMap(render = True, renderVector = True)
  1854. wx.PostEvent(self.parent.mapWin, up_map_evt)#TODO optimization
  1855. else:
  1856. up_map_evt = gUpdateMap(render = False, renderVector = False)
  1857. wx.PostEvent(self.parent.mapWin, up_map_evt)
  1858. def OnApply(self, event):
  1859. """!Button 'Apply' pressed"""
  1860. self.UpdateSettings()
  1861. #self.Close()
  1862. def OnClose(self, event):
  1863. """!Button 'Cancel' pressed"""
  1864. self.Close()
  1865. class AddLayerDialog(wx.Dialog):
  1866. def __init__(self, parent,id=wx.ID_ANY,
  1867. title =_("Save analysis result"), style=wx.DEFAULT_DIALOG_STYLE):
  1868. """!Save analysis result"""
  1869. wx.Dialog.__init__(self, parent, id, title = _(title), style = style)
  1870. self.panel = wx.Panel(parent = self)
  1871. # text fields and it's captions
  1872. self.vectSel = Select(parent = self.panel, type = 'vector',
  1873. mapsets = [grass.gisenv()['MAPSET']],size = (-1, -1))
  1874. self.vectSellabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  1875. label = _("Name:"))
  1876. # buttons
  1877. self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
  1878. self.btnOk = wx.Button(self.panel, wx.ID_OK)
  1879. self.btnOk.SetDefault()
  1880. self.SetInitialSize((400, -1))
  1881. self._layout()
  1882. def _layout(self):
  1883. sizer = wx.BoxSizer(wx.VERTICAL)
  1884. box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
  1885. label = "Vector map")
  1886. boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1887. boxSizer.Add(item = self.vectSellabel,
  1888. flag = wx.ALIGN_CENTER_VERTICAL,
  1889. proportion = 0)
  1890. boxSizer.Add(item = self.vectSel, proportion = 1,
  1891. flag = wx.EXPAND | wx.ALL, border = 5)
  1892. sizer.Add(item = boxSizer, proportion = 1,
  1893. flag = wx.EXPAND | wx.ALL, border = 5)
  1894. btnSizer = wx.StdDialogButtonSizer()
  1895. btnSizer.AddButton(self.btnCancel)
  1896. btnSizer.AddButton(self.btnOk)
  1897. btnSizer.Realize()
  1898. sizer.Add(item = btnSizer, proportion = 0,
  1899. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  1900. self.panel.SetSizer(sizer)
  1901. sizer.Fit(self)
  1902. class VnetTmpVectMaps:
  1903. """!Class which creates, stores and destroys all tmp maps created during analysis"""
  1904. def __init__(self, parent):
  1905. self.tmpMaps = [] # temporary maps
  1906. self.parent = parent
  1907. self.mapWin = self.parent.mapWin
  1908. def AddTmpVectMap(self, mapName, msg):
  1909. """!New temporary map
  1910. @return instance of VectMap representing temporary map
  1911. """
  1912. currMapSet = grass.gisenv()['MAPSET']
  1913. tmpMap = grass.find_file(name = mapName,
  1914. element = 'vector',
  1915. mapset = currMapSet)
  1916. fullName = tmpMap["fullname"]
  1917. # map already exists
  1918. if fullName:
  1919. #TODO move dialog out of class, AddTmpVectMap(self, mapName, overvrite = False)
  1920. dlg = wx.MessageDialog(parent = self.parent,
  1921. message = msg,
  1922. caption = _("Overwrite map layer"),
  1923. style = wx.YES_NO | wx.NO_DEFAULT |
  1924. wx.ICON_QUESTION | wx.CENTRE)
  1925. ret = dlg.ShowModal()
  1926. dlg.Destroy()
  1927. if ret == wx.ID_NO:
  1928. return None
  1929. else:
  1930. fullName = mapName + "@" + currMapSet
  1931. newVectMap = VectMap(self, fullName)
  1932. self.tmpMaps.append(newVectMap)
  1933. return newVectMap
  1934. def HasTmpVectMap(self, vectMapName):
  1935. """
  1936. @param vectMapName name of vector map
  1937. @return True if it contains the map
  1938. @return False if not
  1939. """
  1940. mapValSpl = vectMapName.strip().split("@")
  1941. if len(mapValSpl) > 1:
  1942. mapSet = mapValSpl[1]
  1943. else:
  1944. mapSet = grass.gisenv()['MAPSET']
  1945. mapName = mapValSpl[0]
  1946. fullName = mapName + "@" + mapSet
  1947. for vectTmpMap in self.tmpMaps:
  1948. if vectTmpMap.GetVectMapName() == fullName:
  1949. return True
  1950. return False
  1951. def GetTmpVectMap(self, vectMapName):
  1952. """ Get instance of VectMap with name vectMapName"""
  1953. for vectMap in self.tmpMaps:
  1954. if vectMap.GetVectMapName() == vectMapName.strip():
  1955. return vectMap
  1956. return None
  1957. def RemoveFromTmpMaps(self, vectMap):
  1958. """!Temporary map is removed from the class instance however it is not deleted
  1959. @param vectMap instance of VectMap class to be removed
  1960. @return True if was removed
  1961. @return False if does not contain the map
  1962. """
  1963. try:
  1964. self.tmpMaps.remove(vectMap)
  1965. return True
  1966. except ValueError:
  1967. return False
  1968. def DeleteTmpMap(self, vectMap):
  1969. """!Temporary map is removed from the class and it is deleted
  1970. @param vectMap instance of VectMap class to be deleted
  1971. @return True if was removed
  1972. @return False if does not contain the map
  1973. """
  1974. if vectMap:
  1975. vectMap.DeleteRenderLayer()
  1976. RunCommand('g.remove',
  1977. vect = vectMap.GetVectMapName())
  1978. self.RemoveFromTmpMaps(vectMap)
  1979. return True
  1980. return False
  1981. def DeleteAllTmpMaps(self):
  1982. """Delete all temporary maps in the class"""
  1983. update = False
  1984. for tmpMap in self.tmpMaps:
  1985. RunCommand('g.remove',
  1986. vect = tmpMap.GetVectMapName())
  1987. if tmpMap.DeleteRenderLayer():
  1988. update = True
  1989. return update
  1990. class VectMap:
  1991. """!Represents map
  1992. It can check if it was modified or render it
  1993. """
  1994. def __init__(self, parent, fullName):
  1995. self.fullName = fullName
  1996. self.parent = parent
  1997. self.renderLayer = None
  1998. self.modifTime = None # time, for modification check
  1999. def __del__(self):
  2000. self.DeleteRenderLayer()
  2001. def AddRenderLayer(self, cmd = None):
  2002. """!Add map from map window layers to render """
  2003. existsMap = grass.find_file(name = self.fullName,
  2004. element = 'vector',
  2005. mapset = grass.gisenv()['MAPSET'])
  2006. if not existsMap["name"]:
  2007. self.DeleteRenderLayer()
  2008. return False
  2009. if not cmd:
  2010. cmd = []
  2011. cmd.insert(0, 'd.vect')
  2012. cmd.append('map=%s' % self.fullName)
  2013. if self.renderLayer:
  2014. self.DeleteRenderLayer()
  2015. self.renderLayer = self.parent.mapWin.Map.AddLayer(ltype = "vector", command = cmd,
  2016. name = self.fullName, active = True,
  2017. opacity = 1.0, render = True,
  2018. pos = -1)
  2019. return True
  2020. def DeleteRenderLayer(self):
  2021. """!Remove map from map window layers to render"""
  2022. if self.renderLayer:
  2023. self.parent.mapWin.Map.DeleteLayer(self.renderLayer)
  2024. self.renderLayer = None
  2025. return True
  2026. return False
  2027. def GetRenderLayer(self):
  2028. return self.renderLayer
  2029. def GetVectMapName(self):
  2030. return self.fullName
  2031. def SaveVectMapState(self):
  2032. """!Save modification time for vector map"""
  2033. self.modifTime = self.GetLastModified()
  2034. def VectMapState(self):
  2035. """!Checks if map was modified
  2036. @return -1 - if no modification time was saved
  2037. @return 0 - if map was modified
  2038. @return 1 - if map was not modified
  2039. """
  2040. if self.modifTime is None:
  2041. return -1
  2042. if self.modifTime != self.GetLastModified():
  2043. return 0
  2044. return 1
  2045. def GetLastModified(self):
  2046. """!Get modification time
  2047. @return MAP DATE time string from vector map head file
  2048. """
  2049. mapValSpl = self.fullName.split("@")
  2050. mapSet = mapValSpl[1]
  2051. mapName = mapValSpl[0]
  2052. headPath = os.path.join(grass.gisenv()['GISDBASE'],
  2053. grass.gisenv()['LOCATION_NAME'],
  2054. mapSet,
  2055. "vector",
  2056. mapName,
  2057. "head")
  2058. try:
  2059. head = open(headPath, 'r')
  2060. for line in head.readlines():
  2061. i = line.find('MAP DATE:', )
  2062. if i == 0:
  2063. head.close()
  2064. return line.split(':', 1)[1].strip()
  2065. head.close()
  2066. return ""
  2067. except IOError:
  2068. return ""
  2069. class History:
  2070. """!Class which reads and saves history data (based on gui.core.settings Settings class file save/load)"""
  2071. def __init__(self, parent):
  2072. # max number of steps in history (zero based)
  2073. self.maxHistSteps = 3
  2074. # current history step
  2075. self.currHistStep = 0
  2076. # number of steps saved in history
  2077. self.histStepsNum = 0
  2078. # dict contains data saved in history for current history step
  2079. self.currHistStepData = {}
  2080. # buffer for data to be saved into history
  2081. self.newHistStepData = {}
  2082. self.histFile = grass.tempfile()
  2083. # key/value separator
  2084. self.sep = ';'
  2085. def __del__(self):
  2086. grass.try_remove(self.histFile)
  2087. def GetNext(self):
  2088. """!Go one step forward in history"""
  2089. self.currHistStep -= 1
  2090. self.currHistStepData.clear()
  2091. self.currHistStepData = self._getHistStepData(self.currHistStep)
  2092. return self.currHistStepData
  2093. def GetPrev(self):
  2094. """!Go one step back in history"""
  2095. self.currHistStep += 1
  2096. self.currHistStepData.clear()
  2097. self.currHistStepData = self._getHistStepData(self.currHistStep)
  2098. return self.currHistStepData
  2099. def GetStepsNum(self):
  2100. """!Get number of steps saved in history"""
  2101. return self.histStepsNum
  2102. def GetCurrHistStep(self):
  2103. """!Get current history step"""
  2104. return self.currHistStep
  2105. def Add(self, key, subkey, value):
  2106. """!Add new data into buffer"""
  2107. if key not in self.newHistStepData:
  2108. self.newHistStepData[key] = {}
  2109. if type(subkey) == types.ListType:
  2110. if subkey[0] not in self.newHistStepData[key]:
  2111. self.newHistStepData[key][subkey[0]] = {}
  2112. self.newHistStepData[key][subkey[0]][subkey[1]] = value
  2113. else:
  2114. self.newHistStepData[key][subkey] = value
  2115. def SaveHistStep(self):
  2116. """!Create new history step with data in buffer"""
  2117. self.maxHistSteps = UserSettings.Get(group ='vnet',
  2118. key = 'other',
  2119. subkey = 'max_hist_steps')
  2120. self.currHistStep = 0
  2121. newHistFile = grass.tempfile()
  2122. newHist = open(newHistFile, "w")
  2123. self._saveNewHistStep(newHist)
  2124. oldHist = open(self.histFile)
  2125. removedHistData = self._savePreviousHist(newHist, oldHist)
  2126. oldHist.close()
  2127. newHist.close()
  2128. grass.try_remove(self.histFile)
  2129. self.histFile = newHistFile
  2130. self.newHistStepData.clear()
  2131. return removedHistData
  2132. def _savePreviousHist(self, newHist, oldHist):
  2133. """!Save previous history into new file"""
  2134. newHistStep = False
  2135. removedHistData = {}
  2136. newHistStepsNum = self.histStepsNum
  2137. for line in oldHist.readlines():
  2138. if not line.strip():
  2139. newHistStep = True
  2140. newHistStepsNum += 1
  2141. continue
  2142. if newHistStep:
  2143. newHistStep = False
  2144. line = line.split("=")
  2145. line[1] = str(newHistStepsNum)
  2146. line = "=".join(line)
  2147. if newHistStepsNum >= self.maxHistSteps:
  2148. removedHistStep = removedHistData[line] = {}
  2149. continue
  2150. else:
  2151. newHist.write('%s%s%s' % (os.linesep, line, os.linesep))
  2152. self.histStepsNum = newHistStepsNum
  2153. else:
  2154. if newHistStepsNum >= self.maxHistSteps:
  2155. self._parseLine(line, removedHistStep)
  2156. else:
  2157. newHist.write('%s' % line)
  2158. return removedHistData
  2159. def _saveNewHistStep(self, newHist):
  2160. """!Save buffer (new step) data into file"""
  2161. newHist.write('%s%s%s' % (os.linesep, "history step=0", os.linesep))
  2162. for key in self.newHistStepData.keys():
  2163. subkeys = self.newHistStepData[key].keys()
  2164. newHist.write('%s%s' % (key, self.sep))
  2165. for idx in range(len(subkeys)):
  2166. value = self.newHistStepData[key][subkeys[idx]]
  2167. if type(value) == types.DictType:
  2168. if idx > 0:
  2169. newHist.write('%s%s%s' % (os.linesep, key, self.sep))
  2170. newHist.write('%s%s' % (subkeys[idx], self.sep))
  2171. kvalues = self.newHistStepData[key][subkeys[idx]].keys()
  2172. srange = range(len(kvalues))
  2173. for sidx in srange:
  2174. svalue = self._parseValue(self.newHistStepData[key][subkeys[idx]][kvalues[sidx]])
  2175. newHist.write('%s%s%s' % (kvalues[sidx], self.sep, svalue))
  2176. if sidx < len(kvalues) - 1:
  2177. newHist.write('%s' % self.sep)
  2178. else:
  2179. if idx > 0 and \
  2180. type( self.newHistStepData[key][subkeys[idx - 1]]) == types.DictType:
  2181. newHist.write('%s%s%s' % (os.linesep, key, self.sep))
  2182. value = self._parseValue(self.newHistStepData[key][subkeys[idx]])
  2183. newHist.write('%s%s%s' % (subkeys[idx], self.sep, value))
  2184. if idx < len(subkeys) - 1 and \
  2185. type(self.newHistStepData[key][subkeys[idx + 1]]) != types.DictType:
  2186. newHist.write('%s' % self.sep)
  2187. newHist.write(os.linesep)
  2188. self.histStepsNum = 0
  2189. def _parseValue(self, value, read = False):
  2190. """!Parse value"""
  2191. if read: # -> read data (cast values)
  2192. if value:
  2193. if value[0] == '[' and value[-1] == ']':# TODO, possible wrong interpretation
  2194. value = value[1:-1].split(',')
  2195. value = map(self._castValue, value)
  2196. return value
  2197. if value == 'True':
  2198. value = True
  2199. elif value == 'False':
  2200. value = False
  2201. elif value == 'None':
  2202. value = None
  2203. elif ':' in value: # -> color
  2204. try:
  2205. value = tuple(map(int, value.split(':')))
  2206. except ValueError: # -> string
  2207. pass
  2208. else:
  2209. try:
  2210. value = int(value)
  2211. except ValueError:
  2212. try:
  2213. value = float(value)
  2214. except ValueError:
  2215. pass
  2216. else: # -> write data
  2217. if type(value) == type(()): # -> color
  2218. value = str(value[0]) + ':' +\
  2219. str(value[1]) + ':' + \
  2220. str(value[2])
  2221. return value
  2222. def _castValue(self, value):
  2223. """!Cast value"""
  2224. try:
  2225. value = int(value)
  2226. except ValueError:
  2227. try:
  2228. value = float(value)
  2229. except ValueError:
  2230. value = value[1:-1]
  2231. return value
  2232. def _getHistStepData(self, histStep):
  2233. """!Load data saved in history step"""
  2234. hist = open(self.histFile)
  2235. histStepData = {}
  2236. newHistStep = False
  2237. isSearchedHistStep = False
  2238. for line in hist.readlines():
  2239. if not line.strip() and isSearchedHistStep:
  2240. break
  2241. elif not line.strip():
  2242. newHistStep = True
  2243. continue
  2244. elif isSearchedHistStep:
  2245. self._parseLine(line, histStepData)
  2246. if newHistStep:
  2247. line = line.split("=")
  2248. if int(line[1]) == histStep:
  2249. isSearchedHistStep = True
  2250. newHistStep = False
  2251. hist.close()
  2252. return histStepData
  2253. def _parseLine(self, line, histStepData):
  2254. """!Parse line in file with history"""
  2255. line = line.rstrip('%s' % os.linesep).split(self.sep)
  2256. key = line[0]
  2257. kv = line[1:]
  2258. idx = 0
  2259. subkeyMaster = None
  2260. if len(kv) % 2 != 0: # multiple (e.g. nviz)
  2261. subkeyMaster = kv[0]
  2262. del kv[0]
  2263. idx = 0
  2264. while idx < len(kv):
  2265. if subkeyMaster:
  2266. subkey = [subkeyMaster, kv[idx]]
  2267. else:
  2268. subkey = kv[idx]
  2269. value = kv[idx+1]
  2270. value = self._parseValue(value, read = True)
  2271. if key not in histStepData:
  2272. histStepData[key] = {}
  2273. if type(subkey) == types.ListType:
  2274. if subkey[0] not in histStepData[key]:
  2275. histStepData[key][subkey[0]] = {}
  2276. histStepData[key][subkey[0]][subkey[1]] = value
  2277. else:
  2278. histStepData[key][subkey] = value
  2279. idx += 2
  2280. def DeleteNewHistStepData(self):
  2281. """!Delete buffer data for new history step"""
  2282. self.newHistStepData.clear()
  2283. class VnetStatusbar(wx.StatusBar):
  2284. """!Extends wx.StatusBar class with functionality to show multiple messages with the highest priority"""
  2285. def __init__(self, parent, style, id = wx.ID_ANY, **kwargs):
  2286. wx.StatusBar.__init__(self, parent, id, style, **kwargs)
  2287. self.maxPriority = 0
  2288. self.statusItems = []
  2289. def AddStatusItem(self, text, key, priority):
  2290. """!Add new item to show
  2291. @param text - string to show
  2292. @param key - item identifier, if already contains
  2293. item with same identifier, overwrites this item
  2294. @param priority - only items with highest priority are showed
  2295. """
  2296. statusTextItem = {
  2297. 'text' : text,
  2298. 'key' : key,
  2299. 'priority' : priority
  2300. }
  2301. for item in self.statusItems:
  2302. if item['key'] == statusTextItem['key']:
  2303. self.statusItems.remove(item)
  2304. self.statusItems.append(statusTextItem)
  2305. if self.maxPriority < statusTextItem['priority']:
  2306. self.maxPriority = statusTextItem['priority']
  2307. self._updateStatus()
  2308. def _updateStatus(self):
  2309. currStatusText = ''
  2310. for item in reversed(self.statusItems):
  2311. if item['priority'] == self.maxPriority:
  2312. if currStatusText:
  2313. currStatusText += '; '
  2314. currStatusText += item['text']
  2315. wx.StatusBar.SetStatusText(self, currStatusText)
  2316. def RemoveStatusItem(self, key):
  2317. """!Remove item
  2318. @param key - item identifier
  2319. """
  2320. update = False
  2321. for iItem, item in enumerate(self.statusItems):
  2322. if item['key'] == key:
  2323. if item['priority'] == self.maxPriority:
  2324. update = True
  2325. self.statusItems.pop(iItem)
  2326. if update:
  2327. for item in self.statusItems:
  2328. self.maxPriority = 0
  2329. if self.maxPriority < item['priority']:
  2330. self.maxPriority = item['priority']
  2331. self._updateStatus()