vdigit.py 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546
  1. """!
  2. @package vdigit
  3. @brief Dialogs for wxGUI vector digitizer
  4. Classes:
  5. - VDigit
  6. - VDigitSettingsDialog
  7. - VDigitCategoryDialog
  8. - CategoryListCtrl
  9. - VDigitZBulkDialog
  10. - VDigitDuplicatesDialog
  11. - CheckListFeature
  12. (C) 2007-2011 by the GRASS Development Team
  13. This program is free software under the GNU General Public License
  14. (>=v2). Read the file COPYING that comes with GRASS for details.
  15. @author Martin Landa <landa.martin gmail.com>
  16. """
  17. import os
  18. import sys
  19. import string
  20. import copy
  21. import textwrap
  22. import traceback
  23. from threading import Thread
  24. import wx
  25. import wx.lib.colourselect as csel
  26. import wx.lib.mixins.listctrl as listmix
  27. import gcmd
  28. import dbm
  29. from debug import Debug as Debug
  30. import gselect
  31. import globalvar
  32. from units import Units
  33. from preferences import globalSettings as UserSettings
  34. try:
  35. from wxvdigit import IVDigit, GV_LINES
  36. haveVDigit = True
  37. errorMsg = ''
  38. except ImportError, err:
  39. haveVDigit = False
  40. errorMsg = err
  41. GV_LINES = -1
  42. class IVDigit:
  43. def __init__(self):
  44. pass
  45. class VDigit(IVDigit):
  46. def __init__(self, mapwindow):
  47. """!Base class of vector digitizer
  48. @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance
  49. """
  50. IVDigit.__init__(self, mapwindow)
  51. class VDigitSettingsDialog(wx.Dialog):
  52. def __init__(self, parent, title, style = wx.DEFAULT_DIALOG_STYLE):
  53. """!Standard settings dialog for digitization purposes
  54. """
  55. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
  56. self.parent = parent # mapdisplay.MapFrame class instance
  57. self.digit = self.parent.MapWindow.digit
  58. # notebook
  59. notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
  60. self._createSymbologyPage(notebook)
  61. self.digit.SetCategory()
  62. self._createGeneralPage(notebook)
  63. self._createAttributesPage(notebook)
  64. self._createQueryPage(notebook)
  65. # buttons
  66. btnApply = wx.Button(self, wx.ID_APPLY)
  67. btnCancel = wx.Button(self, wx.ID_CANCEL)
  68. btnSave = wx.Button(self, wx.ID_SAVE)
  69. btnSave.SetDefault()
  70. # bindigs
  71. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  72. btnApply.SetToolTipString(_("Apply changes for this session"))
  73. btnApply.SetDefault()
  74. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  75. btnSave.SetToolTipString(_("Close dialog and save changes to user settings file"))
  76. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  77. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  78. # sizers
  79. btnSizer = wx.StdDialogButtonSizer()
  80. btnSizer.AddButton(btnCancel)
  81. btnSizer.AddButton(btnApply)
  82. btnSizer.AddButton(btnSave)
  83. btnSizer.Realize()
  84. mainSizer = wx.BoxSizer(wx.VERTICAL)
  85. mainSizer.Add(item = notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
  86. mainSizer.Add(item = btnSizer, proportion = 0,
  87. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  88. self.Bind(wx.EVT_CLOSE, self.OnCancel)
  89. self.SetSizer(mainSizer)
  90. mainSizer.Fit(self)
  91. def _createSymbologyPage(self, notebook):
  92. """!Create notebook page concerning symbology settings"""
  93. panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
  94. notebook.AddPage(page = panel, text = _("Symbology"))
  95. sizer = wx.BoxSizer(wx.VERTICAL)
  96. flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
  97. flexSizer.AddGrowableCol(0)
  98. self.symbology = {}
  99. for label, key in self._symbologyData():
  100. textLabel = wx.StaticText(panel, wx.ID_ANY, label)
  101. color = csel.ColourSelect(panel, id = wx.ID_ANY,
  102. colour = UserSettings.Get(group = 'vdigit', key = 'symbol',
  103. subkey = [key, 'color']), size = globalvar.DIALOG_COLOR_SIZE)
  104. isEnabled = UserSettings.Get(group = 'vdigit', key = 'symbol',
  105. subkey = [key, 'enabled'])
  106. if isEnabled is not None:
  107. enabled = wx.CheckBox(panel, id = wx.ID_ANY, label = "")
  108. enabled.SetValue(isEnabled)
  109. self.symbology[key] = (enabled, color)
  110. else:
  111. enabled = (1, 1)
  112. self.symbology[key] = (None, color)
  113. flexSizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  114. flexSizer.Add(enabled, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  115. flexSizer.Add(color, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  116. color.SetName("GetColour")
  117. sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 10)
  118. panel.SetSizer(sizer)
  119. return panel
  120. def _createGeneralPage(self, notebook):
  121. """!Create notebook page concerning general settings"""
  122. panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
  123. notebook.AddPage(page = panel, text = _("General"))
  124. border = wx.BoxSizer(wx.VERTICAL)
  125. #
  126. # display section
  127. #
  128. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Display"))
  129. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  130. flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
  131. flexSizer.AddGrowableCol(0)
  132. # line width
  133. text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width"))
  134. self.lineWidthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
  135. initial = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'value'),
  136. min = 1, max = 1e6)
  137. units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1),
  138. label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'),
  139. style = wx.ALIGN_LEFT)
  140. flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  141. flexSizer.Add(self.lineWidthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  142. flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  143. border = 10)
  144. sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
  145. border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
  146. #
  147. # snapping section
  148. #
  149. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Snapping"))
  150. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  151. flexSizer = wx.FlexGridSizer(cols = 3, hgap = 5, vgap = 5)
  152. flexSizer.AddGrowableCol(0)
  153. # snapping
  154. text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Snapping threshold"))
  155. self.snappingValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
  156. initial = UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'value'),
  157. min = -1, max = 1e6)
  158. self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue)
  159. self.snappingValue.Bind(wx.EVT_TEXT, self.OnChangeSnappingValue)
  160. self.snappingUnit = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1),
  161. choices = [_("screen pixels"), _("map units")])
  162. self.snappingUnit.SetStringSelection(UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'units'))
  163. self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits)
  164. flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  165. flexSizer.Add(self.snappingValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  166. flexSizer.Add(self.snappingUnit, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  167. vertexSizer = wx.BoxSizer(wx.VERTICAL)
  168. self.snapVertex = wx.CheckBox(parent = panel, id = wx.ID_ANY,
  169. label = _("Snap also to vertex"))
  170. self.snapVertex.SetValue(UserSettings.Get(group = 'vdigit', key = "snapToVertex", subkey = 'enabled'))
  171. vertexSizer.Add(item = self.snapVertex, proportion = 0, flag = wx.EXPAND)
  172. self.mapUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
  173. self.snappingInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
  174. label = _("Snapping threshold is %(value).1f %(units)s") % \
  175. {'value' : self.digit.GetDisplay().GetThreshold(),
  176. 'units' : self.mapUnits})
  177. vertexSizer.Add(item = self.snappingInfo, proportion = 0,
  178. flag = wx.ALL | wx.EXPAND, border = 1)
  179. sizer.Add(item = flexSizer, proportion = 1, flag = wx.EXPAND)
  180. sizer.Add(item = vertexSizer, proportion = 1, flag = wx.EXPAND)
  181. border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  182. #
  183. # select box
  184. #
  185. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Select vector features"))
  186. # feature type
  187. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  188. inSizer = wx.BoxSizer(wx.HORIZONTAL)
  189. self.selectFeature = {}
  190. for feature in ('point', 'line',
  191. 'centroid', 'boundary'):
  192. chkbox = wx.CheckBox(parent = panel, label = feature)
  193. self.selectFeature[feature] = chkbox.GetId()
  194. chkbox.SetValue(UserSettings.Get(group = 'vdigit', key = 'selectType',
  195. subkey = [feature, 'enabled']))
  196. inSizer.Add(item = chkbox, proportion = 0,
  197. flag = wx.EXPAND | wx.ALL, border = 5)
  198. sizer.Add(item = inSizer, proportion = 0, flag = wx.EXPAND)
  199. # threshold
  200. flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
  201. flexSizer.AddGrowableCol(0)
  202. text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select threshold"))
  203. self.selectThreshValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
  204. initial = UserSettings.Get(group = 'vdigit', key = "selectThresh", subkey = 'value'),
  205. min = 1, max = 1e6)
  206. units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1),
  207. label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'),
  208. style = wx.ALIGN_LEFT)
  209. flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  210. flexSizer.Add(self.selectThreshValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  211. flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  212. border = 10)
  213. self.selectIn = wx.CheckBox(parent = panel, id = wx.ID_ANY,
  214. label = _("Select only features inside of selection bounding box"))
  215. self.selectIn.SetValue(UserSettings.Get(group = 'vdigit', key = "selectInside", subkey = 'enabled'))
  216. self.selectIn.SetToolTipString(_("By default are selected all features overlapping selection bounding box "))
  217. self.checkForDupl = wx.CheckBox(parent = panel, id = wx.ID_ANY,
  218. label = _("Check for duplicates"))
  219. self.checkForDupl.SetValue(UserSettings.Get(group = 'vdigit', key = "checkForDupl", subkey = 'enabled'))
  220. sizer.Add(item = flexSizer, proportion = 0, flag = wx.EXPAND)
  221. sizer.Add(item = self.selectIn, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1)
  222. sizer.Add(item = self.checkForDupl, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1)
  223. border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  224. #
  225. # digitize lines box
  226. #
  227. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize line features"))
  228. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  229. self.intersect = wx.CheckBox(parent = panel, label = _("Break lines at intersection"))
  230. self.intersect.SetValue(UserSettings.Get(group = 'vdigit', key = 'breakLines', subkey = 'enabled'))
  231. sizer.Add(item = self.intersect, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  232. border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  233. #
  234. # save-on-exit box
  235. #
  236. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Save changes"))
  237. # save changes on exit?
  238. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  239. self.save = wx.CheckBox(parent = panel, label = _("Save changes on exit"))
  240. self.save.SetValue(UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled'))
  241. sizer.Add(item = self.save, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  242. border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  243. panel.SetSizer(border)
  244. return panel
  245. def _createQueryPage(self, notebook):
  246. """!Create notebook page for query tool"""
  247. panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
  248. notebook.AddPage(page = panel, text = _("Query tool"))
  249. border = wx.BoxSizer(wx.VERTICAL)
  250. #
  251. # query tool box
  252. #
  253. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Choose query tool"))
  254. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  255. LocUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
  256. self.queryBox = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Select by box"))
  257. self.queryBox.SetValue(UserSettings.Get(group = 'vdigit', key = "query", subkey = 'box'))
  258. sizer.Add(item = self.queryBox, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  259. sizer.Add((0, 5))
  260. #
  261. # length
  262. #
  263. self.queryLength = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("length"))
  264. self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  265. sizer.Add(item = self.queryLength, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  266. flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5)
  267. flexSizer.AddGrowableCol(0)
  268. txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select lines"))
  269. self.queryLengthSL = wx.Choice (parent = panel, id = wx.ID_ANY,
  270. choices = [_("shorter than"), _("longer than")])
  271. self.queryLengthSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection'))
  272. self.queryLengthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
  273. initial = 1,
  274. min = 0, max = 1e6)
  275. self.queryLengthValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'thresh'))
  276. units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits)
  277. flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  278. flexSizer.Add(self.queryLengthSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  279. flexSizer.Add(self.queryLengthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  280. flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  281. sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  282. #
  283. # dangle
  284. #
  285. self.queryDangle = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("dangle"))
  286. self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  287. sizer.Add(item = self.queryDangle, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  288. flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5)
  289. flexSizer.AddGrowableCol(0)
  290. txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select dangles"))
  291. self.queryDangleSL = wx.Choice (parent = panel, id = wx.ID_ANY,
  292. choices = [_("shorter than"), _("longer than")])
  293. self.queryDangleSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection'))
  294. self.queryDangleValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
  295. initial = 1,
  296. min = 0, max = 1e6)
  297. self.queryDangleValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'thresh'))
  298. units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits)
  299. flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  300. flexSizer.Add(self.queryDangleSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  301. flexSizer.Add(self.queryDangleValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  302. flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  303. sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  304. if UserSettings.Get(group = 'vdigit', key = "query", subkey = 'selection') == 0:
  305. self.queryLength.SetValue(True)
  306. else:
  307. self.queryDangle.SetValue(True)
  308. # enable & disable items
  309. self.OnChangeQuery(None)
  310. border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
  311. panel.SetSizer(border)
  312. return panel
  313. def _createAttributesPage(self, notebook):
  314. """!Create notebook page for attributes"""
  315. panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
  316. notebook.AddPage(page = panel, text = _("Attributes"))
  317. border = wx.BoxSizer(wx.VERTICAL)
  318. #
  319. # add new record
  320. #
  321. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize new feature"))
  322. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  323. # checkbox
  324. self.addRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY,
  325. label = _("Add new record into table"))
  326. self.addRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'))
  327. sizer.Add(item = self.addRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  328. # settings
  329. flexSizer = wx.FlexGridSizer(cols = 2, hgap = 3, vgap = 3)
  330. flexSizer.AddGrowableCol(0)
  331. settings = ((_("Layer"), 1), (_("Category"), 1), (_("Mode"), _("Next to use")))
  332. # layer
  333. text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Layer"))
  334. self.layer = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1),
  335. min = 1, max = 1e3)
  336. self.layer.SetValue(int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')))
  337. flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  338. flexSizer.Add(item = self.layer, proportion = 0,
  339. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  340. # category number
  341. text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category number"))
  342. self.category = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1),
  343. initial = UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'),
  344. min = -1e9, max = 1e9)
  345. if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') != 1:
  346. self.category.Enable(False)
  347. flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  348. flexSizer.Add(item = self.category, proportion = 0,
  349. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  350. # category mode
  351. text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category mode"))
  352. self.categoryMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1),
  353. choices = [_("Next to use"), _("Manual entry"), _("No category")])
  354. self.categoryMode.SetSelection(UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection'))
  355. flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  356. flexSizer.Add(item = self.categoryMode, proportion = 0,
  357. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  358. sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
  359. border.Add(item = sizer, proportion = 0,
  360. flag = wx.ALL | wx.EXPAND, border = 5)
  361. #
  362. # delete existing record
  363. #
  364. box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Delete existing feature(s)"))
  365. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  366. # checkbox
  367. self.deleteRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY,
  368. label = _("Delete record from table"))
  369. self.deleteRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "delRecord", subkey = 'enabled'))
  370. sizer.Add(item = self.deleteRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
  371. border.Add(item = sizer, proportion = 0,
  372. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  373. #
  374. # geometry attributes (currently only length and area are supported)
  375. #
  376. box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
  377. label = " %s " % _("Geometry attributes"))
  378. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  379. gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
  380. gridSizer.AddGrowableCol(0)
  381. self.geomAttrb = { 'length' : { 'label' : _('length') },
  382. 'area' : { 'label' : _('area') },
  383. 'perimeter' : { 'label' : _('perimeter') } }
  384. digitToolbar = self.parent.toolbars['vdigit']
  385. try:
  386. vectorName = digitToolbar.GetLayer().GetName()
  387. except AttributeError:
  388. vectorName = None # no vector selected for editing
  389. layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
  390. mapLayer = self.parent.toolbars['vdigit'].GetLayer()
  391. tree = self.parent.tree
  392. item = tree.FindItemByData('maplayer', mapLayer)
  393. row = 0
  394. for attrb in ['length', 'area', 'perimeter']:
  395. # checkbox
  396. check = wx.CheckBox(parent = panel, id = wx.ID_ANY,
  397. label = self.geomAttrb[attrb]['label'])
  398. ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled'))
  399. check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb)
  400. # column (only numeric)
  401. column = gselect.ColumnSelect(parent = panel, size = (200, -1))
  402. column.InsertColumns(vector = vectorName,
  403. layer = layer, excludeKey = True,
  404. type = ['integer', 'double precision'])
  405. # units
  406. if attrb == 'area':
  407. choices = Units.GetUnitsList('area')
  408. else:
  409. choices = Units.GetUnitsList('length')
  410. win_units = wx.Choice(parent = panel, id = wx.ID_ANY,
  411. choices = choices, size = (120, -1))
  412. # default values
  413. check.SetValue(False)
  414. if item and tree.GetPyData(item)[0]['vdigit'] and \
  415. 'geomAttr' in tree.GetPyData(item)[0]['vdigit'] and \
  416. attrb in tree.GetPyData(item)[0]['vdigit']['geomAttr']:
  417. check.SetValue(True)
  418. column.SetStringSelection(tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['column'])
  419. if attrb == 'area':
  420. type = 'area'
  421. else:
  422. type = 'length'
  423. unitsIdx = Units.GetUnitsIndex(type,
  424. tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['units'])
  425. win_units.SetSelection(unitsIdx)
  426. if not vectorName:
  427. check.Enable(False)
  428. column.Enable(False)
  429. if not check.IsChecked():
  430. column.Enable(False)
  431. self.geomAttrb[attrb]['check'] = check.GetId()
  432. self.geomAttrb[attrb]['column'] = column.GetId()
  433. self.geomAttrb[attrb]['units'] = win_units.GetId()
  434. gridSizer.Add(item = check,
  435. flag = wx.ALIGN_CENTER_VERTICAL,
  436. pos = (row, 0))
  437. gridSizer.Add(item = column,
  438. pos = (row, 1))
  439. gridSizer.Add(item = win_units,
  440. pos = (row, 2))
  441. row += 1
  442. note = '\n'.join(textwrap.wrap(_("Note: These settings are stored "
  443. "in the workspace not in the vector digitizer "
  444. "preferences."), 55))
  445. gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
  446. label = note),
  447. pos = (3, 0), span = (1, 3))
  448. sizer.Add(item = gridSizer, proportion = 1,
  449. flag = wx.ALL | wx.EXPAND, border = 1)
  450. border.Add(item = sizer, proportion = 0,
  451. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  452. # bindings
  453. self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord)
  454. self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode)
  455. self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer)
  456. panel.SetSizer(border)
  457. return panel
  458. def _symbologyData(self):
  459. """!Data for _createSymbologyPage()
  460. label | checkbox | color
  461. """
  462. return (
  463. # ("Background", "symbolBackground"),
  464. (_("Highlight"), "highlight"),
  465. (_("Highlight (duplicates)"), "highlightDupl"),
  466. (_("Point"), "point"),
  467. (_("Line"), "line"),
  468. (_("Boundary (no area)"), "boundaryNo"),
  469. (_("Boundary (one area)"), "boundaryOne"),
  470. (_("Boundary (two areas)"), "boundaryTwo"),
  471. (_("Centroid (in area)"), "centroidIn"),
  472. (_("Centroid (outside area)"), "centroidOut"),
  473. (_("Centroid (duplicate in area)"), "centroidDup"),
  474. (_("Node (one line)"), "nodeOne"),
  475. (_("Node (two lines)"), "nodeTwo"),
  476. (_("Vertex"), "vertex"),
  477. (_("Area (closed boundary + centroid)"), "area"),
  478. (_("Direction"), "direction"),)
  479. def OnGeomAttrb(self, event):
  480. """!Register geometry attributes (enable/disable)
  481. """
  482. checked = event.IsChecked()
  483. id = event.GetId()
  484. key = None
  485. for attrb, val in self.geomAttrb.iteritems():
  486. if val['check'] == id:
  487. key = attrb
  488. break
  489. column = self.FindWindowById(self.geomAttrb[key]['column'])
  490. if checked:
  491. column.Enable()
  492. else:
  493. column.Enable(False)
  494. def OnChangeCategoryMode(self, event):
  495. """!Change category mode
  496. """
  497. mode = event.GetSelection()
  498. UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', value = mode)
  499. if mode == 1: # manual entry
  500. self.category.Enable(True)
  501. elif self.category.IsEnabled(): # disable
  502. self.category.Enable(False)
  503. if mode == 2 and self.addRecord.IsChecked(): # no category
  504. self.addRecord.SetValue(False)
  505. self.digit.SetCategory()
  506. self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value'))
  507. def OnChangeLayer(self, event):
  508. """!Layer changed
  509. """
  510. layer = event.GetInt()
  511. if layer > 0:
  512. UserSettings.Set(group = 'vdigit', key = 'layer', subkey = 'value', value = layer)
  513. self.digit.SetCategory()
  514. self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value'))
  515. event.Skip()
  516. def OnChangeAddRecord(self, event):
  517. """!Checkbox 'Add new record' status changed
  518. """
  519. self.category.SetValue(self.digit.SetCategory())
  520. def OnChangeSnappingValue(self, event):
  521. """!Change snapping value - update static text
  522. """
  523. value = self.snappingValue.GetValue()
  524. if value < 0:
  525. region = self.parent.MapWindow.Map.GetRegion()
  526. res = (region['nsres'] + region['ewres']) / 2.
  527. threshold = self.digit.GetDisplay().GetThreshold(value = res)
  528. else:
  529. if self.snappingUnit.GetStringSelection() == "map units":
  530. threshold = value
  531. else:
  532. threshold = self.digit.GetDisplay().GetThreshold(value = value)
  533. if value == 0:
  534. self.snappingInfo.SetLabel(_("Snapping disabled"))
  535. elif value < 0:
  536. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s "
  537. "(based on comp. resolution)") %
  538. {'value' : threshold,
  539. 'units' : self.mapUnits.lower()})
  540. else:
  541. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") %
  542. {'value' : threshold,
  543. 'units' : self.mapUnits.lower()})
  544. event.Skip()
  545. def OnChangeSnappingUnits(self, event):
  546. """!Snapping units change -> update static text
  547. """
  548. value = self.snappingValue.GetValue()
  549. units = self.snappingUnit.GetStringSelection()
  550. threshold = self.digit.GetDisplay().GetThreshold(value = value, units = units)
  551. if units == "map units":
  552. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") %
  553. {'value' : value,
  554. 'units' : self.mapUnits})
  555. else:
  556. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") %
  557. {'value' : threshold,
  558. 'units' : self.mapUnits})
  559. event.Skip()
  560. def OnChangeQuery(self, event):
  561. """!Change query
  562. """
  563. if self.queryLength.GetValue():
  564. # length
  565. self.queryLengthSL.Enable(True)
  566. self.queryLengthValue.Enable(True)
  567. self.queryDangleSL.Enable(False)
  568. self.queryDangleValue.Enable(False)
  569. else:
  570. # dangle
  571. self.queryLengthSL.Enable(False)
  572. self.queryLengthValue.Enable(False)
  573. self.queryDangleSL.Enable(True)
  574. self.queryDangleValue.Enable(True)
  575. def OnSave(self, event):
  576. """!Button 'Save' pressed
  577. """
  578. self.UpdateSettings()
  579. self.parent.toolbars['vdigit'].settingsDialog = None
  580. fileSettings = {}
  581. UserSettings.ReadSettingsFile(settings = fileSettings)
  582. fileSettings['vdigit'] = UserSettings.Get(group = 'vdigit')
  583. file = UserSettings.SaveToFile(fileSettings)
  584. self.parent.GetLayerManager().goutput.WriteLog(_('Vector digitizer settings saved to file <%s>.') % file)
  585. self.Destroy()
  586. event.Skip()
  587. def OnApply(self, event):
  588. """!Button 'Apply' pressed
  589. """
  590. self.UpdateSettings()
  591. def OnCancel(self, event):
  592. """!Button 'Cancel' pressed
  593. """
  594. self.parent.toolbars['vdigit'].settingsDialog = None
  595. self.Destroy()
  596. if event:
  597. event.Skip()
  598. def UpdateSettings(self):
  599. """!Update digitizer settings
  600. """
  601. self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes
  602. # symbology
  603. for key, (enabled, color) in self.symbology.iteritems():
  604. if enabled:
  605. UserSettings.Set(group = 'vdigit', key = 'symbol',
  606. subkey = [key, 'enabled'],
  607. value = enabled.IsChecked())
  608. UserSettings.Set(group = 'vdigit', key = 'symbol',
  609. subkey = [key, 'color'],
  610. value = tuple(color.GetColour()))
  611. else:
  612. UserSettings.Set(group = 'vdigit', key = 'symbol',
  613. subkey = [key, 'color'],
  614. value = tuple(color.GetColour()))
  615. # display
  616. UserSettings.Set(group = 'vdigit', key = "lineWidth", subkey = 'value',
  617. value = int(self.lineWidthValue.GetValue()))
  618. # snapping
  619. UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'value',
  620. value = int(self.snappingValue.GetValue()))
  621. UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'units',
  622. value = self.snappingUnit.GetStringSelection())
  623. UserSettings.Set(group = 'vdigit', key = "snapToVertex", subkey = 'enabled',
  624. value = self.snapVertex.IsChecked())
  625. # digitize new feature
  626. UserSettings.Set(group = 'vdigit', key = "addRecord", subkey = 'enabled',
  627. value = self.addRecord.IsChecked())
  628. UserSettings.Set(group = 'vdigit', key = "layer", subkey = 'value',
  629. value = int(self.layer.GetValue()))
  630. UserSettings.Set(group = 'vdigit', key = "category", subkey = 'value',
  631. value = int(self.category.GetValue()))
  632. UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection',
  633. value = self.categoryMode.GetSelection())
  634. # delete existing feature
  635. UserSettings.Set(group = 'vdigit', key = "delRecord", subkey = 'enabled',
  636. value = self.deleteRecord.IsChecked())
  637. # geometry attributes (workspace)
  638. mapLayer = self.parent.toolbars['vdigit'].GetLayer()
  639. tree = self.parent.tree
  640. item = tree.FindItemByData('maplayer', mapLayer)
  641. for key, val in self.geomAttrb.iteritems():
  642. checked = self.FindWindowById(val['check']).IsChecked()
  643. column = self.FindWindowById(val['column']).GetValue()
  644. unitsIdx = self.FindWindowById(val['units']).GetSelection()
  645. if item and not tree.GetPyData(item)[0]['vdigit']:
  646. tree.GetPyData(item)[0]['vdigit'] = { 'geomAttr' : dict() }
  647. if checked: # enable
  648. if key == 'area':
  649. type = key
  650. else:
  651. type = 'length'
  652. unitsKey = Units.GetUnitsKey(type, unitsIdx)
  653. tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] = { 'column' : column,
  654. 'units' : unitsKey }
  655. else:
  656. if item and tree.GetPyData(item)[0]['vdigit'] and \
  657. key in tree.GetPyData(item)[0]['vdigit']['geomAttr']:
  658. del tree.GetPyData(item)[0]['vdigit']['geomAttr'][key]
  659. # query tool
  660. if self.queryLength.GetValue():
  661. UserSettings.Set(group = 'vdigit', key = "query", subkey = 'selection',
  662. value = 0)
  663. else:
  664. UserSettings.Set(group = 'vdigit', key = "query", subkey = 'type',
  665. value = 1)
  666. UserSettings.Set(group = 'vdigit', key = "query", subkey = 'box',
  667. value = self.queryBox.IsChecked())
  668. UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'than-selection',
  669. value = self.queryLengthSL.GetSelection())
  670. UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'thresh',
  671. value = int(self.queryLengthValue.GetValue()))
  672. UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'than-selection',
  673. value = self.queryDangleSL.GetSelection())
  674. UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'thresh',
  675. value = int(self.queryDangleValue.GetValue()))
  676. # select features
  677. for feature in ('point', 'line',
  678. 'centroid', 'boundary'):
  679. UserSettings.Set(group = 'vdigit', key = 'selectType',
  680. subkey = [feature, 'enabled'],
  681. value = self.FindWindowById(self.selectFeature[feature]).IsChecked())
  682. UserSettings.Set(group = 'vdigit', key = "selectThresh", subkey = 'value',
  683. value = int(self.selectThreshValue.GetValue()))
  684. UserSettings.Set(group = 'vdigit', key = "checkForDupl", subkey = 'enabled',
  685. value = self.checkForDupl.IsChecked())
  686. UserSettings.Set(group = 'vdigit', key = "selectInside", subkey = 'enabled',
  687. value = self.selectIn.IsChecked())
  688. # on-exit
  689. UserSettings.Set(group = 'vdigit', key = "saveOnExit", subkey = 'enabled',
  690. value = self.save.IsChecked())
  691. # break lines
  692. UserSettings.Set(group = 'vdigit', key = "breakLines", subkey = 'enabled',
  693. value = self.intersect.IsChecked())
  694. self.digit.UpdateSettings()
  695. # redraw map if auto-rendering is enabled
  696. if self.parent.statusbarWin['render'].GetValue():
  697. self.parent.OnRender(None)
  698. class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin):
  699. def __init__(self, parent, title,
  700. map, query = None, cats = None,
  701. pos = wx.DefaultPosition,
  702. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  703. """!Dialog used to display/modify categories of vector objects
  704. @param parent
  705. @param title dialog title
  706. @param query {coordinates, qdist} - used by v.edit/v.what
  707. @param cats directory of lines (layer/categories) - used by vdigit
  708. @param pos
  709. @param style
  710. """
  711. # parent
  712. self.parent = parent # mapdisplay.BufferedWindow class instance
  713. self.digit = parent.digit
  714. # map name
  715. self.map = map
  716. # line : {layer: [categories]}
  717. self.cats = {}
  718. # do not display dialog if no line is found (-> self.cats)
  719. if cats is None:
  720. if self._getCategories(query[0], query[1]) == 0 or not self.line:
  721. Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
  722. else:
  723. self.cats = cats
  724. for line in cats.keys():
  725. for layer in cats[line].keys():
  726. self.cats[line][layer] = list(cats[line][layer])
  727. layers = []
  728. for layer in self.digit.GetLayers():
  729. layers.append(str(layer))
  730. # make copy of cats (used for 'reload')
  731. self.cats_orig = copy.deepcopy(self.cats)
  732. wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY, title = title,
  733. style = style, pos = pos)
  734. # list of categories
  735. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  736. label = " %s " % _("List of categories - right-click to delete"))
  737. listSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  738. self.list = CategoryListCtrl(parent = self, id = wx.ID_ANY,
  739. style = wx.LC_REPORT |
  740. wx.BORDER_NONE |
  741. wx.LC_SORT_ASCENDING |
  742. wx.LC_HRULES |
  743. wx.LC_VRULES)
  744. # sorter
  745. self.fid = self.cats.keys()[0]
  746. self.itemDataMap = self.list.Populate(self.cats[self.fid])
  747. listmix.ColumnSorterMixin.__init__(self, 2)
  748. self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
  749. size = (150, -1))
  750. self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature)
  751. self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
  752. if len(self.cats.keys()) == 1:
  753. self.fidMulti.Show(False)
  754. self.fidText.SetLabel(str(self.fid))
  755. else:
  756. self.fidText.Show(False)
  757. choices = []
  758. for fid in self.cats.keys():
  759. choices.append(str(fid))
  760. self.fidMulti.SetItems(choices)
  761. self.fidMulti.SetSelection(0)
  762. listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND)
  763. # add new category
  764. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  765. label = " %s " % _("Add new category"))
  766. addSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  767. flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5)
  768. flexSizer.AddGrowableCol(3)
  769. layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
  770. label = "%s:" % _("Layer"))
  771. self.layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1),
  772. choices = layers)
  773. if len(layers) > 0:
  774. self.layerNew.SetSelection(0)
  775. catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
  776. label = "%s:" % _("Category"))
  777. try:
  778. newCat = max(self.cats[self.fid][1]) + 1
  779. except KeyError:
  780. newCat = 1
  781. self.catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1),
  782. initial = newCat, min = 0, max = 1e9)
  783. btnAddCat = wx.Button(self, wx.ID_ADD)
  784. flexSizer.Add(item = layerNewTxt, proportion = 0,
  785. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  786. flexSizer.Add(item = self.layerNew, proportion = 0,
  787. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  788. flexSizer.Add(item = catNewTxt, proportion = 0,
  789. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  790. border = 10)
  791. flexSizer.Add(item = self.catNew, proportion = 0,
  792. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  793. flexSizer.Add(item = btnAddCat, proportion = 0,
  794. flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  795. addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
  796. # buttons
  797. btnApply = wx.Button(self, wx.ID_APPLY)
  798. btnApply.SetToolTipString(_("Apply changes"))
  799. btnCancel = wx.Button(self, wx.ID_CANCEL)
  800. btnCancel.SetToolTipString(_("Ignore changes and close dialog"))
  801. btnOk = wx.Button(self, wx.ID_OK)
  802. btnOk.SetToolTipString(_("Apply changes and close dialog"))
  803. btnOk.SetDefault()
  804. # sizers
  805. btnSizer = wx.StdDialogButtonSizer()
  806. btnSizer.AddButton(btnCancel)
  807. #btnSizer.AddButton(btnReload)
  808. #btnSizer.SetNegativeButton(btnReload)
  809. btnSizer.AddButton(btnApply)
  810. btnSizer.AddButton(btnOk)
  811. btnSizer.Realize()
  812. mainSizer = wx.BoxSizer(wx.VERTICAL)
  813. mainSizer.Add(item = listSizer, proportion = 1,
  814. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  815. mainSizer.Add(item = addSizer, proportion = 0,
  816. flag = wx.EXPAND | wx.ALIGN_CENTER |
  817. wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  818. fidSizer = wx.BoxSizer(wx.HORIZONTAL)
  819. fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
  820. label = _("Feature id:")),
  821. proportion = 0, border = 5,
  822. flag = wx.ALIGN_CENTER_VERTICAL)
  823. fidSizer.Add(item = self.fidMulti, proportion = 0,
  824. flag = wx.EXPAND | wx.ALL, border = 5)
  825. fidSizer.Add(item = self.fidText, proportion = 0,
  826. flag = wx.EXPAND | wx.ALL, border = 5)
  827. mainSizer.Add(item = fidSizer, proportion = 0,
  828. flag = wx.EXPAND | wx.ALL, border = 5)
  829. mainSizer.Add(item = btnSizer, proportion = 0,
  830. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  831. self.SetSizer(mainSizer)
  832. mainSizer.Fit(self)
  833. self.SetAutoLayout(True)
  834. # set min size for dialog
  835. self.SetMinSize(self.GetBestSize())
  836. # bindings
  837. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  838. btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
  839. btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat)
  840. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  841. # list
  842. self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
  843. self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
  844. self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list)
  845. self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list)
  846. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
  847. def GetListCtrl(self):
  848. """!Used by ColumnSorterMixin
  849. """
  850. return self.list
  851. def OnColClick(self, event):
  852. """!Click on column header (order by)
  853. """
  854. event.Skip()
  855. def OnBeginEdit(self, event):
  856. """!Editing of item started
  857. """
  858. event.Allow()
  859. def OnEndEdit(self, event):
  860. """!Finish editing of item
  861. """
  862. itemIndex = event.GetIndex()
  863. layerOld = int (self.list.GetItem(itemIndex, 0).GetText())
  864. catOld = int (self.list.GetItem(itemIndex, 1).GetText())
  865. if event.GetColumn() == 0:
  866. layerNew = int(event.GetLabel())
  867. catNew = catOld
  868. else:
  869. layerNew = layerOld
  870. catNew = int(event.GetLabel())
  871. try:
  872. if layerNew not in self.cats[self.fid].keys():
  873. self.cats[self.fid][layerNew] = []
  874. self.cats[self.fid][layerNew].append(catNew)
  875. self.cats[self.fid][layerOld].remove(catOld)
  876. except:
  877. event.Veto()
  878. self.list.SetStringItem(itemIndex, 0, str(layerNew))
  879. self.list.SetStringItem(itemIndex, 1, str(catNew))
  880. dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
  881. "Layer and category number must be integer.\n"
  882. "Layer number must be greater then zero.") %
  883. { 'layer': self.layerNew.GetStringSelection(),
  884. 'category' : str(self.catNew.GetValue()) },
  885. _("Error"), wx.OK | wx.ICON_ERROR)
  886. dlg.ShowModal()
  887. dlg.Destroy()
  888. return False
  889. def OnRightDown(self, event):
  890. """!Mouse right button down
  891. """
  892. x = event.GetX()
  893. y = event.GetY()
  894. item, flags = self.list.HitTest((x, y))
  895. if item != wx.NOT_FOUND and \
  896. flags & wx.LIST_HITTEST_ONITEM:
  897. self.list.Select(item)
  898. event.Skip()
  899. def OnRightUp(self, event):
  900. """!Mouse right button up
  901. """
  902. if not hasattr(self, "popupID1"):
  903. self.popupID1 = wx.NewId()
  904. self.popupID2 = wx.NewId()
  905. self.popupID3 = wx.NewId()
  906. self.Bind(wx.EVT_MENU, self.OnItemDelete, id = self.popupID1)
  907. self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id = self.popupID2)
  908. self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3)
  909. # generate popup-menu
  910. menu = wx.Menu()
  911. menu.Append(self.popupID1, _("Delete selected"))
  912. if self.list.GetFirstSelected() == -1:
  913. menu.Enable(self.popupID1, False)
  914. menu.Append(self.popupID2, _("Delete all"))
  915. menu.AppendSeparator()
  916. menu.Append(self.popupID3, _("Reload"))
  917. self.PopupMenu(menu)
  918. menu.Destroy()
  919. def OnItemSelected(self, event):
  920. """!Item selected
  921. """
  922. event.Skip()
  923. def OnItemDelete(self, event):
  924. """!Delete selected item(s) from the list (layer/category pair)
  925. """
  926. item = self.list.GetFirstSelected()
  927. while item != -1:
  928. layer = int (self.list.GetItem(item, 0).GetText())
  929. cat = int (self.list.GetItem(item, 1).GetText())
  930. self.list.DeleteItem(item)
  931. self.cats[self.fid][layer].remove(cat)
  932. item = self.list.GetFirstSelected()
  933. event.Skip()
  934. def OnItemDeleteAll(self, event):
  935. """!Delete all items from the list
  936. """
  937. self.list.DeleteAllItems()
  938. self.cats[self.fid] = {}
  939. event.Skip()
  940. def OnFeature(self, event):
  941. """!Feature id changed (on duplicates)
  942. """
  943. self.fid = int(event.GetString())
  944. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  945. update = True)
  946. try:
  947. newCat = max(self.cats[self.fid][1]) + 1
  948. except KeyError:
  949. newCat = 1
  950. self.catNew.SetValue(newCat)
  951. event.Skip()
  952. def _getCategories(self, coords, qdist):
  953. """!Get layer/category pairs for all available
  954. layers
  955. Return True line found or False if not found
  956. """
  957. ret = gcmd.RunCommand('v.what',
  958. parent = self,
  959. quiet = True,
  960. map = self.map,
  961. east_north = '%f,%f' % \
  962. (float(coords[0]), float(coords[1])),
  963. distance = qdist)
  964. if not ret:
  965. return False
  966. for item in ret.splitlines():
  967. litem = item.lower()
  968. if "id:" in litem: # get line id
  969. self.line = int(item.split(':')[1].strip())
  970. elif "layer:" in litem: # add layer
  971. layer = int(item.split(':')[1].strip())
  972. if layer not in self.cats.keys():
  973. self.cats[layer] = []
  974. elif "category:" in litem: # add category
  975. self.cats[layer].append(int(item.split(':')[1].strip()))
  976. return True
  977. def OnReload(self, event):
  978. """!Reload button pressed
  979. """
  980. # restore original list
  981. self.cats = copy.deepcopy(self.cats_orig)
  982. # polulate list
  983. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  984. update = True)
  985. event.Skip()
  986. def OnCancel(self, event):
  987. """!Cancel button pressed
  988. """
  989. self.parent.parent.dialogs['category'] = None
  990. if self.digit:
  991. self.digit.GetDisplay().SetSelected([])
  992. self.parent.UpdateMap(render = False)
  993. else:
  994. self.parent.parent.OnRender(None)
  995. self.Close()
  996. def OnApply(self, event):
  997. """!Apply button pressed
  998. """
  999. for fid in self.cats.keys():
  1000. newfid = self.ApplyChanges(fid)
  1001. if fid == self.fid:
  1002. self.fid = newfid
  1003. def ApplyChanges(self, fid):
  1004. """!Apply changes
  1005. @param fid feature id
  1006. """
  1007. cats = self.cats[fid]
  1008. cats_orig = self.cats_orig[fid]
  1009. # action : (catsFrom, catsTo)
  1010. check = {'catadd': (cats, cats_orig),
  1011. 'catdel': (cats_orig, cats)}
  1012. newfid = -1
  1013. # add/delete new category
  1014. for action, catsCurr in check.iteritems():
  1015. for layer in catsCurr[0].keys():
  1016. catList = []
  1017. for cat in catsCurr[0][layer]:
  1018. if layer not in catsCurr[1].keys() or \
  1019. cat not in catsCurr[1][layer]:
  1020. catList.append(cat)
  1021. if catList != []:
  1022. if action == 'catadd':
  1023. add = True
  1024. else:
  1025. add = False
  1026. newfid = self.digit.SetLineCats(fid, layer,
  1027. catList, add)
  1028. if len(self.cats.keys()) == 1:
  1029. self.fidText.SetLabel("%d" % newfid)
  1030. else:
  1031. choices = self.fidMulti.GetItems()
  1032. choices[choices.index(str(fid))] = str(newfid)
  1033. self.fidMulti.SetItems(choices)
  1034. self.fidMulti.SetStringSelection(str(newfid))
  1035. self.cats[newfid] = self.cats[fid]
  1036. del self.cats[fid]
  1037. fid = newfid
  1038. if self.fid < 0:
  1039. wx.MessageBox(parent = self, message = _("Unable to update vector map."),
  1040. caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
  1041. self.cats_orig[fid] = copy.deepcopy(cats)
  1042. return newfid
  1043. def OnOK(self, event):
  1044. """!OK button pressed
  1045. """
  1046. self.OnApply(event)
  1047. self.OnCancel(event)
  1048. def OnAddCat(self, event):
  1049. """!Button 'Add' new category pressed
  1050. """
  1051. try:
  1052. layer = int(self.layerNew.GetStringSelection())
  1053. cat = int(self.catNew.GetValue())
  1054. if layer <= 0:
  1055. raise ValueError
  1056. except ValueError:
  1057. dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
  1058. "Layer and category number must be integer.\n"
  1059. "Layer number must be greater then zero.") %
  1060. {'layer' : str(self.layerNew.GetValue()),
  1061. 'category' : str(self.catNew.GetValue())},
  1062. _("Error"), wx.OK | wx.ICON_ERROR)
  1063. dlg.ShowModal()
  1064. dlg.Destroy()
  1065. return False
  1066. if layer not in self.cats[self.fid].keys():
  1067. self.cats[self.fid][layer] = []
  1068. self.cats[self.fid][layer].append(cat)
  1069. # reload list
  1070. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  1071. update = True)
  1072. # update category number for add
  1073. self.catNew.SetValue(cat + 1)
  1074. event.Skip()
  1075. return True
  1076. def GetLine(self):
  1077. """!Get id of selected line of 'None' if no line is selected
  1078. """
  1079. return self.cats.keys()
  1080. def UpdateDialog(self, query = None, cats = None):
  1081. """!Update dialog
  1082. @param query {coordinates, distance} - v.what
  1083. @param cats directory layer/cats - vdigit
  1084. Return True if updated otherwise False
  1085. """
  1086. # line: {layer: [categories]}
  1087. self.cats = {}
  1088. # do not display dialog if no line is found (-> self.cats)
  1089. if cats is None:
  1090. ret = self._getCategories(query[0], query[1])
  1091. else:
  1092. self.cats = cats
  1093. for line in cats.keys():
  1094. for layer in cats[line].keys():
  1095. self.cats[line][layer] = list(cats[line][layer])
  1096. ret = 1
  1097. if ret == 0 or len(self.cats.keys()) < 1:
  1098. Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
  1099. return False
  1100. # make copy of cats (used for 'reload')
  1101. self.cats_orig = copy.deepcopy(self.cats)
  1102. # polulate list
  1103. self.fid = self.cats.keys()[0]
  1104. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  1105. update = True)
  1106. try:
  1107. newCat = max(self.cats[self.fid][1]) + 1
  1108. except KeyError:
  1109. newCat = 1
  1110. self.catNew.SetValue(newCat)
  1111. if len(self.cats.keys()) == 1:
  1112. self.fidText.Show(True)
  1113. self.fidMulti.Show(False)
  1114. self.fidText.SetLabel("%d" % self.fid)
  1115. else:
  1116. self.fidText.Show(False)
  1117. self.fidMulti.Show(True)
  1118. choices = []
  1119. for fid in self.cats.keys():
  1120. choices.append(str(fid))
  1121. self.fidMulti.SetItems(choices)
  1122. self.fidMulti.SetSelection(0)
  1123. self.Layout()
  1124. return True
  1125. class CategoryListCtrl(wx.ListCtrl,
  1126. listmix.ListCtrlAutoWidthMixin,
  1127. listmix.TextEditMixin):
  1128. def __init__(self, parent, id, pos = wx.DefaultPosition,
  1129. size = wx.DefaultSize, style = 0):
  1130. """!List of layers/categories"""
  1131. self.parent = parent
  1132. wx.ListCtrl.__init__(self, parent, id, pos, size, style)
  1133. listmix.ListCtrlAutoWidthMixin.__init__(self)
  1134. listmix.TextEditMixin.__init__(self)
  1135. def Populate(self, cats, update = False):
  1136. """!Populate the list
  1137. """
  1138. itemData = {} # requested by sorter
  1139. if not update:
  1140. self.InsertColumn(0, _("Layer"))
  1141. self.InsertColumn(1, _("Category"))
  1142. else:
  1143. self.DeleteAllItems()
  1144. i = 1
  1145. for layer in cats.keys():
  1146. catsList = cats[layer]
  1147. for cat in catsList:
  1148. index = self.InsertStringItem(sys.maxint, str(catsList[0]))
  1149. self.SetStringItem(index, 0, str(layer))
  1150. self.SetStringItem(index, 1, str(cat))
  1151. self.SetItemData(index, i)
  1152. itemData[i] = (str(layer), str(cat))
  1153. i = i + 1
  1154. if not update:
  1155. self.SetColumnWidth(0, 100)
  1156. self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
  1157. self.currentItem = 0
  1158. return itemData
  1159. class VDigitZBulkDialog(wx.Dialog):
  1160. def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE):
  1161. """!Dialog used for Z bulk-labeling tool
  1162. """
  1163. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
  1164. self.parent = parent # mapdisplay.BufferedWindow class instance
  1165. # panel = wx.Panel(parent=self, id=wx.ID_ANY)
  1166. border = wx.BoxSizer(wx.VERTICAL)
  1167. txt = wx.StaticText(parent = self,
  1168. label = _("%d lines selected for z bulk-labeling") % nselected);
  1169. border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
  1170. box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value"))
  1171. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1172. flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
  1173. flexSizer.AddGrowableCol(0)
  1174. # starting value
  1175. txt = wx.StaticText(parent = self,
  1176. label = _("Starting value"));
  1177. self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
  1178. initial = 0,
  1179. min = -1e6, max = 1e6)
  1180. flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  1181. flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1182. # step
  1183. txt = wx.StaticText(parent = self,
  1184. label = _("Step"))
  1185. self.step = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
  1186. initial = 0,
  1187. min = 0, max = 1e6)
  1188. flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  1189. flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1190. sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
  1191. border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0)
  1192. # buttons
  1193. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1194. btnOk = wx.Button(self, wx.ID_OK)
  1195. btnOk.SetDefault()
  1196. # sizers
  1197. btnSizer = wx.StdDialogButtonSizer()
  1198. btnSizer.AddButton(btnCancel)
  1199. btnSizer.AddButton(btnOk)
  1200. btnSizer.Realize()
  1201. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1202. mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
  1203. mainSizer.Add(item = btnSizer, proportion = 0,
  1204. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  1205. self.SetSizer(mainSizer)
  1206. mainSizer.Fit(self)
  1207. class VDigitDuplicatesDialog(wx.Dialog):
  1208. def __init__(self, parent, data, title = _("List of duplicates"),
  1209. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  1210. pos = wx.DefaultPosition):
  1211. """!Show duplicated feature ids
  1212. """
  1213. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
  1214. pos = pos)
  1215. self.parent = parent # BufferedWindow
  1216. self.data = data
  1217. self.winList = []
  1218. # panel = wx.Panel(parent=self, id=wx.ID_ANY)
  1219. # notebook
  1220. self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
  1221. id = 1
  1222. for key in self.data.keys():
  1223. panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY)
  1224. self.notebook.AddPage(page = panel, text = " %d " % (id))
  1225. # notebook body
  1226. border = wx.BoxSizer(wx.VERTICAL)
  1227. win = CheckListFeature(parent = panel, data = list(self.data[key]))
  1228. self.winList.append(win.GetId())
  1229. border.Add(item = win, proportion = 1,
  1230. flag = wx.ALL | wx.EXPAND, border = 5)
  1231. panel.SetSizer(border)
  1232. id += 1
  1233. # buttons
  1234. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1235. btnOk = wx.Button(self, wx.ID_OK)
  1236. btnOk.SetDefault()
  1237. # sizers
  1238. btnSizer = wx.StdDialogButtonSizer()
  1239. btnSizer.AddButton(btnCancel)
  1240. btnSizer.AddButton(btnOk)
  1241. btnSizer.Realize()
  1242. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1243. mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
  1244. mainSizer.Add(item = btnSizer, proportion = 0,
  1245. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  1246. self.SetSizer(mainSizer)
  1247. mainSizer.Fit(self)
  1248. self.SetAutoLayout(True)
  1249. # set min size for dialog
  1250. self.SetMinSize((250, 180))
  1251. def GetUnSelected(self):
  1252. """!Get unselected items (feature id)
  1253. @return list of ids
  1254. """
  1255. ids = []
  1256. for id in self.winList:
  1257. wlist = self.FindWindowById(id)
  1258. for item in range(wlist.GetItemCount()):
  1259. if not wlist.IsChecked(item):
  1260. ids.append(int(wlist.GetItem(item, 0).GetText()))
  1261. return ids
  1262. class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
  1263. def __init__(self, parent, data,
  1264. pos = wx.DefaultPosition, log = None):
  1265. """!List of mapset/owner/group
  1266. """
  1267. self.parent = parent
  1268. self.data = data
  1269. wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
  1270. style = wx.LC_REPORT)
  1271. listmix.CheckListCtrlMixin.__init__(self)
  1272. self.log = log
  1273. # setup mixins
  1274. listmix.ListCtrlAutoWidthMixin.__init__(self)
  1275. self.LoadData(self.data)
  1276. def LoadData(self, data):
  1277. """!Load data into list
  1278. """
  1279. self.InsertColumn(0, _('Feature id'))
  1280. self.InsertColumn(1, _('Layer (Categories)'))
  1281. for item in data:
  1282. index = self.InsertStringItem(sys.maxint, str(item[0]))
  1283. self.SetStringItem(index, 1, str(item[1]))
  1284. # enable all items by default
  1285. for item in range(self.GetItemCount()):
  1286. self.CheckItem(item, True)
  1287. self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
  1288. self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER)
  1289. def OnCheckItem(self, index, flag):
  1290. """!Mapset checked/unchecked
  1291. """
  1292. pass