preferences.py 40 KB

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