help.py 25 KB

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