vdigit.py 108 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822
  1. """
  2. MODULE: vdigit
  3. CLASSES:
  4. * AbstractDigit
  5. * VEdit
  6. * VDigit
  7. * AbstractDisplayDriver
  8. * CDisplayDriver
  9. * VDigitSettingsDialog
  10. * VDigitCategoryDialog
  11. * VDigitZBulkDialog
  12. * VDigitDuplicatesDialog
  13. PURPOSE: Vector digitization tool for wxPython GUI
  14. Note: Initial version under development
  15. Progress:
  16. (1) v.edit called on the background (class VEdit)
  17. (2) Reimplentation of v.digit (VDigit)
  18. Import:
  19. from vdigit import VDigit as VDigit
  20. AUTHORS: The GRASS Development Team
  21. Martin Landa <landa.martin gmail.com>
  22. COPYRIGHT: (C) 2007-2008 by the GRASS Development Team
  23. This program is free software under the GNU General Public
  24. License (>=v2). Read the file COPYING that comes with GRASS
  25. for details.
  26. """
  27. import os
  28. import sys
  29. import string
  30. import copy
  31. import wx
  32. import wx.lib.colourselect as csel
  33. import wx.lib.mixins.listctrl as listmix
  34. import gcmd
  35. import dbm
  36. from debug import Debug as Debug
  37. import gselect
  38. import globalvar
  39. from preferences import globalSettings as UserSettings
  40. try:
  41. digitPath = os.path.join(globalvar.ETCWXDIR, "vdigit")
  42. sys.path.append(digitPath)
  43. import grass7_wxvdigit as wxvdigit
  44. GV_LINES = wxvdigit.GV_LINES
  45. digitErr = ''
  46. except ImportError, err:
  47. GV_LINES = None
  48. digitErr = err
  49. # print >> sys.stderr, "%sWARNING: Digitization tool is disabled (%s). " \
  50. # "Detailed information in README file." % \
  51. # (os.linesep, err)
  52. # which interface to use?
  53. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') == 'vedit' and GV_LINES is not None:
  54. print >> sys.stderr, "%sWARNING: Digitization tool uses v.edit interface. " \
  55. "This can significantly slow down some operations especially for " \
  56. "middle-large vector maps. "\
  57. "You can change the digitization interface in 'User preferences' " \
  58. "(menu 'Config'->'Preferences')." % \
  59. os.linesep
  60. class AbstractDigit:
  61. """
  62. Abstract digitization class
  63. """
  64. def __init__(self, mapwindow):
  65. """Initialization
  66. @param mapwindow reference to mapwindow (MapFrame) instance
  67. @param settings initial settings of digitization tool
  68. """
  69. self.map = None
  70. self.mapWindow = mapwindow
  71. Debug.msg (3, "AbstractDigit.__init__(): map=%s" % \
  72. self.map)
  73. #self.SetCategory()
  74. self.driver = CDisplayDriver(self, mapwindow)
  75. def SetCategoryNextToUse(self):
  76. """Find maximum category number in the map layer
  77. and update Digit.settings['category']
  78. @return 'True' on success, 'False' on failure
  79. """
  80. # vector map layer without categories, reset to '1'
  81. UserSettings.Set(group='vdigit', key='category', subkey='value', value=1)
  82. if self.map:
  83. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') == 'vedit':
  84. categoryCmd = gcmd.Command(cmd=["v.category", "-g", "--q",
  85. "input=%s" % self.map,
  86. "option=report"])
  87. if categoryCmd.returncode != 0:
  88. return False
  89. for line in categoryCmd.ReadStdOutput():
  90. if "all" in line:
  91. if UserSettings.Get(group='vdigit', key='layer', subkey='value') != int(line.split(' ')[0]):
  92. continue
  93. try:
  94. maxCat = int(line.split(' ')[-1]) + 1
  95. UserSettings.Set(group='vdigit', key='category', subkey='value', value=maxCat)
  96. except:
  97. return False
  98. return True
  99. else:
  100. cat = self.digit.GetCategory(UserSettings.Get(group='vdigit', key='layer', subkey='value'))
  101. UserSettings.Set(group='vdigit', key='category', subkey='value',
  102. value=cat + 1)
  103. def SetCategory(self):
  104. """Return category number to use (according Settings)"""
  105. if UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection') == 0:
  106. self.SetCategoryNextToUse()
  107. return UserSettings.Get(group='vdigit', key="category", subkey='value')
  108. def SetMapName(self, map):
  109. """Set map name
  110. @param map map name to be set up or None (will close currently edited map)
  111. """
  112. Debug.msg (3, "AbstractDigit.SetMapName map=%s" % map)
  113. self.map = map
  114. try:
  115. ret = self.driver.Reset(self.map)
  116. except StandardError, e:
  117. raise gcmd.DigitError(parent=self.mapWindow.parent,
  118. message=_('Unable to initialize display driver, '
  119. 'see README file for more information.%s%s'
  120. 'Details: %s (%s)') % (os.linesep, os.linesep, e, digitErr))
  121. if map and ret == -1:
  122. raise gcmd.DigitError(parent=self.mapWindow.parent,
  123. message=_('Unable to open vector map <%s> for editing. '
  124. 'Data are probably corrupted, '
  125. 'try to run v.build for rebuilding the topology.') % map)
  126. if not map and ret != 0:
  127. raise gcmd.DigitError(parent=self.mapWindow.parent,
  128. message=_('Unable to open vector map <%s> for editing. '
  129. 'Data are probably corrupted, '
  130. 'try to run v.build for rebuilding the topology.') % map)
  131. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') != 'v.edit':
  132. try:
  133. self.digit.InitCats()
  134. except:
  135. pass
  136. # avoid using current vector map as background map
  137. if self.map == UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value'):
  138. UserSettings.Set(group='vdigit', key='backgroundMap', subkey='value', value='')
  139. def SelectLinesByQueryThresh(self):
  140. """Generic method used for SelectLinesByQuery()
  141. -- to get threshold value"""
  142. thresh = 0.0
  143. if UserSettings.Get(group='vdigit', key='query', subkey='selection') == 0:
  144. thresh = UserSettings.Get(group='vdigit', key='queryLength', subkey='thresh')
  145. if UserSettings.Get(group='vdigit', key="queryLength", subkey='than-selection') == 0:
  146. thresh = -1 * thresh
  147. else:
  148. thresh = UserSettings.Get(group='vdigit', key='queryDangle', subkey='thresh')
  149. if UserSettings.Get(group='vdigit', key="queryDangle", subkey='than-selection') == 0:
  150. thresh = -1 * thresh
  151. return thresh
  152. def GetSelectType(self):
  153. """Get type(s) to be selected
  154. Used by SelectLinesByBox() and SelectLinesByPoint()"""
  155. type = 0
  156. for feature in (('Point', wxvdigit.GV_POINT),
  157. ('Line', wxvdigit.GV_LINE),
  158. ('Centroid', wxvdigit.GV_CENTROID),
  159. ('Boundary', wxvdigit.GV_BOUNDARY)):
  160. if UserSettings.Get(group='vdigit', key='selectFeature'+feature[0], subkey='enabled') is True:
  161. type |= feature[1]
  162. return type
  163. def SelectLinesFromBackgroundMap(self, pos1, pos2):
  164. """Select features from background map
  165. @param pos1,pos2 bounding box defifinition
  166. """
  167. if UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value') == '':
  168. Debug.msg(4, "VEdit.SelectLinesFromBackgroundMap(): []")
  169. return []
  170. x1, y1 = pos1
  171. x2, y2 = pos2
  172. vEditCmd = gcmd.Command(['v.edit',
  173. '--q',
  174. 'map=%s' % UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value'),
  175. 'tool=select',
  176. 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1])])
  177. #'polygon=%f,%f,%f,%f,%f,%f,%f,%f,%f,%f' % \
  178. # (x1, y1, x2, y1, x2, y2, x1, y2, x1, y1)])
  179. try:
  180. output = vEditCmd.ReadStdOutput()[0] # first line
  181. ids = output.split(',')
  182. ids = map(int, ids) # str -> int
  183. except:
  184. return []
  185. Debug.msg(4, "VEdit.SelectLinesFromBackgroundMap(): %s" % \
  186. ",".join(["%d" % v for v in ids]))
  187. return ids
  188. class VEdit(AbstractDigit):
  189. """
  190. Prototype of digitization class based on v.edit command
  191. Note: This should be replaced by VDigit class.
  192. """
  193. def __init__(self, mapwindow):
  194. """Initialization
  195. @param mapwindow reference to mapwindow (MapFrame) instance
  196. @param settings initial settings of digitization tool
  197. """
  198. AbstractDigit.__init__(self, mapwindow)
  199. def AddPoint (self, map, point, x, y, z=None):
  200. """Add point/centroid
  201. @param map map name
  202. @param point feature type (True for point, otherwise centroid)
  203. @param x,y,z coordinates
  204. """
  205. if point:
  206. key = "P"
  207. else:
  208. key = "C"
  209. if UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection') == 2:
  210. layer = -1 # -> no category
  211. cat = -1
  212. else:
  213. layer = UserSettings.Get(group='vdigit', key="layer", subkey='value')
  214. cat = self.SetCategory()
  215. if layer > 0 and cat != "None":
  216. addstring = "%s 1 1\n" % (key)
  217. else:
  218. addstring = "%s 1\n" % (key)
  219. addstring += "%f %f\n" % (x, y)
  220. if layer > 0 and cat != "None":
  221. addstring += "%d %d\n" % (layer, cat)
  222. Debug.msg (3, "VEdit.AddPoint(): map=%s, type=%s, layer=%d, cat=%d, x=%f, y=%f" % \
  223. (map, type, layer, cat, x, y))
  224. else:
  225. Debug.msg (3, "VEdit.AddPoint(): map=%s, type=%s, x=%f, y=%f" % \
  226. (map, type, x, y))
  227. Debug.msg (4, "Vline.AddPoint(): input=%s" % addstring)
  228. self.__AddFeature (map=map, input=addstring)
  229. def AddLine (self, map, line, coords):
  230. """Add line/boundary
  231. @param map map name
  232. @param line feature type (True for line, otherwise boundary)
  233. @param list of coordinates
  234. """
  235. if len(coords) < 2:
  236. return
  237. if UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection') == 2:
  238. layer = -1 # -> no category
  239. cat = -1
  240. else:
  241. layer = UserSettings.Get(group='vdigit', key="layer", subkey='value')
  242. cat = self.SetCategory()
  243. if line:
  244. key = "L"
  245. flags = []
  246. else:
  247. key = "B"
  248. flags = ['-c'] # close boundaries
  249. if layer > 0 and cat != "None":
  250. addstring = "%s %d 1\n" % (key, len(coords))
  251. else:
  252. addstring = "%s %d\n" % (key, len(coords))
  253. for point in coords:
  254. addstring += "%f %f\n" % \
  255. (float(point[0]), float(point [1]))
  256. if layer > 0 and cat != "None":
  257. addstring += "%d %d\n" % (layer, cat)
  258. Debug.msg (3, "Vline.AddLine(): type=%s, layer=%d, cat=%d coords=%s" % \
  259. (key, layer, cat, coords))
  260. else:
  261. Debug.msg (3, "Vline.AddLine(): type=%s, coords=%s" % \
  262. (key, coords))
  263. Debug.msg (4, "VEdit.AddLine(): input=%s" % addstring)
  264. self.__AddFeature (map=map, input=addstring, flags=flags)
  265. def __AddFeature (self, map, input, flags=[]):
  266. """Generic method to add new vector feature
  267. @param map map name
  268. @param input feature definition in GRASS ASCII format
  269. @param flags additional flags
  270. """
  271. if UserSettings.Get(group='vdigit', key='snapping', subkey='value') <= 0.0:
  272. snap = "no"
  273. else:
  274. if UserSettings.Get(group='vdigit', key='snapToVertex', subkey='enabled') is True:
  275. snap = "vertex"
  276. else:
  277. snap = "node"
  278. command = ["v.edit", "-n", "--q",
  279. "map=%s" % map,
  280. "tool=add",
  281. "thresh=%f,%f" % (self.driver.GetThreshold(type='selectThresh'), self.driver.GetThreshold(type='snapping')),
  282. "snap=%s" % snap]
  283. if UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value') != '':
  284. command.append("bgmap=%s" % UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value'))
  285. # additional flags
  286. for flag in flags:
  287. command.append(flag)
  288. # run the command
  289. Debug.msg(4, "VEdit.AddFeature(): input=%s" % input)
  290. vedit = gcmd.Command(cmd=command, stdin=input, stderr=None)
  291. # reload map (needed for v.edit)
  292. self.driver.ReloadMap()
  293. def DeleteSelectedLines(self):
  294. """Delete selected features"""
  295. selected = self.driver.GetSelected() # grassId
  296. if len(selected) <= 0:
  297. return False
  298. ids = ",".join(["%d" % v for v in selected])
  299. Debug.msg(4, "Digit.DeleteSelectedLines(): ids=%s" % \
  300. ids)
  301. # delete also attributes if requested
  302. if UserSettings.Get(group='vdigit', key='delRecord', subkey='enabled') is True:
  303. layerCommand = gcmd.Command(cmd=["v.db.connect",
  304. "-g", "--q",
  305. "map=%s" % self.map],
  306. rerr=None, stderr=None)
  307. if layerCommand.returncode == 0:
  308. layers = {}
  309. for line in layerCommand.ReadStdOutput():
  310. lineList = line.split(' ')
  311. layers[int(lineList[0])] = { "table" : lineList[1],
  312. "key" : lineList[2],
  313. "database" : lineList[3],
  314. "driver" : lineList[4] }
  315. for layer in layers.keys():
  316. printCats = gcmd.Command(['v.category',
  317. '--q',
  318. 'input=%s' % self.map,
  319. 'layer=%d' % layer,
  320. 'option=print',
  321. 'id=%s' % ids])
  322. sql = 'DELETE FROM %s WHERE' % layers[layer]['table']
  323. n_cats = 0
  324. for cat in printCats.ReadStdOutput():
  325. for c in cat.split('/'):
  326. sql += ' cat = %d or' % int(c)
  327. n_cats += 1
  328. sql = sql.rstrip(' or')
  329. if n_cats > 0:
  330. gcmd.Command(['db.execute',
  331. '--q',
  332. 'driver=%s' % layers[layer]['driver'],
  333. 'database=%s' % layers[layer]['database']],
  334. stdin=sql,
  335. rerr=None, stderr=None)
  336. command = [ "v.edit",
  337. "map=%s" % self.map,
  338. "tool=delete",
  339. "ids=%s" % ids]
  340. # run the command
  341. vedit = gcmd.Command(cmd=command, stderr=None)
  342. # reload map (needed for v.edit)
  343. self.driver.ReloadMap()
  344. return True
  345. def MoveSelectedLines(self, move):
  346. """Move selected features
  347. @param move X,Y direction
  348. """
  349. return self.__MoveFeature("move", None, move)
  350. def MoveSelectedVertex(self, coords, move):
  351. """Move selected vertex
  352. Feature geometry is changed.
  353. @param coords click coordinates
  354. @param move X,Y direction
  355. """
  356. return self.__MoveFeature("vertexmove", coords, move)
  357. def __MoveFeature(self, tool, coords, move):
  358. """Move selected vector feature (line, vertex)
  359. @param tool tool for v.edit
  360. @param coords click coordinates
  361. @param move direction (x, y)
  362. """
  363. selected = self.driver.GetSelected()
  364. if len(selected) <= 0:
  365. return False
  366. ids = ",".join(["%d" % v for v in selected])
  367. Debug.msg(4, "Digit.MoveSelectedLines(): ids=%s, move=%s" % \
  368. (ids, move))
  369. if UserSettings.Get(group='vdigit', key='snapping', subkey='value') <= 0.0:
  370. snap = "no"
  371. else:
  372. if UserSettings.Get(group='vdigit', key='snapToVertex', subkey='enabled') is True:
  373. snap = "vertex"
  374. else:
  375. snap = "node"
  376. command = ["v.edit", "--q",
  377. "map=%s" % self.map,
  378. "tool=%s" % tool,
  379. "ids=%s" % ids,
  380. "move=%f,%f" % (float(move[0]),float(move[1])),
  381. "thresh=%f,%f" % (self.driver.GetThreshold(type='selectThresh'), self.driver.GetThreshold(type='snapping')),
  382. "snap=%s" % snap]
  383. if tool == "vertexmove":
  384. command.append("coords=%f,%f" % (float(coords[0]), float(coords[1])))
  385. command.append("-1") # modify only first selected
  386. if UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value') != '':
  387. command.append("bgmap=%s" % UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value'))
  388. # run the command
  389. vedit = gcmd.Command(cmd=command, stderr=None)
  390. # reload map (needed for v.edit)
  391. self.driver.ReloadMap()
  392. return True
  393. def AddVertex(self, coords):
  394. """Add new vertex to the selected line/boundary on position 'coords'
  395. @param coords coordinates to add vertex
  396. """
  397. return self.__ModifyVertex(coords, "vertexadd")
  398. def RemoveVertex(self, coords):
  399. """Remove vertex from the selected line/boundary on position 'coords'
  400. @param coords coordinates to remove vertex
  401. """
  402. return self.__ModifyVertex(coords, "vertexdel")
  403. def __ModifyVertex(self, coords, action):
  404. """Generic method for vertex manipulation
  405. @param coords coordinates
  406. @param action operation to perform
  407. """
  408. try:
  409. line = self.driver.GetSelected()[0]
  410. except:
  411. return False
  412. command = ["v.edit", "--q",
  413. "map=%s" % self.map,
  414. "tool=%s" % action,
  415. "ids=%s" % line,
  416. "coords=%f,%f" % (float(coords[0]),float(coords[1])),
  417. "thresh=%f,%f" % (self.driver.GetThreshold(type='selectThresh'), self.driver.GetThreshold(type='snapping'))]
  418. # run the command
  419. vedit = gcmd.Command(cmd=command, stderr=None)
  420. # reload map (needed for v.edit)
  421. self.driver.ReloadMap()
  422. return True
  423. def SplitLine(self, coords):
  424. """Split selected line/boundary on position 'coords'
  425. @param coords coordinates to split line
  426. """
  427. try:
  428. line = self.driver.GetSelected()[0]
  429. except:
  430. return False
  431. command = ["v.edit", "--q",
  432. "map=%s" % self.map,
  433. "tool=break",
  434. "ids=%s" % line,
  435. "coords=%f,%f" % (float(coords[0]),float(coords[1])),
  436. "thresh=%f" % self.driver.GetThreshold(type='selectThresh')]
  437. # run the command
  438. vedit = gcmd.Command(cmd=command, stderr=None)
  439. # redraw map
  440. self.driver.ReloadMap()
  441. return True
  442. def EditLine(self, line, coords):
  443. """Edit existing line/boundary
  444. @param line id of line to be modified
  445. @param coords list of coordinates of modified line
  446. """
  447. # remove line
  448. vEditDelete = gcmd.Command(['v.edit',
  449. '--q',
  450. 'map=%s' % self.map,
  451. 'tool=delete',
  452. 'ids=%s' % line], stderr=None)
  453. # add line
  454. if len(coords) > 0:
  455. self.AddLine(self.map, "line", coords)
  456. # reload map (needed for v.edit)
  457. self.driver.ReloadMap()
  458. def __ModifyLines(self, tool):
  459. """Generic method to modify selected lines/boundaries
  460. @param tool operation to be performed by v.edit
  461. """
  462. ids = self.driver.GetSelected()
  463. if len(ids) <= 0:
  464. return False
  465. vEdit = ['v.edit',
  466. '--q',
  467. 'map=%s' % self.map,
  468. 'tool=%s' % tool,
  469. 'ids=%s' % ",".join(["%d" % v for v in ids])]
  470. if tool in ['snap', 'connect']:
  471. vEdit.append("thresh=%f,%f" % (self.driver.GetThreshold(type='selectThresh'), self.driver.GetThreshold(type='snapping')))
  472. runCmd = gcmd.Command(vEdit)
  473. # reload map (needed for v.edit)
  474. self.driver.ReloadMap()
  475. return True
  476. def FlipLine(self):
  477. """Flip selected lines/boundaries"""
  478. return self.__ModifyLines('flip')
  479. def MergeLine(self):
  480. """Merge selected lines/boundaries"""
  481. return self.__ModifyLines('merge')
  482. def BreakLine(self):
  483. """Break selected lines/boundaries"""
  484. return self.__ModifyLines('break')
  485. def SnapLine(self):
  486. """Snap selected lines/boundaries"""
  487. return self.__ModifyLines('snap')
  488. def ConnectLine(self):
  489. """Connect selected lines/boundaries"""
  490. return self.__ModifyLines('connect')
  491. def TypeConvForSelectedLines(self):
  492. """Feature type conversion for selected objects.
  493. Supported conversions:
  494. - point <-> centroid
  495. - line <-> boundary
  496. """
  497. return self.__ModifyLines('chtype')
  498. def ZBulkLine(self, pos1, pos2, value, step):
  499. """Provide z bulk-labeling (automated assigment of z coordinate
  500. to 3d lines
  501. @param pos1,pos2 bounding box definition for selecting lines to be labeled
  502. @param value starting value
  503. @param step step value
  504. """
  505. gcmd.Command(['v.edit',
  506. '--q',
  507. 'map=%s' % self.map,
  508. 'tool=zbulk',
  509. 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1]),
  510. 'zbulk=%f,%f' % (value, step)])
  511. def CopyLine(self, ids=None):
  512. """Copy features from (background) vector map
  513. @param ids list of line ids to be copied
  514. """
  515. if not ids:
  516. ids = self.driver.GetSelected()
  517. if len(ids) <= 0:
  518. return False
  519. vEdit = ['v.edit',
  520. '--q',
  521. 'map=%s' % self.map,
  522. 'tool=copy',
  523. 'ids=%s' % ",".join(["%d" % v for v in ids])]
  524. if UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value') != '':
  525. vEdit.append('bgmap=%s' % UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value'))
  526. runCmd = gcmd.Command(vEdit)
  527. # reload map (needed for v.edit)
  528. self.driver.ReloadMap()
  529. return True
  530. def CopyCats(self, cats, ids):
  531. """Copy given categories to objects with id listed in ids
  532. @param cats list of cats to be copied
  533. @param ids ids of lines to be modified
  534. """
  535. if len(cats) == 0 or len(ids) == 0:
  536. return False
  537. # collect cats
  538. gcmd.Command(['v.edit',
  539. '--q',
  540. 'map=%s' % self.map,
  541. 'tool=catadd',
  542. 'cats=%s' % ",".join(["%d" % v for v in cats]),
  543. 'ids=%s' % ",".join(["%d" % v for v in ids])])
  544. # reload map (needed for v.edit)
  545. self.driver.ReloadMap()
  546. return True
  547. def SelectLinesByQuery(self, pos1, pos2):
  548. """Select features by query
  549. @param pos1, pos2 bounding box definition
  550. """
  551. thresh = self.SelectLinesByQueryThresh()
  552. w, n = pos1
  553. e, s = pos2
  554. if UserSettings.Get(group='vdigit', key='query', subkey='box') == False: # select globaly
  555. vInfo = gcmd.Command(['v.info',
  556. 'map=%s' % self.map,
  557. '-g'])
  558. for item in vInfo.ReadStdOutput():
  559. if 'north' in item:
  560. n = float(item.split('=')[1])
  561. elif 'south' in item:
  562. s = float(item.split('=')[1])
  563. elif 'east' in item:
  564. e = float(item.split('=')[1])
  565. elif 'west' in item:
  566. w = float(item.split('=')[1])
  567. if UserSettings.Get(group='vdigit', key='query', subkey='selection') == 0:
  568. qtype = 'length'
  569. else:
  570. qtype = 'dangle'
  571. vEdit = (['v.edit',
  572. '--q',
  573. 'map=%s' % self.map,
  574. 'tool=select',
  575. 'bbox=%f,%f,%f,%f' % (w, n, e, s),
  576. 'query=%s' % qtype,
  577. 'thresh=0,0,%f' % thresh])
  578. vEditCmd = gcmd.Command(vEdit)
  579. try:
  580. output = vEditCmd.ReadStdOutput()[0] # first line
  581. ids = output.split(',')
  582. ids = map(int, ids) # str -> int
  583. except:
  584. return []
  585. Debug.msg(4, "VEdit.SelectLinesByQuery(): %s" % \
  586. ",".join(["%d" % v for v in ids]))
  587. return ids
  588. def GetLayers(self):
  589. """Return list of layers"""
  590. layerCommand = gcmd.Command(cmd=["v.db.connect",
  591. "-g", "--q",
  592. "map=%s" % self.map],
  593. rerr=None, stderr=None)
  594. if layerCommand.returncode == 0:
  595. layers = []
  596. for line in layerCommand.ReadStdOutput():
  597. lineList = line.split(' ')
  598. layers.append(int(lineList[0]))
  599. return layers
  600. return [1,]
  601. def Undo(self, level=-1):
  602. """Undo not implemented here"""
  603. wx.MessageBox(parent=self.mapWindow, message=_("Undo is not implemented in vedit component. "
  604. "Use vdigit instead."),
  605. caption=_("Message"), style=wx.ID_OK | wx.ICON_INFORMATION | wx.CENTRE)
  606. class VDigit(AbstractDigit):
  607. """
  608. Prototype of digitization class based on v.digit reimplementation
  609. Under development (wxWidgets C/C++ background)
  610. """
  611. def __init__(self, mapwindow):
  612. """Initialization
  613. @param mapwindow reference to mapwindow (MapFrame) instance
  614. @param settings initial settings of digitization tool
  615. """
  616. AbstractDigit.__init__(self, mapwindow)
  617. try:
  618. self.digit = wxvdigit.Digit(self.driver.GetDevice())
  619. except (ImportError, NameError):
  620. self.digit = None
  621. self.toolbar = mapwindow.parent.toolbars['vdigit']
  622. def __del__(self):
  623. del self.digit
  624. def AddPoint (self, map, point, x, y, z=None):
  625. """Add new point/centroid
  626. @param map map name (unused, for compatability with VEdit)
  627. @param point feature type (if true point otherwise centroid)
  628. @param x,y,z coordinates
  629. """
  630. if UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection') == 2:
  631. layer = -1 # -> no category
  632. cat = -1
  633. else:
  634. layer = UserSettings.Get(group='vdigit', key="layer", subkey='value')
  635. cat = self.SetCategory()
  636. if point:
  637. type = wxvdigit.GV_POINT
  638. else:
  639. type = wxvdigit.GV_CENTROID
  640. snap, thresh = self.__getSnapThreshold()
  641. if z:
  642. ret = self.digit.AddLine(type, [x, y, z], layer, cat,
  643. str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
  644. else:
  645. ret = self.digit.AddLine(type, [x, y], layer, cat,
  646. str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
  647. if ret == -1:
  648. raise gcmd.DigitError, _("Adding new feature to vector map <%s> failed.") % map
  649. self.toolbar.EnableUndo()
  650. def AddLine (self, map, line, coords):
  651. """Add line/boundary
  652. @param map map name (unused, for compatability with VEdit)
  653. @param line feature type (if True line, otherwise boundary)
  654. @param coords list of coordinates
  655. """
  656. if len(coords) < 2:
  657. return
  658. if UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection') == 2:
  659. layer = -1 # -> no category
  660. cat = -1
  661. else:
  662. layer = UserSettings.Get(group='vdigit', key="layer", subkey='value')
  663. cat = self.SetCategory()
  664. if line:
  665. type = wxvdigit.GV_LINE
  666. else:
  667. type = wxvdigit.GV_BOUNDARY
  668. listCoords = []
  669. for c in coords:
  670. for x in c:
  671. listCoords.append(x)
  672. snap, thresh = self.__getSnapThreshold()
  673. ret = self.digit.AddLine(type, listCoords, layer, cat,
  674. str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
  675. if ret == -1:
  676. raise gcmd.DigitError, _("Adding new feature to vector map <%s> failed.") % map
  677. self.toolbar.EnableUndo()
  678. def DeleteSelectedLines(self):
  679. """Delete selected features
  680. @return number of deleted lines
  681. """
  682. nlines = self.digit.DeleteLines(UserSettings.Get(group='vdigit', key='delRecord', subkey='enabled'))
  683. if nlines > 0:
  684. self.toolbar.EnableUndo()
  685. return nlines
  686. def MoveSelectedLines(self, move):
  687. """Move selected features
  688. @param move direction (x, y)
  689. """
  690. snap, thresh = self.__getSnapThreshold()
  691. nlines = self.digit.MoveLines(move[0], move[1], 0.0, # TODO 3D
  692. str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
  693. if nlines > 0:
  694. self.toolbar.EnableUndo()
  695. return nlines
  696. def MoveSelectedVertex(self, coords, move):
  697. """Move selected vertex of the line
  698. @param coords click coordinates
  699. @param move X,Y direction
  700. @return 1 vertex moved
  701. @return 0 vertex not moved (not found, line is not selected)
  702. """
  703. snap, thresh = self.__getSnapThreshold()
  704. moved = self.digit.MoveVertex(coords[0], coords[1], 0.0, # TODO 3D
  705. move[0], move[1], 0.0,
  706. str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap,
  707. self.driver.GetThreshold(type='selectThresh'), thresh)
  708. if moved:
  709. self.toolbar.EnableUndo()
  710. return moved
  711. def AddVertex(self, coords):
  712. """Add new vertex to the selected line/boundary on position 'coords'
  713. @param coords coordinates to add vertex
  714. @return 1 vertex added
  715. @return 0 nothing changed
  716. @return -1 on failure
  717. """
  718. added = self.digit.ModifyLineVertex(1, coords[0], coords[1], 0.0, # TODO 3D
  719. self.driver.GetThreshold(type='selectThresh'))
  720. if added > 0:
  721. self.toolbar.EnableUndo()
  722. return added
  723. def RemoveVertex(self, coords):
  724. """Remove vertex from the selected line/boundary on position 'coords'
  725. @param coords coordinates to remove vertex
  726. @return 1 vertex removed
  727. @return 0 nothing changed
  728. @return -1 on failure
  729. """
  730. deleted = self.digit.ModifyLineVertex(0, coords[0], coords[1], 0.0, # TODO 3D
  731. self.driver.GetThreshold(type='selectThresh'))
  732. if deleted > 0:
  733. self.toolbar.EnableUndo()
  734. return deleted
  735. def SplitLine(self, coords):
  736. """Split selected line/boundary on position 'coords'
  737. @param coords coordinates to split line
  738. @return 1 line modified
  739. @return 0 nothing changed
  740. @return -1 error
  741. """
  742. ret = self.digit.SplitLine(coords[0], coords[1], 0.0, # TODO 3D
  743. self.driver.GetThreshold('selectThresh'))
  744. if ret > 0:
  745. self.toolbar.EnableUndo()
  746. return ret
  747. def EditLine(self, line, coords):
  748. """Edit existing line/boundary
  749. @param line id of line to be modified
  750. @param coords list of coordinates of modified line
  751. @return feature id of new line
  752. @return -1 on error
  753. """
  754. try:
  755. lineid = line[0]
  756. except:
  757. lineid = -1
  758. if len(coords) < 2:
  759. self.DeleteSelectedLines()
  760. return 0
  761. listCoords = []
  762. for c in coords:
  763. for x in c:
  764. listCoords.append(x)
  765. snap, thresh = self.__getSnapThreshold()
  766. ret = self.digit.RewriteLine(lineid, listCoords,
  767. str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
  768. if ret > 0:
  769. self.toolbar.EnableUndo()
  770. return ret
  771. def FlipLine(self):
  772. """Flip selected lines/boundaries
  773. @return number of modified lines
  774. @return -1 on error
  775. """
  776. ret = self.digit.FlipLines()
  777. if ret > 0:
  778. self.toolbar.EnableUndo()
  779. return ret
  780. def MergeLine(self):
  781. """Merge selected lines/boundaries
  782. @return number of modified lines
  783. @return -1 on error
  784. """
  785. ret = self.digit.MergeLines()
  786. if ret > 0:
  787. self.toolbar.EnableUndo()
  788. return ret
  789. def BreakLine(self):
  790. """Break selected lines/boundaries
  791. @return number of modified lines
  792. @return -1 on error
  793. """
  794. ret = self.digit.BreakLines()
  795. if ret > 0:
  796. self.toolbar.EnableUndo()
  797. return ret
  798. def SnapLine(self):
  799. """Snap selected lines/boundaries
  800. @return on success
  801. @return -1 on error
  802. """
  803. snap, thresh = self.__getSnapThreshold()
  804. ret = self.digit.SnapLines(thresh)
  805. if ret == 0:
  806. self.toolbar.EnableUndo()
  807. return ret
  808. def ConnectLine(self):
  809. """Connect selected lines/boundaries
  810. @return 1 lines connected
  811. @return 0 lines not connected
  812. @return -1 on error
  813. """
  814. snap, thresh = self.__getSnapThreshold()
  815. ret = self.digit.ConnectLines(thresh)
  816. if ret > 0:
  817. self.toolbar.EnableUndo()
  818. return ret
  819. def CopyLine(self, ids=None):
  820. """Copy features from (background) vector map
  821. @param ids list of line ids to be copied
  822. @return number of copied features
  823. @return -1 on error
  824. """
  825. ret = self.digit.CopyLines(ids, str(UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value')))
  826. if ret > 0:
  827. self.toolbar.EnableUndo()
  828. return ret
  829. def CopyCats(self, cats, ids):
  830. """Copy given categories to objects with id listed in ids
  831. @param cats list of cats to be copied
  832. @param ids ids of lines to be modified
  833. @return number of modified features
  834. @return -1 on error
  835. """
  836. if len(cats) == 0 or len(ids) == 0:
  837. return 0
  838. ret = self.digit.CopyCats(cats, ids)
  839. if ret > 0:
  840. self.toolbar.EnableUndo()
  841. return ret
  842. def SelectLinesByQuery(self, pos1, pos2):
  843. """Select features by query
  844. @param pos1, pos2 bounding box definition
  845. """
  846. thresh = self.SelectLinesByQueryThresh()
  847. w, n = pos1
  848. e, s = pos2
  849. query = wxvdigit.QUERY_UNKNOWN
  850. if UserSettings.Get(group='vdigit', key='query', subkey='selection') == 0:
  851. query = wxvdigit.QUERY_LENGTH
  852. else:
  853. query = wxvdigit.QUERY_DANGLE
  854. type = wxvdigit.GV_POINTS | wxvdigit.GV_LINES # TODO: 3D
  855. ids = self.digit.SelectLinesByQuery(w, n, 0.0, e, s, 1000.0,
  856. UserSettings.Get(group='vdigit', key='query', subkey='box'),
  857. query, type, thresh)
  858. Debug.msg(4, "VDigit.SelectLinesByQuery(): %s" % \
  859. ",".join(["%d" % v for v in ids]))
  860. return ids
  861. def GetLineCats(self, line=-1):
  862. """Get layer/category pairs from given (selected) line
  863. @param line feature id (-1 for first selected line)
  864. """
  865. return self.digit.GetLineCats(line)
  866. def SetLineCats(self, line, layer, cats, add=True):
  867. """Set categories for given line and layer
  868. @param line feature id
  869. @param layer layer number (-1 for first selected line)
  870. @param cats list of categories
  871. @param add if True to add, otherwise do delete categories
  872. @return new feature id (feature need to be rewritten)
  873. @return -1 on error
  874. """
  875. ret = self.digit.SetLineCats(line, layer, cats, add)
  876. if ret > 0:
  877. self.toolbar.EnableUndo()
  878. return ret
  879. def GetLayers(self):
  880. """Get list of layers"""
  881. return self.digit.GetLayers()
  882. def TypeConvForSelectedLines(self):
  883. """Feature type conversion for selected objects.
  884. Supported conversions:
  885. - point <-> centroid
  886. - line <-> boundary
  887. @return number of modified features
  888. @return -1 on error
  889. """
  890. ret = self.digit.TypeConvLines()
  891. if ret > 0:
  892. self.toolbar.EnableUndo()
  893. return ret
  894. def Undo(self, level=-1):
  895. """Undo action
  896. @param level levels to undo (0 to revert all)
  897. @return id of current changeset
  898. """
  899. try:
  900. ret = self.digit.Undo(level)
  901. except SystemExit:
  902. ret = -2
  903. if ret == -2:
  904. raise gcmd.DigitError, _("Undo failed, data corrupted.")
  905. self.mapWindow.UpdateMap(render=False)
  906. if ret < 0: # disable undo tool
  907. self.toolbar.EnableUndo(False)
  908. def GetUndoLevel(self):
  909. """Get undo level (number of active changesets)"""
  910. return self.digit.GetUndoLevel()
  911. def __getSnapThreshold(self):
  912. """Get snap mode and threshold value
  913. @return (snap, thresh)
  914. """
  915. thresh = self.driver.GetThreshold()
  916. if thresh > 0.0:
  917. if UserSettings.Get(group='vdigit', key='snapToVertex', subkey='enabled') is True:
  918. snap = wxvdigit.SNAPVERTEX
  919. else:
  920. snap = wxvdigit.SNAP
  921. else:
  922. snap = wxvdigit.NO_SNAP
  923. return (snap, thresh)
  924. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') == 'vedit':
  925. class Digit(VEdit):
  926. """Default digit class"""
  927. def __init__(self, mapwindow):
  928. VEdit.__init__(self, mapwindow)
  929. self.type = 'vedit'
  930. else:
  931. class Digit(VDigit):
  932. """Default digit class"""
  933. def __init__(self, mapwindow):
  934. VDigit.__init__(self, mapwindow)
  935. self.type = 'vdigit'
  936. def __del__(self):
  937. VDigit.__del__(self)
  938. class AbstractDisplayDriver:
  939. """Abstract classs for display driver"""
  940. def __init__(self, parent, mapwindow):
  941. """Initialization
  942. @param parent
  943. @param mapwindow reference to mapwindow (MFrame)
  944. """
  945. self.parent = parent
  946. self.mapwindow = mapwindow
  947. self.ids = {} # dict[g6id] = [pdcId]
  948. self.selected = [] # list of selected objects (grassId!)
  949. def GetThreshold(self, type='snapping', value=None, units=None):
  950. """Return threshold in map units
  951. @param value threshold to be set up
  952. @param units units (map, screen)
  953. """
  954. if value is None:
  955. value = UserSettings.Get(group='vdigit', key=type, subkey='value')
  956. if units is None:
  957. units = UserSettings.Get(group='vdigit', key=type, subkey='units')
  958. if units == "screen pixels":
  959. # pixel -> cell
  960. reg = self.mapwindow.Map.region
  961. if reg['nsres'] > reg['ewres']:
  962. res = reg['nsres']
  963. else:
  964. res = reg['ewres']
  965. threshold = value * res
  966. else:
  967. threshold = value
  968. Debug.msg(4, "AbstractDisplayDriver.GetThreshold(): type=%s, thresh=%f" % (type, threshold))
  969. return threshold
  970. class CDisplayDriver(AbstractDisplayDriver):
  971. """
  972. Display driver using grass6_wxdriver module
  973. """
  974. def __init__(self, parent, mapwindow):
  975. """Initialization
  976. @param parent
  977. @param mapwindow reference to mapwindow (MFrame)
  978. """
  979. AbstractDisplayDriver.__init__(self, parent, mapwindow)
  980. self.mapWindow = mapwindow
  981. # initialize wx display driver
  982. try:
  983. self.__display = wxvdigit.DisplayDriver(mapwindow.pdcVector)
  984. except:
  985. self.__display = None
  986. self.UpdateSettings()
  987. def GetDevice(self):
  988. """Get device"""
  989. return self.__display
  990. def SetDevice(self, pdc):
  991. """Set device for driver
  992. @param pdc wx.PseudoDC instance
  993. """
  994. self.__display.SetDevice(pdc)
  995. def Reset(self, map):
  996. """Reset map
  997. Open or close the vector map by driver.
  998. @param map map name or None to close the map
  999. @return 0 on success (close map)
  1000. @return topo level on success (open map)
  1001. @return non-zero (close map)
  1002. @return -1 on error (open map)
  1003. """
  1004. if map:
  1005. name, mapset = map.split('@')
  1006. try:
  1007. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') == 'vedit':
  1008. ret = self.__display.OpenMap(str(name), str(mapset), False)
  1009. else:
  1010. ret = self.__display.OpenMap(str(name), str(mapset), True)
  1011. except SystemExit:
  1012. ret = -1
  1013. else:
  1014. ret = self.__display.CloseMap()
  1015. return ret
  1016. def ReloadMap(self):
  1017. """Reload map (close and re-open).
  1018. Needed for v.edit, TODO: get rid of that..."""
  1019. Debug.msg(4, "CDisplayDriver.ReloadMap():")
  1020. self.__display.ReloadMap()
  1021. def DrawMap(self):
  1022. """Draw vector map layer content
  1023. @return wx.Image instance
  1024. """
  1025. nlines = self.__display.DrawMap(True) # force
  1026. Debug.msg(3, "CDisplayDriver.DrawMap(): nlines=%d" % nlines)
  1027. return nlines
  1028. def SelectLinesByBox(self, begin, end, type=0):
  1029. """Select vector features by given bounding box.
  1030. If type is given, only vector features of given type are selected.
  1031. @param begin,end bounding box definition
  1032. @param type select only objects of given type
  1033. """
  1034. x1, y1 = begin
  1035. x2, y2 = end
  1036. nselected = self.__display.SelectLinesByBox(x1, y1, -1.0 * wxvdigit.PORT_DOUBLE_MAX,
  1037. x2, y2, wxvdigit.PORT_DOUBLE_MAX,
  1038. type)
  1039. Debug.msg(4, "CDisplayDriver.SelectLinesByBox(): selected=%d" % \
  1040. nselected)
  1041. return nselected
  1042. def SelectLineByPoint(self, point, type=0):
  1043. """Select vector feature by coordinates of click point (in given threshold).
  1044. If type is given, only vector features of given type are selected.
  1045. @param point click coordinates (bounding box given by threshold)
  1046. @param type select only objects of given type
  1047. """
  1048. pointOnLine = self.__display.SelectLineByPoint(point[0], point[1], 0.0,
  1049. self.GetThreshold(type='selectThresh'),
  1050. type, 0); # without_z
  1051. if len(pointOnLine) > 0:
  1052. Debug.msg(4, "CDisplayDriver.SelectLineByPoint(): pointOnLine=%f,%f" % \
  1053. (pointOnLine[0], pointOnLine[1]))
  1054. return pointOnLine
  1055. else:
  1056. Debug.msg(4, "CDisplayDriver.SelectLineByPoint(): no line found")
  1057. return None
  1058. def GetSelected(self, grassId=True):
  1059. """Return ids of selected vector features
  1060. @param grassId if grassId is True returns GRASS ids, otherwise
  1061. internal ids of objects drawn in PseudoDC"""
  1062. if grassId:
  1063. selected = self.__display.GetSelected(True)
  1064. else:
  1065. selected = self.__display.GetSelected(False)
  1066. Debug.msg(4, "CDisplayDriver.GetSelected(): grassId=%d, ids=%s" % \
  1067. (grassId, (",".join(["%d" % v for v in selected]))))
  1068. return selected
  1069. def GetDuplicates(self):
  1070. """Return ids of (selected) duplicated vector features
  1071. """
  1072. # -> id : (list of ids)
  1073. dupl = dict(self.__display.GetDuplicates())
  1074. vdigitComp = UserSettings.Get(group='advanced', key='digitInterface', subkey='type')
  1075. # -> id : ((id, cat), ...)
  1076. dupl_full = {}
  1077. for key in dupl.keys():
  1078. dupl_full[key] = []
  1079. for id in dupl[key]:
  1080. catStr = ''
  1081. # categories not supported for v.edit !
  1082. if vdigitComp == 'vdigit':
  1083. cats = self.parent.GetLineCats(line=id)
  1084. for layer in cats.keys():
  1085. if len(cats[layer]) > 0:
  1086. catStr = "%d: (" % layer
  1087. for cat in cats[layer]:
  1088. catStr += "%d," % cat
  1089. catStr = catStr.rstrip(',')
  1090. catStr += ')'
  1091. dupl_full[key].append([id, catStr])
  1092. return dupl_full
  1093. def GetSelectedVertex(self, coords):
  1094. """Get PseudoDC id(s) of vertex (of selected line)
  1095. on position 'coords'
  1096. @param coords click position
  1097. """
  1098. x, y = coords
  1099. id = self.__display.GetSelectedVertex(x, y, self.GetThreshold(type='selectThresh'))
  1100. Debug.msg(4, "CDisplayDriver.GetSelectedVertex(): id=%s" % \
  1101. (",".join(["%d" % v for v in id])))
  1102. return id
  1103. def SetSelected(self, id):
  1104. """Set selected vector features
  1105. @param id line id to be selected
  1106. """
  1107. Debug.msg(4, "CDisplayDriver.SetSelected(): id=%s" % \
  1108. ",".join(["%d" % v for v in id]))
  1109. self.__display.SetSelected(id)
  1110. def UnSelect(self, id):
  1111. """Unselect vector features
  1112. @param id list of feature id(s)
  1113. """
  1114. Debug.msg(4, "CDisplayDriver.UnSelect(): id=%s" % \
  1115. ",".join(["%d" % v for v in id]))
  1116. self.__display.UnSelect(id)
  1117. def UpdateRegion(self):
  1118. """Set geographical region
  1119. Needed for 'cell2pixel' conversion"""
  1120. map = self.mapwindow.Map
  1121. reg = map.region
  1122. self.__display.SetRegion(reg['n'],
  1123. reg['s'],
  1124. reg['e'],
  1125. reg['w'],
  1126. reg['nsres'],
  1127. reg['ewres'],
  1128. reg['center_easting'],
  1129. reg['center_northing'],
  1130. map.width, map.height)
  1131. def GetMapBoundingBox(self):
  1132. """Return bounding box of given vector map layer
  1133. @return (w,s,b,e,n,t)
  1134. """
  1135. return self.__display.GetMapBoundingBox()
  1136. def DrawSelected(self, draw=True):
  1137. """Show/hide selected features"""
  1138. self.__display.DrawSelected(draw)
  1139. def UpdateSettings(self):
  1140. """Update display driver settings"""
  1141. # TODO map units
  1142. if not self.__display:
  1143. return
  1144. self.__display.UpdateSettings (wx.Color(UserSettings.Get(group='vdigit', key='symbolHighlight', subkey='color')[0],
  1145. UserSettings.Get(group='vdigit', key='symbolHighlight', subkey='color')[1],
  1146. UserSettings.Get(group='vdigit', key='symbolHighlight', subkey='color')[2],
  1147. 255).GetRGB(),
  1148. UserSettings.Get(group='vdigit', key='checkForDupl', subkey='enabled'),
  1149. wx.Color(UserSettings.Get(group='vdigit', key='symbolHighlightDupl', subkey='color')[0],
  1150. UserSettings.Get(group='vdigit', key='symbolHighlightDupl', subkey='color')[1],
  1151. UserSettings.Get(group='vdigit', key='symbolHighlightDupl', subkey='color')[2],
  1152. 255).GetRGB(),
  1153. UserSettings.Get(group='vdigit', key='symbolPoint', subkey='enabled'),
  1154. wx.Color(UserSettings.Get(group='vdigit', key='symbolPoint', subkey='color')[0],
  1155. UserSettings.Get(group='vdigit', key='symbolPoint', subkey='color')[1],
  1156. UserSettings.Get(group='vdigit', key='symbolPoint', subkey='color')[2],
  1157. 255).GetRGB(),
  1158. UserSettings.Get(group='vdigit', key='symbolLine', subkey='enabled'),
  1159. wx.Color(UserSettings.Get(group='vdigit', key='symbolLine', subkey='color')[0],
  1160. UserSettings.Get(group='vdigit', key='symbolLine', subkey='color')[1],
  1161. UserSettings.Get(group='vdigit', key='symbolLine', subkey='color')[2],
  1162. 255).GetRGB(),
  1163. UserSettings.Get(group='vdigit', key='symbolBoundaryNo', subkey='enabled'),
  1164. wx.Color(UserSettings.Get(group='vdigit', key='symbolBoundaryNo', subkey='color')[0],
  1165. UserSettings.Get(group='vdigit', key='symbolBoundaryNo', subkey='color')[1],
  1166. UserSettings.Get(group='vdigit', key='symbolBoundaryNo', subkey='color')[2],
  1167. 255).GetRGB(),
  1168. UserSettings.Get(group='vdigit', key='symbolBoundaryOne', subkey='enabled'),
  1169. wx.Color(UserSettings.Get(group='vdigit', key='symbolBoundaryOne', subkey='color')[0],
  1170. UserSettings.Get(group='vdigit', key='symbolBoundaryOne', subkey='color')[1],
  1171. UserSettings.Get(group='vdigit', key='symbolBoundaryOne', subkey='color')[2],
  1172. 255).GetRGB(),
  1173. UserSettings.Get(group='vdigit', key='symbolBoundaryTwo', subkey='enabled'),
  1174. wx.Color(UserSettings.Get(group='vdigit', key='symbolBoundaryTwo', subkey='color')[0],
  1175. UserSettings.Get(group='vdigit', key='symbolBoundaryTwo', subkey='color')[1],
  1176. UserSettings.Get(group='vdigit', key='symbolBoundaryTwo', subkey='color')[2],
  1177. 255).GetRGB(),
  1178. UserSettings.Get(group='vdigit', key='symbolCentroidIn', subkey='enabled'),
  1179. wx.Color(UserSettings.Get(group='vdigit', key='symbolCentroidIn', subkey='color')[0],
  1180. UserSettings.Get(group='vdigit', key='symbolCentroidIn', subkey='color')[1],
  1181. UserSettings.Get(group='vdigit', key='symbolCentroidIn', subkey='color')[2],
  1182. 255).GetRGB(),
  1183. UserSettings.Get(group='vdigit', key='symbolCentroidOut', subkey='enabled'),
  1184. wx.Color(UserSettings.Get(group='vdigit', key='symbolCentroidOut', subkey='color')[0],
  1185. UserSettings.Get(group='vdigit', key='symbolCentroidOut', subkey='color')[1],
  1186. UserSettings.Get(group='vdigit', key='symbolCentroidOut', subkey='color')[2],
  1187. 255).GetRGB(),
  1188. UserSettings.Get(group='vdigit', key='symbolCentroidDup', subkey='enabled'),
  1189. wx.Color(UserSettings.Get(group='vdigit', key='symbolCentroidDup', subkey='color')[0],
  1190. UserSettings.Get(group='vdigit', key='symbolCentroidDup', subkey='color')[1],
  1191. UserSettings.Get(group='vdigit', key='symbolCentroidDup', subkey='color')[2],
  1192. 255).GetRGB(),
  1193. UserSettings.Get(group='vdigit', key='symbolNodeOne', subkey='enabled'),
  1194. wx.Color(UserSettings.Get(group='vdigit', key='symbolNodeOne', subkey='color')[0],
  1195. UserSettings.Get(group='vdigit', key='symbolNodeOne', subkey='color')[1],
  1196. UserSettings.Get(group='vdigit', key='symbolNodeOne', subkey='color')[2],
  1197. 255).GetRGB(),
  1198. UserSettings.Get(group='vdigit', key='symbolNodeTwo', subkey='enabled'),
  1199. wx.Color(UserSettings.Get(group='vdigit', key='symbolNodeTwo', subkey='color')[0],
  1200. UserSettings.Get(group='vdigit', key='symbolNodeTwo', subkey='color')[1],
  1201. UserSettings.Get(group='vdigit', key='symbolNodeTwo', subkey='color')[2],
  1202. 255).GetRGB(),
  1203. UserSettings.Get(group='vdigit', key='symbolVertex', subkey='enabled'),
  1204. wx.Color(UserSettings.Get(group='vdigit', key='symbolVertex', subkey='color')[0],
  1205. UserSettings.Get(group='vdigit', key='symbolVertex', subkey='color')[1],
  1206. UserSettings.Get(group='vdigit', key='symbolVertex', subkey='color')[2],
  1207. 255).GetRGB(),
  1208. UserSettings.Get(group='vdigit', key='symbolArea', subkey='enabled'),
  1209. wx.Color(UserSettings.Get(group='vdigit', key='symbolArea', subkey='color')[0],
  1210. UserSettings.Get(group='vdigit', key='symbolArea', subkey='color')[1],
  1211. UserSettings.Get(group='vdigit', key='symbolArea', subkey='color')[2],
  1212. 255).GetRGB(),
  1213. UserSettings.Get(group='vdigit', key='symbolDirection', subkey='enabled'),
  1214. wx.Color(UserSettings.Get(group='vdigit', key='symbolDirection', subkey='color')[0],
  1215. UserSettings.Get(group='vdigit', key='symbolDirection', subkey='color')[1],
  1216. UserSettings.Get(group='vdigit', key='symbolDirection', subkey='color')[2],
  1217. 255).GetRGB(),
  1218. UserSettings.Get(group='vdigit', key='lineWidth', subkey='value'))
  1219. class VDigitSettingsDialog(wx.Dialog):
  1220. """
  1221. Standard settings dialog for digitization purposes
  1222. """
  1223. def __init__(self, parent, title, style=wx.DEFAULT_DIALOG_STYLE):
  1224. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
  1225. self.parent = parent # mapdisplay.BufferedWindow class instance
  1226. # notebook
  1227. notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  1228. self.__CreateSymbologyPage(notebook)
  1229. parent.digit.SetCategory() # update category number (next to use)
  1230. self.__CreateGeneralPage(notebook)
  1231. self.__CreateAttributesPage(notebook)
  1232. self.__CreateQueryPage(notebook)
  1233. # buttons
  1234. btnApply = wx.Button(self, wx.ID_APPLY)
  1235. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1236. btnSave = wx.Button(self, wx.ID_SAVE)
  1237. btnSave.SetDefault()
  1238. # bindigs
  1239. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1240. btnApply.SetToolTipString(_("Apply changes for this session"))
  1241. btnApply.SetDefault()
  1242. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1243. btnSave.SetToolTipString(_("Close dialog and save changes to user settings file"))
  1244. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  1245. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  1246. # sizers
  1247. btnSizer = wx.StdDialogButtonSizer()
  1248. btnSizer.AddButton(btnCancel)
  1249. btnSizer.AddButton(btnApply)
  1250. btnSizer.AddButton(btnSave)
  1251. btnSizer.Realize()
  1252. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1253. mainSizer.Add(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  1254. mainSizer.Add(item=btnSizer, proportion=0,
  1255. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  1256. self.SetSizer(mainSizer)
  1257. mainSizer.Fit(self)
  1258. def __CreateSymbologyPage(self, notebook):
  1259. """Create notebook page concerning with symbology settings"""
  1260. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1261. notebook.AddPage(page=panel, text=_("Symbology"))
  1262. sizer = wx.BoxSizer(wx.VERTICAL)
  1263. flexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
  1264. flexSizer.AddGrowableCol(0)
  1265. self.symbology = {}
  1266. for label, key in self.__SymbologyData():
  1267. textLabel = wx.StaticText(panel, wx.ID_ANY, label)
  1268. color = csel.ColourSelect(panel, id=wx.ID_ANY,
  1269. colour=UserSettings.Get(group='vdigit', key=key, subkey='color'), size=(25, 25))
  1270. isEnabled = UserSettings.Get(group='vdigit', key=key, subkey='enabled')
  1271. if isEnabled is not None:
  1272. enabled = wx.CheckBox(panel, id=wx.ID_ANY, label="")
  1273. enabled.SetValue(isEnabled)
  1274. self.symbology[key] = (enabled, color)
  1275. else:
  1276. enabled = (1, 1)
  1277. self.symbology[key] = (None, color)
  1278. flexSizer.Add(textLabel, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1279. flexSizer.Add(enabled, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1280. flexSizer.Add(color, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1281. sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=10)
  1282. panel.SetSizer(sizer)
  1283. return panel
  1284. def __CreateGeneralPage(self, notebook):
  1285. """Create notebook page concerning with symbology settings"""
  1286. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1287. notebook.AddPage(page=panel, text=_("General"))
  1288. border = wx.BoxSizer(wx.VERTICAL)
  1289. #
  1290. # display section
  1291. #
  1292. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Display"))
  1293. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1294. flexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
  1295. flexSizer.AddGrowableCol(0)
  1296. # line width
  1297. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width"))
  1298. self.lineWidthValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(75, -1),
  1299. initial=UserSettings.Get(group='vdigit', key="lineWidth", subkey='value'),
  1300. min=1, max=1e6)
  1301. units = wx.StaticText(parent=panel, id=wx.ID_ANY, size=(115, -1),
  1302. label=UserSettings.Get(group='vdigit', key="lineWidth", subkey='units'),
  1303. style=wx.ALIGN_LEFT)
  1304. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1305. flexSizer.Add(self.lineWidthValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1306. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  1307. border=10)
  1308. sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=1)
  1309. border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  1310. #
  1311. # snapping section
  1312. #
  1313. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Snapping"))
  1314. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1315. flexSizer1 = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
  1316. flexSizer1.AddGrowableCol(0)
  1317. flexSizer2 = wx.FlexGridSizer (cols=2, hgap=5, vgap=5)
  1318. flexSizer2.AddGrowableCol(0)
  1319. # snapping
  1320. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Snapping threshold"))
  1321. self.snappingValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(75, -1),
  1322. initial=UserSettings.Get(group='vdigit', key="snapping", subkey='value'),
  1323. min=0, max=1e6)
  1324. self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue)
  1325. self.snappingUnit = wx.Choice(parent=panel, id=wx.ID_ANY, size=(125, -1),
  1326. choices=["screen pixels", "map units"])
  1327. self.snappingUnit.SetStringSelection(UserSettings.Get(group='vdigit', key="snapping", subkey='units'))
  1328. self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits)
  1329. flexSizer1.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1330. flexSizer1.Add(self.snappingValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1331. flexSizer1.Add(self.snappingUnit, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1332. # background map
  1333. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Background vector map"))
  1334. self.backgroundMap = gselect.Select(parent=panel, id=wx.ID_ANY, size=(200,-1),
  1335. type="vector", exceptOf=[self.parent.digit.map])
  1336. self.backgroundMap.SetValue(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value'))
  1337. self.backgroundMap.Bind(wx.EVT_TEXT, self.OnChangeBackgroundMap)
  1338. flexSizer2.Add(text, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL)
  1339. flexSizer2.Add(self.backgroundMap, proportion=1, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1340. #flexSizer.Add(self.snappingUnit, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1341. vertexSizer = wx.BoxSizer(wx.VERTICAL)
  1342. self.snapVertex = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1343. label=_("Snap also to vertex"))
  1344. self.snapVertex.SetValue(UserSettings.Get(group='vdigit', key="snapToVertex", subkey='enabled'))
  1345. vertexSizer.Add(item=self.snapVertex, proportion=0, flag=wx.EXPAND)
  1346. self.mapUnits = self.parent.MapWindow.Map.ProjInfo()['units']
  1347. self.snappingInfo = wx.StaticText(parent=panel, id=wx.ID_ANY,
  1348. label=_("Snapping threshold is %(value).1f %(units)s") % \
  1349. {'value' : self.parent.digit.driver.GetThreshold(),
  1350. 'units' : self.mapUnits})
  1351. vertexSizer.Add(item=self.snappingInfo, proportion=0,
  1352. flag=wx.ALL | wx.EXPAND, border=1)
  1353. sizer.Add(item=flexSizer1, proportion=1, flag=wx.TOP | wx.LEFT | wx.EXPAND, border=1)
  1354. sizer.Add(item=flexSizer2, proportion=1, flag=wx.TOP | wx.LEFT | wx.EXPAND, border=1)
  1355. sizer.Add(item=vertexSizer, proportion=1, flag=wx.BOTTOM | wx.LEFT | wx.EXPAND, border=1)
  1356. border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  1357. #
  1358. # select box
  1359. #
  1360. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Select vector features"))
  1361. # feature type
  1362. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1363. inSizer = wx.BoxSizer(wx.HORIZONTAL)
  1364. self.selectFeature = {}
  1365. for feature in ('Point', 'Line',
  1366. 'Centroid', 'Boundary'):
  1367. chkbox = wx.CheckBox(parent=panel, label=feature)
  1368. self.selectFeature[feature] = chkbox.GetId()
  1369. chkbox.SetValue(UserSettings.Get(group='vdigit', key='selectFeature'+feature, subkey='enabled'))
  1370. inSizer.Add(item=chkbox, proportion=0,
  1371. flag=wx.EXPAND | wx.ALL, border=5)
  1372. sizer.Add(item=inSizer, proportion=0, flag=wx.EXPAND)
  1373. # threshold
  1374. flexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
  1375. flexSizer.AddGrowableCol(0)
  1376. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select threshold"))
  1377. self.selectThreshValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(75, -1),
  1378. initial=UserSettings.Get(group='vdigit', key="selectThresh", subkey='value'),
  1379. min=1, max=1e6)
  1380. units = wx.StaticText(parent=panel, id=wx.ID_ANY, size=(115, -1),
  1381. label=UserSettings.Get(group='vdigit', key="lineWidth", subkey='units'),
  1382. style=wx.ALIGN_LEFT)
  1383. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1384. flexSizer.Add(self.selectThreshValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1385. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  1386. border=10)
  1387. self.checkForDupl = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1388. label=_("Check for duplicates"))
  1389. self.checkForDupl.SetValue(UserSettings.Get(group='vdigit', key="checkForDupl", subkey='enabled'))
  1390. flexSizer.Add(item=self.checkForDupl, proportion=0, flag=wx.EXPAND)
  1391. sizer.Add(item=flexSizer, proportion=0, flag=wx.EXPAND)
  1392. border.Add(item=sizer, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  1393. #
  1394. # save-on-exit box
  1395. #
  1396. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Save changes"))
  1397. # save changes on exit?
  1398. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1399. self.save = wx.CheckBox(parent=panel, label=_("Save changes on exit automatically"))
  1400. self.save.SetValue(UserSettings.Get(group='vdigit', key='saveOnExit', subkey='enabled'))
  1401. sizer.Add(item=self.save, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1402. border.Add(item=sizer, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  1403. panel.SetSizer(border)
  1404. return panel
  1405. def __CreateQueryPage(self, notebook):
  1406. """Create notebook page for query tool"""
  1407. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1408. notebook.AddPage(page=panel, text=_("Query tool"))
  1409. border = wx.BoxSizer(wx.VERTICAL)
  1410. #
  1411. # query tool box
  1412. #
  1413. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Choose query tool"))
  1414. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1415. LocUnits = self.parent.MapWindow.Map.ProjInfo()['units']
  1416. self.queryBox = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=_("Select by box"))
  1417. self.queryBox.SetValue(UserSettings.Get(group='vdigit', key="query", subkey='box'))
  1418. sizer.Add(item=self.queryBox, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1419. sizer.Add((0, 5))
  1420. #
  1421. # length
  1422. #
  1423. self.queryLength = wx.RadioButton(parent=panel, id=wx.ID_ANY, label=_("length"))
  1424. self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  1425. sizer.Add(item=self.queryLength, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1426. flexSizer = wx.FlexGridSizer (cols=4, hgap=5, vgap=5)
  1427. flexSizer.AddGrowableCol(0)
  1428. txt = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select lines"))
  1429. self.queryLengthSL = wx.Choice (parent=panel, id=wx.ID_ANY,
  1430. choices = [_("shorter than"), _("longer than")])
  1431. self.queryLengthSL.SetSelection(UserSettings.Get(group='vdigit', key="queryLength", subkey='than-selection'))
  1432. self.queryLengthValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(100, -1),
  1433. initial=1,
  1434. min=0, max=1e6)
  1435. self.queryLengthValue.SetValue(UserSettings.Get(group='vdigit', key="queryLength", subkey='thresh'))
  1436. units = wx.StaticText(parent=panel, id=wx.ID_ANY, label="%s" % LocUnits)
  1437. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1438. flexSizer.Add(self.queryLengthSL, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1439. flexSizer.Add(self.queryLengthValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1440. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1441. sizer.Add(item=flexSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1442. #
  1443. # dangle
  1444. #
  1445. self.queryDangle = wx.RadioButton(parent=panel, id=wx.ID_ANY, label=_("dangle"))
  1446. self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  1447. sizer.Add(item=self.queryDangle, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1448. flexSizer = wx.FlexGridSizer (cols=4, hgap=5, vgap=5)
  1449. flexSizer.AddGrowableCol(0)
  1450. txt = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select dangles"))
  1451. self.queryDangleSL = wx.Choice (parent=panel, id=wx.ID_ANY,
  1452. choices = [_("shorter than"), _("longer than")])
  1453. self.queryDangleSL.SetSelection(UserSettings.Get(group='vdigit', key="queryDangle", subkey='than-selection'))
  1454. self.queryDangleValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(100, -1),
  1455. initial=1,
  1456. min=0, max=1e6)
  1457. self.queryDangleValue.SetValue(UserSettings.Get(group='vdigit', key="queryDangle", subkey='thresh'))
  1458. units = wx.StaticText(parent=panel, id=wx.ID_ANY, label="%s" % LocUnits)
  1459. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1460. flexSizer.Add(self.queryDangleSL, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1461. flexSizer.Add(self.queryDangleValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  1462. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1463. sizer.Add(item=flexSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1464. if UserSettings.Get(group='vdigit', key="query", subkey='selection') == 0:
  1465. self.queryLength.SetValue(True)
  1466. else:
  1467. self.queryDangle.SetValue(True)
  1468. # enable & disable items
  1469. self.OnChangeQuery(None)
  1470. border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  1471. panel.SetSizer(border)
  1472. return panel
  1473. def __CreateAttributesPage(self, notebook):
  1474. """Create notebook page for query tool"""
  1475. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1476. notebook.AddPage(page=panel, text=_("Attributes"))
  1477. border = wx.BoxSizer(wx.VERTICAL)
  1478. #
  1479. # add new record
  1480. #
  1481. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Digitize new feature"))
  1482. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1483. # checkbox
  1484. self.addRecord = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1485. label=_("Add new record into table"))
  1486. self.addRecord.SetValue(UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled'))
  1487. sizer.Add(item=self.addRecord, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1488. # settings
  1489. flexSizer = wx.FlexGridSizer(cols=2, hgap=3, vgap=3)
  1490. flexSizer.AddGrowableCol(0)
  1491. settings = ((_("Layer"), 1), (_("Category"), 1), (_("Mode"), _("Next to use")))
  1492. # layer
  1493. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Layer"))
  1494. if self.parent.digit.map:
  1495. layers = map(str, self.parent.digit.GetLayers())
  1496. if len(layers) == 0:
  1497. layers = [str(UserSettings.Get(group='vdigit', key="layer", subkey='value')), ]
  1498. else:
  1499. layers = [str(UserSettings.Get(group='vdigit', key="layer", subkey='value')), ]
  1500. self.layer = wx.Choice(parent=panel, id=wx.ID_ANY, size=(125, -1),
  1501. choices=layers)
  1502. self.layer.SetStringSelection(str(UserSettings.Get(group='vdigit', key="layer", subkey='value')))
  1503. flexSizer.Add(item=text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1504. flexSizer.Add(item=self.layer, proportion=0,
  1505. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  1506. # category number
  1507. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Category number"))
  1508. self.category = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(125, -1),
  1509. initial=UserSettings.Get(group='vdigit', key="category", subkey='value'),
  1510. min=-1e9, max=1e9)
  1511. if UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection') != 1:
  1512. self.category.Enable(False)
  1513. flexSizer.Add(item=text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1514. flexSizer.Add(item=self.category, proportion=0,
  1515. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  1516. # category mode
  1517. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Category mode"))
  1518. self.categoryMode = wx.Choice(parent=panel, id=wx.ID_ANY, size=(125, -1),
  1519. choices=[_("Next to use"), _("Manual entry"), _("No category")])
  1520. self.categoryMode.SetSelection(UserSettings.Get(group='vdigit', key="categoryMode", subkey='selection'))
  1521. flexSizer.Add(item=text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1522. flexSizer.Add(item=self.categoryMode, proportion=0,
  1523. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  1524. sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=1)
  1525. border.Add(item=sizer, proportion=0,
  1526. flag=wx.ALL | wx.EXPAND, border=5)
  1527. #
  1528. # delete existing record
  1529. #
  1530. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Delete existing feature(s)"))
  1531. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1532. # checkbox
  1533. self.deleteRecord = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1534. label=_("Delete record from table"))
  1535. self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled'))
  1536. sizer.Add(item=self.deleteRecord, proportion=0, flag=wx.ALL | wx.EXPAND, border=1)
  1537. border.Add(item=sizer, proportion=0,
  1538. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  1539. # bindings
  1540. self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord)
  1541. self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode)
  1542. self.Bind(wx.EVT_CHOICE, self.OnChangeLayer, self.layer)
  1543. panel.SetSizer(border)
  1544. return panel
  1545. def __SymbologyData(self):
  1546. """
  1547. Data for __CreateSymbologyPage()
  1548. label | checkbox | color
  1549. """
  1550. return (
  1551. # ("Background", "symbolBackground"),
  1552. (_("Highlight"), "symbolHighlight"),
  1553. (_("Highlight (duplicates)"), "symbolHighlightDupl"),
  1554. (_("Point"), "symbolPoint"),
  1555. (_("Line"), "symbolLine"),
  1556. (_("Boundary (no area)"), "symbolBoundaryNo"),
  1557. (_("Boundary (one area)"), "symbolBoundaryOne"),
  1558. (_("Boundary (two areas)"), "symbolBoundaryTwo"),
  1559. (_("Centroid (in area)"), "symbolCentroidIn"),
  1560. (_("Centroid (outside area)"), "symbolCentroidOut"),
  1561. (_("Centroid (duplicate in area)"), "symbolCentroidDup"),
  1562. (_("Node (one line)"), "symbolNodeOne"),
  1563. (_("Node (two lines)"), "symbolNodeTwo"),
  1564. (_("Vertex"), "symbolVertex"),
  1565. (_("Area (closed boundary + centroid)"), "symbolArea"),
  1566. (_("Direction"), "symbolDirection"),)
  1567. def OnChangeCategoryMode(self, event):
  1568. """Change category mode"""
  1569. mode = event.GetSelection()
  1570. UserSettings.Set(group='vdigit', key="categoryMode", subkey='selection', value=mode)
  1571. if mode == 1: # manual entry
  1572. self.category.Enable(True)
  1573. elif self.category.IsEnabled(): # disable
  1574. self.category.Enable(False)
  1575. if mode == 2 and self.addRecord.IsChecked(): # no category
  1576. self.addRecord.SetValue(False)
  1577. self.parent.digit.SetCategory()
  1578. self.category.SetValue(UserSettings.Get(group='vdigit', key='category', subkey='value'))
  1579. def OnChangeLayer(self, event):
  1580. """Layer changed"""
  1581. layer = int(event.GetString())
  1582. if layer > 0:
  1583. UserSettings.Set(group='vdigit', key='layer', subkey='value', value=layer)
  1584. self.parent.digit.SetCategory()
  1585. self.category.SetValue(UserSettings.Get(group='vdigit', key='category', subkey='value'))
  1586. event.Skip()
  1587. def OnChangeAddRecord(self, event):
  1588. """Checkbox 'Add new record' status changed"""
  1589. self.category.SetValue(self.parent.digit.SetCategory())
  1590. def OnChangeSnappingValue(self, event):
  1591. """Change snapping value - update static text"""
  1592. value = self.snappingValue.GetValue()
  1593. if self.snappingUnit.GetStringSelection() == "map units":
  1594. threshold = value
  1595. else:
  1596. threshold = self.parent.digit.driver.GetThreshold(value=value)
  1597. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") %
  1598. {'value' : threshold,
  1599. 'units' : self.mapUnits})
  1600. event.Skip()
  1601. def OnChangeSnappingUnits(self, event):
  1602. """Snapping units change -> update static text"""
  1603. value = self.snappingValue.GetValue()
  1604. units = self.snappingUnit.GetStringSelection()
  1605. threshold = self.parent.digit.driver.GetThreshold(value=value, units=units)
  1606. if units == "map units":
  1607. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") %
  1608. {'value' : value,
  1609. 'units' : self.mapUnits})
  1610. else:
  1611. self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") %
  1612. {'value' : threshold,
  1613. 'units' : self.mapUnits})
  1614. event.Skip()
  1615. def OnChangeBackgroundMap(self, event):
  1616. """Change background map"""
  1617. map = self.backgroundMap.GetValue()
  1618. UserSettings.Set(group='vdigit', key='backgroundMap', subkey='value', value=map)
  1619. def OnChangeQuery(self, event):
  1620. """Change query"""
  1621. if self.queryLength.GetValue():
  1622. # length
  1623. self.queryLengthSL.Enable(True)
  1624. self.queryLengthValue.Enable(True)
  1625. self.queryDangleSL.Enable(False)
  1626. self.queryDangleValue.Enable(False)
  1627. else:
  1628. # dangle
  1629. self.queryLengthSL.Enable(False)
  1630. self.queryLengthValue.Enable(False)
  1631. self.queryDangleSL.Enable(True)
  1632. self.queryDangleValue.Enable(True)
  1633. def OnSave(self, event):
  1634. """Button 'Save' clicked"""
  1635. self.UpdateSettings()
  1636. self.parent.toolbars['vdigit'].settingsDialog = None
  1637. fileSettings = {}
  1638. UserSettings.ReadSettingsFile(settings=fileSettings)
  1639. fileSettings['vdigit'] = UserSettings.Get(group='vdigit')
  1640. file = UserSettings.SaveToFile(fileSettings)
  1641. self.parent.gismanager.goutput.WriteLog(_('Vector digitizer settings saved to file <%s>.') % file)
  1642. self.Close()
  1643. def OnApply(self, event):
  1644. """Button 'Apply' clicked"""
  1645. self.UpdateSettings()
  1646. def OnCancel(self, event):
  1647. """Button 'Cancel' clicked"""
  1648. self.parent.toolbars['vdigit'].settingsDialog = None
  1649. self.Close()
  1650. def UpdateSettings(self):
  1651. """Update UserSettings"""
  1652. # symbology
  1653. for key, (enabled, color) in self.symbology.iteritems():
  1654. if enabled:
  1655. UserSettings.Set(group='vdigit', key=key, subkey='enabled',
  1656. value=enabled.IsChecked())
  1657. UserSettings.Set(group='vdigit', key=key, subkey='color',
  1658. value=color.GetColour())
  1659. else:
  1660. UserSettings.Set(group='vdigit', key=key, subkey='color',
  1661. value=color.GetColour())
  1662. # display
  1663. UserSettings.Set(group='vdigit', key="lineWidth", subkey='value',
  1664. value=int(self.lineWidthValue.GetValue()))
  1665. # snapping
  1666. UserSettings.Set(group='vdigit', key="snapping", subkey='value',
  1667. value=int(self.snappingValue.GetValue()))
  1668. UserSettings.Set(group='vdigit', key="snapping", subkey='units',
  1669. value=self.snappingUnit.GetStringSelection())
  1670. UserSettings.Set(group='vdigit', key="snapToVertex", subkey='enabled',
  1671. value=self.snapVertex.IsChecked())
  1672. # digitize new feature
  1673. UserSettings.Set(group='vdigit', key="addRecord", subkey='enabled',
  1674. value=self.addRecord.IsChecked())
  1675. UserSettings.Set(group='vdigit', key="layer", subkey='value',
  1676. value=int(self.layer.GetStringSelection()))
  1677. UserSettings.Set(group='vdigit', key="category", subkey='value',
  1678. value=int(self.category.GetValue()))
  1679. UserSettings.Set(group='vdigit', key="categoryMode", subkey='selection',
  1680. value=self.categoryMode.GetSelection())
  1681. # delete existing feature
  1682. UserSettings.Set(group='vdigit', key="delRecord", subkey='enabled',
  1683. value=self.deleteRecord.IsChecked())
  1684. # snapping threshold
  1685. self.parent.digit.threshold = self.parent.digit.driver.GetThreshold()
  1686. # query tool
  1687. if self.queryLength.GetValue():
  1688. UserSettings.Set(group='vdigit', key="query", subkey='selection',
  1689. value=0)
  1690. else:
  1691. UserSettings.Set(group='vdigit', key="query", subkey='type',
  1692. value=1)
  1693. UserSettings.Set(group='vdigit', key="query", subkey='box',
  1694. value=self.queryBox.IsChecked())
  1695. UserSettings.Set(group='vdigit', key="queryLength", subkey='than-selection',
  1696. value=self.queryLengthSL.GetSelection())
  1697. UserSettings.Set(group='vdigit', key="queryLength", subkey='thresh',
  1698. value=int(self.queryLengthValue.GetValue()))
  1699. UserSettings.Set(group='vdigit', key="queryDangle", subkey='than-selection',
  1700. value=self.queryDangleSL.GetSelection())
  1701. UserSettings.Set(group='vdigit', key="queryDangle", subkey='thresh',
  1702. value=int(self.queryDangleValue.GetValue()))
  1703. # select features
  1704. for feature in ('Point', 'Line',
  1705. 'Centroid', 'Boundary'):
  1706. UserSettings.Set(group='vdigit', key='selectFeature'+feature, subkey='enabled',
  1707. value=self.FindWindowById(self.selectFeature[feature]).IsChecked())
  1708. UserSettings.Set(group='vdigit', key="selectThresh", subkey='value',
  1709. value=int(self.selectThreshValue.GetValue()))
  1710. UserSettings.Set(group='vdigit', key="checkForDupl", subkey='enabled',
  1711. value=self.checkForDupl.IsChecked())
  1712. # on-exit
  1713. UserSettings.Set(group='vdigit', key="saveOnExit", subkey='enabled',
  1714. value=self.save.IsChecked())
  1715. # update driver settings
  1716. self.parent.digit.driver.UpdateSettings()
  1717. # redraw map if auto-rendering is enabled
  1718. if self.parent.autoRender.GetValue():
  1719. self.parent.OnRender(None)
  1720. class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin):
  1721. """
  1722. Dialog used to display/modify categories of vector objects
  1723. @param parent
  1724. @param title dialog title
  1725. @param query {coordinates, qdist} - v.edit/v.what
  1726. @param cats directory of categories - vdigit
  1727. @param line line id - vdigit
  1728. @param pos
  1729. @param style
  1730. """
  1731. def __init__(self, parent, title,
  1732. map, query=None, cats=None, line=None,
  1733. pos=wx.DefaultPosition,
  1734. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  1735. # parent
  1736. self.parent = parent # mapdisplay.BufferedWindow class instance
  1737. # map name
  1738. self.map = map
  1739. # line id (if not found remains 'None')
  1740. self.line = None
  1741. # {layer: [categories]}
  1742. self.cats = {}
  1743. # do not display dialog if no line is found (-> self.cats)
  1744. if cats is None:
  1745. if self.__GetCategories(query[0], query[1]) == 0 or not self.line:
  1746. Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
  1747. return
  1748. else:
  1749. # self.cats = dict(cats)
  1750. for layer in cats.keys():
  1751. self.cats[layer] = list(cats[layer]) # TODO: tuple to list
  1752. self.line = line
  1753. # make copy of cats (used for 'reload')
  1754. self.cats_orig = copy.deepcopy(self.cats)
  1755. Debug.msg(3, "VDigitCategoryDialog(): line=%d, cats=%s" % \
  1756. (self.line, self.cats))
  1757. wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title=title,
  1758. style=style, pos=pos)
  1759. # list of categories
  1760. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1761. label=" %s " % _("List of categories"))
  1762. listSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1763. self.list = CategoryListCtrl(parent=self, id=wx.ID_ANY,
  1764. style=wx.LC_REPORT |
  1765. wx.BORDER_NONE |
  1766. wx.LC_SORT_ASCENDING |
  1767. wx.LC_HRULES |
  1768. wx.LC_VRULES)
  1769. # sorter
  1770. self.itemDataMap = self.list.Populate()
  1771. listmix.ColumnSorterMixin.__init__(self, 2)
  1772. listSizer.Add(item=self.list, proportion=1, flag=wx.EXPAND)
  1773. # add new category
  1774. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1775. label=" %s " % _("Add new category"))
  1776. addSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1777. flexSizer = wx.FlexGridSizer (cols=5, hgap=5, vgap=5)
  1778. flexSizer.AddGrowableCol(3)
  1779. layerNewTxt = wx.StaticText(parent=self, id=wx.ID_ANY,
  1780. label="%s:" % _("Layer"))
  1781. self.layerNew = wx.SpinCtrl(parent=self, id=wx.ID_ANY, size=(50, -1),
  1782. initial=1, min=1, max=1e9)
  1783. catNewTxt = wx.StaticText(parent=self, id=wx.ID_ANY,
  1784. label="%s:" % _("Category"))
  1785. try:
  1786. newCat = max(self.cats[1]) + 1
  1787. except:
  1788. newCat = 1
  1789. self.catNew = wx.SpinCtrl(parent=self, id=wx.ID_ANY, size=(75, -1),
  1790. initial=newCat, min=-1e9, max=1e9)
  1791. btnAddCat = wx.Button(self, wx.ID_ADD)
  1792. flexSizer.Add(item=layerNewTxt, proportion=0,
  1793. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  1794. flexSizer.Add(item=self.layerNew, proportion=0,
  1795. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  1796. flexSizer.Add(item=catNewTxt, proportion=0,
  1797. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  1798. border=10)
  1799. flexSizer.Add(item=self.catNew, proportion=0,
  1800. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  1801. flexSizer.Add(item=btnAddCat, proportion=0,
  1802. flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1803. addSizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  1804. # buttons
  1805. btnApply = wx.Button(self, wx.ID_APPLY)
  1806. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1807. #btnReload = wx.Button(self, wx.ID_UNDO, _("&Reload"))
  1808. btnOk = wx.Button(self, wx.ID_OK)
  1809. btnOk.SetDefault()
  1810. # sizers
  1811. btnSizer = wx.StdDialogButtonSizer()
  1812. btnSizer.AddButton(btnCancel)
  1813. #btnSizer.AddButton(btnReload)
  1814. #btnSizer.SetNegativeButton(btnReload)
  1815. btnSizer.AddButton(btnApply)
  1816. btnSizer.AddButton(btnOk)
  1817. btnSizer.Realize()
  1818. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1819. mainSizer.Add(item=listSizer, proportion=1,
  1820. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  1821. mainSizer.Add(item=addSizer, proportion=0,
  1822. flag=wx.EXPAND | wx.ALIGN_CENTER |
  1823. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  1824. mainSizer.Add(item=btnSizer, proportion=0,
  1825. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  1826. self.SetSizer(mainSizer)
  1827. mainSizer.Fit(self)
  1828. self.SetAutoLayout(True)
  1829. # set min size for dialog
  1830. self.SetMinSize(self.GetBestSize())
  1831. # bindings
  1832. # buttons
  1833. #btnReload.Bind(wx.EVT_BUTTON, self.OnReload)
  1834. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1835. btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
  1836. btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat)
  1837. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  1838. # list
  1839. # self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list)
  1840. # self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
  1841. self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
  1842. self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
  1843. self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list)
  1844. self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list)
  1845. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
  1846. def GetListCtrl(self):
  1847. """Used by ColumnSorterMixin"""
  1848. return self.list
  1849. def OnColClick(self, event):
  1850. """Click on column header (order by)"""
  1851. event.Skip()
  1852. def OnBeginEdit(self, event):
  1853. """Editing of item started"""
  1854. event.Allow()
  1855. def OnEndEdit(self, event):
  1856. """Finish editing of item"""
  1857. itemIndex = event.GetIndex()
  1858. layerOld = int (self.list.GetItem(itemIndex, 0).GetText())
  1859. catOld = int (self.list.GetItem(itemIndex, 1).GetText())
  1860. if event.GetColumn() == 0:
  1861. layerNew = int(event.GetLabel())
  1862. catNew = catOld
  1863. else:
  1864. layerNew = layerOld
  1865. catNew = int(event.GetLabel())
  1866. try:
  1867. if layerNew not in self.cats.keys():
  1868. self.cats[layerNew] = []
  1869. self.cats[layerNew].append(catNew)
  1870. self.cats[layerOld].remove(catOld)
  1871. except:
  1872. event.Veto()
  1873. self.list.SetStringItem(itemIndex, 0, str(layerNew))
  1874. self.list.SetStringItem(itemIndex, 1, str(catNew))
  1875. dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
  1876. "Layer and category number must be integer.\n"
  1877. "Layer number must be greater then zero.") %
  1878. { 'layer': str(self.layerNew.GetValue()),
  1879. 'category' : str(self.catNew.GetValue()) },
  1880. _("Error"), wx.OK | wx.ICON_ERROR)
  1881. dlg.ShowModal()
  1882. dlg.Destroy()
  1883. return False
  1884. def OnRightDown(self, event):
  1885. """Mouse right button down"""
  1886. x = event.GetX()
  1887. y = event.GetY()
  1888. item, flags = self.list.HitTest((x, y))
  1889. if item != wx.NOT_FOUND and \
  1890. flags & wx.LIST_HITTEST_ONITEM:
  1891. self.list.Select(item)
  1892. event.Skip()
  1893. def OnRightUp(self, event):
  1894. """Mouse right button up"""
  1895. if not hasattr(self, "popupID1"):
  1896. self.popupID1 = wx.NewId()
  1897. self.popupID2 = wx.NewId()
  1898. self.popupID3 = wx.NewId()
  1899. self.Bind(wx.EVT_MENU, self.OnItemDelete, id=self.popupID1)
  1900. self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id=self.popupID2)
  1901. self.Bind(wx.EVT_MENU, self.OnReload, id=self.popupID3)
  1902. # generate popup-menu
  1903. menu = wx.Menu()
  1904. menu.Append(self.popupID1, _("Delete selected"))
  1905. if self.list.GetFirstSelected() == -1:
  1906. menu.Enable(self.popupID1, False)
  1907. menu.Append(self.popupID2, _("Delete all"))
  1908. menu.AppendSeparator()
  1909. menu.Append(self.popupID3, _("Reload"))
  1910. self.PopupMenu(menu)
  1911. menu.Destroy()
  1912. def OnItemSelected(self, event):
  1913. """Item selected"""
  1914. event.Skip()
  1915. def OnItemDelete(self, event):
  1916. """Delete selected item(s) from the list (layer/category pair)"""
  1917. item = self.list.GetFirstSelected()
  1918. while item != -1:
  1919. layer = int (self.list.GetItem(item, 0).GetText())
  1920. cat = int (self.list.GetItem(item, 1).GetText())
  1921. self.list.DeleteItem(item)
  1922. self.cats[layer].remove(cat)
  1923. item = self.list.GetFirstSelected()
  1924. event.Skip()
  1925. def OnItemDeleteAll(self, event):
  1926. """Delete all items from the list"""
  1927. self.list.DeleteAllItems()
  1928. self.cats = {}
  1929. event.Skip()
  1930. def __GetCategories(self, coords, qdist):
  1931. """Get layer/category pairs for all available
  1932. layers
  1933. Return True line found or False if not found"""
  1934. cmdWhat = gcmd.Command(cmd=['v.what',
  1935. '--q',
  1936. 'map=%s' % self.map,
  1937. 'east_north=%f,%f' % \
  1938. (float(coords[0]), float(coords[1])),
  1939. 'distance=%f' % qdist])
  1940. if cmdWhat.returncode != 0:
  1941. return False
  1942. for item in cmdWhat.ReadStdOutput():
  1943. litem = item.lower()
  1944. if "line:" in litem: # get line id
  1945. self.line = int(item.split(':')[1].strip())
  1946. elif "layer:" in litem: # add layer
  1947. layer = int(item.split(':')[1].strip())
  1948. if layer not in self.cats.keys():
  1949. self.cats[layer] = []
  1950. elif "category:" in litem: # add category
  1951. self.cats[layer].append(int(item.split(':')[1].strip()))
  1952. return True
  1953. def OnReload(self, event):
  1954. """Reload button pressed"""
  1955. # restore original list
  1956. self.cats = copy.deepcopy(self.cats_orig)
  1957. # polulate list
  1958. self.itemDataMap = self.list.Populate(update=True)
  1959. event.Skip()
  1960. def OnCancel(self, event):
  1961. """Cancel button pressed"""
  1962. self.parent.parent.dialogs['category'] = None
  1963. if self.parent.parent.digit:
  1964. self.parent.parent.digit.driver.SetSelected([])
  1965. self.parent.UpdateMap(render=False)
  1966. else:
  1967. self.parent.parent.OnRender(None)
  1968. self.Close()
  1969. def OnApply(self, event):
  1970. """Apply button pressed"""
  1971. # action : (catsFrom, catsTo)
  1972. check = {'catadd': (self.cats, self.cats_orig),
  1973. 'catdel': (self.cats_orig, self.cats)}
  1974. # add/delete new category
  1975. for action, cats in check.iteritems():
  1976. for layer in cats[0].keys():
  1977. catList = []
  1978. for cat in cats[0][layer]:
  1979. if layer not in cats[1].keys() or \
  1980. cat not in cats[1][layer]:
  1981. catList.append(cat)
  1982. if catList != []:
  1983. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') == 'vedit':
  1984. vEditCmd = ['v.edit', '--q',
  1985. 'map=%s' % self.map,
  1986. 'layer=%d' % layer,
  1987. 'tool=%s' % action,
  1988. 'cats=%s' % ",".join(["%d" % v for v in catList]),
  1989. 'id=%d' % self.line]
  1990. gcmd.Command(vEditCmd)
  1991. else:
  1992. if action == 'catadd':
  1993. add = True
  1994. else:
  1995. add = False
  1996. self.line = self.parent.parent.digit.SetLineCats(-1, layer,
  1997. catList, add)
  1998. if self.line < 0:
  1999. wx.MessageBox(parent=self, message=_("Unable to update vector map."),
  2000. caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
  2001. if UserSettings.Get(group='advanced', key='digitInterface', subkey='type') == 'vedit':
  2002. # reload map (needed for v.edit)
  2003. self.parent.parent.digit.driver.ReloadMap()
  2004. self.cats_orig = copy.deepcopy(self.cats)
  2005. event.Skip()
  2006. def OnOK(self, event):
  2007. """OK button pressed"""
  2008. self.OnApply(event)
  2009. self.OnCancel(event)
  2010. def OnAddCat(self, event):
  2011. """Button 'Add' new category pressed"""
  2012. try:
  2013. layer = int(self.layerNew.GetValue())
  2014. cat = int(self.catNew.GetValue())
  2015. if layer <= 0:
  2016. raise ValueError
  2017. except ValueError:
  2018. dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
  2019. "Layer and category number must be integer.\n"
  2020. "Layer number must be greater then zero.") %
  2021. {'layer' : str(self.layerNew.GetValue()),
  2022. 'category' : str(self.catNew.GetValue())},
  2023. _("Error"), wx.OK | wx.ICON_ERROR)
  2024. dlg.ShowModal()
  2025. dlg.Destroy()
  2026. return False
  2027. if layer not in self.cats.keys():
  2028. self.cats[layer] = []
  2029. self.cats[layer].append(cat)
  2030. # reload list
  2031. self.itemDataMap = self.list.Populate(update=True)
  2032. # update category number for add
  2033. self.catNew.SetValue(cat + 1)
  2034. event.Skip()
  2035. return True
  2036. def GetLine(self):
  2037. """Get id of selected line of 'None' if no line is selected"""
  2038. return self.line
  2039. def UpdateDialog(self, query=None, cats=None, line=None):
  2040. """Update dialog
  2041. @param query {coordinates, distance} - v.edit/v.what
  2042. @param cats directory layer/cats - vdigit
  2043. Return True if updated otherwise False
  2044. """
  2045. # line id (if not found remains 'None')
  2046. self.line = None
  2047. # {layer: [categories]}
  2048. self.cats = {}
  2049. # do not display dialog if no line is found (-> self.cats)
  2050. if cats is None:
  2051. ret = self.__GetCategories(query[0], query[1])
  2052. else:
  2053. # self.cats = dict(cats)
  2054. for layer in cats.keys():
  2055. self.cats[layer] = list(cats[layer]) # TODO: tuple to list
  2056. self.line = line
  2057. ret = 1
  2058. if ret == 0 or not self.line:
  2059. Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
  2060. return False
  2061. # make copy of cats (used for 'reload')
  2062. self.cats_orig = copy.deepcopy(self.cats)
  2063. # polulate list
  2064. self.itemDataMap = self.list.Populate(update=True)
  2065. try:
  2066. newCat = max(self.cats[1]) + 1
  2067. except:
  2068. newCat = 1
  2069. self.catNew.SetValue(newCat)
  2070. return True
  2071. class CategoryListCtrl(wx.ListCtrl,
  2072. listmix.ListCtrlAutoWidthMixin,
  2073. listmix.TextEditMixin):
  2074. """List of layers/categories"""
  2075. def __init__(self, parent, id, pos=wx.DefaultPosition,
  2076. size=wx.DefaultSize, style=0):
  2077. self.parent = parent
  2078. wx.ListCtrl.__init__(self, parent, id, pos, size, style)
  2079. listmix.ListCtrlAutoWidthMixin.__init__(self)
  2080. listmix.TextEditMixin.__init__(self)
  2081. def Populate(self, update=False):
  2082. """Populate the list"""
  2083. itemData = {} # requested by sorter
  2084. if not update:
  2085. self.InsertColumn(0, _("Layer"))
  2086. self.InsertColumn(1, _("Category"))
  2087. else:
  2088. self.DeleteAllItems()
  2089. i = 1
  2090. for layer in self.parent.cats.keys():
  2091. catsList = self.parent.cats[layer]
  2092. for cat in catsList:
  2093. index = self.InsertStringItem(sys.maxint, str(catsList[0]))
  2094. self.SetStringItem(index, 0, str(layer))
  2095. self.SetStringItem(index, 1, str(cat))
  2096. self.SetItemData(index, i)
  2097. itemData[i] = (str(layer), str(cat))
  2098. i = i + 1
  2099. if not update:
  2100. self.SetColumnWidth(0, 100)
  2101. self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
  2102. self.currentItem = 0
  2103. return itemData
  2104. class VDigitZBulkDialog(wx.Dialog):
  2105. """
  2106. Dialog used for Z bulk-labeling tool
  2107. """
  2108. def __init__(self, parent, title, nselected, style=wx.DEFAULT_DIALOG_STYLE):
  2109. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
  2110. self.parent = parent # mapdisplay.BufferedWindow class instance
  2111. # panel = wx.Panel(parent=self, id=wx.ID_ANY)
  2112. border = wx.BoxSizer(wx.VERTICAL)
  2113. txt = wx.StaticText(parent=self,
  2114. label=_("%d lines selected for z bulk-labeling") % nselected);
  2115. border.Add(item=txt, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  2116. box = wx.StaticBox (parent=self, id=wx.ID_ANY, label=" %s " % _("Set value"))
  2117. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  2118. flexSizer = wx.FlexGridSizer (cols=2, hgap=5, vgap=5)
  2119. flexSizer.AddGrowableCol(0)
  2120. # starting value
  2121. txt = wx.StaticText(parent=self,
  2122. label=_("Starting value"));
  2123. self.value = wx.SpinCtrl(parent=self, id=wx.ID_ANY, size=(150, -1),
  2124. initial=0,
  2125. min=-1e6, max=1e6)
  2126. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  2127. flexSizer.Add(self.value, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  2128. # step
  2129. txt = wx.StaticText(parent=self,
  2130. label=_("Step"))
  2131. self.step = wx.SpinCtrl(parent=self, id=wx.ID_ANY, size=(150, -1),
  2132. initial=0,
  2133. min=0, max=1e6)
  2134. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  2135. flexSizer.Add(self.step, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  2136. sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=1)
  2137. border.Add(item=sizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  2138. # buttons
  2139. btnCancel = wx.Button(self, wx.ID_CANCEL)
  2140. btnOk = wx.Button(self, wx.ID_OK)
  2141. btnOk.SetDefault()
  2142. # sizers
  2143. btnSizer = wx.StdDialogButtonSizer()
  2144. btnSizer.AddButton(btnCancel)
  2145. btnSizer.AddButton(btnOk)
  2146. btnSizer.Realize()
  2147. mainSizer = wx.BoxSizer(wx.VERTICAL)
  2148. mainSizer.Add(item=border, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  2149. mainSizer.Add(item=btnSizer, proportion=0,
  2150. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  2151. self.SetSizer(mainSizer)
  2152. mainSizer.Fit(self)
  2153. class VDigitDuplicatesDialog(wx.Dialog):
  2154. """
  2155. Show duplicated feature ids
  2156. """
  2157. def __init__(self, parent, data, title=_("List of duplicates"),
  2158. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  2159. pos=wx.DefaultPosition):
  2160. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style,
  2161. pos=pos)
  2162. self.parent = parent # BufferedWindow
  2163. self.data = data
  2164. self.winList = []
  2165. # panel = wx.Panel(parent=self, id=wx.ID_ANY)
  2166. # notebook
  2167. self.notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  2168. id = 1
  2169. for key in self.data.keys():
  2170. panel = wx.Panel(parent=self.notebook, id=wx.ID_ANY)
  2171. self.notebook.AddPage(page=panel, text=" %d " % (id))
  2172. # notebook body
  2173. border = wx.BoxSizer(wx.VERTICAL)
  2174. win = CheckListFeature(parent=panel, data=list(self.data[key]))
  2175. self.winList.append(win.GetId())
  2176. border.Add(item=win, proportion=1,
  2177. flag=wx.ALL | wx.EXPAND, border=5)
  2178. panel.SetSizer(border)
  2179. id += 1
  2180. # buttons
  2181. btnCancel = wx.Button(self, wx.ID_CANCEL)
  2182. btnOk = wx.Button(self, wx.ID_OK)
  2183. btnOk.SetDefault()
  2184. # sizers
  2185. btnSizer = wx.StdDialogButtonSizer()
  2186. btnSizer.AddButton(btnCancel)
  2187. btnSizer.AddButton(btnOk)
  2188. btnSizer.Realize()
  2189. mainSizer = wx.BoxSizer(wx.VERTICAL)
  2190. mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  2191. mainSizer.Add(item=btnSizer, proportion=0,
  2192. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  2193. self.SetSizer(mainSizer)
  2194. mainSizer.Fit(self)
  2195. self.SetAutoLayout(True)
  2196. # set min size for dialog
  2197. self.SetMinSize((250, 180))
  2198. def GetUnSelected(self):
  2199. """Get unselected items (feature id)
  2200. @return list of ids
  2201. """
  2202. ids = []
  2203. for id in self.winList:
  2204. wlist = self.FindWindowById(id)
  2205. for item in range(wlist.GetItemCount()):
  2206. if not wlist.IsChecked(item):
  2207. ids.append(int(wlist.GetItem(item, 0).GetText()))
  2208. return ids
  2209. class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
  2210. """List of mapset/owner/group"""
  2211. def __init__(self, parent, data,
  2212. pos=wx.DefaultPosition, log=None):
  2213. self.parent = parent
  2214. self.data = data
  2215. wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
  2216. style=wx.LC_REPORT)
  2217. listmix.CheckListCtrlMixin.__init__(self)
  2218. self.log = log
  2219. # setup mixins
  2220. listmix.ListCtrlAutoWidthMixin.__init__(self)
  2221. self.LoadData(self.data)
  2222. def LoadData(self, data):
  2223. """Load data into list"""
  2224. self.InsertColumn(0, _('Feature id'))
  2225. self.InsertColumn(1, _('Layer (Categories)'))
  2226. for item in data:
  2227. index = self.InsertStringItem(sys.maxint, str(item[0]))
  2228. self.SetStringItem(index, 1, str(item[1]))
  2229. # enable all items by default
  2230. for item in range(self.GetItemCount()):
  2231. self.CheckItem(item, True)
  2232. self.SetColumnWidth(col=0, width=wx.LIST_AUTOSIZE_USEHEADER)
  2233. self.SetColumnWidth(col=1, width=wx.LIST_AUTOSIZE_USEHEADER)
  2234. def OnCheckItem(self, index, flag):
  2235. """Mapset checked/unchecked"""
  2236. pass