vdigit.py 64 KB

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