help.py 25 KB

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