settings.py 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  1. """
  2. @package core.settings
  3. @brief Default GUI settings
  4. List of classes:
  5. - settings::Settings
  6. Usage:
  7. @code
  8. from core.settings import UserSettings
  9. @endcode
  10. (C) 2007-2017 by the GRASS Development Team
  11. This program is free software under the GNU General Public License
  12. (>=v2). Read the file COPYING that comes with GRASS for details.
  13. @author Martin Landa <landa.martin gmail.com>
  14. @author Luca Delucchi <lucadeluge gmail.com> (language choice)
  15. """
  16. from __future__ import print_function
  17. import os
  18. import sys
  19. import copy
  20. import wx
  21. from core import globalvar
  22. from core.gcmd import GException, GError
  23. from core.utils import GetSettingsPath, PathJoin, rgb2str
  24. class Settings:
  25. """Generic class where to store settings"""
  26. def __init__(self):
  27. # settings file
  28. self.filePath = os.path.join(GetSettingsPath(), 'wx')
  29. # key/value separator
  30. self.sep = ';'
  31. # define default settings
  32. self._defaultSettings() # -> self.defaultSettings
  33. # read settings from the file
  34. self.userSettings = copy.deepcopy(self.defaultSettings)
  35. try:
  36. self.ReadSettingsFile()
  37. except GException as e:
  38. print(e.value, file=sys.stderr)
  39. # define internal settings
  40. self._internalSettings() # -> self.internalSettings
  41. def _generateLocale(self):
  42. """Generate locales
  43. """
  44. try:
  45. self.locs = os.listdir(
  46. os.path.join(
  47. os.environ['GISBASE'],
  48. 'locale'))
  49. self.locs.append('en') # GRASS doesn't ship EN po files
  50. self.locs.sort()
  51. # Add a default choice to not override system locale
  52. self.locs.insert(0, 'system')
  53. except:
  54. # No NLS
  55. self.locs = ['system']
  56. return 'system'
  57. def _defaultSettings(self):
  58. """Define default settings
  59. """
  60. try:
  61. projFile = PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
  62. except KeyError:
  63. projFile = ''
  64. id_loc = self._generateLocale()
  65. self.defaultSettings = {
  66. #
  67. # general
  68. #
  69. 'general': {
  70. # use default window layout (layer manager, displays, ...)
  71. 'defWindowPos': {
  72. 'enabled': True,
  73. 'dim' : '1,1,%d,%d,%d,1,%d,%d' % \
  74. (globalvar.GM_WINDOW_SIZE[0],
  75. globalvar.GM_WINDOW_SIZE[1],
  76. globalvar.GM_WINDOW_SIZE[0] + 1,
  77. globalvar.MAP_WINDOW_SIZE[0],
  78. globalvar.MAP_WINDOW_SIZE[1])
  79. },
  80. # workspace
  81. 'workspace': {
  82. 'posDisplay': {
  83. 'enabled': False
  84. },
  85. 'posManager': {
  86. 'enabled': False
  87. },
  88. },
  89. # region
  90. 'region': {
  91. 'resAlign': {
  92. 'enabled' : False
  93. },
  94. },
  95. },
  96. #
  97. # datacatalog
  98. #
  99. 'datacatalog': {
  100. # grassdb string
  101. 'grassdbs': {
  102. 'listAsString': ""
  103. },
  104. },
  105. 'manager': {
  106. # show opacity level widget
  107. 'changeOpacityLevel': {
  108. 'enabled': False
  109. },
  110. # ask when removing layer from layer tree
  111. 'askOnRemoveLayer': {
  112. 'enabled': True
  113. },
  114. # ask when quiting wxGUI or closing display
  115. 'askOnQuit': {
  116. 'enabled': True
  117. },
  118. # hide tabs
  119. 'hideTabs': {
  120. 'search': False,
  121. 'pyshell': False,
  122. },
  123. 'copySelectedTextToClipboard': {
  124. 'enabled': False
  125. },
  126. },
  127. #
  128. # appearance
  129. #
  130. 'appearance': {
  131. 'outputfont': {
  132. 'type': 'Courier New',
  133. 'size': '10',
  134. },
  135. # expand/collapse element list
  136. 'elementListExpand': {
  137. 'selection': 0
  138. },
  139. 'menustyle': {
  140. 'selection': 1
  141. },
  142. 'gSelectPopupHeight': {
  143. 'value': 200
  144. },
  145. 'iconTheme': {
  146. 'type': 'grass'
  147. },
  148. 'commandNotebook': {
  149. 'selection': 0 if sys.platform in ('win32', 'darwin') else 1
  150. },
  151. },
  152. #
  153. # language
  154. #
  155. 'language': {
  156. 'locale': {
  157. 'lc_all': id_loc
  158. }
  159. },
  160. #
  161. # display
  162. #
  163. 'display': {
  164. 'font': {
  165. 'type': '',
  166. 'encoding': 'UTF-8',
  167. },
  168. 'driver': {
  169. 'type': 'cairo'
  170. },
  171. 'alignExtent': {
  172. 'enabled': True
  173. },
  174. 'compResolution': {
  175. 'enabled': False
  176. },
  177. 'autoRendering': {
  178. 'enabled': True
  179. },
  180. 'autoZooming': {
  181. 'enabled': False
  182. },
  183. 'showCompExtent': {
  184. 'enabled': True
  185. },
  186. 'statusbarMode': {
  187. 'selection': 0
  188. },
  189. 'bgcolor': {
  190. 'color': (255, 255, 255, 255),
  191. },
  192. 'mouseWheelZoom': {
  193. 'selection': 1,
  194. },
  195. 'scrollDirection': {
  196. 'selection': 0,
  197. },
  198. 'nvizDepthBuffer': {
  199. 'value': '16',
  200. },
  201. },
  202. #
  203. # projection
  204. #
  205. 'projection': {
  206. 'statusbar': {
  207. 'proj4': '',
  208. 'epsg': '',
  209. 'projFile': projFile,
  210. },
  211. 'format': {
  212. 'll': 'DMS',
  213. 'precision': 2,
  214. },
  215. },
  216. #
  217. # Attribute Table Manager
  218. #
  219. 'atm': {
  220. 'highlight': {
  221. 'color': (255, 255, 0, 255),
  222. 'width': 2,
  223. 'auto': True,
  224. },
  225. 'leftDbClick': {
  226. 'selection': 1 # draw selected
  227. },
  228. 'askOnDeleteRec': {
  229. 'enabled': True
  230. },
  231. 'keycolumn': {
  232. 'value': 'cat'
  233. },
  234. 'encoding': {
  235. 'value': '',
  236. }
  237. },
  238. #
  239. # Command
  240. #
  241. 'cmd': {
  242. 'overwrite': {
  243. 'enabled': False
  244. },
  245. 'closeDlg': {
  246. 'enabled': False
  247. },
  248. 'verbosity': {
  249. 'selection': 'grassenv'
  250. },
  251. 'addNewLayer': {
  252. 'enabled': True,
  253. },
  254. 'interactiveInput': {
  255. 'enabled': True,
  256. },
  257. },
  258. #
  259. # d.rast
  260. #
  261. 'rasterLayer': {
  262. 'opaque': {
  263. 'enabled': False
  264. },
  265. 'colorTable': {
  266. 'enabled': False,
  267. 'selection': 'rainbow'
  268. },
  269. },
  270. #
  271. # d.vect
  272. #
  273. 'vectorLayer': {
  274. 'featureColor': {
  275. 'color': (0, 0, 0),
  276. 'transparent': {
  277. 'enabled': False
  278. }
  279. },
  280. 'areaFillColor': {
  281. 'color': (200, 200, 200),
  282. 'transparent': {
  283. 'enabled': False
  284. }
  285. },
  286. 'line': {
  287. 'width': 0,
  288. },
  289. 'point': {
  290. 'symbol': 'basic/x',
  291. 'size': 5,
  292. },
  293. 'showType': {
  294. 'point': {
  295. 'enabled': True
  296. },
  297. 'line': {
  298. 'enabled': True
  299. },
  300. 'centroid': {
  301. 'enabled': False
  302. },
  303. 'boundary': {
  304. 'enabled': False
  305. },
  306. 'area': {
  307. 'enabled': True
  308. },
  309. 'face': {
  310. 'enabled': True
  311. },
  312. },
  313. 'randomColors': {
  314. 'enabled': False,
  315. },
  316. },
  317. #
  318. # vdigit
  319. #
  320. 'vdigit': {
  321. # symbology
  322. 'symbol': {
  323. 'newSegment': {
  324. 'enabled': None,
  325. 'color': (255, 0, 0, 255)
  326. }, # red
  327. 'newLine': {
  328. 'enabled': None,
  329. 'color': (0, 86, 45, 255)
  330. }, # dark green
  331. 'highlight': {
  332. 'enabled': None,
  333. 'color': (255, 255, 0, 255)
  334. }, # yellow
  335. 'highlightDupl': {
  336. 'enabled': None,
  337. 'color': (255, 72, 0, 255)
  338. }, # red
  339. 'point': {
  340. 'enabled': True,
  341. 'color': (0, 0, 0, 255)
  342. }, # black
  343. 'line': {
  344. 'enabled': True,
  345. 'color': (0, 0, 0, 255)
  346. }, # black
  347. 'boundaryNo': {
  348. 'enabled': True,
  349. 'color': (126, 126, 126, 255)
  350. }, # grey
  351. 'boundaryOne': {
  352. 'enabled': True,
  353. 'color': (0, 255, 0, 255)
  354. }, # green
  355. 'boundaryTwo': {
  356. 'enabled': True,
  357. 'color': (255, 135, 0, 255)
  358. }, # orange
  359. 'centroidIn': {
  360. 'enabled': True,
  361. 'color': (0, 0, 255, 255)
  362. }, # blue
  363. 'centroidOut': {
  364. 'enabled': True,
  365. 'color': (165, 42, 42, 255)
  366. }, # brown
  367. 'centroidDup': {
  368. 'enabled': True,
  369. 'color': (156, 62, 206, 255)
  370. }, # violet
  371. 'nodeOne': {
  372. 'enabled': True,
  373. 'color': (255, 0, 0, 255)
  374. }, # red
  375. 'nodeTwo': {
  376. 'enabled': True,
  377. 'color': (0, 86, 45, 255)
  378. }, # dark green
  379. 'vertex': {
  380. 'enabled': False,
  381. 'color': (255, 20, 147, 255)
  382. }, # deep pink
  383. 'area': {
  384. 'enabled': True,
  385. 'color': (217, 255, 217, 255)
  386. }, # green
  387. 'direction': {
  388. 'enabled': False,
  389. 'color': (255, 0, 0, 255)
  390. }, # red
  391. },
  392. # display
  393. 'lineWidth': {
  394. 'value': 2,
  395. 'units': 'screen pixels'
  396. },
  397. # snapping
  398. 'snapping': {
  399. 'value': 10,
  400. 'unit': 0, # new
  401. 'units': 'screen pixels' # old for backwards comp.
  402. },
  403. 'snapToVertex': {
  404. 'enabled': True
  405. },
  406. # digitize new record
  407. 'addRecord': {
  408. 'enabled': True
  409. },
  410. 'layer': {
  411. 'value': 1
  412. },
  413. 'category': {
  414. 'value': 1
  415. },
  416. 'categoryMode': {
  417. 'selection': 0
  418. },
  419. # delete existing feature(s)
  420. 'delRecord': {
  421. 'enabled': True
  422. },
  423. # query tool
  424. 'query': {
  425. 'selection': 0,
  426. 'box': True
  427. },
  428. 'queryLength': {
  429. 'than-selection': 0,
  430. 'thresh': 0
  431. },
  432. 'queryDangle': {
  433. 'than-selection': 0,
  434. 'thresh': 0
  435. },
  436. # select feature (point, line, centroid, boundary)
  437. 'selectType': {
  438. 'point': {
  439. 'enabled': True
  440. },
  441. 'line': {
  442. 'enabled': True
  443. },
  444. 'centroid': {
  445. 'enabled': True
  446. },
  447. 'boundary': {
  448. 'enabled': True
  449. },
  450. },
  451. 'selectThresh': {
  452. 'value': 10,
  453. 'unit': 0, # new
  454. 'units': 'screen pixels' # old for backwards comp.
  455. },
  456. 'checkForDupl': {
  457. 'enabled': False
  458. },
  459. 'selectInside': {
  460. 'enabled': False
  461. },
  462. # exit
  463. 'saveOnExit': {
  464. 'enabled': False,
  465. },
  466. # break lines on intersection
  467. 'breakLines': {
  468. 'enabled': True,
  469. },
  470. # close boundary (snap to the first node)
  471. 'closeBoundary': {
  472. 'enabled': False,
  473. }
  474. },
  475. #
  476. # plots for profiles, histograms, and scatterplots
  477. #
  478. 'profile': {
  479. 'raster': {
  480. 'pcolor': (0, 0, 255, 255), # line color
  481. 'pwidth': 1, # line width
  482. 'pstyle': 'solid', # line pen style
  483. 'datatype': 'cell', # raster type
  484. },
  485. 'font': {
  486. 'titleSize': 12,
  487. 'axisSize': 11,
  488. 'legendSize': 10,
  489. 'defaultSize': 11,
  490. 'family': wx.FONTFAMILY_SWISS,
  491. 'style': wx.FONTSTYLE_NORMAL,
  492. 'weight': wx.FONTWEIGHT_NORMAL,
  493. },
  494. 'marker': {
  495. 'color': (0, 0, 0, 255),
  496. 'fill': 'transparent',
  497. 'size': 2,
  498. 'type': 'triangle',
  499. 'legend': _('Segment break'),
  500. },
  501. 'grid': {
  502. 'color': (200, 200, 200, 255),
  503. 'enabled': True,
  504. },
  505. 'x-axis': {
  506. 'type': 'auto', # axis format
  507. 'min': 0, # axis min for custom axis range
  508. 'max': 0, # axis max for custom axis range
  509. 'log': False,
  510. },
  511. 'y-axis': {
  512. 'type': 'auto', # axis format
  513. 'min': 0, # axis min for custom axis range
  514. 'max': 0, # axis max for custom axis range
  515. 'log': False,
  516. },
  517. 'legend': {
  518. 'enabled': True
  519. },
  520. },
  521. 'histogram': {
  522. 'raster': {
  523. 'pcolor': (0, 0, 255, 255), # line color
  524. 'pwidth': 1, # line width
  525. 'pstyle': 'solid', # line pen style
  526. 'datatype': 'cell', # raster type
  527. },
  528. 'font': {
  529. 'titleSize': 12,
  530. 'axisSize': 11,
  531. 'legendSize': 10,
  532. 'defaultSize': 11,
  533. 'family': wx.FONTFAMILY_SWISS,
  534. 'style': wx.FONTSTYLE_NORMAL,
  535. 'weight': wx.FONTWEIGHT_NORMAL,
  536. },
  537. 'grid': {
  538. 'color': (200, 200, 200, 255),
  539. 'enabled': True,
  540. },
  541. 'x-axis': {
  542. 'type': 'auto', # axis format
  543. 'min': 0, # axis min for custom axis range
  544. 'max': 0, # axis max for custom axis range
  545. 'log': False,
  546. },
  547. 'y-axis': {
  548. 'type': 'auto', # axis format
  549. 'min': 0, # axis min for custom axis range
  550. 'max': 0, # axis max for custom axis range
  551. 'log': False,
  552. },
  553. 'legend': {
  554. 'enabled': True
  555. },
  556. },
  557. 'scatter': {
  558. 'raster': {
  559. 'pcolor': (0, 0, 255, 255),
  560. 'pfill': 'solid',
  561. 'psize': 1,
  562. 'ptype': 'dot',
  563. # FIXME: this is only a quick fix
  564. # using also names used in a base class for compatibility
  565. # probably used only for initialization
  566. # base should be rewritten to not require this
  567. 'pwidth': 1, # required by wxplot/base, maybe useless here
  568. 'pstyle': 'dot', # line pen style
  569. 'plegend': _('Data point'),
  570. 0: {'datatype': 'CELL'},
  571. 1: {'datatype': 'CELL'},
  572. },
  573. 'font': {
  574. 'titleSize': 12,
  575. 'axisSize': 11,
  576. 'legendSize': 10,
  577. 'defaultSize': 11,
  578. 'family': wx.FONTFAMILY_SWISS,
  579. 'style': wx.FONTSTYLE_NORMAL,
  580. 'weight': wx.FONTWEIGHT_NORMAL,
  581. },
  582. 'grid': {
  583. 'color': (200, 200, 200, 255),
  584. 'enabled': True,
  585. },
  586. 'x-axis': {
  587. 'type': 'auto', # axis format
  588. 'min': 0, # axis min for custom axis range
  589. 'max': 0, # axis max for custom axis range
  590. 'log': False,
  591. },
  592. 'y-axis': {
  593. 'type': 'auto', # axis format
  594. 'min': 0, # axis min for custom axis range
  595. 'max': 0, # axis max for custom axis range
  596. 'log': False,
  597. },
  598. 'legend': {
  599. 'enabled': True
  600. },
  601. },
  602. 'gcpman': {
  603. 'rms': {
  604. 'highestonly': True,
  605. 'sdfactor': 1,
  606. },
  607. 'symbol': {
  608. 'color': (0, 0, 255, 255),
  609. 'hcolor': (255, 0, 0, 255),
  610. 'scolor': (0, 255, 0, 255),
  611. 'ucolor': (255, 165, 0, 255),
  612. 'unused': True,
  613. 'size': 8,
  614. 'width': 2,
  615. },
  616. 'map': {
  617. 'overwrite': False,
  618. },
  619. },
  620. 'nviz': {
  621. 'view': {
  622. 'persp': {
  623. 'value': 20,
  624. 'step': 2,
  625. },
  626. 'position': {
  627. 'x': 0.84,
  628. 'y': 0.16,
  629. },
  630. 'twist': {
  631. 'value': 0,
  632. },
  633. 'z-exag': {
  634. 'min': 0,
  635. 'max': 10,
  636. 'value': 1,
  637. },
  638. 'background': {
  639. 'color': (255, 255, 255, 255), # white
  640. },
  641. },
  642. 'fly': {
  643. 'exag': {
  644. 'move': 5,
  645. 'turn': 5,
  646. }
  647. },
  648. 'animation': {
  649. 'fps': 24,
  650. 'prefix': _("animation")
  651. },
  652. 'surface': {
  653. 'shine': {
  654. 'map': False,
  655. 'value': 60.0,
  656. },
  657. 'color': {
  658. 'map': True,
  659. 'value': (100, 100, 100, 255), # constant: grey
  660. },
  661. 'draw': {
  662. 'wire-color': (136, 136, 136, 255),
  663. 'mode': 1, # fine
  664. 'style': 1, # surface
  665. 'shading': 1, # gouraud
  666. 'res-fine': 6,
  667. 'res-coarse': 9,
  668. },
  669. 'position': {
  670. 'x': 0,
  671. 'y': 0,
  672. 'z': 0,
  673. },
  674. },
  675. 'constant': {
  676. 'color': (100, 100, 100, 255),
  677. 'value': 0.0,
  678. 'transp': 0,
  679. 'resolution': 6
  680. },
  681. 'vector': {
  682. 'lines': {
  683. 'show': False,
  684. 'width': 2,
  685. 'color': (0, 0, 0, 255),
  686. 'flat': False,
  687. 'height': 0,
  688. 'rgbcolumn': None,
  689. 'sizecolumn': None,
  690. },
  691. 'points': {
  692. 'show': False,
  693. 'size': 100,
  694. 'autosize': True,
  695. 'width': 2,
  696. 'marker': 2,
  697. 'color': (0, 0, 0, 255),
  698. 'height': 0,
  699. 'rgbcolumn': None,
  700. 'sizecolumn': None,
  701. }
  702. },
  703. 'volume': {
  704. 'color': {
  705. 'map': True,
  706. 'value': (100, 100, 100, 255), # constant: grey
  707. },
  708. 'draw': {
  709. 'mode': 0, # isosurfaces
  710. 'shading': 1, # gouraud
  711. 'resolution': 3, # polygon resolution
  712. 'box': False # draw wire box
  713. },
  714. 'shine': {
  715. 'map': False,
  716. 'value': 60,
  717. },
  718. 'topo': {
  719. 'map': None,
  720. 'value': 0.0
  721. },
  722. 'transp': {
  723. 'map': None,
  724. 'value': 0
  725. },
  726. 'mask': {
  727. 'map': None,
  728. 'value': ''
  729. },
  730. 'slice_position': {
  731. 'x1': 0,
  732. 'x2': 1,
  733. 'y1': 0,
  734. 'y2': 1,
  735. 'z1': 0,
  736. 'z2': 1,
  737. 'axis': 0,
  738. }
  739. },
  740. 'cplane': {
  741. 'shading': 4,
  742. 'rotation': {
  743. 'rot': 180,
  744. 'tilt': 0
  745. },
  746. 'position': {
  747. 'x': 0,
  748. 'y': 0,
  749. 'z': 0
  750. }
  751. },
  752. 'light': {
  753. 'position': {
  754. 'x': 0.68,
  755. 'y': -0.68,
  756. 'z': 80,
  757. },
  758. 'bright': 80,
  759. 'color': (255, 255, 255, 255), # white
  760. 'ambient': 20,
  761. },
  762. 'fringe': {
  763. 'elev': 55,
  764. 'color': (128, 128, 128, 255), # grey
  765. },
  766. 'arrow': {
  767. 'color': (0, 0, 0),
  768. },
  769. 'scalebar': {
  770. 'color': (0, 0, 0),
  771. }
  772. },
  773. 'modeler': {
  774. 'disabled': {
  775. 'color': (211, 211, 211, 255), # light grey
  776. },
  777. 'action': {
  778. 'color': {
  779. 'valid': (180, 234, 154, 255), # light green
  780. 'invalid': (255, 255, 255, 255), # white
  781. 'running': (255, 0, 0, 255), # red
  782. },
  783. 'size': {
  784. 'width': 125,
  785. 'height': 50,
  786. },
  787. 'width': {
  788. 'parameterized': 2,
  789. 'default': 1,
  790. },
  791. },
  792. 'data': {
  793. 'color': {
  794. 'raster': (215, 215, 248, 255), # light blue
  795. 'raster3d': (215, 248, 215, 255), # light green
  796. 'vector': (248, 215, 215, 255), # light red
  797. 'dbtable': (255, 253, 194, 255), # light yellow
  798. },
  799. 'size': {
  800. 'width': 175,
  801. 'height': 50,
  802. },
  803. },
  804. 'loop': {
  805. 'color': {
  806. 'valid': (234, 226, 154, 255), # dark yellow
  807. },
  808. 'size': {
  809. 'width': 175,
  810. 'height': 40,
  811. },
  812. },
  813. 'if-else': {
  814. 'size': {
  815. 'width': 150,
  816. 'height': 40,
  817. },
  818. },
  819. 'comment': {
  820. 'color': (255, 233, 208, 255), # light yellow
  821. 'size': {
  822. 'width': 200,
  823. 'height': 100,
  824. },
  825. },
  826. },
  827. 'mapswipe': {
  828. 'cursor': {
  829. 'color': (0, 0, 0, 255),
  830. 'size': 12,
  831. 'width': 1,
  832. 'type': {
  833. 'selection': 0,
  834. }
  835. },
  836. },
  837. 'animation': {
  838. 'bgcolor': {
  839. 'color': (255, 255, 255, 255),
  840. },
  841. 'nprocs': {
  842. 'value': -1,
  843. },
  844. 'font': {
  845. 'bgcolor': (255, 255, 255, 255),
  846. 'fgcolor': (0, 0, 0, 255),
  847. },
  848. 'temporal': {
  849. 'format': '%Y-%m-%d %H:%M:%S',
  850. 'nodata': {
  851. 'enable': False
  852. },
  853. },
  854. },
  855. }
  856. # quick fix, http://trac.osgeo.org/grass/ticket/1233
  857. # TODO
  858. if sys.platform == 'darwin':
  859. self.defaultSettings['general']['defWindowPos']['enabled'] = False
  860. def _internalSettings(self):
  861. """Define internal settings (based on user settings)
  862. """
  863. self.internalSettings = {}
  864. for group in list(self.userSettings.keys()):
  865. self.internalSettings[group] = {}
  866. for key in list(self.userSettings[group].keys()):
  867. self.internalSettings[group][key] = {}
  868. # self.internalSettings['general']["mapsetPath"]['value'] = self.GetMapsetPath()
  869. self.internalSettings['appearance']['elementListExpand']['choices'] = \
  870. (_("Collapse all except PERMANENT and current"),
  871. _("Collapse all except PERMANENT"),
  872. _("Collapse all except current"),
  873. _("Collapse all"),
  874. _("Expand all"))
  875. self.internalSettings['language'][
  876. 'locale']['choices'] = tuple(self.locs)
  877. self.internalSettings['atm']['leftDbClick']['choices'] = (
  878. _('Edit selected record'), _('Display selected'))
  879. self.internalSettings['cmd']['verbosity']['choices'] = ('grassenv',
  880. 'verbose',
  881. 'quiet')
  882. self.internalSettings['appearance'][
  883. 'iconTheme']['choices'] = ('grass',)
  884. self.internalSettings['appearance']['menustyle']['choices'] = \
  885. (_("Classic (labels only)"),
  886. _("Combined (labels and module names)"),
  887. _("Expert (module names only)"))
  888. self.internalSettings['appearance']['gSelectPopupHeight']['min'] = 50
  889. # there is also maxHeight given to TreeCtrlComboPopup.GetAdjustedSize
  890. self.internalSettings['appearance']['gSelectPopupHeight']['max'] = 1000
  891. self.internalSettings['appearance']['commandNotebook']['choices'] = \
  892. (_("Basic top"),
  893. _("Basic left"),
  894. _("Fancy green"),
  895. _("List left"))
  896. self.internalSettings['display'][
  897. 'driver']['choices'] = ['cairo', 'png']
  898. self.internalSettings['display']['statusbarMode'][
  899. 'choices'] = None # set during MapFrame init
  900. self.internalSettings['display']['mouseWheelZoom']['choices'] = (
  901. _('Zoom and recenter'), _('Zoom to mouse cursor'), _('Nothing'))
  902. self.internalSettings['display']['scrollDirection']['choices'] = (
  903. _('Scroll forward to zoom in'), _('Scroll back to zoom in'))
  904. self.internalSettings['nviz']['view'] = {}
  905. self.internalSettings['nviz']['view']['twist'] = {}
  906. self.internalSettings['nviz']['view']['twist']['min'] = -180
  907. self.internalSettings['nviz']['view']['twist']['max'] = 180
  908. self.internalSettings['nviz']['view']['persp'] = {}
  909. self.internalSettings['nviz']['view']['persp']['min'] = 1
  910. self.internalSettings['nviz']['view']['persp']['max'] = 100
  911. self.internalSettings['nviz']['view']['height'] = {}
  912. self.internalSettings['nviz']['view']['height']['value'] = -1
  913. self.internalSettings['nviz']['view']['z-exag'] = {}
  914. self.internalSettings['nviz']['view']['z-exag']['llRatio'] = 1
  915. self.internalSettings['nviz']['view']['rotation'] = None
  916. self.internalSettings['nviz']['view']['focus'] = {}
  917. self.internalSettings['nviz']['view']['focus']['x'] = -1
  918. self.internalSettings['nviz']['view']['focus']['y'] = -1
  919. self.internalSettings['nviz']['view']['focus']['z'] = -1
  920. self.internalSettings['nviz']['view']['dir'] = {}
  921. self.internalSettings['nviz']['view']['dir']['x'] = -1
  922. self.internalSettings['nviz']['view']['dir']['y'] = -1
  923. self.internalSettings['nviz']['view']['dir']['z'] = -1
  924. self.internalSettings['nviz']['view']['dir']['use'] = False
  925. for decor in ('arrow', 'scalebar'):
  926. self.internalSettings['nviz'][decor] = {}
  927. self.internalSettings['nviz'][decor]['position'] = {}
  928. self.internalSettings['nviz'][decor]['position']['x'] = 0
  929. self.internalSettings['nviz'][decor]['position']['y'] = 0
  930. self.internalSettings['nviz'][decor]['size'] = 100
  931. self.internalSettings['nviz']['vector'] = {}
  932. self.internalSettings['nviz']['vector']['points'] = {}
  933. self.internalSettings['nviz']['vector']['points']['marker'] = ("x",
  934. _("box"),
  935. _("sphere"),
  936. _("cube"),
  937. _("diamond"),
  938. _("aster"),
  939. _("gyro"),
  940. _("histogram"))
  941. self.internalSettings['vdigit']['bgmap'] = {}
  942. self.internalSettings['vdigit']['bgmap']['value'] = ''
  943. self.internalSettings['mapswipe']['cursor']['type'] = {}
  944. self.internalSettings['mapswipe']['cursor']['type'][
  945. 'choices'] = (_("cross"), _("box"), _("circle"))
  946. def ReadSettingsFile(self, settings=None):
  947. """Reads settings file (mapset, location, gisdbase)"""
  948. if settings is None:
  949. settings = self.userSettings
  950. self._readFile(self.filePath, settings)
  951. # set environment variables
  952. font = self.Get(group='display', key='font', subkey='type')
  953. enc = self.Get(group='display', key='font', subkey='encoding')
  954. if font:
  955. os.environ["GRASS_FONT"] = font
  956. if enc:
  957. os.environ["GRASS_ENCODING"] = enc
  958. def _readFile(self, filename, settings=None):
  959. """Read settings from file to dict
  960. :param filename: settings file path
  961. :param settings: dict where to store settings (None for self.userSettings)
  962. """
  963. if settings is None:
  964. settings = self.userSettings
  965. if not os.path.exists(filename):
  966. return
  967. try:
  968. fd = open(filename, "r")
  969. except IOError:
  970. sys.stderr.write(
  971. _("Unable to read settings file <%s>\n") %
  972. filename)
  973. return
  974. try:
  975. line = ''
  976. for line in fd.readlines():
  977. line = line.rstrip('%s' % os.linesep)
  978. group, key = line.split(self.sep)[0:2]
  979. kv = line.split(self.sep)[2:]
  980. subkeyMaster = None
  981. if len(kv) % 2 != 0: # multiple (e.g. nviz)
  982. subkeyMaster = kv[0]
  983. del kv[0]
  984. idx = 0
  985. while idx < len(kv):
  986. if subkeyMaster:
  987. subkey = [subkeyMaster, kv[idx]]
  988. else:
  989. subkey = kv[idx]
  990. value = kv[idx + 1]
  991. value = self._parseValue(value, read=True)
  992. self.Append(settings, group, key, subkey, value)
  993. idx += 2
  994. except ValueError as e:
  995. print(_(
  996. "Error: Reading settings from file <%(file)s> failed.\n"
  997. "\t\tDetails: %(detail)s\n"
  998. "\t\tLine: '%(line)s'\n") % {
  999. 'file': filename, 'detail': e, 'line': line},
  1000. file=sys.stderr)
  1001. fd.close()
  1002. fd.close()
  1003. def SaveToFile(self, settings=None):
  1004. """Save settings to the file"""
  1005. if settings is None:
  1006. settings = self.userSettings
  1007. dirPath = GetSettingsPath()
  1008. if not os.path.exists(dirPath):
  1009. try:
  1010. os.mkdir(dirPath)
  1011. except:
  1012. GError(_('Unable to create settings directory'))
  1013. return
  1014. try:
  1015. newline = '\n'
  1016. file = open(self.filePath, "w")
  1017. for group in list(settings.keys()):
  1018. for key in list(settings[group].keys()):
  1019. subkeys = list(settings[group][key].keys())
  1020. file.write('%s%s%s%s' % (group, self.sep, key, self.sep))
  1021. for idx in range(len(subkeys)):
  1022. value = settings[group][key][subkeys[idx]]
  1023. if isinstance(value, dict):
  1024. if idx > 0:
  1025. file.write(
  1026. '%s%s%s%s%s' %
  1027. (newline, group, self.sep, key, self.sep))
  1028. file.write('%s%s' % (subkeys[idx], self.sep))
  1029. kvalues = list(settings[group][key][subkeys[idx]].keys())
  1030. srange = range(len(kvalues))
  1031. for sidx in srange:
  1032. svalue = self._parseValue(
  1033. settings[group][key][
  1034. subkeys[idx]][
  1035. kvalues[sidx]])
  1036. file.write('%s%s%s' % (kvalues[sidx], self.sep,
  1037. svalue))
  1038. if sidx < len(kvalues) - 1:
  1039. file.write('%s' % self.sep)
  1040. else:
  1041. if idx > 0 and isinstance(
  1042. settings[group][key][subkeys[idx - 1]],
  1043. dict):
  1044. file.write(
  1045. '%s%s%s%s%s' %
  1046. (newline, group, self.sep, key, self.sep))
  1047. value = self._parseValue(
  1048. settings[group][key][subkeys[idx]])
  1049. file.write(
  1050. '%s%s%s' %
  1051. (subkeys[idx], self.sep, value))
  1052. if idx < len(subkeys) - 1 and not isinstance(
  1053. settings[group][key][subkeys[idx + 1]],
  1054. dict):
  1055. file.write('%s' % self.sep)
  1056. file.write(newline)
  1057. except IOError as e:
  1058. raise GException(e)
  1059. except Exception as e:
  1060. raise GException(_('Writing settings to file <%(file)s> failed.'
  1061. '\n\nDetails: %(detail)s') %
  1062. {'file': self.filePath, 'detail': e})
  1063. file.close()
  1064. return self.filePath
  1065. def _parseValue(self, value, read=False):
  1066. """Parse value to be store in settings file"""
  1067. if read: # -> read settings (cast values)
  1068. if value == 'True':
  1069. value = True
  1070. elif value == 'False':
  1071. value = False
  1072. elif value == 'None':
  1073. value = None
  1074. elif ':' in value: # -> color
  1075. try:
  1076. value = tuple(map(int, value.split(':')))
  1077. except ValueError: # -> string
  1078. pass
  1079. else:
  1080. try:
  1081. value = int(value)
  1082. except ValueError:
  1083. try:
  1084. value = float(value)
  1085. except ValueError:
  1086. pass
  1087. else: # -> write settings
  1088. if isinstance(value, type(())): # -> color
  1089. value = str(value[0]) + ':' +\
  1090. str(value[1]) + ':' + \
  1091. str(value[2])
  1092. return value
  1093. def Get(self, group, key=None, subkey=None, settings_type='user'):
  1094. """Get value by key/subkey
  1095. Raise KeyError if key is not found
  1096. :param group: settings group
  1097. :param key: (value, None)
  1098. :param subkey: (value, list or None)
  1099. :param settings_type: 'user', 'internal', 'default'
  1100. :return: value
  1101. """
  1102. if settings_type == 'user':
  1103. settings = self.userSettings
  1104. elif settings_type == 'internal':
  1105. settings = self.internalSettings
  1106. else:
  1107. settings = self.defaultSettings
  1108. try:
  1109. if subkey is None:
  1110. if key is None:
  1111. return settings[group]
  1112. else:
  1113. return settings[group][key]
  1114. else:
  1115. if isinstance(subkey, type(tuple())) or \
  1116. isinstance(subkey, type(list())):
  1117. return settings[group][key][subkey[0]][subkey[1]]
  1118. else:
  1119. return settings[group][key][subkey]
  1120. except KeyError:
  1121. print("Settings: unable to get value '%s:%s:%s'\n" % (
  1122. group, key, subkey), file=sys.stderr)
  1123. def Set(self, group, value, key=None, subkey=None, settings_type='user'):
  1124. """Set value of key/subkey
  1125. Raise KeyError if group/key is not found
  1126. :param group: settings group
  1127. :param key: key (value, None)
  1128. :param subkey: subkey (value, list or None)
  1129. :param value: value
  1130. :param settings_type: 'user', 'internal', 'default'
  1131. """
  1132. if settings_type == 'user':
  1133. settings = self.userSettings
  1134. elif settings_type == 'internal':
  1135. settings = self.internalSettings
  1136. else:
  1137. settings = self.defaultSettings
  1138. try:
  1139. if subkey is None:
  1140. if key is None:
  1141. settings[group] = value
  1142. else:
  1143. settings[group][key] = value
  1144. else:
  1145. if isinstance(subkey, type(tuple())) or \
  1146. isinstance(subkey, type(list())):
  1147. settings[group][key][subkey[0]][subkey[1]] = value
  1148. else:
  1149. settings[group][key][subkey] = value
  1150. except KeyError:
  1151. raise GException("%s '%s:%s:%s'" %
  1152. (_("Unable to set "), group, key, subkey))
  1153. def Append(self, dict, group, key, subkey, value, overwrite=True):
  1154. """Set value of key/subkey
  1155. Create group/key/subkey if not exists
  1156. :param dict: settings dictionary to use
  1157. :param group: settings group
  1158. :param key: key
  1159. :param subkey: subkey (value or list)
  1160. :param value: value
  1161. :param overwrite: True to overwrite existing value
  1162. """
  1163. hasValue = True
  1164. if group not in dict:
  1165. dict[group] = {}
  1166. hasValue = False
  1167. if key not in dict[group]:
  1168. dict[group][key] = {}
  1169. hasValue = False
  1170. if isinstance(subkey, list):
  1171. # TODO: len(subkey) > 2
  1172. if subkey[0] not in dict[group][key]:
  1173. dict[group][key][subkey[0]] = {}
  1174. hasValue = False
  1175. if subkey[1] not in dict[group][key][subkey[0]]:
  1176. hasValue = False
  1177. try:
  1178. if overwrite or (not overwrite and not hasValue):
  1179. dict[group][key][subkey[0]][subkey[1]] = value
  1180. except TypeError:
  1181. print(_("Unable to parse settings '%s'") % value +
  1182. ' (' + group + ':' + key + ':' + subkey[0] +
  1183. ':' + subkey[1] + ')', file=sys.stderr)
  1184. else:
  1185. if subkey not in dict[group][key]:
  1186. hasValue = False
  1187. try:
  1188. if overwrite or (not overwrite and not hasValue):
  1189. dict[group][key][subkey] = value
  1190. except TypeError:
  1191. print(_("Unable to parse settings '%s'") % value +
  1192. ' (' + group + ':' + key + ':' + subkey + ')',
  1193. file=sys.stderr)
  1194. def GetDefaultSettings(self):
  1195. """Get default user settings"""
  1196. return self.defaultSettings
  1197. def Reset(self, key=None):
  1198. """Reset to default settings
  1199. :param key: key in settings dict (None for all keys)
  1200. """
  1201. if not key:
  1202. self.userSettings = copy.deepcopy(self.defaultSettings)
  1203. else:
  1204. self.userSettings[key] = copy.deepcopy(self.defaultSettings[key])
  1205. UserSettings = Settings()
  1206. def GetDisplayVectSettings():
  1207. settings = list()
  1208. if not UserSettings.Get(
  1209. group='vectorLayer', key='featureColor',
  1210. subkey=['transparent', 'enabled']):
  1211. featureColor = UserSettings.Get(
  1212. group='vectorLayer',
  1213. key='featureColor',
  1214. subkey='color')
  1215. settings.append('color=%s' % rgb2str.get(
  1216. featureColor, ':'.join(map(str, featureColor))))
  1217. else:
  1218. settings.append('color=none')
  1219. if not UserSettings.Get(
  1220. group='vectorLayer', key='areaFillColor',
  1221. subkey=['transparent', 'enabled']):
  1222. fillColor = UserSettings.Get(
  1223. group='vectorLayer',
  1224. key='areaFillColor',
  1225. subkey='color')
  1226. settings.append('fcolor=%s' %
  1227. rgb2str.get(fillColor, ':'.join(map(str, fillColor))))
  1228. else:
  1229. settings.append('fcolor=none')
  1230. settings.append(
  1231. 'width=%s' %
  1232. UserSettings.Get(
  1233. group='vectorLayer',
  1234. key='line',
  1235. subkey='width'))
  1236. settings.append(
  1237. 'icon=%s' %
  1238. UserSettings.Get(
  1239. group='vectorLayer',
  1240. key='point',
  1241. subkey='symbol'))
  1242. settings.append(
  1243. 'size=%s' %
  1244. UserSettings.Get(
  1245. group='vectorLayer',
  1246. key='point',
  1247. subkey='size'))
  1248. types = []
  1249. for ftype in ['point', 'line', 'boundary', 'centroid', 'area', 'face']:
  1250. if UserSettings.Get(group='vectorLayer',
  1251. key='showType', subkey=[ftype, 'enabled']):
  1252. types.append(ftype)
  1253. settings.append('type=%s' % ','.join(types))
  1254. if UserSettings.Get(group='vectorLayer',
  1255. key='randomColors', subkey='enabled'):
  1256. settings.append('-c')
  1257. return settings