vdigit.py 66 KB

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