vdigit.py 66 KB

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