settings.py 46 KB

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