preferences.py 58 KB

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