preferences.py 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761
  1. """
  2. @package preferences
  3. @brief User preferences dialog
  4. Sets default display font, etc.
  5. Classes:
  6. - PreferencesDialog
  7. - DefaultFontDialog
  8. - MapsetAccess
  9. (C) 2007-2008 by the GRASS Development Team
  10. This program is free software under the GNU General Public
  11. License (>=v2). Read the file COPYING that comes with GRASS
  12. for details.
  13. @author Michael Barton (Arizona State University)
  14. Martin Landa <landa.martin gmail.com>
  15. """
  16. import os
  17. import sys
  18. import copy
  19. import stat
  20. if os.name in ('posix', 'mac'):
  21. import pwd
  22. import wx
  23. import wx.lib.filebrowsebutton as filebrowse
  24. import wx.lib.colourselect as csel
  25. import wx.lib.mixins.listctrl as listmix
  26. from wx.lib.wordwrap import wordwrap
  27. import gcmd
  28. import grassenv
  29. import utils
  30. import globalvar
  31. from debug import Debug as Debug
  32. class Settings:
  33. """Generic class where to store settings"""
  34. def __init__(self):
  35. #
  36. # settings filename
  37. #
  38. self.fileName = ".grasswx7"
  39. self.filePath = None
  40. #
  41. # key/value separator
  42. #
  43. self.sep = ';'
  44. #
  45. # default settings
  46. #
  47. self.defaultSettings = {
  48. #
  49. # general
  50. #
  51. 'general': {
  52. # use default window layout (layer manager, displays, ...)
  53. 'defWindowPos' : {
  54. 'enabled' : False,
  55. 'dim' : ''
  56. },
  57. # expand/collapse element list
  58. 'elementListExpand' : {
  59. 'selection' : 0
  60. },
  61. },
  62. 'manager' : {
  63. # show opacity level widget
  64. 'changeOpacityLevel' : {
  65. 'enabled' : False
  66. },
  67. # ask when removing layer from layer tree
  68. 'askOnRemoveLayer' : {
  69. 'enabled' : True
  70. },
  71. },
  72. #
  73. # display
  74. #
  75. 'display': {
  76. 'font' : {
  77. 'type' : '',
  78. 'encoding': 'ISO-8859-1',
  79. },
  80. 'driver': {
  81. 'type': 'cairo'
  82. },
  83. 'compResolution' : {
  84. 'enabled' : False
  85. },
  86. 'autoRendering': {
  87. 'enabled' : False
  88. },
  89. 'statusbarMode': {
  90. 'selection' : 0
  91. },
  92. },
  93. #
  94. # advanced
  95. #
  96. 'advanced' : {
  97. 'settingsFile' : {
  98. 'type' : 'home'
  99. }, # home, gisdbase, location, mapset
  100. 'iconTheme' : {
  101. 'type' : 'grass'
  102. }, # grass, silk
  103. },
  104. #
  105. # Attribute Table Manager
  106. #
  107. 'atm' : {
  108. 'highlight' : {
  109. 'color' : (255, 255, 0, 255),
  110. 'width' : 2
  111. },
  112. 'leftDbClick' : {
  113. 'selection' : 0
  114. },
  115. 'askOnDeleteRec' : {
  116. 'enabled' : True
  117. },
  118. 'keycolumn' : {
  119. 'value' : 'cat'
  120. },
  121. },
  122. #
  123. # Command
  124. #
  125. 'cmd': {
  126. 'overwrite' : {
  127. 'enabled' : False
  128. },
  129. 'closeDlg' : {
  130. 'enabled' : False
  131. },
  132. 'verbosity' : {
  133. 'selection' : 'grassenv'
  134. },
  135. # d.rast
  136. 'rasterOpaque' : {
  137. 'enabled' : False
  138. },
  139. # d.vect
  140. 'showType': {
  141. 'point' : {
  142. 'enabled' : True
  143. },
  144. 'line' : {
  145. 'enabled' : True
  146. },
  147. 'centroid' : {
  148. 'enabled' : True
  149. },
  150. 'boundary' : {
  151. 'enabled' : True
  152. },
  153. 'area' : {
  154. 'enabled' : True
  155. },
  156. 'face' : {
  157. 'enabled' : True
  158. },
  159. },
  160. 'addNewLayer' : {
  161. 'enabled' : False
  162. },
  163. },
  164. #
  165. # Workspace
  166. #
  167. 'workspace' : {
  168. 'posDisplay' : {
  169. 'enabled' : False
  170. },
  171. 'posManager' : {
  172. 'enabled' : False
  173. },
  174. },
  175. #
  176. # vdigit
  177. #
  178. 'vdigit' : {
  179. # symbology
  180. 'symbol' : {
  181. 'highlight' : {
  182. 'enabled' : None,
  183. 'color' : (255, 255, 0, 255)
  184. }, # yellow
  185. 'highlightDupl' : {
  186. 'enabled' : None,
  187. 'color' : (255, 72, 0, 255)
  188. }, # red
  189. 'point' : {
  190. 'enabled' : True,
  191. 'color' : (0, 0, 0, 255)
  192. }, # black
  193. 'line' : {
  194. 'enabled' : True,
  195. 'color' : (0, 0, 0, 255)
  196. }, # black
  197. 'boundaryNo' : {
  198. 'enabled' : True,
  199. 'color' : (126, 126, 126, 255)
  200. }, # grey
  201. 'boundaryOne' : {
  202. 'enabled' : True,
  203. 'color' : (0, 255, 0, 255)
  204. }, # green
  205. 'boundaryTwo' : {
  206. 'enabled' : True,
  207. 'color' : (255, 135, 0, 255)
  208. }, # orange
  209. 'centroidIn' : {
  210. 'enabled' : True,
  211. 'color' : (0, 0, 255, 255)
  212. }, # blue
  213. 'centroidOut' : {
  214. 'enabled' : True,
  215. 'color' : (165, 42, 42, 255)
  216. }, # brown
  217. 'centroidDup' : {
  218. 'enabled' : True,
  219. 'color' : (156, 62, 206, 255)
  220. }, # violet
  221. 'nodeOne' : {
  222. 'enabled' : True,
  223. 'color' : (255, 0, 0, 255)
  224. }, # red
  225. 'nodeTwo' : {
  226. 'enabled' : True,
  227. 'color' : (0, 86, 45, 255)
  228. }, # dark green
  229. 'vertex' : {
  230. 'enabled' : False,
  231. 'color' : (255, 20, 147, 255)
  232. }, # deep pink
  233. 'area' : {
  234. 'enabled' : False,
  235. 'color' : (217, 255, 217, 255)
  236. }, # green
  237. 'direction' : {
  238. 'enabled' : False,
  239. 'color' : (255, 0, 0, 255)
  240. }, # red
  241. },
  242. # display
  243. 'lineWidth' : {
  244. 'value' : 2,
  245. 'units' : 'screen pixels'
  246. },
  247. # snapping
  248. 'snapping' : {
  249. 'value' : 10,
  250. 'units' : 'screen pixels'
  251. },
  252. 'snapToVertex' : {
  253. 'enabled' : False
  254. },
  255. # digitize new record
  256. 'addRecord' : {
  257. 'enabled' : True
  258. },
  259. 'layer' :{
  260. 'value' : 1
  261. },
  262. 'category' : {
  263. 'value' : 1
  264. },
  265. 'categoryMode' : {
  266. 'selection' : 0
  267. },
  268. # delete existing feature(s)
  269. 'delRecord' : {
  270. 'enabled' : True
  271. },
  272. # query tool
  273. 'query' : {
  274. 'selection' : 0,
  275. 'box' : True
  276. },
  277. 'queryLength' : {
  278. 'than-selection' : 0,
  279. 'thresh' : 0
  280. },
  281. 'queryDangle' : {
  282. 'than-selection' : 0,
  283. 'thresh' : 0
  284. },
  285. # select feature (point, line, centroid, boundary)
  286. 'selectType': {
  287. 'point' : {
  288. 'enabled' : True
  289. },
  290. 'line' : {
  291. 'enabled' : True
  292. },
  293. 'centroid' : {
  294. 'enabled' : True
  295. },
  296. 'boundary' : {
  297. 'enabled' : True
  298. },
  299. },
  300. 'selectThresh' : {
  301. 'value' : 10,
  302. 'units' : 'screen pixels'
  303. },
  304. 'checkForDupl' : {
  305. 'enabled' : False
  306. },
  307. 'selectInside' : {
  308. 'enabled' : False
  309. },
  310. # exit
  311. 'saveOnExit' : {
  312. 'enabled' : False,
  313. },
  314. # break lines on intersection
  315. 'breakLines' : {
  316. 'enabled' : False,
  317. },
  318. },
  319. 'profile': {
  320. 'raster0' : {
  321. 'pcolor' : (0, 0, 255, 255), # profile line color
  322. 'pwidth' : 1, # profile line width
  323. 'pstyle' : 'solid', # profile line pen style
  324. },
  325. 'raster1' : {
  326. 'pcolor' : (255, 0, 0, 255),
  327. 'pwidth' : 1,
  328. 'pstyle' : 'solid',
  329. },
  330. 'raster2' : {
  331. 'pcolor' : (0, 255, 0, 255),
  332. 'pwidth' : 1,
  333. 'pstyle' : 'solid',
  334. },
  335. 'font' : {
  336. 'titleSize' : 12,
  337. 'axisSize' : 11,
  338. 'legendSize' : 10,
  339. },
  340. 'marker' : {
  341. 'color' : (0, 0, 0, 255),
  342. 'fill' : 'transparent',
  343. 'size' : 2,
  344. 'type' : 'triangle',
  345. 'legend' : _('Segment break'),
  346. },
  347. 'grid' : {
  348. 'color' : (200, 200, 200, 255),
  349. 'enabled' : True,
  350. },
  351. 'x-axis' : {
  352. 'type' : 'auto', # axis format
  353. 'min' : 0, # axis min for custom axis range
  354. 'max': 0, # axis max for custom axis range
  355. 'log' : False,
  356. },
  357. 'y-axis' : {
  358. 'type' : 'auto', # axis format
  359. 'min' : 0, # axis min for custom axis range
  360. 'max': 0, # axis max for custom axis range
  361. 'log' : False,
  362. },
  363. 'legend' : {
  364. 'enabled' : True
  365. },
  366. },
  367. 'georect' : {
  368. 'symbol' : {
  369. 'color' : (0, 0, 255, 255),
  370. 'width' : 2,
  371. },
  372. },
  373. 'nviz' : {
  374. 'view' : {
  375. 'persp' : {
  376. 'value' : 40,
  377. 'step' : 5,
  378. },
  379. 'pos' : {
  380. 'x' : 0.85,
  381. 'y' : 0.85,
  382. },
  383. 'height' : {
  384. 'step' : 100,
  385. },
  386. 'twist' : {
  387. 'value' : 0,
  388. 'step' : 5,
  389. },
  390. 'z-exag' : {
  391. 'value': 1,
  392. 'step' : 1,
  393. },
  394. },
  395. 'surface' : {
  396. 'shine': {
  397. 'map' : False,
  398. 'value' : 60.0,
  399. },
  400. 'color' : {
  401. 'map' : True,
  402. 'value' : (0, 0, 0, 255), # constant: black
  403. },
  404. 'draw' : {
  405. 'wire-color' : (136, 136, 136, 255),
  406. 'mode' : 1, # fine
  407. 'style' : 1, # surface
  408. 'shading' : 1, # gouraud
  409. 'res-fine' : 6,
  410. 'res-coarse' : 9,
  411. },
  412. 'position' : {
  413. 'x' : 0,
  414. 'y' : 0,
  415. 'z' : 0,
  416. },
  417. },
  418. 'vector' : {
  419. 'lines' : {
  420. 'show' : False,
  421. 'width' : 2,
  422. 'color' : (0, 0, 255, 255), # blue
  423. 'flat' : False,
  424. 'height' : 0,
  425. },
  426. 'points' : {
  427. 'show' : False,
  428. 'size' : 100,
  429. 'width' : 2,
  430. 'marker' : 2,
  431. 'color' : (0, 0, 255, 255), # blue
  432. 'height' : 0,
  433. }
  434. },
  435. 'volume' : {
  436. 'color' : {
  437. 'map' : True,
  438. 'value' : (0, 0, 0, 255), # constant: black
  439. },
  440. 'draw' : {
  441. 'mode' : 0, # isosurfaces
  442. 'shading' : 1, # gouraud
  443. 'resolution' : 3, # polygon resolution
  444. },
  445. 'shine': {
  446. 'map' : False,
  447. 'value' : 60.0,
  448. },
  449. },
  450. 'settings': {
  451. 'general' : {
  452. 'bgcolor' : (255, 255, 255, 255), # white
  453. },
  454. },
  455. },
  456. }
  457. #
  458. # user settings
  459. #
  460. self.userSettings = copy.deepcopy(self.defaultSettings)
  461. try:
  462. self.ReadSettingsFile()
  463. except gcmd.SettingsError, e:
  464. print >> sys.stderr, e.message
  465. #
  466. # internal settings (based on user settings)
  467. #
  468. self.internalSettings = {}
  469. for group in self.userSettings.keys():
  470. self.internalSettings[group] = {}
  471. for key in self.userSettings[group].keys():
  472. self.internalSettings[group][key] = {}
  473. # self.internalSettings['general']["mapsetPath"]['value'] = self.GetMapsetPath()
  474. self.internalSettings['general']['elementListExpand']['choices'] = (_("Collapse all except PERMANENT and current"),
  475. _("Collapse all except PERMANENT"),
  476. _("Collapse all"),
  477. _("Expand all"))
  478. self.internalSettings['atm']['leftDbClick']['choices'] = (_('Edit selected record'),
  479. _('Display selected'))
  480. self.internalSettings['advanced']['settingsFile']['choices'] = ('home',
  481. 'gisdbase',
  482. 'location',
  483. 'mapset')
  484. self.internalSettings['advanced']['iconTheme']['choices'] = ('grass',
  485. 'silk')
  486. self.internalSettings['cmd']['verbosity']['choices'] = ('grassenv',
  487. 'verbose',
  488. 'quiet')
  489. self.internalSettings['display']['driver']['choices'] = ['cairo', 'png']
  490. self.internalSettings['display']['statusbarMode']['choices'] = globalvar.MAP_DISPLAY_STATUSBAR_MODE
  491. self.internalSettings['nviz']['view'] = {}
  492. self.internalSettings['nviz']['view']['twist'] = {}
  493. self.internalSettings['nviz']['view']['twist']['min'] = -180
  494. self.internalSettings['nviz']['view']['twist']['max'] = 180
  495. self.internalSettings['nviz']['view']['persp'] = {}
  496. self.internalSettings['nviz']['view']['persp']['min'] = 1
  497. self.internalSettings['nviz']['view']['persp']['max'] = 100
  498. self.internalSettings['nviz']['view']['height'] = {}
  499. self.internalSettings['nviz']['view']['height']['value'] = -1
  500. self.internalSettings['nviz']['vector'] = {}
  501. self.internalSettings['nviz']['vector']['points'] = {}
  502. self.internalSettings['nviz']['vector']['points']['marker'] = ("x",
  503. _("box"),
  504. _("sphere"),
  505. _("cube"),
  506. _("diamond"),
  507. _("dtree"),
  508. _("ctree"),
  509. _("aster"),
  510. _("gyro"),
  511. _("histogram"))
  512. self.internalSettings['vdigit']['bgmap'] = {}
  513. self.internalSettings['vdigit']['bgmap']['value'] = ''
  514. def ReadSettingsFile(self, settings=None):
  515. """Reads settings file (mapset, location, gisdbase)"""
  516. if settings is None:
  517. settings = self.userSettings
  518. # look for settings file
  519. # -> mapser
  520. # -> location
  521. # -> gisdbase
  522. gisdbase = grassenv.GetGRASSVariable("GISDBASE")
  523. location_name = grassenv.GetGRASSVariable("LOCATION_NAME")
  524. mapset_name = grassenv.GetGRASSVariable("MAPSET")
  525. mapset_file = os.path.join(gisdbase, location_name, mapset_name, self.fileName)
  526. location_file = os.path.join(gisdbase, location_name, self.fileName)
  527. gisdbase_file = os.path.join(gisdbase, self.fileName)
  528. home_file = os.path.join(os.path.expanduser("~"), self.fileName) # MS Windows fix ?
  529. if os.path.isfile(mapset_file):
  530. self.filePath = mapset_file
  531. elif os.path.isfile(location_file):
  532. self.filePath = location_file
  533. elif os.path.isfile(gisdbase_file):
  534. self.filePath = gisdbase_file
  535. elif os.path.isfile(home_file):
  536. self.filePath = home_file
  537. if self.filePath:
  538. self.__ReadFile(self.filePath, settings)
  539. # set environment variables
  540. os.environ["GRASS_FONT"] = self.Get(group='display',
  541. key='font', subkey='type')
  542. os.environ["GRASS_ENCODING"] = self.Get(group='display',
  543. key='font', subkey='encoding')
  544. def __ReadFile(self, filename, settings=None):
  545. """Read settings from file to dict"""
  546. if settings is None:
  547. settings = self.userSettings
  548. try:
  549. file = open(filename, "r")
  550. line = ''
  551. for line in file.readlines():
  552. line = line.rstrip('%s' % os.linesep)
  553. group, key = line.split(self.sep)[0:2]
  554. kv = line.split(self.sep)[2:]
  555. subkeyMaster = None
  556. if len(kv) % 2 != 0: # multiple (e.g. nviz)
  557. subkeyMaster = kv[0]
  558. del kv[0]
  559. idx = 0
  560. while idx < len(kv):
  561. if subkeyMaster:
  562. subkey = [subkeyMaster, kv[idx]]
  563. else:
  564. subkey = kv[idx]
  565. value = kv[idx+1]
  566. value = self.__parseValue(value, read=True)
  567. self.Append(settings, group, key, subkey, value)
  568. idx += 2
  569. except ValueError, e:
  570. print >> sys.stderr, _("Error: Reading settings from file <%(file)s> failed.\n"
  571. " Details: %(detail)s\n"
  572. " Line: '%(line)s'") % { 'file' : filename,
  573. 'detail' : e,
  574. 'line' : line }
  575. file.close()
  576. file.close()
  577. def SaveToFile(self, settings=None):
  578. """Save settings to the file"""
  579. if settings is None:
  580. settings = self.userSettings
  581. loc = self.Get(group='advanced', key='settingsFile', subkey='type')
  582. home = os.path.expanduser("~") # MS Windows fix ?
  583. gisdbase = grassenv.GetGRASSVariable("GISDBASE")
  584. location_name = grassenv.GetGRASSVariable("LOCATION_NAME")
  585. mapset_name = grassenv.GetGRASSVariable("MAPSET")
  586. filePath = None
  587. if loc == 'home':
  588. filePath = os.path.join(home, self.fileName)
  589. elif loc == 'gisdbase':
  590. filePath = os.path.join(gisdbase, self.fileName)
  591. elif loc == 'location':
  592. filePath = os.path.join(gisdbase, location_name, self.fileName)
  593. elif loc == 'mapset':
  594. filePath = os.path.join(gisdbase, location_name, mapset_name, self.fileName)
  595. if filePath is None:
  596. raise gcmd.SettingsError(_('Uknown settings file location.'))
  597. try:
  598. file = open(filePath, "w")
  599. for group in settings.keys():
  600. for key in settings[group].keys():
  601. file.write('%s%s%s%s' % (group, self.sep, key, self.sep))
  602. subkeys = settings[group][key].keys()
  603. for idx in range(len(subkeys)):
  604. value = settings[group][key][subkeys[idx]]
  605. if type(value) == type({}):
  606. if idx > 0:
  607. file.write('%s%s%s%s%s' % (os.linesep, group, self.sep, key, self.sep))
  608. file.write('%s%s' % (subkeys[idx], self.sep))
  609. kvalues = settings[group][key][subkeys[idx]].keys()
  610. srange = range(len(kvalues))
  611. for sidx in srange:
  612. svalue = self.__parseValue(settings[group][key][subkeys[idx]][kvalues[sidx]])
  613. file.write('%s%s%s' % (kvalues[sidx], self.sep,
  614. svalue))
  615. if sidx < len(kvalues) - 1:
  616. file.write('%s' % self.sep)
  617. else:
  618. value = self.__parseValue(settings[group][key][subkeys[idx]])
  619. file.write('%s%s%s' % (subkeys[idx], self.sep, value))
  620. if idx < len(subkeys) - 1:
  621. file.write('%s' % self.sep)
  622. file.write('%s' % os.linesep)
  623. except IOError, e:
  624. raise gcmd.SettingsError(message=e)
  625. except StandardError, e:
  626. raise gcmd.SettingsError(message=_('Writing settings to file <%(file)s> failed.'
  627. '\n\nDetails: %(detail)s') % { 'file' : filePath,
  628. 'detail' : e })
  629. file.close()
  630. return filePath
  631. def __parseValue(self, value, read=False):
  632. """Parse value to be store in settings file"""
  633. if read: # -> read settings (cast values)
  634. if value == 'True':
  635. value = True
  636. elif value == 'False':
  637. value = False
  638. elif value == 'None':
  639. value = None
  640. elif ':' in value: # -> color
  641. value = tuple(map(int, value.split(':')))
  642. else:
  643. try:
  644. value = int(value)
  645. except ValueError:
  646. try:
  647. value = float(value)
  648. except ValueError:
  649. pass
  650. else: # -> write settings
  651. if type(value) == type(()): # -> color
  652. value = str(value[0]) + ':' +\
  653. str(value[1]) + ':' + \
  654. str(value[2])
  655. return value
  656. def Get(self, group, key=None, subkey=None, internal=False):
  657. """Get value by key/subkey
  658. Raise KeyError if key is not found
  659. @param group settings group
  660. @param key (value, None)
  661. @param subkey (value, list or None)
  662. @param internal use internal settings instead
  663. @return value
  664. """
  665. if internal is True:
  666. settings = self.internalSettings
  667. else:
  668. settings = self.userSettings
  669. try:
  670. if subkey is None:
  671. if key is None:
  672. return settings[group]
  673. else:
  674. return settings[group][key]
  675. else:
  676. if type(subkey) == type([]) or \
  677. type(subkey) == type(()):
  678. return settings[group][key][subkey[0]][subkey[1]]
  679. else:
  680. return settings[group][key][subkey]
  681. except KeyError:
  682. #raise gcmd.SettingsError("%s %s:%s:%s." % (_("Unable to get value"),
  683. # group, key, subkey))
  684. print >> sys.stderr, "Settings: unable to get value '%s:%s:%s'\n" % \
  685. (group, key, subkey)
  686. def Set(self, group, value, key=None, subkey=None, internal=False):
  687. """Set value of key/subkey
  688. Raise KeyError if group/key is not found
  689. @param group settings group
  690. @param key key (value, None)
  691. @param subkey subkey (value, list or None)
  692. @param value value
  693. @param internal use internal settings instead
  694. """
  695. if internal is True:
  696. settings = self.internalSettings
  697. else:
  698. settings = self.userSettings
  699. try:
  700. if subkey is None:
  701. if key is None:
  702. settings[group] = value
  703. else:
  704. settings[group][key] = value
  705. else:
  706. if type(subkey) == type([]):
  707. settings[group][key][subkey[0]][subkey[1]] = value
  708. else:
  709. settings[group][key][subkey] = value
  710. except KeyError:
  711. raise gcmd.SettingsError("%s '%s:%s:%s'" % (_("Unable to set "), group, key, subkey))
  712. def Append(self, dict, group, key, subkey, value):
  713. """Set value of key/subkey
  714. Create group/key/subkey if not exists
  715. @param dict settings dictionary to use
  716. @param group settings group
  717. @param key key
  718. @param subkey subkey (value or list)
  719. @param value value
  720. """
  721. if not dict.has_key(group):
  722. dict[group] = {}
  723. if not dict[group].has_key(key):
  724. dict[group][key] = {}
  725. if type(subkey) == type([]):
  726. # TODO: len(subkey) > 2
  727. if not dict[group][key].has_key(subkey[0]):
  728. dict[group][key][subkey[0]] = {}
  729. dict[group][key][subkey[0]][subkey[1]] = value
  730. else:
  731. dict[group][key][subkey] = value
  732. def GetDefaultSettings(self):
  733. """Get default user settings"""
  734. return self.defaultSettings
  735. globalSettings = Settings()
  736. class PreferencesDialog(wx.Dialog):
  737. """User preferences dialog"""
  738. def __init__(self, parent, title=_("User GUI settings"),
  739. settings=globalSettings,
  740. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  741. self.parent = parent # GMFrame
  742. self.title = title
  743. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title,
  744. style=style, size=(-1, -1))
  745. self.settings = settings
  746. # notebook
  747. notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  748. # dict for window ids
  749. self.winId = {}
  750. # create notebook pages
  751. self.__CreateGeneralPage(notebook)
  752. self.__CreateDisplayPage(notebook)
  753. self.__CreateCmdPage(notebook)
  754. self.__CreateAttributeManagerPage(notebook)
  755. self.__CreateWorkspacePage(notebook)
  756. self.__CreateAdvancedPage(notebook)
  757. # buttons
  758. btnDefault = wx.Button(self, wx.ID_ANY, _("Set to default"))
  759. btnSave = wx.Button(self, wx.ID_SAVE)
  760. btnApply = wx.Button(self, wx.ID_APPLY)
  761. btnCancel = wx.Button(self, wx.ID_CANCEL)
  762. btnSave.SetDefault()
  763. # bindigs
  764. btnDefault.Bind(wx.EVT_BUTTON, self.OnDefault)
  765. btnDefault.SetToolTipString(_("Revert settings to default and apply changes"))
  766. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  767. btnApply.SetToolTipString(_("Apply changes for the current session"))
  768. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  769. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  770. btnSave.SetDefault()
  771. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  772. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  773. # sizers
  774. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  775. btnSizer.Add(item=btnDefault, proportion=1,
  776. flag=wx.ALL, border=5)
  777. btnStdSizer = wx.StdDialogButtonSizer()
  778. btnStdSizer.AddButton(btnCancel)
  779. btnStdSizer.AddButton(btnSave)
  780. btnStdSizer.AddButton(btnApply)
  781. btnStdSizer.Realize()
  782. mainSizer = wx.BoxSizer(wx.VERTICAL)
  783. mainSizer.Add(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  784. mainSizer.Add(item=btnSizer, proportion=0,
  785. flag=wx.EXPAND, border=0)
  786. mainSizer.Add(item=btnStdSizer, proportion=0,
  787. flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
  788. self.SetSizer(mainSizer)
  789. mainSizer.Fit(self)
  790. self.SetMinSize(self.GetBestSize())
  791. self.SetSize((500, 375))
  792. def __CreateGeneralPage(self, notebook):
  793. """Create notebook page for general settings"""
  794. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  795. notebook.AddPage(page=panel, text=_("General"))
  796. border = wx.BoxSizer(wx.VERTICAL)
  797. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("General settings"))
  798. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  799. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  800. gridSizer.AddGrowableCol(0)
  801. #
  802. # expand element list
  803. #
  804. row = 0
  805. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  806. label=_("Element list:")),
  807. flag=wx.ALIGN_LEFT |
  808. wx.ALIGN_CENTER_VERTICAL,
  809. pos=(row, 0))
  810. elementList = wx.Choice(parent=panel, id=wx.ID_ANY,
  811. choices=self.settings.Get(group='general', key='elementListExpand',
  812. subkey='choices', internal=True),
  813. name="GetSelection")
  814. elementList.SetSelection(self.settings.Get(group='general', key='elementListExpand',
  815. subkey='selection'))
  816. self.winId['general:elementListExpand:selection'] = elementList.GetId()
  817. gridSizer.Add(item=elementList,
  818. flag=wx.ALIGN_RIGHT |
  819. wx.ALIGN_CENTER_VERTICAL,
  820. pos=(row, 1))
  821. #
  822. # default window layout
  823. #
  824. row += 1
  825. defaultPos = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  826. label=_("Save current window layout as default"),
  827. name='IsChecked')
  828. defaultPos.SetValue(self.settings.Get(group='general', key='defWindowPos', subkey='enabled'))
  829. defaultPos.SetToolTip(wx.ToolTip (_("Save current position and size of Layer Manager window and opened "
  830. "Map Display window(s) and use as default for next sessions.")))
  831. self.winId['general:defWindowPos:enabled'] = defaultPos.GetId()
  832. gridSizer.Add(item=defaultPos,
  833. pos=(row, 0), span=(1, 2))
  834. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  835. border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
  836. #
  837. # Layer Manager settings
  838. #
  839. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Layer Manager settings"))
  840. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  841. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  842. gridSizer.AddGrowableCol(0)
  843. #
  844. # ask when removing map layer from layer tree
  845. #
  846. row = 0
  847. askOnRemoveLayer = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  848. label=_("Ask when removing map layer from layer tree"),
  849. name='IsChecked')
  850. askOnRemoveLayer.SetValue(self.settings.Get(group='manager', key='askOnRemoveLayer', subkey='enabled'))
  851. self.winId['manager:askOnRemoveLayer:enabled'] = askOnRemoveLayer.GetId()
  852. gridSizer.Add(item=askOnRemoveLayer,
  853. pos=(row, 0), span=(1, 2))
  854. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  855. border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  856. panel.SetSizer(border)
  857. return panel
  858. def __CreateDisplayPage(self, notebook):
  859. """Create notebook page for display settings"""
  860. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  861. notebook.AddPage(page=panel, text=_("Display"))
  862. border = wx.BoxSizer(wx.VERTICAL)
  863. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Font settings"))
  864. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  865. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  866. gridSizer.AddGrowableCol(0)
  867. #
  868. # font settings
  869. #
  870. row = 0
  871. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  872. label=_("Default font for GRASS displays:")),
  873. flag=wx.ALIGN_LEFT |
  874. wx.ALIGN_CENTER_VERTICAL,
  875. pos=(row, 0))
  876. fontButton = wx.Button(parent=panel, id=wx.ID_ANY,
  877. label=_("Set font"), size=(100, -1))
  878. gridSizer.Add(item=fontButton,
  879. flag=wx.ALIGN_RIGHT |
  880. wx.ALIGN_CENTER_VERTICAL,
  881. pos=(row, 1))
  882. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  883. border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
  884. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Default display settings"))
  885. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  886. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  887. gridSizer.AddGrowableCol(0)
  888. #
  889. # display driver
  890. #
  891. row = 0
  892. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  893. label=_("Display driver:")),
  894. flag=wx.ALIGN_LEFT |
  895. wx.ALIGN_CENTER_VERTICAL,
  896. pos=(row, 0))
  897. listOfDrivers = self.settings.Get(group='display', key='driver', subkey='choices', internal=True)
  898. driver = wx.Choice(parent=panel, id=wx.ID_ANY, size=(150, -1),
  899. choices=listOfDrivers,
  900. name="GetStringSelection")
  901. driver.SetStringSelection(self.settings.Get(group='display', key='driver', subkey='type'))
  902. self.winId['display:driver:type'] = driver.GetId()
  903. gridSizer.Add(item=driver,
  904. flag=wx.ALIGN_RIGHT,
  905. pos=(row, 1))
  906. #
  907. # Statusbar mode
  908. #
  909. row += 1
  910. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  911. label=_("Statusbar mode:")),
  912. flag=wx.ALIGN_LEFT |
  913. wx.ALIGN_CENTER_VERTICAL,
  914. pos=(row, 0))
  915. listOfModes = self.settings.Get(group='display', key='statusbarMode', subkey='choices', internal=True)
  916. statusbarMode = wx.Choice(parent=panel, id=wx.ID_ANY, size=(150, -1),
  917. choices=listOfModes,
  918. name="GetSelection")
  919. statusbarMode.SetSelection(self.settings.Get(group='display', key='statusbarMode', subkey='selection'))
  920. self.winId['display:statusbarMode:selection'] = statusbarMode.GetId()
  921. gridSizer.Add(item=statusbarMode,
  922. flag=wx.ALIGN_RIGHT,
  923. pos=(row, 1))
  924. #
  925. # Use computation resolution
  926. #
  927. row += 1
  928. compResolution = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  929. label=_("Constrain display resolution to computational settings"),
  930. name="IsChecked")
  931. compResolution.SetValue(self.settings.Get(group='display', key='compResolution', subkey='enabled'))
  932. self.winId['display:compResolution:enabled'] = compResolution.GetId()
  933. gridSizer.Add(item=compResolution,
  934. pos=(row, 0), span=(1, 2))
  935. #
  936. # auto-rendering
  937. #
  938. row += 1
  939. autoRendering = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  940. label=_("Enable auto-rendering"),
  941. name="IsChecked")
  942. autoRendering.SetValue(self.settings.Get(group='display', key='autoRendering', subkey='enabled'))
  943. self.winId['display:autoRendering:enabled'] = autoRendering.GetId()
  944. gridSizer.Add(item=autoRendering,
  945. pos=(row, 0), span=(1, 2))
  946. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  947. border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  948. panel.SetSizer(border)
  949. # bindings
  950. fontButton.Bind(wx.EVT_BUTTON, self.OnSetFont)
  951. return panel
  952. def __CreateCmdPage(self, notebook):
  953. """Create notebook page for commad dialog settings"""
  954. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  955. notebook.AddPage(page=panel, text=_("Command"))
  956. border = wx.BoxSizer(wx.VERTICAL)
  957. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Command dialog settings"))
  958. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  959. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  960. gridSizer.AddGrowableCol(0)
  961. #
  962. # command dialog settings
  963. #
  964. row = 0
  965. # overwrite
  966. overwrite = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  967. label=_("Allow output files to overwrite existing files"),
  968. name="IsChecked")
  969. overwrite.SetValue(self.settings.Get(group='cmd', key='overwrite', subkey='enabled'))
  970. self.winId['cmd:overwrite:enabled'] = overwrite.GetId()
  971. gridSizer.Add(item=overwrite,
  972. pos=(row, 0), span=(1, 2))
  973. row += 1
  974. # close
  975. close = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  976. label=_("Close dialog on finish"),
  977. name="IsChecked")
  978. close.SetValue(self.settings.Get(group='cmd', key='closeDlg', subkey='enabled'))
  979. self.winId['cmd:closeDlg:enabled'] = close.GetId()
  980. gridSizer.Add(item=close,
  981. pos=(row, 0), span=(1, 2))
  982. row += 1
  983. # add layer
  984. add = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  985. label=_("Add created map into layer tree"),
  986. name="IsChecked")
  987. add.SetValue(self.settings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
  988. self.winId['cmd:addNewLayer:enabled'] = add.GetId()
  989. gridSizer.Add(item=add,
  990. pos=(row, 0), span=(1, 2))
  991. row += 1
  992. # verbosity
  993. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  994. label=_("Verbosity level:")),
  995. flag=wx.ALIGN_LEFT |
  996. wx.ALIGN_CENTER_VERTICAL,
  997. pos=(row, 0))
  998. verbosity = wx.Choice(parent=panel, id=wx.ID_ANY, size=(200, -1),
  999. choices=self.settings.Get(group='cmd', key='verbosity', subkey='choices', internal=True),
  1000. name="GetStringSelection")
  1001. verbosity.SetStringSelection(self.settings.Get(group='cmd', key='verbosity', subkey='selection'))
  1002. self.winId['cmd:verbosity:selection'] = verbosity.GetId()
  1003. gridSizer.Add(item=verbosity,
  1004. pos=(row, 1))
  1005. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  1006. border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
  1007. #
  1008. # raster settings
  1009. #
  1010. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Raster settings"))
  1011. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1012. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  1013. gridSizer.AddGrowableCol(0)
  1014. #
  1015. # raster overlay
  1016. #
  1017. row = 0
  1018. rasterOpaque = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1019. label=_("Make null cells opaque"),
  1020. name='IsChecked')
  1021. rasterOpaque.SetValue(self.settings.Get(group='cmd', key='rasterOpaque', subkey='enabled'))
  1022. self.winId['cmd:rasterOpaque:enabled'] = rasterOpaque.GetId()
  1023. gridSizer.Add(item=rasterOpaque,
  1024. pos=(row, 0), span=(1, 2))
  1025. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  1026. border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  1027. #
  1028. # vector settings
  1029. #
  1030. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Vector settings"))
  1031. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1032. gridSizer = wx.FlexGridSizer (cols=7, hgap=3, vgap=3)
  1033. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  1034. label=_("Display:")),
  1035. flag=wx.ALIGN_CENTER_VERTICAL)
  1036. for type in ('point', 'line', 'centroid', 'boundary',
  1037. 'area', 'face'):
  1038. chkbox = wx.CheckBox(parent=panel, label=type)
  1039. checked = self.settings.Get(group='cmd', key='showType',
  1040. subkey=[type, 'enabled'])
  1041. chkbox.SetValue(checked)
  1042. self.winId['cmd:showType:%s:enabled' % type] = chkbox.GetId()
  1043. gridSizer.Add(item=chkbox)
  1044. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  1045. border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  1046. panel.SetSizer(border)
  1047. return panel
  1048. def __CreateAttributeManagerPage(self, notebook):
  1049. """Create notebook page for 'Attribute Table Manager' settings"""
  1050. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1051. notebook.AddPage(page=panel, text=_("Attributes"))
  1052. pageSizer = wx.BoxSizer(wx.VERTICAL)
  1053. #
  1054. # highlighting
  1055. #
  1056. highlightBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  1057. label=" %s " % _("Highlighting"))
  1058. highlightSizer = wx.StaticBoxSizer(highlightBox, wx.VERTICAL)
  1059. flexSizer = wx.FlexGridSizer (cols=2, hgap=5, vgap=5)
  1060. flexSizer.AddGrowableCol(0)
  1061. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label="Color")
  1062. hlColor = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
  1063. colour=self.settings.Get(group='atm', key='highlight', subkey='color'),
  1064. size=(25, 25))
  1065. hlColor.SetName('GetColour')
  1066. self.winId['atm:highlight:color'] = hlColor.GetId()
  1067. flexSizer.Add(label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1068. flexSizer.Add(hlColor, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1069. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width (in pixels)"))
  1070. hlWidth = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(50, -1),
  1071. initial=self.settings.Get(group='atm', key='highlight',subkey='width'),
  1072. min=1, max=1e6)
  1073. self.winId['atm:highlight:width'] = hlWidth.GetId()
  1074. flexSizer.Add(label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1075. flexSizer.Add(hlWidth, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1076. highlightSizer.Add(item=flexSizer,
  1077. proportion=0,
  1078. flag=wx.ALL | wx.EXPAND,
  1079. border=5)
  1080. pageSizer.Add(item=highlightSizer,
  1081. proportion=0,
  1082. flag=wx.ALL | wx.EXPAND,
  1083. border=5)
  1084. #
  1085. # data browser related settings
  1086. #
  1087. dataBrowserBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  1088. label=" %s " % _("Data browser"))
  1089. dataBrowserSizer = wx.StaticBoxSizer(dataBrowserBox, wx.VERTICAL)
  1090. flexSizer = wx.FlexGridSizer (cols=2, hgap=5, vgap=5)
  1091. flexSizer.AddGrowableCol(0)
  1092. label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Left mouse double click"))
  1093. leftDbClick = wx.Choice(parent=panel, id=wx.ID_ANY,
  1094. choices=self.settings.Get(group='atm', key='leftDbClick', subkey='choices', internal=True),
  1095. name="GetSelection")
  1096. leftDbClick.SetSelection(self.settings.Get(group='atm', key='leftDbClick', subkey='selection'))
  1097. self.winId['atm:leftDbClick:selection'] = leftDbClick.GetId()
  1098. flexSizer.Add(label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1099. flexSizer.Add(leftDbClick, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1100. # ask on delete record
  1101. askOnDeleteRec = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1102. label=_("Ask when deleting data record(s) from table"),
  1103. name='IsChecked')
  1104. askOnDeleteRec.SetValue(self.settings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'))
  1105. self.winId['atm:askOnDeleteRec:enabled'] = askOnDeleteRec.GetId()
  1106. flexSizer.Add(askOnDeleteRec, proportion=0)
  1107. dataBrowserSizer.Add(item=flexSizer,
  1108. proportion=0,
  1109. flag=wx.ALL | wx.EXPAND,
  1110. border=5)
  1111. pageSizer.Add(item=dataBrowserSizer,
  1112. proportion=0,
  1113. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
  1114. border=3)
  1115. #
  1116. # create table
  1117. #
  1118. createTableBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  1119. label=" %s " % _("Create table"))
  1120. createTableSizer = wx.StaticBoxSizer(createTableBox, wx.VERTICAL)
  1121. flexSizer = wx.FlexGridSizer (cols=2, hgap=5, vgap=5)
  1122. flexSizer.AddGrowableCol(0)
  1123. label = wx.StaticText(parent=panel, id=wx.ID_ANY,
  1124. label=_("Key column"))
  1125. keyColumn = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
  1126. size=(250, -1))
  1127. keyColumn.SetValue(self.settings.Get(group='atm', key='keycolumn', subkey='value'))
  1128. self.winId['atm:keycolumn:value'] = keyColumn.GetId()
  1129. flexSizer.Add(label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
  1130. flexSizer.Add(keyColumn, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  1131. createTableSizer.Add(item=flexSizer,
  1132. proportion=0,
  1133. flag=wx.ALL | wx.EXPAND,
  1134. border=5)
  1135. pageSizer.Add(item=createTableSizer,
  1136. proportion=0,
  1137. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
  1138. border=3)
  1139. panel.SetSizer(pageSizer)
  1140. return panel
  1141. def __CreateWorkspacePage(self, notebook):
  1142. """Create notebook page for workspace settings"""
  1143. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1144. notebook.AddPage(page=panel, text=_("Workspace"))
  1145. border = wx.BoxSizer(wx.VERTICAL)
  1146. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Loading workspace"))
  1147. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1148. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  1149. gridSizer.AddGrowableCol(0)
  1150. row = 0
  1151. #
  1152. # positioning
  1153. #
  1154. posDisplay = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1155. label=_("Suppress positioning Map Display Window(s)"),
  1156. name='IsChecked')
  1157. posDisplay.SetValue(self.settings.Get(group='workspace', key='posDisplay', subkey='enabled'))
  1158. self.winId['workspace:posDisplay:enabled'] = posDisplay.GetId()
  1159. gridSizer.Add(item=posDisplay,
  1160. pos=(row, 0), span=(1, 2))
  1161. row +=1
  1162. posManager = wx.CheckBox(parent=panel, id=wx.ID_ANY,
  1163. label=_("Suppress positioning Layer Manager window"),
  1164. name='IsChecked')
  1165. posManager.SetValue(self.settings.Get(group='workspace', key='posManager', subkey='enabled'))
  1166. self.winId['workspace:posManager:enabled'] = posManager.GetId()
  1167. gridSizer.Add(item=posManager,
  1168. pos=(row, 0), span=(1, 2))
  1169. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  1170. border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
  1171. panel.SetSizer(border)
  1172. return panel
  1173. def __CreateAdvancedPage(self, notebook):
  1174. """Create notebook page for advanced settings"""
  1175. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  1176. notebook.AddPage(page=panel, text=_("Advanced"))
  1177. border = wx.BoxSizer(wx.VERTICAL)
  1178. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Advanced settings"))
  1179. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1180. gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
  1181. gridSizer.AddGrowableCol(0)
  1182. row = 0
  1183. #
  1184. # place where to store settings
  1185. #
  1186. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  1187. label=_("Place where to store settings:")),
  1188. flag=wx.ALIGN_LEFT |
  1189. wx.ALIGN_CENTER_VERTICAL,
  1190. pos=(row, 0))
  1191. settingsFile = wx.Choice(parent=panel, id=wx.ID_ANY, size=(125, -1),
  1192. choices=self.settings.Get(group='advanced', key='settingsFile',
  1193. subkey='choices', internal=True),
  1194. name='GetStringSelection')
  1195. settingsFile.SetStringSelection(self.settings.Get(group='advanced', key='settingsFile', subkey='type'))
  1196. self.winId['advanced:settingsFile:type'] = settingsFile.GetId()
  1197. gridSizer.Add(item=settingsFile,
  1198. flag=wx.ALIGN_RIGHT |
  1199. wx.ALIGN_CENTER_VERTICAL,
  1200. pos=(row, 1))
  1201. row += 1
  1202. #
  1203. # icon theme
  1204. #
  1205. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  1206. label=_("Icon theme:")),
  1207. flag=wx.ALIGN_LEFT |
  1208. wx.ALIGN_CENTER_VERTICAL,
  1209. pos=(row, 0))
  1210. iconTheme = wx.Choice(parent=panel, id=wx.ID_ANY, size=(125, -1),
  1211. choices=self.settings.Get(group='advanced', key='iconTheme',
  1212. subkey='choices', internal=True),
  1213. name="GetStringSelection")
  1214. iconTheme.SetStringSelection(self.settings.Get(group='advanced', key='iconTheme', subkey='type'))
  1215. self.winId['advanced:iconTheme:type'] = iconTheme.GetId()
  1216. gridSizer.Add(item=iconTheme,
  1217. flag=wx.ALIGN_RIGHT |
  1218. wx.ALIGN_CENTER_VERTICAL,
  1219. pos=(row, 1))
  1220. row += 1
  1221. iconNote = wordwrap(_("Note: Requires GUI restart."),
  1222. self.GetSize()[0]-50, wx.ClientDC(self))
  1223. gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  1224. label=iconNote),
  1225. flag=wx.ALIGN_LEFT |
  1226. wx.ALIGN_CENTER_VERTICAL,
  1227. pos=(row, 0), span=(1, 2))
  1228. row += 1
  1229. sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  1230. border.Add(item=sizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=3)
  1231. panel.SetSizer(border)
  1232. return panel
  1233. def OnSetFont(self, event):
  1234. """'Set font' button pressed"""
  1235. dlg = DefaultFontDialog(parent=self, id=wx.ID_ANY,
  1236. title=_('Select default display font'),
  1237. style=wx.DEFAULT_DIALOG_STYLE)
  1238. if dlg.ShowModal() == wx.ID_OK:
  1239. # set default font and encoding environmental variables
  1240. if dlg.font:
  1241. os.environ["GRASS_FONT"] = dlg.font
  1242. self.settings.Set(group='display', value=dlg.font,
  1243. key='font', subkey='type')
  1244. if dlg.encoding and \
  1245. dlg.encoding != "ISO-8859-1":
  1246. os.environ["GRASS_ENCODING"] = dlg.encoding
  1247. self.settings.Set(group='display', value=dlg.encoding,
  1248. key='font', subkey='encoding')
  1249. dlg.Destroy()
  1250. event.Skip()
  1251. def OnSave(self, event):
  1252. """Button 'Save' pressed"""
  1253. if self.__UpdateSettings():
  1254. file = self.settings.SaveToFile()
  1255. self.parent.goutput.WriteLog(_('Settings saved to file \'%s\'.') % file)
  1256. self.Close()
  1257. def OnApply(self, event):
  1258. """Button 'Apply' pressed"""
  1259. if self.__UpdateSettings():
  1260. self.Close()
  1261. def OnCancel(self, event):
  1262. """Button 'Cancel' pressed"""
  1263. self.Close()
  1264. def OnDefault(self, event):
  1265. """Button 'Set to default' pressed"""
  1266. self.settings.userSettings = copy.deepcopy(self.settings.defaultSettings)
  1267. # update widgets
  1268. for gks in self.winId.keys():
  1269. try:
  1270. group, key, subkey = gks.split(':')
  1271. value = self.settings.Get(group, key, subkey)
  1272. except ValueError:
  1273. group, key, subkey, subkey1 = gks.split(':')
  1274. value = self.settings.Get(group, key, [subkey, subkey1])
  1275. win = self.FindWindowById(self.winId[gks])
  1276. if win.GetName() in ('GetValue', 'IsChecked'):
  1277. value = win.SetValue(value)
  1278. elif win.GetName() == 'GetSelection':
  1279. value = win.SetSelection(value)
  1280. elif win.GetName() == 'GetStringSelection':
  1281. value = win.SetStringSelection(value)
  1282. else:
  1283. value = win.SetValue(value)
  1284. def __UpdateSettings(self):
  1285. """Update user settings"""
  1286. for item in self.winId.keys():
  1287. try:
  1288. group, key, subkey = item.split(':')
  1289. subkey1 = None
  1290. except ValueError:
  1291. group, key, subkey, subkey1 = item.split(':')
  1292. id = self.winId[item]
  1293. win = self.FindWindowById(id)
  1294. if win.GetName() == 'GetValue':
  1295. value = win.GetValue()
  1296. elif win.GetName() == 'GetSelection':
  1297. value = win.GetSelection()
  1298. elif win.GetName() == 'IsChecked':
  1299. value = win.IsChecked()
  1300. elif win.GetName() == 'GetStringSelection':
  1301. value = win.GetStringSelection()
  1302. elif win.GetName() == 'GetColour':
  1303. value = tuple(win.GetValue())
  1304. else:
  1305. value = win.GetValue()
  1306. if key == 'keycolumn' and value == '':
  1307. wx.MessageBox(parent=self,
  1308. message=_("Key column cannot be empty string."),
  1309. caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
  1310. win.SetValue(self.settings.Get(group='atm', key='keycolumn', subkey='value'))
  1311. return False
  1312. if subkey1:
  1313. self.settings.Set(group, value, key, [subkey, subkey1])
  1314. else:
  1315. self.settings.Set(group, value, key, subkey)
  1316. #
  1317. # update default window dimension
  1318. #
  1319. if self.settings.Get(group='general', key='defWindowPos', subkey='enabled') is True:
  1320. dim = ''
  1321. # layer manager
  1322. pos = self.parent.GetPosition()
  1323. size = self.parent.GetSize()
  1324. dim = '%d,%d,%d,%d' % (pos[0], pos[1], size[0], size[1])
  1325. # opened displays
  1326. for page in range(0, self.parent.gm_cb.GetPageCount()):
  1327. pos = self.parent.gm_cb.GetPage(page).maptree.mapdisplay.GetPosition()
  1328. size = self.parent.gm_cb.GetPage(page).maptree.mapdisplay.GetSize()
  1329. dim += ',%d,%d,%d,%d' % (pos[0], pos[1], size[0], size[1])
  1330. self.settings.Set(group='general', key='defWindowPos', subkey='dim', value=dim)
  1331. else:
  1332. self.settings.Set(group='general', key='defWindowPos', subkey='dim', value='')
  1333. return True
  1334. class DefaultFontDialog(wx.Dialog):
  1335. """
  1336. Opens a file selection dialog to select default font
  1337. to use in all GRASS displays
  1338. """
  1339. def __init__(self, parent, id, title,
  1340. pos=wx.DefaultPosition, size=wx.DefaultSize,
  1341. style=wx.DEFAULT_DIALOG_STYLE,
  1342. settings=globalSettings):
  1343. self.settings = settings
  1344. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  1345. panel = wx.Panel(parent=self, id=wx.ID_ANY)
  1346. if "GRASS_FONT" in os.environ:
  1347. self.font = os.environ["GRASS_FONT"]
  1348. else:
  1349. self.font = self.settings.Get(group='display',
  1350. key='font', subkey='type')
  1351. self.fontlist = self.GetFonts()
  1352. self.encoding = self.settings.Get(group='display',
  1353. key='font', subkey='encoding')
  1354. border = wx.BoxSizer(wx.VERTICAL)
  1355. box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Font settings"))
  1356. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  1357. gridSizer = wx.GridBagSizer (hgap=5, vgap=5)
  1358. gridSizer.AddGrowableCol(0)
  1359. label = wx.StaticText(parent=panel, id=wx.ID_ANY,
  1360. label=_("Select font:"))
  1361. gridSizer.Add(item=label,
  1362. flag=wx.ALIGN_TOP,
  1363. pos=(0,0))
  1364. self.fontlb = wx.ListBox(parent=panel, id=wx.ID_ANY, pos=wx.DefaultPosition,
  1365. choices=self.fontlist,
  1366. style=wx.LB_SINGLE|wx.LB_SORT)
  1367. self.Bind(wx.EVT_LISTBOX, self.EvtListBox, self.fontlb)
  1368. self.Bind(wx.EVT_LISTBOX_DCLICK, self.EvtListBoxDClick, self.fontlb)
  1369. if self.font:
  1370. self.fontlb.SetStringSelection(self.font, True)
  1371. gridSizer.Add(item=self.fontlb,
  1372. flag=wx.EXPAND, pos=(0, 1))
  1373. label = wx.StaticText(parent=panel, id=wx.ID_ANY,
  1374. label=("Character encoding:"))
  1375. gridSizer.Add(item=label,
  1376. flag=wx.ALIGN_CENTER_VERTICAL,
  1377. pos=(1, 0))
  1378. self.textentry = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
  1379. value=self.encoding)
  1380. gridSizer.Add(item=self.textentry,
  1381. flag=wx.EXPAND, pos=(1, 1))
  1382. self.textentry.Bind(wx.EVT_TEXT, self.OnEncoding)
  1383. sizer.Add(item=gridSizer, proportion=1,
  1384. flag=wx.EXPAND | wx.ALL,
  1385. border=5)
  1386. border.Add(item=sizer, proportion=1,
  1387. flag=wx.ALL | wx.EXPAND, border=3)
  1388. btnsizer = wx.StdDialogButtonSizer()
  1389. btn = wx.Button(parent=panel, id=wx.ID_OK)
  1390. btn.SetDefault()
  1391. btnsizer.AddButton(btn)
  1392. btn = wx.Button(parent=panel, id=wx.ID_CANCEL)
  1393. btnsizer.AddButton(btn)
  1394. btnsizer.Realize()
  1395. border.Add(item=btnsizer, proportion=0,
  1396. flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
  1397. panel.SetAutoLayout(True)
  1398. panel.SetSizer(border)
  1399. border.Fit(self)
  1400. self.Layout()
  1401. def EvtRadioBox(self, event):
  1402. if event.GetInt() == 0:
  1403. self.fonttype = 'grassfont'
  1404. elif event.GetInt() == 1:
  1405. self.fonttype = 'truetype'
  1406. self.fontlist = self.GetFonts(self.fonttype)
  1407. self.fontlb.SetItems(self.fontlist)
  1408. def OnEncoding(self, event):
  1409. self.encoding = event.GetString()
  1410. def EvtListBox(self, event):
  1411. self.font = event.GetString()
  1412. event.Skip()
  1413. def EvtListBoxDClick(self, event):
  1414. self.font = event.GetString()
  1415. event.Skip()
  1416. def GetFonts(self):
  1417. """
  1418. parses fonts directory or fretypecap file to get a list of fonts for the listbox
  1419. """
  1420. fontlist = []
  1421. cmd = ["d.font", "-l"]
  1422. p = gcmd.Command(cmd, stderr=None)
  1423. dfonts = p.ReadStdOutput()
  1424. dfonts.sort(lambda x,y: cmp(x.lower(), y.lower()))
  1425. for item in range(len(dfonts)):
  1426. # ignore duplicate fonts and those starting with #
  1427. if not dfonts[item].startswith('#') and \
  1428. dfonts[item] != dfonts[item-1]:
  1429. fontlist.append(dfonts[item])
  1430. return fontlist
  1431. class MapsetAccess(wx.Dialog):
  1432. """
  1433. Controls setting options and displaying/hiding map overlay decorations
  1434. """
  1435. def __init__(self, parent, id, title=_('Set/unset access to mapsets in current location'),
  1436. pos=wx.DefaultPosition, size=(350, 400),
  1437. style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
  1438. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  1439. self.all_mapsets = utils.ListOfMapsets(all=True)
  1440. self.accessible_mapsets = utils.ListOfMapsets(all=False)
  1441. self.curr_mapset = grassenv.GetGRASSVariable('MAPSET')
  1442. # make a checklistbox from available mapsets and check those that are active
  1443. sizer = wx.BoxSizer(wx.VERTICAL)
  1444. label = wx.StaticText(parent=self, id=wx.ID_ANY,
  1445. label=_("Check mapset to make it accessible, uncheck it to hide it.%s"
  1446. "Note: PERMANENT and current mapset are always accessible.") % os.linesep)
  1447. sizer.Add(item=label, proportion=0,
  1448. flag=wx.ALL, border=5)
  1449. self.mapsetlb = CheckListMapset(parent=self)
  1450. self.mapsetlb.LoadData(self.all_mapsets)
  1451. sizer.Add(item=self.mapsetlb, proportion=1,
  1452. flag=wx.ALL | wx.EXPAND, border=5)
  1453. # check all accessible mapsets
  1454. for mset in self.accessible_mapsets:
  1455. self.mapsetlb.CheckItem(self.all_mapsets.index(mset), True)
  1456. # dialog buttons
  1457. line = wx.StaticLine(parent=self, id=wx.ID_ANY,
  1458. style=wx.LI_HORIZONTAL)
  1459. sizer.Add(item=line, proportion=0,
  1460. flag=wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border=5)
  1461. btnsizer = wx.StdDialogButtonSizer()
  1462. okbtn = wx.Button(self, wx.ID_OK)
  1463. okbtn.SetDefault()
  1464. btnsizer.AddButton(okbtn)
  1465. cancelbtn = wx.Button(self, wx.ID_CANCEL)
  1466. btnsizer.AddButton(cancelbtn)
  1467. btnsizer.Realize()
  1468. sizer.Add(item=btnsizer, proportion=0,
  1469. flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
  1470. # do layout
  1471. self.Layout()
  1472. self.SetSizer(sizer)
  1473. sizer.Fit(self)
  1474. self.SetMinSize(size)
  1475. def GetMapsets(self):
  1476. """Get list of checked mapsets"""
  1477. ms = []
  1478. i = 0
  1479. for mset in self.all_mapsets:
  1480. if self.mapsetlb.IsChecked(i):
  1481. ms.append(mset)
  1482. i += 1
  1483. return ms
  1484. class CheckListMapset(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
  1485. """List of mapset/owner/group"""
  1486. def __init__(self, parent, pos=wx.DefaultPosition,
  1487. log=None):
  1488. self.parent = parent
  1489. wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
  1490. style=wx.LC_REPORT)
  1491. listmix.CheckListCtrlMixin.__init__(self)
  1492. self.log = log
  1493. # setup mixins
  1494. listmix.ListCtrlAutoWidthMixin.__init__(self)
  1495. def LoadData(self, mapsets):
  1496. """Load data into list"""
  1497. self.InsertColumn(0, _('Mapset'))
  1498. self.InsertColumn(1, _('Owner'))
  1499. self.InsertColumn(2, _('Group'))
  1500. locationPath = os.path.join(grassenv.GetGRASSVariable('GISDBASE'),
  1501. grassenv.GetGRASSVariable('LOCATION_NAME'))
  1502. for mapset in mapsets:
  1503. index = self.InsertStringItem(sys.maxint, mapset)
  1504. mapsetPath = os.path.join(locationPath,
  1505. mapset)
  1506. stat_info = os.stat(mapsetPath)
  1507. if os.name in ('posix', 'mac'):
  1508. self.SetStringItem(index, 1, "%s" % pwd.getpwuid(stat_info.st_uid)[0])
  1509. # FIXME: get group name
  1510. self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid)
  1511. else:
  1512. # FIXME: no pwd under MS Windows (owner: 0, group: 0)
  1513. self.SetStringItem(index, 1, "%-8s" % stat_info.st_uid)
  1514. self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid)
  1515. self.SetColumnWidth(col=0, width=wx.LIST_AUTOSIZE)
  1516. self.SetColumnWidth(col=1, width=wx.LIST_AUTOSIZE)
  1517. def OnCheckItem(self, index, flag):
  1518. """Mapset checked/unchecked"""
  1519. mapset = self.parent.all_mapsets[index]
  1520. if mapset == 'PERMANENT' or mapset == self.parent.curr_mapset:
  1521. self.CheckItem(index, True)