preferences.py 57 KB

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