preferences.py 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  1. """
  2. @package vdigit.preferences
  3. @brief wxGUI vector digitizer preferences dialogs
  4. Classes:
  5. - preferences::VDigitSettingsDialog
  6. (C) 2007-2011 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. @author Martin Landa <landa.martin gmail.com>
  10. """
  11. import textwrap
  12. import wx
  13. import wx.lib.colourselect as csel
  14. from core import globalvar
  15. from core.debug import Debug
  16. from gui_core.gselect import ColumnSelect
  17. from core.units import Units
  18. from core.settings import UserSettings
  19. from core.utils import _
  20. from gui_core.wrap import SpinCtrl, Button
  21. class VDigitSettingsDialog(wx.Dialog):
  22. def __init__(self, parent, giface, title=_("Digitization settings"),
  23. style=wx.DEFAULT_DIALOG_STYLE):
  24. """Standard settings dialog for digitization purposes
  25. """
  26. wx.Dialog.__init__(
  27. self,
  28. parent=parent,
  29. id=wx.ID_ANY,
  30. title=title,
  31. style=style)
  32. self._giface = giface
  33. self.parent = parent # MapFrame
  34. self.digit = self.parent.MapWindow.digit
  35. # notebook
  36. notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  37. self._createGeneralPage(notebook)
  38. self._createSymbologyPage(notebook)
  39. self.digit.SetCategory()
  40. self._createAttributesPage(notebook)
  41. self._createQueryPage(notebook)
  42. # buttons
  43. btnApply = Button(self, wx.ID_APPLY)
  44. btnCancel = Button(self, wx.ID_CLOSE)
  45. btnSave = Button(self, wx.ID_SAVE)
  46. btnSave.SetDefault()
  47. # bindigs
  48. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  49. btnApply.SetToolTip(_("Apply changes for this session"))
  50. btnApply.SetDefault()
  51. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  52. btnSave.SetToolTip(
  53. _("Close dialog and save changes to user settings file"))
  54. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  55. btnCancel.SetToolTip(_("Close dialog and ignore changes"))
  56. # sizers
  57. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  58. btnSizer.Add(btnCancel, proportion=0,
  59. flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  60. btnSizer.Add(btnApply, proportion=0,
  61. flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  62. btnSizer.Add(btnSave, proportion=0,
  63. flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  64. mainSizer = wx.BoxSizer(wx.VERTICAL)
  65. mainSizer.Add(
  66. notebook,
  67. proportion=1,
  68. flag=wx.EXPAND | wx.ALL,
  69. border=5)
  70. mainSizer.Add(btnSizer, proportion=0,
  71. flag=wx.ALIGN_RIGHT, border=5)
  72. self.Bind(wx.EVT_CLOSE, self.OnCancel)
  73. self.SetSizer(mainSizer)
  74. mainSizer.Fit(self)
  75. def _createSymbologyPage(self, notebook):
  76. """Create notebook page concerning symbology settings"""
  77. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  78. notebook.AddPage(page=panel, text=_("Symbology"))
  79. sizer = wx.BoxSizer(wx.VERTICAL)
  80. flexSizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
  81. flexSizer.AddGrowableCol(0)
  82. self.symbology = {}
  83. for label, key in self._symbologyData():
  84. textLabel = wx.StaticText(panel, wx.ID_ANY, label)
  85. color = csel.ColourSelect(
  86. panel, id=wx.ID_ANY, colour=UserSettings.Get(
  87. group='vdigit', key='symbol', subkey=[
  88. key, 'color']), size=(
  89. 40, 25))
  90. isEnabled = UserSettings.Get(group='vdigit', key='symbol',
  91. subkey=[key, 'enabled'])
  92. if isEnabled is not None:
  93. enabled = wx.CheckBox(panel, id=wx.ID_ANY, label="")
  94. enabled.SetValue(isEnabled)
  95. self.symbology[key] = (enabled, color)
  96. else:
  97. enabled = (1, 1)
  98. self.symbology[key] = (None, color)
  99. flexSizer.Add(
  100. textLabel,
  101. proportion=0,
  102. flag=wx.ALIGN_CENTER_VERTICAL)
  103. flexSizer.Add(
  104. enabled,
  105. proportion=0,
  106. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  107. flexSizer.Add(
  108. color,
  109. proportion=0,
  110. flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  111. color.SetName("GetColour")
  112. sizer.Add(
  113. flexSizer,
  114. proportion=1,
  115. flag=wx.ALL | wx.EXPAND,
  116. border=10)
  117. panel.SetSizer(sizer)
  118. return panel
  119. def _createGeneralPage(self, notebook):
  120. """Create notebook page concerning general settings"""
  121. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  122. notebook.AddPage(page=panel, text=_("General"))
  123. border = wx.BoxSizer(wx.VERTICAL)
  124. #
  125. # display section
  126. #
  127. box = wx.StaticBox(
  128. parent=panel,
  129. id=wx.ID_ANY,
  130. label=" %s " %
  131. _("Display"))
  132. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  133. flexSizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
  134. flexSizer.AddGrowableCol(0)
  135. # line width
  136. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width"))
  137. self.lineWidthValue = SpinCtrl(
  138. parent=panel, id=wx.ID_ANY, size=(75, -1),
  139. initial=UserSettings.Get(
  140. group='vdigit', key="lineWidth", subkey='value'),
  141. min=1, max=1e6)
  142. units = wx.StaticText(
  143. parent=panel, id=wx.ID_ANY, size=(115, -1),
  144. label=UserSettings.Get(
  145. group='vdigit', key="lineWidth", subkey='units'),
  146. style=wx.ALIGN_LEFT)
  147. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  148. flexSizer.Add(
  149. self.lineWidthValue,
  150. proportion=0,
  151. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  152. flexSizer.Add(
  153. units,
  154. proportion=0,
  155. flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  156. border=10)
  157. sizer.Add(
  158. flexSizer,
  159. proportion=1,
  160. flag=wx.ALL | wx.EXPAND,
  161. border=1)
  162. border.Add(sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  163. #
  164. # snapping section
  165. #
  166. box = wx.StaticBox(
  167. parent=panel,
  168. id=wx.ID_ANY,
  169. label=" %s " %
  170. _("Snapping"))
  171. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  172. flexSizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
  173. flexSizer.AddGrowableCol(0)
  174. # snapping
  175. text = wx.StaticText(
  176. parent=panel,
  177. id=wx.ID_ANY,
  178. label=_("Snapping threshold"))
  179. self.snappingValue = SpinCtrl(
  180. parent=panel, id=wx.ID_ANY, size=(75, -1),
  181. initial=UserSettings.Get(
  182. group='vdigit', key="snapping", subkey='value'),
  183. min=-1, max=1e6)
  184. self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue)
  185. self.snappingValue.Bind(wx.EVT_TEXT, self.OnChangeSnappingValue)
  186. self.snappingUnit = wx.Choice(parent=panel, id=wx.ID_ANY, size=(
  187. 125, -1), choices=[_("screen pixels"), _("map units")])
  188. try:
  189. self.snappingUnit.SetSelection(UserSettings.Get(group='vdigit',
  190. key="snapping",
  191. subkey='unit'))
  192. except:
  193. self.snappingUnit.SetSelection(0)
  194. self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits)
  195. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  196. flexSizer.Add(
  197. self.snappingValue,
  198. proportion=0,
  199. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  200. flexSizer.Add(
  201. self.snappingUnit,
  202. proportion=0,
  203. flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  204. vertexSizer = wx.BoxSizer(wx.VERTICAL)
  205. self.snapVertex = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  206. label=_("Snap also to vertex"))
  207. self.snapVertex.SetValue(
  208. UserSettings.Get(
  209. group='vdigit',
  210. key="snapToVertex",
  211. subkey='enabled'))
  212. vertexSizer.Add(self.snapVertex, proportion=0, flag=wx.EXPAND)
  213. self.mapUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
  214. self.snappingInfo = wx.StaticText(
  215. parent=panel, id=wx.ID_ANY,
  216. label=_("Snapping threshold is %(value).1f %(units)s") %
  217. {'value': self.digit.GetDisplay().GetThreshold(),
  218. 'units': self.mapUnits})
  219. vertexSizer.Add(self.snappingInfo, proportion=0,
  220. flag=wx.ALL | wx.EXPAND, border=1)
  221. sizer.Add(flexSizer, proportion=1, flag=wx.EXPAND)
  222. sizer.Add(vertexSizer, proportion=1, flag=wx.EXPAND)
  223. border.Add(sizer, proportion=0, flag=wx.LEFT |
  224. wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  225. #
  226. # select box
  227. #
  228. box = wx.StaticBox(
  229. parent=panel,
  230. id=wx.ID_ANY,
  231. label=" %s " %
  232. _("Select vector features"))
  233. # feature type
  234. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  235. inSizer = wx.BoxSizer(wx.HORIZONTAL)
  236. self.selectFeature = {}
  237. for feature in ('point', 'line',
  238. 'centroid', 'boundary'):
  239. chkbox = wx.CheckBox(parent=panel, label=feature)
  240. self.selectFeature[feature] = chkbox.GetId()
  241. chkbox.SetValue(UserSettings.Get(group='vdigit', key='selectType',
  242. subkey=[feature, 'enabled']))
  243. inSizer.Add(chkbox, proportion=0,
  244. flag=wx.EXPAND | wx.ALL, border=5)
  245. sizer.Add(inSizer, proportion=0, flag=wx.EXPAND)
  246. # threshold
  247. flexSizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5)
  248. flexSizer.AddGrowableCol(0)
  249. text = wx.StaticText(
  250. parent=panel,
  251. id=wx.ID_ANY,
  252. label=_("Select threshold"))
  253. self.selectThreshValue = SpinCtrl(
  254. parent=panel, id=wx.ID_ANY, size=(75, -1),
  255. initial=UserSettings.Get(
  256. group='vdigit', key="selectThresh", subkey='value'),
  257. min=1, max=1e6)
  258. units = wx.StaticText(
  259. parent=panel, id=wx.ID_ANY, size=(115, -1),
  260. label=UserSettings.Get(
  261. group='vdigit', key="lineWidth", subkey='units'),
  262. style=wx.ALIGN_LEFT)
  263. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  264. flexSizer.Add(self.selectThreshValue, proportion=0,
  265. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  266. flexSizer.Add(
  267. units,
  268. proportion=0,
  269. flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
  270. border=10)
  271. self.selectIn = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=_(
  272. "Select only features inside of selection bounding box"))
  273. self.selectIn.SetValue(
  274. UserSettings.Get(
  275. group='vdigit',
  276. key="selectInside",
  277. subkey='enabled'))
  278. self.selectIn.SetToolTipString(
  279. _("By default are selected all features overlapping selection bounding box "))
  280. self.checkForDupl = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  281. label=_("Check for duplicates"))
  282. self.checkForDupl.SetValue(
  283. UserSettings.Get(
  284. group='vdigit',
  285. key="checkForDupl",
  286. subkey='enabled'))
  287. sizer.Add(flexSizer, proportion=0, flag=wx.EXPAND)
  288. sizer.Add(
  289. self.selectIn,
  290. proportion=0,
  291. flag=wx.EXPAND | wx.ALL,
  292. border=1)
  293. sizer.Add(
  294. self.checkForDupl,
  295. proportion=0,
  296. flag=wx.EXPAND | wx.ALL,
  297. border=1)
  298. border.Add(sizer, proportion=0, flag=wx.EXPAND |
  299. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  300. #
  301. # digitize lines box
  302. #
  303. box = wx.StaticBox(
  304. parent=panel, id=wx.ID_ANY, label=" %s " %
  305. _("Digitize lines/boundaries"))
  306. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  307. self.intersect = wx.CheckBox(
  308. parent=panel, label=_("Break lines at intersection"))
  309. self.intersect.SetValue(
  310. UserSettings.Get(
  311. group='vdigit',
  312. key='breakLines',
  313. subkey='enabled'))
  314. sizer.Add(
  315. self.intersect,
  316. proportion=0,
  317. flag=wx.ALL | wx.EXPAND,
  318. border=1)
  319. border.Add(sizer, proportion=0, flag=wx.EXPAND |
  320. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  321. #
  322. # digitize areas box
  323. #
  324. box = wx.StaticBox(
  325. parent=panel,
  326. id=wx.ID_ANY,
  327. label=" %s " %
  328. _("Digitize areas"))
  329. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  330. self.closeBoundary = wx.CheckBox(
  331. parent=panel, label=_("Close boundary (snap to the start node)"))
  332. self.closeBoundary.SetValue(
  333. UserSettings.Get(
  334. group='vdigit',
  335. key='closeBoundary',
  336. subkey='enabled'))
  337. sizer.Add(
  338. self.closeBoundary,
  339. proportion=0,
  340. flag=wx.ALL | wx.EXPAND,
  341. border=1)
  342. border.Add(sizer, proportion=0, flag=wx.EXPAND |
  343. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  344. #
  345. # save-on-exit box
  346. #
  347. box = wx.StaticBox(
  348. parent=panel,
  349. id=wx.ID_ANY,
  350. label=" %s " %
  351. _("Save changes"))
  352. # save changes on exit?
  353. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  354. self.save = wx.CheckBox(parent=panel, label=_("Save changes on exit"))
  355. self.save.SetValue(
  356. UserSettings.Get(
  357. group='vdigit',
  358. key='saveOnExit',
  359. subkey='enabled'))
  360. sizer.Add(
  361. self.save,
  362. proportion=0,
  363. flag=wx.ALL | wx.EXPAND,
  364. border=1)
  365. border.Add(sizer, proportion=0, flag=wx.EXPAND |
  366. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
  367. panel.SetSizer(border)
  368. return panel
  369. def _createQueryPage(self, notebook):
  370. """Create notebook page for query tool"""
  371. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  372. notebook.AddPage(page=panel, text=_("Query tool"))
  373. border = wx.BoxSizer(wx.VERTICAL)
  374. #
  375. # query tool box
  376. #
  377. box = wx.StaticBox(
  378. parent=panel,
  379. id=wx.ID_ANY,
  380. label=" %s " %
  381. _("Choose query tool"))
  382. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  383. LocUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
  384. self.queryBox = wx.CheckBox(
  385. parent=panel,
  386. id=wx.ID_ANY,
  387. label=_("Select by box"))
  388. self.queryBox.SetValue(
  389. UserSettings.Get(
  390. group='vdigit',
  391. key="query",
  392. subkey='box'))
  393. sizer.Add(
  394. self.queryBox,
  395. proportion=0,
  396. flag=wx.ALL | wx.EXPAND,
  397. border=1)
  398. sizer.Add((0, 5))
  399. #
  400. # length
  401. #
  402. self.queryLength = wx.RadioButton(
  403. parent=panel, id=wx.ID_ANY, label=_("length"))
  404. self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  405. sizer.Add(
  406. self.queryLength,
  407. proportion=0,
  408. flag=wx.ALL | wx.EXPAND,
  409. border=1)
  410. flexSizer = wx.FlexGridSizer(cols=4, hgap=5, vgap=5)
  411. flexSizer.AddGrowableCol(0)
  412. txt = wx.StaticText(
  413. parent=panel,
  414. id=wx.ID_ANY,
  415. label=_("Select lines"))
  416. self.queryLengthSL = wx.Choice(
  417. parent=panel, id=wx.ID_ANY, choices=[
  418. _("shorter than"), _("longer than")])
  419. self.queryLengthSL.SetSelection(
  420. UserSettings.Get(
  421. group='vdigit',
  422. key="queryLength",
  423. subkey='than-selection'))
  424. self.queryLengthValue = SpinCtrl(
  425. parent=panel, id=wx.ID_ANY, size=(
  426. 100, -1), initial=1, min=0, max=1e6)
  427. self.queryLengthValue.SetValue(
  428. UserSettings.Get(
  429. group='vdigit',
  430. key="queryLength",
  431. subkey='thresh'))
  432. units = wx.StaticText(
  433. parent=panel,
  434. id=wx.ID_ANY,
  435. label="%s" %
  436. LocUnits)
  437. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  438. flexSizer.Add(
  439. self.queryLengthSL,
  440. proportion=0,
  441. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  442. flexSizer.Add(
  443. self.queryLengthValue,
  444. proportion=0,
  445. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  446. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  447. sizer.Add(
  448. flexSizer,
  449. proportion=0,
  450. flag=wx.ALL | wx.EXPAND,
  451. border=1)
  452. #
  453. # dangle
  454. #
  455. self.queryDangle = wx.RadioButton(
  456. parent=panel, id=wx.ID_ANY, label=_("dangle"))
  457. self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  458. sizer.Add(
  459. self.queryDangle,
  460. proportion=0,
  461. flag=wx.ALL | wx.EXPAND,
  462. border=1)
  463. flexSizer = wx.FlexGridSizer(cols=4, hgap=5, vgap=5)
  464. flexSizer.AddGrowableCol(0)
  465. txt = wx.StaticText(
  466. parent=panel,
  467. id=wx.ID_ANY,
  468. label=_("Select dangles"))
  469. self.queryDangleSL = wx.Choice(
  470. parent=panel, id=wx.ID_ANY, choices=[
  471. _("shorter than"), _("longer than")])
  472. self.queryDangleSL.SetSelection(
  473. UserSettings.Get(
  474. group='vdigit',
  475. key="queryDangle",
  476. subkey='than-selection'))
  477. self.queryDangleValue = SpinCtrl(
  478. parent=panel, id=wx.ID_ANY, size=(
  479. 100, -1), initial=1, min=0, max=1e6)
  480. self.queryDangleValue.SetValue(
  481. UserSettings.Get(
  482. group='vdigit',
  483. key="queryDangle",
  484. subkey='thresh'))
  485. units = wx.StaticText(
  486. parent=panel,
  487. id=wx.ID_ANY,
  488. label="%s" %
  489. LocUnits)
  490. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  491. flexSizer.Add(
  492. self.queryDangleSL,
  493. proportion=0,
  494. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  495. flexSizer.Add(
  496. self.queryDangleValue,
  497. proportion=0,
  498. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  499. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  500. sizer.Add(
  501. flexSizer,
  502. proportion=0,
  503. flag=wx.ALL | wx.EXPAND,
  504. border=1)
  505. if UserSettings.Get(group='vdigit', key="query",
  506. subkey='selection') == 0:
  507. self.queryLength.SetValue(True)
  508. else:
  509. self.queryDangle.SetValue(True)
  510. # enable & disable items
  511. self.OnChangeQuery(None)
  512. border.Add(sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  513. panel.SetSizer(border)
  514. return panel
  515. def _createAttributesPage(self, notebook):
  516. """Create notebook page for attributes"""
  517. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  518. notebook.AddPage(page=panel, text=_("Attributes"))
  519. border = wx.BoxSizer(wx.VERTICAL)
  520. #
  521. # add new record
  522. #
  523. box = wx.StaticBox(
  524. parent=panel,
  525. id=wx.ID_ANY,
  526. label=" %s " %
  527. _("Digitize new feature"))
  528. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  529. # checkbox
  530. self.addRecord = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  531. label=_("Add new record into table"))
  532. self.addRecord.SetValue(
  533. UserSettings.Get(
  534. group='vdigit',
  535. key="addRecord",
  536. subkey='enabled'))
  537. sizer.Add(
  538. self.addRecord,
  539. proportion=0,
  540. flag=wx.ALL | wx.EXPAND,
  541. border=1)
  542. # settings
  543. flexSizer = wx.FlexGridSizer(cols=2, hgap=3, vgap=3)
  544. flexSizer.AddGrowableCol(0)
  545. settings = ((_("Layer"), 1), (_("Category"), 1),
  546. (_("Mode"), _("Next to use")))
  547. # layer
  548. text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Layer"))
  549. self.layer = SpinCtrl(parent=panel, id=wx.ID_ANY, size=(125, -1),
  550. min=1, max=1e3)
  551. self.layer.SetValue(int(UserSettings.Get(
  552. group='vdigit', key="layer", subkey='value')))
  553. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  554. flexSizer.Add(self.layer, proportion=0,
  555. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  556. # category number
  557. text = wx.StaticText(
  558. parent=panel,
  559. id=wx.ID_ANY,
  560. label=_("Category number"))
  561. self.category = SpinCtrl(
  562. parent=panel, id=wx.ID_ANY, size=(125, -1),
  563. initial=UserSettings.Get(
  564. group='vdigit', key="category", subkey='value'),
  565. min=-1e9, max=1e9)
  566. if UserSettings.Get(group='vdigit', key="categoryMode",
  567. subkey='selection') != 1:
  568. self.category.Enable(False)
  569. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  570. flexSizer.Add(self.category, proportion=0,
  571. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  572. # category mode
  573. text = wx.StaticText(
  574. parent=panel,
  575. id=wx.ID_ANY,
  576. label=_("Category mode"))
  577. self.categoryMode = wx.Choice(parent=panel, id=wx.ID_ANY, size=(
  578. 125, -1), choices=[_("Next to use"), _("Manual entry"), _("No category")])
  579. self.categoryMode.SetSelection(
  580. UserSettings.Get(
  581. group='vdigit',
  582. key="categoryMode",
  583. subkey='selection'))
  584. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  585. flexSizer.Add(self.categoryMode, proportion=0,
  586. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  587. sizer.Add(
  588. flexSizer,
  589. proportion=1,
  590. flag=wx.ALL | wx.EXPAND,
  591. border=1)
  592. border.Add(sizer, proportion=0,
  593. flag=wx.ALL | wx.EXPAND, border=5)
  594. #
  595. # delete existing record
  596. #
  597. box = wx.StaticBox(
  598. parent=panel, id=wx.ID_ANY, label=" %s " %
  599. _("Delete existing feature(s)"))
  600. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  601. # checkbox
  602. self.deleteRecord = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  603. label=_("Delete record from table"))
  604. self.deleteRecord.SetValue(
  605. UserSettings.Get(
  606. group='vdigit',
  607. key="delRecord",
  608. subkey='enabled'))
  609. sizer.Add(
  610. self.deleteRecord,
  611. proportion=0,
  612. flag=wx.ALL | wx.EXPAND,
  613. border=1)
  614. border.Add(sizer, proportion=0,
  615. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  616. #
  617. # geometry attributes (currently only length and area are supported)
  618. #
  619. box = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  620. label=" %s " % _("Geometry attributes"))
  621. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  622. gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
  623. self.geomAttrb = {'length': {'label': _('length')},
  624. 'area': {'label': _('area')},
  625. 'perimeter': {'label': _('perimeter')}}
  626. digitToolbar = self.parent.toolbars['vdigit']
  627. try:
  628. vectorName = digitToolbar.GetLayer().GetName()
  629. except AttributeError:
  630. vectorName = None # no vector selected for editing
  631. layer = UserSettings.Get(group='vdigit', key="layer", subkey='value')
  632. mapLayer = self.parent.toolbars['vdigit'].GetLayer()
  633. tree = self.parent.tree
  634. if tree:
  635. item = tree.FindItemByData('maplayer', mapLayer)
  636. else:
  637. item = None
  638. row = 0
  639. for attrb in ['length', 'area', 'perimeter']:
  640. # checkbox
  641. check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  642. label=self.geomAttrb[attrb]['label'])
  643. ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled'))
  644. check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb)
  645. # column (only numeric)
  646. column = ColumnSelect(parent=panel, size=(200, -1))
  647. column.InsertColumns(vector=vectorName,
  648. layer=layer, excludeKey=True,
  649. type=['integer', 'double precision'])
  650. # units
  651. if attrb == 'area':
  652. choices = Units.GetUnitsList('area')
  653. else:
  654. choices = Units.GetUnitsList('length')
  655. win_units = wx.Choice(parent=panel, id=wx.ID_ANY,
  656. choices=choices, size=(120, -1))
  657. # default values
  658. check.SetValue(False)
  659. if item and tree.GetLayerInfo(item, key='vdigit') and \
  660. 'geomAttr' in tree.GetLayerInfo(item, key='vdigit') and \
  661. attrb in tree.GetLayerInfo(item, key='vdigit')['geomAttr']:
  662. check.SetValue(True)
  663. column.SetStringSelection(
  664. tree.GetLayerInfo(item, key='vdigit')['geomAttr']
  665. [attrb]['column'])
  666. if attrb == 'area':
  667. type = 'area'
  668. else:
  669. type = 'length'
  670. unitsIdx = Units.GetUnitsIndex(type, tree.GetLayerInfo(
  671. item, key='vdigit')['geomAttr'][attrb]['units'])
  672. win_units.SetSelection(unitsIdx)
  673. if not vectorName:
  674. check.Enable(False)
  675. column.Enable(False)
  676. if not check.IsChecked():
  677. column.Enable(False)
  678. self.geomAttrb[attrb]['check'] = check.GetId()
  679. self.geomAttrb[attrb]['column'] = column.GetId()
  680. self.geomAttrb[attrb]['units'] = win_units.GetId()
  681. gridSizer.Add(check,
  682. flag=wx.ALIGN_CENTER_VERTICAL,
  683. pos=(row, 0))
  684. gridSizer.Add(column,
  685. pos=(row, 1))
  686. gridSizer.Add(win_units,
  687. pos=(row, 2))
  688. row += 1
  689. note = '\n'.join(textwrap.wrap(_("Note: These settings are stored "
  690. "in the workspace not in the vector digitizer "
  691. "preferences."), 55))
  692. gridSizer.Add(wx.StaticText(parent=panel, id=wx.ID_ANY,
  693. label=note),
  694. pos=(3, 0), span=(1, 3))
  695. gridSizer.AddGrowableCol(0)
  696. sizer.Add(gridSizer, proportion=1,
  697. flag=wx.ALL | wx.EXPAND, border=1)
  698. border.Add(sizer, proportion=0,
  699. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  700. # bindings
  701. self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord)
  702. self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode)
  703. self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer)
  704. panel.SetSizer(border)
  705. return panel
  706. def _symbologyData(self):
  707. """Data for _createSymbologyPage()
  708. label | checkbox | color
  709. """
  710. return (
  711. (_("Digitize new line segment"), "newSegment"),
  712. (_("Digitize new line/boundary"), "newLine"),
  713. (_("Highlight"), "highlight"),
  714. (_("Highlight (duplicates)"), "highlightDupl"),
  715. (_("Point"), "point"),
  716. (_("Line"), "line"),
  717. (_("Boundary (no area)"), "boundaryNo"),
  718. (_("Boundary (one area)"), "boundaryOne"),
  719. (_("Boundary (two areas)"), "boundaryTwo"),
  720. (_("Centroid (in area)"), "centroidIn"),
  721. (_("Centroid (outside area)"), "centroidOut"),
  722. (_("Centroid (duplicate in area)"), "centroidDup"),
  723. (_("Node (one line)"), "nodeOne"),
  724. (_("Node (two lines)"), "nodeTwo"),
  725. (_("Vertex"), "vertex"),
  726. (_("Area (closed boundary + centroid)"), "area"),
  727. (_("Direction"), "direction"),)
  728. def OnGeomAttrb(self, event):
  729. """Register geometry attributes (enable/disable)
  730. """
  731. checked = event.IsChecked()
  732. id = event.GetId()
  733. key = None
  734. for attrb, val in self.geomAttrb.iteritems():
  735. if val['check'] == id:
  736. key = attrb
  737. break
  738. column = self.FindWindowById(self.geomAttrb[key]['column'])
  739. if checked:
  740. column.Enable()
  741. else:
  742. column.Enable(False)
  743. def OnChangeCategoryMode(self, event):
  744. """Change category mode
  745. """
  746. mode = event.GetSelection()
  747. UserSettings.Set(
  748. group='vdigit',
  749. key="categoryMode",
  750. subkey='selection',
  751. value=mode)
  752. if mode == 1: # manual entry
  753. self.category.Enable(True)
  754. elif self.category.IsEnabled(): # disable
  755. self.category.Enable(False)
  756. if mode == 2 and self.addRecord.IsChecked(): # no category
  757. self.addRecord.SetValue(False)
  758. self.digit.SetCategory()
  759. self.category.SetValue(
  760. UserSettings.Get(
  761. group='vdigit',
  762. key='category',
  763. subkey='value'))
  764. def OnChangeLayer(self, event):
  765. """Layer changed
  766. """
  767. layer = event.GetInt()
  768. if layer > 0:
  769. UserSettings.Set(
  770. group='vdigit',
  771. key='layer',
  772. subkey='value',
  773. value=layer)
  774. self.digit.SetCategory()
  775. self.category.SetValue(
  776. UserSettings.Get(
  777. group='vdigit',
  778. key='category',
  779. subkey='value'))
  780. event.Skip()
  781. def OnChangeAddRecord(self, event):
  782. """Checkbox 'Add new record' status changed
  783. """
  784. pass
  785. # self.category.SetValue(self.digit.SetCategory())
  786. def OnChangeSnappingValue(self, event):
  787. """Change snapping value - update static text
  788. """
  789. value = self.snappingValue.GetValue()
  790. if value < 0:
  791. region = self.parent.MapWindow.Map.GetRegion()
  792. res = (region['nsres'] + region['ewres']) / 2.
  793. threshold = self.digit.GetDisplay().GetThreshold(value=res)
  794. else:
  795. if self.snappingUnit.GetSelection() == 1: # map units
  796. threshold = value
  797. else:
  798. threshold = self.digit.GetDisplay().GetThreshold(value=value)
  799. if value == 0:
  800. self.snappingInfo.SetLabel(_("Snapping disabled"))
  801. elif value < 0:
  802. self.snappingInfo.SetLabel(
  803. _(
  804. "Snapping threshold is %(value).1f %(units)s "
  805. "(based on comp. resolution)") %
  806. {'value': threshold, 'units': self.mapUnits.lower()})
  807. else:
  808. self.snappingInfo.SetLabel(
  809. _("Snapping threshold is %(value).1f %(units)s") %
  810. {'value': threshold, 'units': self.mapUnits.lower()})
  811. event.Skip()
  812. def OnChangeSnappingUnits(self, event):
  813. """Snapping units change -> update static text
  814. """
  815. value = self.snappingValue.GetValue()
  816. units = self.snappingUnit.GetSelection()
  817. threshold = self.digit.GetDisplay().GetThreshold(value=value, units=units)
  818. if units == 1: # map units
  819. self.snappingInfo.SetLabel(
  820. _("Snapping threshold is %(value).1f %(units)s") %
  821. {'value': value, 'units': self.mapUnits})
  822. else:
  823. self.snappingInfo.SetLabel(
  824. _("Snapping threshold is %(value).1f %(units)s") %
  825. {'value': threshold, 'units': self.mapUnits})
  826. event.Skip()
  827. def OnChangeQuery(self, event):
  828. """Change query
  829. """
  830. if self.queryLength.GetValue():
  831. # length
  832. self.queryLengthSL.Enable(True)
  833. self.queryLengthValue.Enable(True)
  834. self.queryDangleSL.Enable(False)
  835. self.queryDangleValue.Enable(False)
  836. else:
  837. # dangle
  838. self.queryLengthSL.Enable(False)
  839. self.queryLengthValue.Enable(False)
  840. self.queryDangleSL.Enable(True)
  841. self.queryDangleValue.Enable(True)
  842. def OnSave(self, event):
  843. """Button 'Save' pressed
  844. """
  845. self.UpdateSettings()
  846. self.parent.toolbars['vdigit'].settingsDialog = None
  847. fileSettings = {}
  848. UserSettings.ReadSettingsFile(settings=fileSettings)
  849. fileSettings['vdigit'] = UserSettings.Get(group='vdigit')
  850. sfile = UserSettings.SaveToFile(fileSettings)
  851. self._giface.WriteLog(
  852. _('Vector digitizer settings saved to file <%s>.') %
  853. sfile)
  854. self.Destroy()
  855. event.Skip()
  856. def OnApply(self, event):
  857. """Button 'Apply' pressed
  858. """
  859. self.UpdateSettings()
  860. def OnCancel(self, event):
  861. """Button 'Cancel' pressed
  862. """
  863. self.parent.toolbars['vdigit'].settingsDialog = None
  864. self.Destroy()
  865. if event:
  866. event.Skip()
  867. def UpdateSettings(self):
  868. """Update digitizer settings
  869. .. todo::
  870. Needs refactoring
  871. """
  872. # TODO: it seems that it needs to be replaced by signal
  873. # but if it makes sense generally for wxGUI it can be added to giface
  874. if self.parent.GetLayerManager():
  875. self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes
  876. # symbology
  877. for key, (enabled, color) in self.symbology.iteritems():
  878. if enabled:
  879. UserSettings.Set(group='vdigit', key='symbol',
  880. subkey=[key, 'enabled'],
  881. value=enabled.IsChecked())
  882. UserSettings.Set(group='vdigit', key='symbol',
  883. subkey=[key, 'color'],
  884. value=tuple(color.GetColour()))
  885. else:
  886. UserSettings.Set(group='vdigit', key='symbol',
  887. subkey=[key, 'color'],
  888. value=tuple(color.GetColour()))
  889. # display
  890. UserSettings.Set(group='vdigit', key="lineWidth", subkey='value',
  891. value=int(self.lineWidthValue.GetValue()))
  892. # snapping
  893. UserSettings.Set(group='vdigit', key="snapping", subkey='value',
  894. value=int(self.snappingValue.GetValue()))
  895. UserSettings.Set(group='vdigit', key="snapping", subkey='unit',
  896. value=self.snappingUnit.GetSelection())
  897. UserSettings.Set(group='vdigit', key="snapToVertex", subkey='enabled',
  898. value=self.snapVertex.IsChecked())
  899. # digitize new feature
  900. UserSettings.Set(group='vdigit', key="addRecord", subkey='enabled',
  901. value=self.addRecord.IsChecked())
  902. UserSettings.Set(group='vdigit', key="layer", subkey='value',
  903. value=int(self.layer.GetValue()))
  904. UserSettings.Set(group='vdigit', key="category", subkey='value',
  905. value=int(self.category.GetValue()))
  906. UserSettings.Set(
  907. group='vdigit',
  908. key="categoryMode",
  909. subkey='selection',
  910. value=self.categoryMode.GetSelection())
  911. # delete existing feature
  912. UserSettings.Set(group='vdigit', key="delRecord", subkey='enabled',
  913. value=self.deleteRecord.IsChecked())
  914. # geometry attributes (workspace)
  915. mapLayer = self.parent.toolbars['vdigit'].GetLayer()
  916. tree = self._giface.GetLayerTree()
  917. if tree:
  918. item = tree.FindItemByData('maplayer', mapLayer)
  919. else:
  920. item = None
  921. for key, val in self.geomAttrb.iteritems():
  922. checked = self.FindWindowById(val['check']).IsChecked()
  923. column = self.FindWindowById(val['column']).GetValue()
  924. unitsIdx = self.FindWindowById(val['units']).GetSelection()
  925. if item and not tree.GetLayerInfo(item, key='vdigit'):
  926. tree.SetLayerInfo(
  927. item, key='vdigit', value={
  928. 'geomAttr': dict()})
  929. if checked: # enable
  930. if key == 'area':
  931. type = key
  932. else:
  933. type = 'length'
  934. unitsKey = Units.GetUnitsKey(type, unitsIdx)
  935. tree.GetLayerInfo(item, key='vdigit')['geomAttr'][key] = {
  936. 'column': column, 'units': unitsKey}
  937. else:
  938. if item and tree.GetLayerInfo(
  939. item, key='vdigit') and key in tree.GetLayerInfo(
  940. item, key='vdigit')['geomAttr']:
  941. del tree.GetLayerInfo(item, key='vdigit')['geomAttr'][key]
  942. # query tool
  943. if self.queryLength.GetValue():
  944. UserSettings.Set(group='vdigit', key="query", subkey='selection',
  945. value=0)
  946. else:
  947. UserSettings.Set(group='vdigit', key="query", subkey='type',
  948. value=1)
  949. UserSettings.Set(group='vdigit', key="query", subkey='box',
  950. value=self.queryBox.IsChecked())
  951. UserSettings.Set(
  952. group='vdigit',
  953. key="queryLength",
  954. subkey='than-selection',
  955. value=self.queryLengthSL.GetSelection())
  956. UserSettings.Set(group='vdigit', key="queryLength", subkey='thresh',
  957. value=int(self.queryLengthValue.GetValue()))
  958. UserSettings.Set(
  959. group='vdigit',
  960. key="queryDangle",
  961. subkey='than-selection',
  962. value=self.queryDangleSL.GetSelection())
  963. UserSettings.Set(group='vdigit', key="queryDangle", subkey='thresh',
  964. value=int(self.queryDangleValue.GetValue()))
  965. # select features
  966. for feature in ('point', 'line',
  967. 'centroid', 'boundary'):
  968. UserSettings.Set(
  969. group='vdigit', key='selectType', subkey=[
  970. feature, 'enabled'], value=self.FindWindowById(
  971. self.selectFeature[feature]).IsChecked())
  972. UserSettings.Set(group='vdigit', key="selectThresh", subkey='value',
  973. value=int(self.selectThreshValue.GetValue()))
  974. UserSettings.Set(group='vdigit', key="checkForDupl", subkey='enabled',
  975. value=self.checkForDupl.IsChecked())
  976. UserSettings.Set(group='vdigit', key="selectInside", subkey='enabled',
  977. value=self.selectIn.IsChecked())
  978. # on-exit
  979. UserSettings.Set(group='vdigit', key="saveOnExit", subkey='enabled',
  980. value=self.save.IsChecked())
  981. # break lines
  982. UserSettings.Set(group='vdigit', key="breakLines", subkey='enabled',
  983. value=self.intersect.IsChecked())
  984. # close boundary
  985. UserSettings.Set(group='vdigit', key="closeBoundary", subkey='enabled',
  986. value=self.closeBoundary.IsChecked())
  987. self.digit.UpdateSettings()
  988. # redraw map if auto-rendering is enabled
  989. if self.parent.IsAutoRendered():
  990. self.parent.OnRender(None)