preferences.py 40 KB

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