preferences.py 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  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, FloatSpin, SpinCtrl, StaticBox, StaticText
  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.ALL, border=5)
  60. btnSizer.Add(btnApply, proportion=0,
  61. flag=wx.ALL, border=5)
  62. btnSizer.Add(btnSave, proportion=0,
  63. flag=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 = 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 = 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 = 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 = 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 = 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 = 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 = StaticText(parent=panel, id=wx.ID_ANY, label=_("Snapping threshold"))
  176. self.snappingValue = FloatSpin(
  177. parent=panel,
  178. id=wx.ID_ANY,
  179. size=(75, -1),
  180. value=UserSettings.Get(group="vdigit", key="snapping", subkey="value"),
  181. min_val=-1,
  182. max_val=1e6,
  183. digits=7,
  184. )
  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(group="vdigit", key="queryLength", subkey="than-selection")
  422. )
  423. self.queryLengthValue = FloatSpin(
  424. parent=panel,
  425. id=wx.ID_ANY,
  426. size=(100, -1),
  427. value=1,
  428. min_val=0,
  429. max_val=1e6,
  430. digits=7,
  431. )
  432. self.queryLengthValue.SetValue(
  433. UserSettings.Get(
  434. group='vdigit',
  435. key="queryLength",
  436. subkey='thresh'))
  437. units = StaticText(
  438. parent=panel,
  439. id=wx.ID_ANY,
  440. label="%s" %
  441. LocUnits)
  442. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  443. flexSizer.Add(
  444. self.queryLengthSL,
  445. proportion=0,
  446. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  447. flexSizer.Add(
  448. self.queryLengthValue,
  449. proportion=0,
  450. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  451. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  452. sizer.Add(
  453. flexSizer,
  454. proportion=0,
  455. flag=wx.ALL | wx.EXPAND,
  456. border=1)
  457. #
  458. # dangle
  459. #
  460. self.queryDangle = wx.RadioButton(
  461. parent=panel, id=wx.ID_ANY, label=_("dangle"))
  462. self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
  463. sizer.Add(
  464. self.queryDangle,
  465. proportion=0,
  466. flag=wx.ALL | wx.EXPAND,
  467. border=1)
  468. flexSizer = wx.FlexGridSizer(cols=4, hgap=5, vgap=5)
  469. flexSizer.AddGrowableCol(0)
  470. txt = StaticText(
  471. parent=panel,
  472. id=wx.ID_ANY,
  473. label=_("Select dangles"))
  474. self.queryDangleSL = wx.Choice(
  475. parent=panel, id=wx.ID_ANY, choices=[
  476. _("shorter than"), _("longer than")])
  477. self.queryDangleSL.SetSelection(
  478. UserSettings.Get(
  479. group='vdigit',
  480. key="queryDangle",
  481. subkey='than-selection'))
  482. self.queryDangleValue = SpinCtrl(
  483. parent=panel, id=wx.ID_ANY, size=(
  484. 100, -1), initial=1, min=0, max=1e6)
  485. self.queryDangleValue.SetValue(
  486. UserSettings.Get(
  487. group='vdigit',
  488. key="queryDangle",
  489. subkey='thresh'))
  490. units = StaticText(
  491. parent=panel,
  492. id=wx.ID_ANY,
  493. label="%s" %
  494. LocUnits)
  495. flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  496. flexSizer.Add(
  497. self.queryDangleSL,
  498. proportion=0,
  499. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  500. flexSizer.Add(
  501. self.queryDangleValue,
  502. proportion=0,
  503. flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  504. flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  505. sizer.Add(
  506. flexSizer,
  507. proportion=0,
  508. flag=wx.ALL | wx.EXPAND,
  509. border=1)
  510. if UserSettings.Get(group='vdigit', key="query",
  511. subkey='selection') == 0:
  512. self.queryLength.SetValue(True)
  513. else:
  514. self.queryDangle.SetValue(True)
  515. # enable & disable items
  516. self.OnChangeQuery(None)
  517. border.Add(sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  518. panel.SetSizer(border)
  519. return panel
  520. def _createAttributesPage(self, notebook):
  521. """Create notebook page for attributes"""
  522. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  523. notebook.AddPage(page=panel, text=_("Attributes"))
  524. border = wx.BoxSizer(wx.VERTICAL)
  525. #
  526. # add new record
  527. #
  528. box = StaticBox(
  529. parent=panel,
  530. id=wx.ID_ANY,
  531. label=" %s " %
  532. _("Digitize new feature"))
  533. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  534. # checkbox
  535. self.addRecord = CheckBox(parent=panel, id=wx.ID_ANY,
  536. label=_("Add new record into table"))
  537. self.addRecord.SetValue(
  538. UserSettings.Get(
  539. group='vdigit',
  540. key="addRecord",
  541. subkey='enabled'))
  542. sizer.Add(
  543. self.addRecord,
  544. proportion=0,
  545. flag=wx.ALL | wx.EXPAND,
  546. border=1)
  547. # settings
  548. flexSizer = wx.FlexGridSizer(cols=2, hgap=3, vgap=3)
  549. flexSizer.AddGrowableCol(0)
  550. settings = ((_("Layer"), 1), (_("Category"), 1),
  551. (_("Mode"), _("Next to use")))
  552. # layer
  553. text = StaticText(parent=panel, id=wx.ID_ANY, label=_("Layer"))
  554. self.layer = SpinCtrl(parent=panel, id=wx.ID_ANY, size=(125, -1),
  555. min=1, max=1e3)
  556. self.layer.SetValue(int(UserSettings.Get(
  557. group='vdigit', key="layer", subkey='value')))
  558. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  559. flexSizer.Add(self.layer, proportion=0,
  560. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  561. # category number
  562. text = StaticText(
  563. parent=panel,
  564. id=wx.ID_ANY,
  565. label=_("Category number"))
  566. self.category = SpinCtrl(
  567. parent=panel, id=wx.ID_ANY, size=(125, -1),
  568. initial=UserSettings.Get(
  569. group='vdigit', key="category", subkey='value'),
  570. min=-1e9, max=1e9)
  571. if UserSettings.Get(group='vdigit', key="categoryMode",
  572. subkey='selection') != 1:
  573. self.category.Enable(False)
  574. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  575. flexSizer.Add(self.category, proportion=0,
  576. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  577. # category mode
  578. text = StaticText(
  579. parent=panel,
  580. id=wx.ID_ANY,
  581. label=_("Category mode"))
  582. self.categoryMode = wx.Choice(parent=panel, id=wx.ID_ANY, size=(
  583. 125, -1), choices=[_("Next to use"), _("Manual entry"), _("No category")])
  584. self.categoryMode.SetSelection(
  585. UserSettings.Get(
  586. group='vdigit',
  587. key="categoryMode",
  588. subkey='selection'))
  589. flexSizer.Add(text, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  590. flexSizer.Add(self.categoryMode, proportion=0,
  591. flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  592. sizer.Add(
  593. flexSizer,
  594. proportion=1,
  595. flag=wx.ALL | wx.EXPAND,
  596. border=1)
  597. border.Add(sizer, proportion=0,
  598. flag=wx.ALL | wx.EXPAND, border=5)
  599. #
  600. # delete existing record
  601. #
  602. box = StaticBox(
  603. parent=panel, id=wx.ID_ANY, label=" %s " %
  604. _("Delete existing feature(s)"))
  605. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  606. # checkbox
  607. self.deleteRecord = CheckBox(parent=panel, id=wx.ID_ANY,
  608. label=_("Delete record from table"))
  609. self.deleteRecord.SetValue(
  610. UserSettings.Get(
  611. group='vdigit',
  612. key="delRecord",
  613. subkey='enabled'))
  614. sizer.Add(
  615. self.deleteRecord,
  616. proportion=0,
  617. flag=wx.ALL | wx.EXPAND,
  618. border=1)
  619. border.Add(sizer, proportion=0,
  620. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  621. #
  622. # geometry attributes (currently only length and area are supported)
  623. #
  624. box = StaticBox(parent=panel, id=wx.ID_ANY,
  625. label=" %s " % _("Geometry attributes"))
  626. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  627. gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
  628. self.geomAttrb = {'length': {'label': _('length')},
  629. 'area': {'label': _('area')},
  630. 'perimeter': {'label': _('perimeter')}}
  631. digitToolbar = self.parent.toolbars['vdigit']
  632. try:
  633. vectorName = digitToolbar.GetLayer().GetName()
  634. except AttributeError:
  635. vectorName = None # no vector selected for editing
  636. layer = UserSettings.Get(group='vdigit', key="layer", subkey='value')
  637. mapLayer = self.parent.toolbars['vdigit'].GetLayer()
  638. tree = self.parent.tree
  639. if tree:
  640. item = tree.FindItemByData('maplayer', mapLayer)
  641. else:
  642. item = None
  643. row = 0
  644. for attrb in ['length', 'area', 'perimeter']:
  645. # checkbox
  646. check = CheckBox(parent=panel, id=wx.ID_ANY,
  647. label=self.geomAttrb[attrb]['label'])
  648. ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled'))
  649. check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb)
  650. # column (only numeric)
  651. column = ColumnSelect(parent=panel, size=(200, -1))
  652. column.InsertColumns(vector=vectorName,
  653. layer=layer, excludeKey=True,
  654. type=['integer', 'double precision'])
  655. # units
  656. if attrb == 'area':
  657. choices = Units.GetUnitsList('area')
  658. else:
  659. choices = Units.GetUnitsList('length')
  660. win_units = wx.Choice(parent=panel, id=wx.ID_ANY,
  661. choices=choices, size=(120, -1))
  662. # default values
  663. check.SetValue(False)
  664. if item and tree.GetLayerInfo(item, key='vdigit') and \
  665. 'geomAttr' in tree.GetLayerInfo(item, key='vdigit') and \
  666. attrb in tree.GetLayerInfo(item, key='vdigit')['geomAttr']:
  667. check.SetValue(True)
  668. column.SetStringSelection(
  669. tree.GetLayerInfo(item, key='vdigit')['geomAttr']
  670. [attrb]['column'])
  671. if attrb == 'area':
  672. type = 'area'
  673. else:
  674. type = 'length'
  675. unitsIdx = Units.GetUnitsIndex(type, tree.GetLayerInfo(
  676. item, key='vdigit')['geomAttr'][attrb]['units'])
  677. win_units.SetSelection(unitsIdx)
  678. if not vectorName:
  679. check.Enable(False)
  680. column.Enable(False)
  681. if not check.IsChecked():
  682. column.Enable(False)
  683. self.geomAttrb[attrb]['check'] = check.GetId()
  684. self.geomAttrb[attrb]['column'] = column.GetId()
  685. self.geomAttrb[attrb]['units'] = win_units.GetId()
  686. gridSizer.Add(check,
  687. flag=wx.ALIGN_CENTER_VERTICAL,
  688. pos=(row, 0))
  689. gridSizer.Add(column,
  690. pos=(row, 1))
  691. gridSizer.Add(win_units,
  692. pos=(row, 2))
  693. row += 1
  694. note = '\n'.join(textwrap.wrap(_("Note: These settings are stored "
  695. "in the workspace not in the vector digitizer "
  696. "preferences."), 55))
  697. gridSizer.Add(StaticText(parent=panel, id=wx.ID_ANY,
  698. label=note),
  699. pos=(3, 0), span=(1, 3))
  700. gridSizer.AddGrowableCol(0)
  701. sizer.Add(gridSizer, proportion=1,
  702. flag=wx.ALL | wx.EXPAND, border=1)
  703. border.Add(sizer, proportion=0,
  704. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  705. # bindings
  706. self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord)
  707. self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode)
  708. self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer)
  709. panel.SetSizer(border)
  710. return panel
  711. def _symbologyData(self):
  712. """Data for _createSymbologyPage()
  713. label | checkbox | color
  714. """
  715. return (
  716. (_("Digitize new line segment"), "newSegment"),
  717. (_("Digitize new line/boundary"), "newLine"),
  718. (_("Highlight"), "highlight"),
  719. (_("Highlight (duplicates)"), "highlightDupl"),
  720. (_("Point"), "point"),
  721. (_("Line"), "line"),
  722. (_("Boundary (no area)"), "boundaryNo"),
  723. (_("Boundary (one area)"), "boundaryOne"),
  724. (_("Boundary (two areas)"), "boundaryTwo"),
  725. (_("Centroid (in area)"), "centroidIn"),
  726. (_("Centroid (outside area)"), "centroidOut"),
  727. (_("Centroid (duplicate in area)"), "centroidDup"),
  728. (_("Node (one line)"), "nodeOne"),
  729. (_("Node (two lines)"), "nodeTwo"),
  730. (_("Vertex"), "vertex"),
  731. (_("Area (closed boundary + centroid)"), "area"),
  732. (_("Direction"), "direction"),)
  733. def OnGeomAttrb(self, event):
  734. """Register geometry attributes (enable/disable)
  735. """
  736. checked = event.IsChecked()
  737. id = event.GetId()
  738. key = None
  739. for attrb, val in six.iteritems(self.geomAttrb):
  740. if val['check'] == id:
  741. key = attrb
  742. break
  743. column = self.FindWindowById(self.geomAttrb[key]['column'])
  744. if checked:
  745. column.Enable()
  746. else:
  747. column.Enable(False)
  748. def OnChangeCategoryMode(self, event):
  749. """Change category mode
  750. """
  751. mode = event.GetSelection()
  752. UserSettings.Set(
  753. group='vdigit',
  754. key="categoryMode",
  755. subkey='selection',
  756. value=mode)
  757. if mode == 1: # manual entry
  758. self.category.Enable(True)
  759. elif self.category.IsEnabled(): # disable
  760. self.category.Enable(False)
  761. if mode == 2 and self.addRecord.IsChecked(): # no category
  762. self.addRecord.SetValue(False)
  763. self.digit.SetCategory()
  764. self.category.SetValue(
  765. UserSettings.Get(
  766. group='vdigit',
  767. key='category',
  768. subkey='value'))
  769. def OnChangeLayer(self, event):
  770. """Layer changed
  771. """
  772. layer = event.GetInt()
  773. if layer > 0:
  774. UserSettings.Set(
  775. group='vdigit',
  776. key='layer',
  777. subkey='value',
  778. value=layer)
  779. self.digit.SetCategory()
  780. self.category.SetValue(
  781. UserSettings.Get(
  782. group='vdigit',
  783. key='category',
  784. subkey='value'))
  785. event.Skip()
  786. def OnChangeAddRecord(self, event):
  787. """Checkbox 'Add new record' status changed
  788. """
  789. pass
  790. # self.category.SetValue(self.digit.SetCategory())
  791. def OnChangeSnappingValue(self, event):
  792. """Change snapping value - update static text
  793. """
  794. value = self.snappingValue.GetValue()
  795. if value < 0:
  796. region = self.parent.MapWindow.Map.GetRegion()
  797. res = (region['nsres'] + region['ewres']) / 2.
  798. threshold = self.digit.GetDisplay().GetThreshold(value=res)
  799. else:
  800. if self.snappingUnit.GetSelection() == 1: # map units
  801. threshold = value
  802. else:
  803. threshold = self.digit.GetDisplay().GetThreshold(value=value)
  804. if value == 0:
  805. self.snappingInfo.SetLabel(_("Snapping disabled"))
  806. elif value < 0:
  807. self.snappingInfo.SetLabel(
  808. _(
  809. "Snapping threshold is %(value).1f %(units)s "
  810. "(based on comp. resolution)") %
  811. {'value': threshold, 'units': self.mapUnits.lower()})
  812. else:
  813. self.snappingInfo.SetLabel(
  814. _("Snapping threshold is %(value).1f %(units)s") %
  815. {'value': threshold, 'units': self.mapUnits.lower()})
  816. event.Skip()
  817. def OnChangeSnappingUnits(self, event):
  818. """Snapping units change -> update static text
  819. """
  820. value = self.snappingValue.GetValue()
  821. units = self.snappingUnit.GetSelection()
  822. threshold = self.digit.GetDisplay().GetThreshold(value=value, units=units)
  823. if units == 1: # map units
  824. self.snappingInfo.SetLabel(
  825. _("Snapping threshold is %(value).1f %(units)s") %
  826. {'value': value, 'units': self.mapUnits})
  827. else:
  828. self.snappingInfo.SetLabel(
  829. _("Snapping threshold is %(value).1f %(units)s") %
  830. {'value': threshold, 'units': self.mapUnits})
  831. event.Skip()
  832. def OnChangeQuery(self, event):
  833. """Change query
  834. """
  835. if self.queryLength.GetValue():
  836. # length
  837. self.queryLengthSL.Enable(True)
  838. self.queryLengthValue.Enable(True)
  839. self.queryDangleSL.Enable(False)
  840. self.queryDangleValue.Enable(False)
  841. else:
  842. # dangle
  843. self.queryLengthSL.Enable(False)
  844. self.queryLengthValue.Enable(False)
  845. self.queryDangleSL.Enable(True)
  846. self.queryDangleValue.Enable(True)
  847. def OnSave(self, event):
  848. """Button 'Save' pressed
  849. """
  850. self.UpdateSettings()
  851. self.parent.toolbars['vdigit'].settingsDialog = None
  852. fileSettings = {}
  853. UserSettings.ReadSettingsFile(settings=fileSettings)
  854. fileSettings['vdigit'] = UserSettings.Get(group='vdigit')
  855. sfile = UserSettings.SaveToFile(fileSettings)
  856. self._giface.WriteLog(
  857. _('Vector digitizer settings saved to file <%s>.') %
  858. sfile)
  859. self.Destroy()
  860. event.Skip()
  861. def OnApply(self, event):
  862. """Button 'Apply' pressed
  863. """
  864. self.UpdateSettings()
  865. def OnCancel(self, event):
  866. """Button 'Cancel' pressed
  867. """
  868. self.parent.toolbars['vdigit'].settingsDialog = None
  869. self.Destroy()
  870. if event:
  871. event.Skip()
  872. def UpdateSettings(self):
  873. """Update digitizer settings
  874. .. todo::
  875. Needs refactoring
  876. """
  877. # TODO: it seems that it needs to be replaced by signal
  878. # but if it makes sense generally for wxGUI it can be added to giface
  879. if self.parent.GetLayerManager():
  880. self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes
  881. # symbology
  882. for key, (enabled, color) in six.iteritems(self.symbology):
  883. if enabled:
  884. UserSettings.Set(group='vdigit', key='symbol',
  885. subkey=[key, 'enabled'],
  886. value=enabled.IsChecked())
  887. UserSettings.Set(group='vdigit', key='symbol',
  888. subkey=[key, 'color'],
  889. value=tuple(color.GetColour()))
  890. else:
  891. UserSettings.Set(group='vdigit', key='symbol',
  892. subkey=[key, 'color'],
  893. value=tuple(color.GetColour()))
  894. # display
  895. UserSettings.Set(group='vdigit', key="lineWidth", subkey='value',
  896. value=int(self.lineWidthValue.GetValue()))
  897. # snapping
  898. UserSettings.Set(
  899. group="vdigit",
  900. key="snapping",
  901. subkey="value",
  902. value=self.snappingValue.GetValue(),
  903. )
  904. UserSettings.Set(
  905. group="vdigit",
  906. key="snapping",
  907. subkey="unit",
  908. value=self.snappingUnit.GetSelection(),
  909. )
  910. UserSettings.Set(
  911. group="vdigit",
  912. key="snapToVertex",
  913. subkey="enabled",
  914. value=self.snapVertex.IsChecked(),
  915. )
  916. # digitize new feature
  917. UserSettings.Set(group='vdigit', key="addRecord", subkey='enabled',
  918. value=self.addRecord.IsChecked())
  919. UserSettings.Set(group='vdigit', key="layer", subkey='value',
  920. value=int(self.layer.GetValue()))
  921. UserSettings.Set(group='vdigit', key="category", subkey='value',
  922. value=int(self.category.GetValue()))
  923. UserSettings.Set(
  924. group='vdigit',
  925. key="categoryMode",
  926. subkey='selection',
  927. value=self.categoryMode.GetSelection())
  928. # delete existing feature
  929. UserSettings.Set(group='vdigit', key="delRecord", subkey='enabled',
  930. value=self.deleteRecord.IsChecked())
  931. # geometry attributes (workspace)
  932. mapLayer = self.parent.toolbars['vdigit'].GetLayer()
  933. tree = self._giface.GetLayerTree()
  934. if tree:
  935. item = tree.FindItemByData('maplayer', mapLayer)
  936. else:
  937. item = None
  938. for key, val in six.iteritems(self.geomAttrb):
  939. checked = self.FindWindowById(val['check']).IsChecked()
  940. column = self.FindWindowById(val['column']).GetValue()
  941. unitsIdx = self.FindWindowById(val['units']).GetSelection()
  942. if item and not tree.GetLayerInfo(item, key='vdigit'):
  943. tree.SetLayerInfo(
  944. item, key='vdigit', value={
  945. 'geomAttr': dict()})
  946. if checked: # enable
  947. if key == 'area':
  948. type = key
  949. else:
  950. type = 'length'
  951. unitsKey = Units.GetUnitsKey(type, unitsIdx)
  952. tree.GetLayerInfo(item, key='vdigit')['geomAttr'][key] = {
  953. 'column': column, 'units': unitsKey}
  954. else:
  955. if item and tree.GetLayerInfo(
  956. item, key='vdigit') and key in tree.GetLayerInfo(
  957. item, key='vdigit')['geomAttr']:
  958. del tree.GetLayerInfo(item, key='vdigit')['geomAttr'][key]
  959. # query tool
  960. if self.queryLength.GetValue():
  961. UserSettings.Set(group='vdigit', key="query", subkey='selection',
  962. value=0)
  963. else:
  964. UserSettings.Set(group='vdigit', key="query", subkey='type',
  965. value=1)
  966. UserSettings.Set(group='vdigit', key="query", subkey='box',
  967. value=self.queryBox.IsChecked())
  968. UserSettings.Set(
  969. group='vdigit',
  970. key="queryLength",
  971. subkey="thresh",
  972. value=self.queryLengthValue.GetValue(),
  973. )
  974. UserSettings.Set(
  975. group='vdigit',
  976. key="queryDangle",
  977. subkey='than-selection',
  978. value=self.queryDangleSL.GetSelection())
  979. UserSettings.Set(group='vdigit', key="queryDangle", subkey='thresh',
  980. value=int(self.queryDangleValue.GetValue()))
  981. # select features
  982. for feature in ('point', 'line',
  983. 'centroid', 'boundary'):
  984. UserSettings.Set(
  985. group='vdigit', key='selectType', subkey=[
  986. feature, 'enabled'], value=self.FindWindowById(
  987. self.selectFeature[feature]).IsChecked())
  988. UserSettings.Set(group='vdigit', key="selectThresh", subkey='value',
  989. value=int(self.selectThreshValue.GetValue()))
  990. UserSettings.Set(group='vdigit', key="checkForDupl", subkey='enabled',
  991. value=self.checkForDupl.IsChecked())
  992. UserSettings.Set(group='vdigit', key="selectInside", subkey='enabled',
  993. value=self.selectIn.IsChecked())
  994. # on-exit
  995. UserSettings.Set(group='vdigit', key="saveOnExit", subkey='enabled',
  996. value=self.save.IsChecked())
  997. # break lines
  998. UserSettings.Set(group='vdigit', key="breakLines", subkey='enabled',
  999. value=self.intersect.IsChecked())
  1000. # close boundary
  1001. UserSettings.Set(group='vdigit', key="closeBoundary", subkey='enabled',
  1002. value=self.closeBoundary.IsChecked())
  1003. self.digit.UpdateSettings()
  1004. # redraw map if auto-rendering is enabled
  1005. if self.parent.IsAutoRendered():
  1006. self.parent.OnRender(None)