preferences.py 61 KB

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