vdigit.py 66 KB

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