vdigit.py 110 KB

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