help.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. """!
  2. @package help.py
  3. @brief Help window
  4. @todo Needs improvements...
  5. Classes:
  6. - HelpWindow
  7. - MenuTreeWindow
  8. - AboutWindow
  9. (C) 2008-2009 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 Martin Landa <landa.martin gmail.com>
  14. """
  15. import os
  16. import wx
  17. import wx.lib.customtreectrl as CT
  18. import wx.lib.flatnotebook as FN
  19. import wx.lib.scrolledpanel as scrolled
  20. from wx.lib.wordwrap import wordwrap
  21. import menudata
  22. import gcmd
  23. import globalvar
  24. class HelpWindow(wx.Frame):
  25. """!GRASS Quickstart help window"""
  26. def __init__(self, parent, id, title, size, file):
  27. wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
  28. sizer = wx.BoxSizer(wx.VERTICAL)
  29. # text
  30. helpFrame = wx.html.HtmlWindow(parent=self, id=wx.ID_ANY)
  31. helpFrame.SetStandardFonts (size = 10)
  32. helpFrame.SetBorders(10)
  33. wx.InitAllImageHandlers()
  34. helpFrame.LoadFile(file)
  35. self.Ok = True
  36. sizer.Add(item=helpFrame, proportion=1, flag=wx.EXPAND)
  37. self.SetAutoLayout(True)
  38. self.SetSizer(sizer)
  39. # sizer.Fit(self)
  40. # sizer.SetSizeHints(self)
  41. self.Layout()
  42. class MenuTreeWindow(wx.Frame):
  43. """!Show menu tree"""
  44. def __init__(self, parent, id = wx.ID_ANY, title = _("Menu tree window"), **kwargs):
  45. self.parent = parent # LayerManager
  46. wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
  47. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  48. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  49. self.dataBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  50. label=" %s " % _("Menu tree (double-click to run command)"))
  51. # tree
  52. self.tree = MenuTree(parent = self.panel, data = menudata.Data())
  53. self.tree.Load()
  54. self.searchDict = { _('label') : 'label', # i18n workaround
  55. _('help') : 'help',
  56. _('command') : 'command',
  57. _('keywords') : 'keywords' }
  58. # search
  59. self.searchBy = wx.Choice(parent = self.panel, id = wx.ID_ANY,
  60. choices = [_('label'),
  61. _('help'),
  62. _('command'),
  63. _('keywords')])
  64. self.search = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
  65. value = "", size = (-1, 25),
  66. style = wx.TE_PROCESS_ENTER)
  67. # statusbar
  68. self.statusbar = self.CreateStatusBar(number=1)
  69. # close on run
  70. self.closeOnRun = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  71. label = _("Close dialog on run"))
  72. self.closeOnRun.SetValue(True)
  73. # buttons
  74. self.btnRun = wx.Button(self.panel, id = wx.ID_OK, label = _("Run"))
  75. self.btnRun.SetToolTipString(_("Run selected command"))
  76. self.btnRun.Enable(False)
  77. self.btnClose = wx.Button(self.panel, id = wx.ID_CLOSE)
  78. self.btnClose.SetToolTipString(_("Close dialog"))
  79. # bindings
  80. self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
  81. self.btnRun.Bind(wx.EVT_BUTTON, self.OnRun)
  82. self.search.Bind(wx.EVT_TEXT_ENTER, self.OnShowItem)
  83. self.search.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
  84. self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
  85. self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnItemSelected)
  86. self.__Layout()
  87. self.search.SetFocus()
  88. def __Layout(self):
  89. """!Do dialog layout"""
  90. sizer = wx.BoxSizer(wx.VERTICAL)
  91. # body
  92. dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
  93. dataSizer.Add(item = self.tree, proportion =1,
  94. flag = wx.EXPAND)
  95. # search
  96. searchSizer = wx.BoxSizer(wx.HORIZONTAL)
  97. searchSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  98. label = _("Search:")),
  99. proportion = 0,
  100. flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  101. border = 3)
  102. searchSizer.Add(item = self.searchBy, proportion = 0,
  103. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT,
  104. border = 5)
  105. searchSizer.Add(item = self.search, proportion = 1,
  106. flag = wx.EXPAND | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL,
  107. border = 5)
  108. # buttons
  109. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  110. btnSizer.Add(item = self.btnRun, proportion = 0,
  111. flag = wx.LEFT | wx.RIGHT, border = 5)
  112. btnSizer.Add(item = self.btnClose, proportion = 0,
  113. flag = wx.LEFT | wx.RIGHT, border = 5)
  114. sizer.Add(item = dataSizer, proportion = 1,
  115. flag = wx.EXPAND | wx.ALL, border = 5)
  116. sizer.Add(item = searchSizer, proportion=0,
  117. flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  118. sizer.Add(item = btnSizer, proportion=0,
  119. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  120. sizer.Add(item = self.closeOnRun, proportion=0,
  121. flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  122. self.panel.SetAutoLayout(True)
  123. self.panel.SetSizer(sizer)
  124. sizer.Fit(self.panel)
  125. self.Layout()
  126. self.SetSize((530, 370))
  127. def OnCloseWindow(self, event):
  128. """!Close window"""
  129. self.Destroy()
  130. def OnRun(self, event):
  131. """!Run selected command"""
  132. if not self.tree.GetSelected():
  133. return # should not happen
  134. data = self.tree.GetPyData(self.tree.GetSelected())
  135. if not data:
  136. return
  137. handler = 'self.parent.' + data['handler'].lstrip('self.')
  138. if data['handler'] == 'self.OnXTerm':
  139. wx.MessageBox(parent = self,
  140. message = _('You must run this command from the menu or command line',
  141. 'This command require an XTerm'),
  142. caption = _('Message'), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  143. elif data['command']:
  144. eval(handler)(event = None, cmd = data['command'].split())
  145. else:
  146. eval(handler)(None)
  147. if self.closeOnRun.IsChecked():
  148. self.OnCloseWindow(None)
  149. def OnItemActivated(self, event):
  150. """!Item activated (double-click)"""
  151. item = event.GetItem()
  152. if not item or not item.IsOk():
  153. return
  154. data = self.tree.GetPyData(item)
  155. if not data or not data.has_key('command'):
  156. return
  157. self.tree.itemSelected = item
  158. self.OnRun(None)
  159. def OnItemSelected(self, event):
  160. """!Item selected"""
  161. item = event.GetItem()
  162. if not item or not item.IsOk():
  163. return
  164. data = self.tree.GetPyData(item)
  165. if not data or not data.has_key('command'):
  166. return
  167. if data['command']:
  168. label = data['command'] + ' -- ' + data['help']
  169. else:
  170. label = data['help']
  171. self.statusbar.SetStatusText(label, 0)
  172. def OnShowItem(self, event):
  173. """!Highlight first found item in menu tree"""
  174. if len(self.tree.itemsMarked) > 0:
  175. if self.tree.GetSelected():
  176. self.tree.ToggleItemSelection(self.tree.GetSelected())
  177. idx = self.tree.itemsMarked.index(self.tree.GetSelected()) + 1
  178. else:
  179. idx = 0
  180. try:
  181. self.tree.ToggleItemSelection(self.tree.itemsMarked[idx])
  182. self.tree.itemSelected = self.tree.itemsMarked[idx]
  183. self.tree.EnsureVisible(self.tree.itemsMarked[idx])
  184. except IndexError:
  185. self.tree.ToggleItemSelection(self.tree.itemsMarked[0]) # reselect first item
  186. self.tree.EnsureVisible(self.tree.itemsMarked[0])
  187. self.tree.itemSelected = self.tree.itemsMarked[0]
  188. else:
  189. for item in self.tree.root.GetChildren():
  190. self.tree.Collapse(item)
  191. itemSelected = self.tree.GetSelection()
  192. if itemSelected:
  193. self.tree.ToggleItemSelection(itemSelected)
  194. self.tree.itemSelected = None
  195. if self.tree.itemSelected:
  196. self.btnRun.Enable()
  197. else:
  198. self.btnRun.Enable(False)
  199. def OnUpdateStatusBar(self, event):
  200. """!Update statusbar text"""
  201. element = self.searchDict[self.searchBy.GetStringSelection()]
  202. self.tree.itemsMarked = self.SearchItems(element = element,
  203. value = event.GetString())
  204. self.tree.itemSelected = None
  205. nItems = len(self.tree.itemsMarked)
  206. if event.GetString():
  207. self.statusbar.SetStatusText(_("%d items match") % nItems, 0)
  208. else:
  209. self.statusbar.SetStatusText("", 0)
  210. event.Skip()
  211. def SearchItems(self, element, value):
  212. """!Search item
  213. @param element element index (see self.searchBy)
  214. @param value
  215. @return list of found tree items
  216. """
  217. items = list()
  218. if not value:
  219. return items
  220. item = self.tree.GetFirstChild(self.tree.root)[0]
  221. self.__ProcessItem(item, element, value, items)
  222. return items
  223. def __ProcessItem(self, item, element, value, listOfItems):
  224. """!Search items (used by SearchItems)
  225. @param item reference item
  226. @param listOfItems list of found items
  227. """
  228. while item and item.IsOk():
  229. subItem = self.tree.GetFirstChild(item)[0]
  230. if subItem:
  231. self.__ProcessItem(subItem, element, value, listOfItems)
  232. data = self.tree.GetPyData(item)
  233. if data and data.has_key(element) and \
  234. value.lower() in data[element].lower():
  235. listOfItems.append(item)
  236. item = self.tree.GetNextSibling(item)
  237. class MenuTree(CT.CustomTreeCtrl):
  238. """!Menu tree class"""
  239. def __init__(self, parent, data, id = wx.ID_ANY,
  240. ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS | \
  241. CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
  242. **kwargs):
  243. self.parent = parent
  244. self.menudata = data
  245. super(MenuTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
  246. self.root = self.AddRoot(_("Menu tree"))
  247. self.itemsMarked = [] # list of marked items
  248. self.itemSelected = None
  249. def Load(self, data = None):
  250. """!Load menu data tree
  251. @param data menu data (None to use self.menudata)
  252. """
  253. if not data:
  254. data = self.menudata
  255. self.itemsMarked = [] # list of marked items
  256. for eachMenuData in data.GetMenu():
  257. for label, items in eachMenuData:
  258. item = self.AppendItem(parentId = self.root,
  259. text = label)
  260. self.__AppendItems(item, items)
  261. def __AppendItems(self, item, data):
  262. """!Append items into tree (used by Load()
  263. @param item tree item (parent)
  264. @parent data menu data"""
  265. for eachItem in data:
  266. if len(eachItem) == 2:
  267. if eachItem[0]:
  268. itemSub = self.AppendItem(parentId = item,
  269. text = eachItem[0])
  270. self.__AppendItems(itemSub, eachItem[1])
  271. else:
  272. if eachItem[0]:
  273. itemNew = self.AppendItem(parentId = item,
  274. text = eachItem[0])
  275. data = { 'label' : eachItem[0],
  276. 'help' : eachItem[1],
  277. 'handler' : eachItem[2],
  278. 'command' : eachItem[3],
  279. 'keywords' : eachItem[4] }
  280. self.SetPyData(itemNew, data)
  281. def GetSelected(self):
  282. """!Get selected item"""
  283. return self.itemSelected
  284. class AboutWindow(wx.Frame):
  285. def __init__(self, parent):
  286. """!Create custom About Window
  287. @todo improve styling
  288. """
  289. wx.Frame.__init__(self, parent=parent, id=wx.ID_ANY, size=(550,400),
  290. title=_('About GRASS GIS'))
  291. panel = wx.Panel(parent = self, id = wx.ID_ANY)
  292. # icon
  293. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  294. # get version and web site
  295. version, svn_gis_h_rev, svn_gis_h_date = gcmd.RunCommand('g.version',
  296. verbose = True, # -> svn revision
  297. flags = 'r',
  298. read = True).splitlines()
  299. infoTxt = wx.Panel(parent = panel, id = wx.ID_ANY)
  300. infoSizer = wx.BoxSizer(wx.VERTICAL)
  301. logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass.ico")
  302. logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
  303. bitmap = wx.Bitmap(name = logo,
  304. type = wx.BITMAP_TYPE_ICO))
  305. infoSizer.Add(item = logoBitmap, proportion = 0,
  306. flag = wx.ALL | wx.ALIGN_CENTER, border = 10)
  307. i = 0
  308. for label in [version.replace('GRASS', 'GRASS GIS').strip() + '\n\n',
  309. _('Official GRASS site: http://grass.osgeo.org') + '\n\n',
  310. _('GIS Library') + ' ' + svn_gis_h_rev + '(' + svn_gis_h_date.split(' ')[1] + ')']:
  311. info = wx.StaticText(parent = infoTxt,
  312. id = wx.ID_ANY,
  313. label = label)
  314. if i == 0:
  315. info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
  316. infoSizer.Add(item = info, proportion = 0,
  317. flag = wx.TOP | wx.ALIGN_CENTER, border = 5)
  318. i += 1
  319. #
  320. # create pages
  321. #
  322. copyrightwin = self.PageCopyright()
  323. licensewin = self.PageLicense()
  324. authorwin = self.PageCredit()
  325. contribwin = self.PageContributors()
  326. transwin = self.PageTranslators()
  327. # create a flat notebook for displaying information about GRASS
  328. nbstyle = FN.FNB_VC8 | \
  329. FN.FNB_BACKGROUND_GRADIENT | \
  330. FN.FNB_TABS_BORDER_SIMPLE | \
  331. FN.FNB_NO_X_BUTTON | \
  332. FN.FNB_NO_NAV_BUTTONS
  333. aboutNotebook = FN.FlatNotebook(panel, id=wx.ID_ANY, style=nbstyle)
  334. aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
  335. # make pages for About GRASS notebook
  336. pg1 = aboutNotebook.AddPage(infoTxt, text=_("Info"))
  337. pg2 = aboutNotebook.AddPage(copyrightwin, text=_("Copyright"))
  338. pg3 = aboutNotebook.AddPage(licensewin, text=_("License"))
  339. pg4 = aboutNotebook.AddPage(authorwin, text=_("Authors"))
  340. pg5 = aboutNotebook.AddPage(contribwin, text=_("Contributors"))
  341. pg5 = aboutNotebook.AddPage(transwin, text=_("Translators"))
  342. # buttons
  343. btnClose = wx.Button(parent = panel, id = wx.ID_CLOSE)
  344. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  345. btnSizer.Add(item = btnClose, proportion = 1,
  346. flag = wx.ALL | wx.EXPAND | wx.ALIGN_RIGHT,
  347. border = 5)
  348. # bindings
  349. # self.aboutNotebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnAGPageChanged)
  350. btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
  351. infoTxt.SetSizer(infoSizer)
  352. infoSizer.Fit(infoTxt)
  353. sizer = wx.BoxSizer(wx.VERTICAL)
  354. sizer.Add(item=aboutNotebook, proportion=1,
  355. flag=wx.EXPAND | wx.ALL, border=1)
  356. sizer.Add(item=btnSizer, proportion=0,
  357. flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=1)
  358. panel.SetSizer(sizer)
  359. self.Layout()
  360. def PageCopyright(self):
  361. """Copyright information"""
  362. copyfile = os.path.join(os.getenv("GISBASE"), "COPYING")
  363. if os.path.exists(copyfile):
  364. copyrightFile = open(copyfile, 'r')
  365. copyrightOut = []
  366. copyright = copyrightFile.readlines()
  367. copytext = wordwrap(''.join(copyright[:11] + copyright[26:-3]),
  368. 575, wx.ClientDC(self))
  369. copyrightFile.close()
  370. else:
  371. copytext = _('%s file missing') % 'COPYING'
  372. # put text into a scrolling panel
  373. copyrightwin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
  374. size=wx.DefaultSize,
  375. style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
  376. copyrighttxt = wx.StaticText(copyrightwin, id=wx.ID_ANY, label=copytext)
  377. copyrightwin.SetAutoLayout(True)
  378. copyrightwin.sizer = wx.BoxSizer(wx.VERTICAL)
  379. copyrightwin.sizer.Add(item=copyrighttxt, proportion=1,
  380. flag=wx.EXPAND | wx.ALL, border=3)
  381. copyrightwin.SetSizer(copyrightwin.sizer)
  382. copyrightwin.Layout()
  383. copyrightwin.SetupScrolling()
  384. return copyrightwin
  385. def PageLicense(self):
  386. """Licence about"""
  387. licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT")
  388. if os.path.exists(licfile):
  389. licenceFile = open(licfile, 'r')
  390. license = ''.join(licenceFile.readlines())
  391. licenceFile.close()
  392. else:
  393. license = _('%s file missing') % 'GPL.TXT'
  394. # put text into a scrolling panel
  395. licensewin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
  396. style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
  397. licensetxt = wx.StaticText(licensewin, id=wx.ID_ANY, label=license)
  398. licensewin.SetAutoLayout(True)
  399. licensewin.sizer = wx.BoxSizer(wx.VERTICAL)
  400. licensewin.sizer.Add(item=licensetxt, proportion=1,
  401. flag=wx.EXPAND | wx.ALL, border=3)
  402. licensewin.SetSizer(licensewin.sizer)
  403. licensewin.Layout()
  404. licensewin.SetupScrolling()
  405. return licensewin
  406. def PageCredit(self):
  407. """Credit about"""
  408. # credits
  409. authfile = os.path.join(os.getenv("GISBASE"), "AUTHORS")
  410. if os.path.exists(authfile):
  411. authorsFile = open(authfile, 'r')
  412. authors = unicode(''.join(authorsFile.readlines()), "utf-8")
  413. authorsFile.close()
  414. else:
  415. authors = _('%s file missing') % 'AUTHORS'
  416. authorwin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
  417. style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
  418. authortxt = wx.StaticText(authorwin, id=wx.ID_ANY, label=str(authors))
  419. authorwin.SetAutoLayout(1)
  420. authorwin.SetupScrolling()
  421. authorwin.sizer = wx.BoxSizer(wx.VERTICAL)
  422. authorwin.sizer.Add(item=authortxt, proportion=1,
  423. flag=wx.EXPAND | wx.ALL, border=3)
  424. authorwin.SetSizer(authorwin.sizer)
  425. authorwin.Layout()
  426. return authorwin
  427. def PageContributors(self):
  428. """Contributors info"""
  429. contribfile = os.path.join(os.getenv("GISBASE"), "contributors.csv")
  430. if os.path.exists(contribfile):
  431. contribFile = open(contribfile, 'r')
  432. contribs = list()
  433. for line in contribFile.readlines():
  434. cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
  435. contribs.append((name, email, country, osgeo_id))
  436. contribs[0] = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
  437. contribFile.close()
  438. else:
  439. contribs = None
  440. contribwin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
  441. style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
  442. contribwin.SetAutoLayout(1)
  443. contribwin.SetupScrolling()
  444. contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
  445. if not contribs:
  446. contribtxt = wx.StaticText(contribwin, id=wx.ID_ANY,
  447. label=_('%s file missing') % 'contibutors.csv')
  448. contribwin.sizer.Add(item=contribtxt, proportion=1,
  449. flag=wx.EXPAND | wx.ALL, border=3)
  450. else:
  451. contribBox = wx.FlexGridSizer(cols=4, vgap=5, hgap=5)
  452. for developer in contribs:
  453. for item in developer:
  454. contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
  455. label = item))
  456. contribwin.sizer.Add(item=contribBox, proportion=1,
  457. flag=wx.EXPAND | wx.ALL, border=3)
  458. contribwin.SetSizer(contribwin.sizer)
  459. contribwin.Layout()
  460. return contribwin
  461. def PageTranslators(self):
  462. """Translators info"""
  463. translatorsfile = os.path.join(os.getenv("GISBASE"), "translators.csv")
  464. if os.path.exists(translatorsfile):
  465. translatorsFile = open(translatorsfile, 'r')
  466. translators = dict()
  467. for line in translatorsFile.readlines()[1:]:
  468. name, email, languages = line.rstrip('\n').split(',')
  469. for language in languages.split(' '):
  470. if not translators.has_key(language):
  471. translators[language] = list()
  472. translators[language].append((name, email))
  473. translatorsFile.close()
  474. else:
  475. translators = None
  476. translatorswin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
  477. style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
  478. translatorswin.SetAutoLayout(1)
  479. translatorswin.SetupScrolling()
  480. translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
  481. if not translators:
  482. translatorstxt = wx.StaticText(translatorswin, id=wx.ID_ANY,
  483. label=_('%s file missing') % 'translators.csv')
  484. translatorswin.sizer.Add(item=translatorstxt, proportion=1,
  485. flag=wx.EXPAND | wx.ALL, border=3)
  486. else:
  487. translatorsBox = wx.FlexGridSizer(cols=3, vgap=5, hgap=5)
  488. languages = translators.keys()
  489. languages.sort()
  490. translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
  491. label = _('Name')))
  492. translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
  493. label = _('E-mail')))
  494. translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
  495. label = _('Language')))
  496. for lang in languages:
  497. for translator in translators[lang]:
  498. name, email = translator
  499. translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
  500. label = name))
  501. translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
  502. label = email))
  503. translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
  504. label = lang))
  505. translatorswin.sizer.Add(item=translatorsBox, proportion=1,
  506. flag=wx.EXPAND | wx.ALL, border=3)
  507. translatorswin.SetSizer(translatorswin.sizer)
  508. translatorswin.Layout()
  509. return translatorswin
  510. def OnCloseWindow(self, event):
  511. """!Close window"""
  512. self.Close()