help.py 24 KB

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