preferences.py 60 KB

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