GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ghelp.py
Go to the documentation of this file.
1 """!
2 @package gui_core.ghelp
3 
4 @brief Help window
5 
6 Classes:
7  - ghelp::SearchModuleWindow
8  - ghelp::AboutWindow
9  - ghelp::HelpFrame
10  - ghelp::HelpWindow
11  - ghelp::HelpPanel
12 
13 (C) 2008-2011 by the GRASS Development Team
14 
15 This program is free software under the GNU General Public License
16 (>=v2). Read the file COPYING that comes with GRASS for details.
17 
18 @author Martin Landa <landa.martin gmail.com>
19 """
20 
21 import os
22 import sys
23 import re
24 import codecs
25 import platform
26 
27 import wx
28 from wx.html import HtmlWindow
29 try:
30  import wx.lib.agw.customtreectrl as CT
31  from wx.lib.agw.hyperlink import HyperLinkCtrl
32 except ImportError:
33  import wx.lib.customtreectrl as CT
34  from wx.lib.hyperlink import HyperLinkCtrl
35 import wx.lib.flatnotebook as FN
36 
37 import grass.script as grass
38 
39 from core import globalvar
40 from core import utils
41 from core.gcmd import GError, DecodeString
42 from gui_core.widgets import GNotebook, StaticWrapText, ScrolledPanel
43 from core.settings import UserSettings
44 
45 class SearchModuleWindow(wx.Panel):
46  """!Search module window (used in MenuTreeWindow)"""
47  def __init__(self, parent, id = wx.ID_ANY, cmdPrompt = None,
48  showChoice = True, showTip = False, **kwargs):
49  self.showTip = showTip
50  self.showChoice = showChoice
51  self.cmdPrompt = cmdPrompt
52 
53  wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
54 
55  self._searchDict = { _('description') : 'description',
56  _('command') : 'command',
57  _('keywords') : 'keywords' }
58 
59  self.box = wx.StaticBox(parent = self, id = wx.ID_ANY,
60  label = " %s " % _("Find module - (press Enter for next match)"))
61 
62  self.searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
63  choices = [_('description'),
64  _('keywords'),
65  _('command')])
66  self.searchBy.SetSelection(0)
67 
68  self.search = wx.SearchCtrl(parent = self, id = wx.ID_ANY,
69  size = (-1, 25), style = wx.TE_PROCESS_ENTER)
70  if self.cmdPrompt:
71  self.search.Bind(wx.EVT_TEXT, self.OnSearchModule)
72 
73  if self.showTip:
74  self.searchTip = StaticWrapText(parent = self, id = wx.ID_ANY,
75  size = (-1, 35))
76 
77  if self.showChoice:
78  self.searchChoice = wx.Choice(parent = self, id = wx.ID_ANY)
79  if self.cmdPrompt:
80  self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
81  self.searchChoice.Bind(wx.EVT_CHOICE, self.OnSelectModule)
82 
83  self._layout()
84 
85  def _layout(self):
86  """!Do layout"""
87  sizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
88  gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
89 
90  gridSizer.Add(item = self.searchBy,
91  flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
92  gridSizer.Add(item = self.search,
93  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (0, 1))
94  row = 1
95  if self.showChoice:
96  gridSizer.Add(item = self.searchChoice,
97  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
98  row += 1
99  if self.showTip:
100  gridSizer.Add(item = self.searchTip,
101  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
102  row += 1
103 
104  gridSizer.AddGrowableCol(1)
105  sizer.Add(item = gridSizer, proportion = 1)
106 
107  self.SetSizer(sizer)
108  sizer.Fit(self)
109 
110  def GetCtrl(self):
111  """!Get SearchCtrl widget"""
112  return self.search
113 
114  def GetSelection(self):
115  """!Get selected element"""
116  selection = self.searchBy.GetStringSelection()
117 
118  return self._searchDict[selection]
119 
120  def SetSelection(self, i):
121  """!Set selection element"""
122  self.searchBy.SetSelection(i)
123 
124  def OnSearchModule(self, event):
125  """!Search module by keywords or description"""
126  if not self.cmdPrompt:
127  event.Skip()
128  return
129 
130  # hide autocomplete
131  if self.cmdPrompt.AutoCompActive():
132  self.cmdPrompt.AutoCompCancel()
133 
134  text = event.GetEventObject().GetValue()
135  if not text:
136  self.cmdPrompt.SetFilter(None)
137  mList = self.cmdPrompt.GetCommandItems()
138  self.searchChoice.SetItems(mList)
139  if self.showTip:
140  self.searchTip.SetLabel(_("%d modules found") % len(mList))
141  event.Skip()
142  return
143 
144  modules = dict()
145  iFound = 0
146  for module, data in self.cmdPrompt.moduleDesc.iteritems():
147  found = False
148  sel = self.searchBy.GetSelection()
149  if sel == 0: # -> description
150  if text in data['desc']:
151  found = True
152  elif sel == 1: # keywords
153  if text in ','.join(data['keywords']):
154  found = True
155  else: # command
156  if module[:len(text)] == text:
157  found = True
158 
159  if found:
160  iFound += 1
161  try:
162  group, name = module.split('.')
163  except ValueError:
164  continue # TODO
165 
166  if group not in modules:
167  modules[group] = list()
168  modules[group].append(name)
169 
170  self.cmdPrompt.SetFilter(modules)
171  self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
172  self.searchChoice.SetSelection(0)
173  if self.showTip:
174  self.searchTip.SetLabel(_("%d modules match") % iFound)
175 
176  event.Skip()
177 
178  def OnSelectModule(self, event):
179  """!Module selected from choice, update command prompt"""
180  cmd = event.GetString().split(' ', 1)[0]
181  text = cmd + ' '
182  pos = len(text)
183 
184  if self.cmdPrompt:
185  self.cmdPrompt.SetText(text)
186  self.cmdPrompt.SetSelectionStart(pos)
187  self.cmdPrompt.SetCurrentPos(pos)
188  self.cmdPrompt.SetFocus()
189 
190  desc = self.cmdPrompt.GetCommandDesc(cmd)
191  if self.showTip:
192  self.searchTip.SetLabel(desc)
193 
194  def Reset(self):
195  """!Reset widget"""
196  self.searchBy.SetSelection(0)
197  self.search.SetValue('')
198  if self.showTip:
199  self.searchTip.SetLabel('')
200 
201 class AboutWindow(wx.Frame):
202  """!Create custom About Window
203  """
204  def __init__(self, parent, size = (650, 460),
205  title = _('About GRASS GIS'), **kwargs):
206  wx.Frame.__init__(self, parent = parent, id = wx.ID_ANY, title = title, size = size, **kwargs)
207 
208  panel = wx.Panel(parent = self, id = wx.ID_ANY)
209 
210  # icon
211  self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
212 
213  # get version and web site
214  vInfo = grass.version()
215 
216  infoTxt = ScrolledPanel(parent = panel)
217  infoTxt.SetupScrolling()
218  infoSizer = wx.BoxSizer(wx.VERTICAL)
219  infoGridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
220  logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass-64x64.png")
221  logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
222  bitmap = wx.Bitmap(name = logo,
223  type = wx.BITMAP_TYPE_PNG))
224  infoSizer.Add(item = logoBitmap, proportion = 0,
225  flag = wx.ALL | wx.ALIGN_CENTER, border = 20)
226 
227  info = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
228  label = 'GRASS GIS ' + vInfo['version'] + '\n\n')
229  info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
230  info.SetForegroundColour(wx.Colour(35, 142, 35))
231  infoSizer.Add(item = info, proportion = 0,
232  flag = wx.BOTTOM | wx.ALIGN_CENTER, border = 1)
233 
234  row = 0
235  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
236  label = _('Official GRASS site:')),
237  pos = (row, 0),
238  flag = wx.ALIGN_RIGHT)
239 
240  infoGridSizer.Add(item = HyperLinkCtrl(parent = infoTxt, id = wx.ID_ANY,
241  label = 'http://grass.osgeo.org'),
242  pos = (row, 1),
243  flag = wx.ALIGN_LEFT)
244 
245  row += 2
246  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
247  label = '%s:' % _('SVN Revision')),
248  pos = (row, 0),
249  flag = wx.ALIGN_RIGHT)
250 
251  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
252  label = vInfo['revision']),
253  pos = (row, 1),
254  flag = wx.ALIGN_LEFT)
255 
256  row += 1
257  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
258  label = '%s:' % _('GIS Library Revision')),
259  pos = (row, 0),
260  flag = wx.ALIGN_RIGHT)
261 
262  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
263  label = vInfo['libgis_revision'] + ' (' +
264  vInfo['libgis_date'].split(' ')[0] + ')'),
265  pos = (row, 1),
266  flag = wx.ALIGN_LEFT)
267 
268  row += 2
269  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
270  label = 'Python:'),
271  pos = (row, 0),
272  flag = wx.ALIGN_RIGHT)
273 
274  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
275  label = platform.python_version()),
276  pos = (row, 1),
277  flag = wx.ALIGN_LEFT)
278 
279  row += 1
280  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
281  label = 'wxPython:'),
282  pos = (row, 0),
283  flag = wx.ALIGN_RIGHT)
284 
285  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
286  label = wx.__version__),
287  pos = (row, 1),
288  flag = wx.ALIGN_LEFT)
289  infoGridSizer.AddGrowableCol(0)
290  infoGridSizer.AddGrowableCol(1)
291 
292  infoSizer.Add(item = infoGridSizer,
293  proportion = 1,
294  flag = wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
295 
296  row += 2
297  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
298  label = "%s:" % _('Language')),
299  pos = (row, 0),
300  flag = wx.ALIGN_RIGHT)
301  lang = grass.gisenv().get('LANG', None)
302  if not lang:
303  import locale
304  loc = locale.getdefaultlocale()
305  if loc == (None, None):
306  lang = _('unknown')
307  else:
308  lang = u'%s.%s' % (loc[0], loc[1])
309  infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
310  label = lang),
311  pos = (row, 1),
312  flag = wx.ALIGN_LEFT)
313 
314  # create a flat notebook for displaying information about GRASS
315  aboutNotebook = GNotebook(panel, style = globalvar.FNPageStyle | FN.FNB_NO_X_BUTTON)
316  aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
317 
318  for title, win in ((_("Info"), infoTxt),
319  (_("Copyright"), self._pageCopyright()),
320  (_("License"), self._pageLicense()),
321  (_("Authors"), self._pageCredit()),
322  (_("Contributors"), self._pageContributors()),
323  (_("Extra contributors"), self._pageContributors(extra = True)),
324  (_("Translators"), self._pageTranslators())):
325  aboutNotebook.AddPage(page = win, text = title)
326  wx.CallAfter(aboutNotebook.SetSelection, 0)
327 
328  # buttons
329  btnClose = wx.Button(parent = panel, id = wx.ID_CLOSE)
330  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
331  btnSizer.Add(item = btnClose, proportion = 0,
332  flag = wx.ALL | wx.ALIGN_RIGHT,
333  border = 5)
334  # bindings
335  btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
336 
337  infoTxt.SetSizer(infoSizer)
338  infoSizer.Fit(infoTxt)
339 
340  sizer = wx.BoxSizer(wx.VERTICAL)
341  sizer.Add(item = aboutNotebook, proportion = 1,
342  flag = wx.EXPAND | wx.ALL, border = 1)
343  sizer.Add(item = btnSizer, proportion = 0,
344  flag = wx.ALL | wx.ALIGN_RIGHT, border = 1)
345  panel.SetSizer(sizer)
346 
347  self.Layout()
348  self.SetMinSize((400, 400))
349 
350  def _pageCopyright(self):
351  """Copyright information"""
352  copyfile = os.path.join(os.getenv("GISBASE"), "COPYING")
353  if os.path.exists(copyfile):
354  copyrightFile = open(copyfile, 'r')
355  copytext = copyrightFile.read()
356  copyrightFile.close()
357  else:
358  copytext = _('%s file missing') % 'COPYING'
359 
360  # put text into a scrolling panel
361  copyrightwin = ScrolledPanel(self)
362 
363  copyrighttxt = wx.StaticText(copyrightwin, id = wx.ID_ANY, label = copytext)
364  copyrightwin.SetAutoLayout(True)
365  copyrightwin.sizer = wx.BoxSizer(wx.VERTICAL)
366  copyrightwin.sizer.Add(item = copyrighttxt, proportion = 1,
367  flag = wx.EXPAND | wx.ALL, border = 3)
368  copyrightwin.SetSizer(copyrightwin.sizer)
369  copyrightwin.Layout()
370  copyrightwin.SetupScrolling()
371 
372  return copyrightwin
373 
374  def _pageLicense(self):
375  """Licence about"""
376  licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT")
377  if os.path.exists(licfile):
378  licenceFile = open(licfile, 'r')
379  license = ''.join(licenceFile.readlines())
380  licenceFile.close()
381  else:
382  license = _('%s file missing') % 'GPL.TXT'
383  # put text into a scrolling panel
384  licensewin = ScrolledPanel(self)
385  licensetxt = wx.StaticText(licensewin, id = wx.ID_ANY, label = license)
386  licensewin.SetAutoLayout(True)
387  licensewin.sizer = wx.BoxSizer(wx.VERTICAL)
388  licensewin.sizer.Add(item = licensetxt, proportion = 1,
389  flag = wx.EXPAND | wx.ALL, border = 3)
390  licensewin.SetSizer(licensewin.sizer)
391  licensewin.Layout()
392  licensewin.SetupScrolling()
393 
394  return licensewin
395 
396  def _pageCredit(self):
397  """Credit about"""
398  # credits
399  authfile = os.path.join(os.getenv("GISBASE"), "AUTHORS")
400  if os.path.exists(authfile):
401  authorsFile = open(authfile, 'r')
402  authors = unicode(''.join(authorsFile.readlines()), "utf-8")
403  authorsFile.close()
404  else:
405  authors = _('%s file missing') % 'AUTHORS'
406  authorwin = ScrolledPanel(self)
407  authortxt = wx.StaticText(authorwin, id = wx.ID_ANY, label = authors)
408  authorwin.SetAutoLayout(True)
409  authorwin.SetupScrolling()
410  authorwin.sizer = wx.BoxSizer(wx.VERTICAL)
411  authorwin.sizer.Add(item = authortxt, proportion = 1,
412  flag = wx.EXPAND | wx.ALL, border = 3)
413  authorwin.SetSizer(authorwin.sizer)
414  authorwin.Layout()
415 
416  return authorwin
417 
418  def _pageContributors(self, extra = False):
419  """Contributors info"""
420  if extra:
421  contribfile = os.path.join(os.getenv("GISBASE"), "contributors_extra.csv")
422  else:
423  contribfile = os.path.join(os.getenv("GISBASE"), "contributors.csv")
424  if os.path.exists(contribfile):
425  contribFile = codecs.open(contribfile, encoding = 'utf-8', mode = 'r')
426  contribs = list()
427  errLines = list()
428  for line in contribFile.readlines()[1:]:
429  line = line.rstrip('\n')
430  try:
431  if extra:
432  name, email, country, rfc2_agreed = line.split(',')
433  else:
434  cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
435  except ValueError:
436  errLines.append(line)
437  continue
438  if extra:
439  contribs.append((name, email))
440  else:
441  contribs.append((name, email, country, osgeo_id))
442 
443  contribFile.close()
444 
445  if errLines:
446  GError(parent = self,
447  message = _("Error when reading file '%s'.") % contribfile + \
448  "\n\n" + _("Lines:") + " %s" % \
449  os.linesep.join(map(DecodeString, errLines)))
450  else:
451  contribs = None
452 
453  contribwin = ScrolledPanel(self)
454  contribwin.SetAutoLayout(True)
455  contribwin.SetupScrolling()
456  contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
457 
458  if not contribs:
459  contribtxt = wx.StaticText(contribwin, id = wx.ID_ANY,
460  label = _('%s file missing') % contribfile)
461  contribwin.sizer.Add(item = contribtxt, proportion = 1,
462  flag = wx.EXPAND | wx.ALL, border = 3)
463  else:
464  if extra:
465  items = (_('Name'), _('E-mail'))
466  else:
467  items = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
468  contribBox = wx.FlexGridSizer(cols = len(items), vgap = 5, hgap = 5)
469  for item in items:
470  contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
471  label = item))
472  for vals in sorted(contribs, key = lambda x: x[0]):
473  for item in vals:
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 
479  contribwin.SetSizer(contribwin.sizer)
480  contribwin.Layout()
481 
482  return contribwin
483 
484  def _pageTranslators(self):
485  """Translators info"""
486  translatorsfile = os.path.join(os.getenv("GISBASE"), "translators.csv")
487  if os.path.exists(translatorsfile):
488  translatorsFile = open(translatorsfile, 'r')
489  translators = dict()
490  errLines = list()
491  for line in translatorsFile.readlines()[1:]:
492  line = line.rstrip('\n')
493  try:
494  name, email, languages = line.split(',')
495  except ValueError:
496  errLines.append(line)
497  continue
498  for language in languages.split(' '):
499  if language not in translators:
500  translators[language] = list()
501  translators[language].append((name, email))
502  translatorsFile.close()
503 
504  if errLines:
505  GError(parent = self,
506  message = _("Error when reading file '%s'.") % translatorsfile + \
507  "\n\n" + _("Lines:") + " %s" % \
508  os.linesep.join(map(DecodeString, errLines)))
509  else:
510  translators = None
511 
512  translatorswin = ScrolledPanel(self)
513  translatorswin.SetAutoLayout(True)
514  translatorswin.SetupScrolling()
515  translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
516 
517  if not translators:
518  translatorstxt = wx.StaticText(translatorswin, id = wx.ID_ANY,
519  label = _('%s file missing') % 'translators.csv')
520  translatorswin.sizer.Add(item = translatorstxt, proportion = 1,
521  flag = wx.EXPAND | wx.ALL, border = 3)
522  else:
523  translatorsBox = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
524  languages = translators.keys()
525  languages.sort()
526  translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
527  label = _('Name')))
528  translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
529  label = _('E-mail')))
530  translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
531  label = _('Language')))
532  for lang in languages:
533  for translator in translators[lang]:
534  name, email = translator
535  translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
536  label = unicode(name, "utf-8")))
537  translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
538  label = email))
539  translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
540  label = lang))
541 
542  translatorswin.sizer.Add(item = translatorsBox, proportion = 1,
543  flag = wx.EXPAND | wx.ALL, border = 3)
544 
545  translatorswin.SetSizer(translatorswin.sizer)
546  translatorswin.Layout()
547 
548  return translatorswin
549 
550  def OnCloseWindow(self, event):
551  """!Close window"""
552  self.Close()
553 
554 class HelpFrame(wx.Dialog):
555  """!GRASS Quickstart help window
556 
557  As a base class wx.Dialog is used, because of not working
558  close button with wx.Frame when dialog is called from wizard.
559  If parent is None, application TopLevelWindow is used (wxPython standard behaviour).
560  """
561  def __init__(self, parent, id, title, size, file):
562  wx.Dialog.__init__(self, parent = parent, id = id, title = title,
563  size = size, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER | wx.MINIMIZE_BOX)
564 
565  sizer = wx.BoxSizer(wx.VERTICAL)
566 
567  # text
568  content = HelpPanel(parent = self)
569  content.LoadPage(file)
570 
571  sizer.Add(item = content, proportion = 1, flag = wx.EXPAND)
572 
573  self.SetAutoLayout(True)
574  self.SetSizer(sizer)
575  self.Layout()
576 
577 
578 class HelpWindow(wx.html.HtmlWindow):
579  """!This panel holds the text from GRASS docs.
580 
581  GISBASE must be set in the environment to find the html docs dir.
582  The SYNOPSIS section is skipped, since this Panel is supposed to
583  be integrated into the cmdPanel and options are obvious there.
584  """
585  def __init__(self, parent, command, text, skipDescription,
586  **kwargs):
587  """!If command is given, the corresponding HTML help
588  file will be presented, with all links pointing to absolute
589  paths of local files.
590 
591  If 'skipDescription' is True, the HTML corresponding to
592  SYNOPSIS will be skipped, thus only presenting the help file
593  from the DESCRIPTION section onwards.
594 
595  If 'text' is given, it must be the HTML text to be presented
596  in the Panel.
597  """
598  self.parent = parent
599  if not globalvar.CheckWxVersion([2, 9]):
600  wx.InitAllImageHandlers()
601  wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
602 
603  self.loaded = False
604  self.history = list()
605  self.historyIdx = 0
606  self.fspath = os.path.join(os.getenv("GISBASE"), "docs", "html")
607 
608  self.SetStandardFonts (size = 10)
609  self.SetBorders(10)
610 
611  if text is None:
612  if skipDescription:
613  url = os.path.join(self.fspath, command + ".html")
614  self.fillContentsFromFile(url,
615  skipDescription = skipDescription)
616  self.history.append(url)
617  self.loaded = True
618  else:
619  ### FIXME: calling LoadPage() is strangely time-consuming (only first call)
620  # self.LoadPage(self.fspath + command + ".html")
621  self.loaded = False
622  else:
623  self.SetPage(text)
624  self.loaded = True
625 
626  def OnLinkClicked(self, linkinfo):
627  url = linkinfo.GetHref()
628  if url[:4] != 'http':
629  url = os.path.join(self.fspath, url)
630  self.history.append(url)
631  self.historyIdx += 1
632  self.parent.OnHistory()
633 
634  super(HelpWindow, self).OnLinkClicked(linkinfo)
635 
636  def fillContentsFromFile(self, htmlFile, skipDescription = True):
637  """!Load content from file"""
638  aLink = re.compile(r'(<a href="?)(.+\.html?["\s]*>)', re.IGNORECASE)
639  imgLink = re.compile(r'(<img src="?)(.+\.[png|gif])', re.IGNORECASE)
640  try:
641  contents = []
642  skip = False
643  for l in file(htmlFile, "rb").readlines():
644  if "DESCRIPTION" in l:
645  skip = False
646  if not skip:
647  # do skip the options description if requested
648  if "SYNOPSIS" in l:
649  skip = skipDescription
650  else:
651  # FIXME: find only first item
652  findALink = aLink.search(l)
653  if findALink is not None:
654  contents.append(aLink.sub(findALink.group(1)+
655  self.fspath+findALink.group(2),l))
656  findImgLink = imgLink.search(l)
657  if findImgLink is not None:
658  contents.append(imgLink.sub(findImgLink.group(1)+
659  self.fspath+findImgLink.group(2),l))
660 
661  if findALink is None and findImgLink is None:
662  contents.append(l)
663  self.SetPage("".join(contents))
664  self.loaded = True
665  except: # The Manual file was not found
666  self.loaded = False
667 
668 class HelpPanel(wx.Panel):
669  def __init__(self, parent, command = "index", text = None,
670  skipDescription = False, **kwargs):
671  self.command = command
672  wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
673 
674  self.content = HelpWindow(self, command, text, skipDescription)
675 
676  self.btnNext = wx.Button(parent = self, id = wx.ID_ANY,
677  label = _("&Next"))
678  self.btnNext.Enable(False)
679  self.btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
680  label = _("&Previous"))
681  self.btnPrev.Enable(False)
682 
683  self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext)
684  self.btnPrev.Bind(wx.EVT_BUTTON, self.OnPrev)
685 
686  self._layout()
687 
688  def _layout(self):
689  """!Do layout"""
690  sizer = wx.BoxSizer(wx.VERTICAL)
691  btnSizer = wx.BoxSizer(wx.HORIZONTAL)
692 
693  btnSizer.Add(item = self.btnPrev, proportion = 0,
694  flag = wx.ALL, border = 5)
695  btnSizer.Add(item = wx.Size(1, 1), proportion = 1)
696  btnSizer.Add(item = self.btnNext, proportion = 0,
697  flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
698 
699  sizer.Add(item = self.content, proportion = 1,
700  flag = wx.EXPAND)
701  sizer.Add(item = btnSizer, proportion = 0,
702  flag = wx.EXPAND)
703 
704  self.SetSizer(sizer)
705  sizer.Fit(self)
706 
707  def LoadPage(self, path = None):
708  """!Load page"""
709  if not path:
710  path = self.GetFile()
711  self.content.history.append(path)
712  self.content.LoadPage(path)
713 
714  def GetFile(self):
715  """!Get HTML file"""
716  fMan = os.path.join(self.content.fspath, self.command + ".html")
717  if os.path.isfile(fMan):
718  return fMan
719 
720  # check also addons
721  aPath = os.getenv('GRASS_ADDON_PATH')
722  if aPath:
723  for path in aPath.split(os.pathsep):
724  faMan = os.path.join(path, "docs", "html",
725  self.command + ".html")
726  if os.path.isfile(faMan):
727  return faMan
728 
729  return None
730 
731  def IsLoaded(self):
732  return self.content.loaded
733 
734  def OnHistory(self):
735  """!Update buttons"""
736  nH = len(self.content.history)
737  iH = self.content.historyIdx
738  if iH == nH - 1:
739  self.btnNext.Enable(False)
740  elif iH > -1:
741  self.btnNext.Enable(True)
742  if iH < 1:
743  self.btnPrev.Enable(False)
744  else:
745  self.btnPrev.Enable(True)
746 
747  def OnNext(self, event):
748  """Load next page"""
749  self.content.historyIdx += 1
750  idx = self.content.historyIdx
751  path = self.content.history[idx]
752  self.content.LoadPage(path)
753  self.OnHistory()
754 
755  event.Skip()
756 
757  def OnPrev(self, event):
758  """Load previous page"""
759  self.content.historyIdx -= 1
760  idx = self.content.historyIdx
761  path = self.content.history[idx]
762  self.content.LoadPage(path)
763  self.OnHistory()
764 
765  event.Skip()
Search module window (used in MenuTreeWindow)
Definition: ghelp.py:45
def GetValue
Definition: widgets.py:118
wxGUI command interface
def Reset
Reset widget.
Definition: ghelp.py:194
def CheckWxVersion
Check wx version.
Definition: globalvar.py:36
def _pageTranslators
Definition: ghelp.py:484
def GetFile
Get HTML file.
Definition: ghelp.py:714
def LoadPage
Load page.
Definition: ghelp.py:707
Core GUI widgets.
def _pageCopyright
Definition: ghelp.py:350
def IsLoaded
Definition: ghelp.py:731
def OnHistory
Update buttons.
Definition: ghelp.py:734
def _pageLicense
Definition: ghelp.py:374
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def GetCtrl
Get SearchCtrl widget.
Definition: ghelp.py:110
Create custom About Window.
Definition: ghelp.py:201
def _layout
Do layout.
Definition: ghelp.py:85
def _layout
Do layout.
Definition: ghelp.py:688
def _pageContributors
Definition: ghelp.py:418
def __init__
Definition: ghelp.py:561
loaded
FIXME: calling LoadPage() is strangely time-consuming (only first call) self.LoadPage(self.fspath + command + &quot;.html&quot;)
Definition: ghelp.py:603
This panel holds the text from GRASS docs.
Definition: ghelp.py:578
def __init__
Definition: ghelp.py:670
def SetSelection
Set selection element.
Definition: ghelp.py:120
def OnCloseWindow
Close window.
Definition: ghelp.py:550
def OnSearchModule
Search module by keywords or description.
Definition: ghelp.py:124
GRASS Quickstart help window.
Definition: ghelp.py:554
def fillContentsFromFile
Load content from file.
Definition: ghelp.py:636
Default GUI settings.
def OnSelectModule
Module selected from choice, update command prompt.
Definition: ghelp.py:178
def __init__
If command is given, the corresponding HTML help file will be presented, with all links pointing to a...
Definition: ghelp.py:586
def OnLinkClicked
Definition: ghelp.py:626
def GetSelection
Get selected element.
Definition: ghelp.py:114