2
@package gui_core.ghelp
7
- ghelp::SearchModuleWindow
8
- ghelp::MenuTreeWindow
15
(C) 2008-2011 by the GRASS Development Team
17
This program is free software under the GNU General Public License
18
(>=v2). Read the file COPYING that comes with GRASS for details.
20
@author Martin Landa <landa.martin gmail.com>
30
from wx.html import HtmlWindow
32
import wx.lib.agw.customtreectrl as CT
33
from wx.lib.agw.hyperlink import HyperLinkCtrl
35
import wx.lib.customtreectrl as CT
36
from wx.lib.hyperlink import HyperLinkCtrl
37
import wx.lib.flatnotebook as FN
39
import grass.script as grass
41
from core import globalvar
42
from core import utils
43
from lmgr.menudata import ManagerData
44
from core.gcmd import GError, DecodeString
45
from gui_core.widgets import GNotebook, StaticWrapText, ItemTree, ScrolledPanel
47
class SearchModuleWindow(wx.Panel):
48
"""!Search module window (used in MenuTreeWindow)"""
49
def __init__(self, parent, id = wx.ID_ANY, cmdPrompt = None,
50
showChoice = True, showTip = False, **kwargs):
51
self.showTip = showTip
52
self.showChoice = showChoice
53
self.cmdPrompt = cmdPrompt
55
wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
57
self._searchDict = { _('description') : 'description',
58
_('command') : 'command',
59
_('keywords') : 'keywords' }
61
self.box = wx.StaticBox(parent = self, id = wx.ID_ANY,
62
label = " %s " % _("Find module(s)"))
64
self.searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
65
choices = [_('description'),
68
self.searchBy.SetSelection(0)
70
self.search = wx.TextCtrl(parent = self, id = wx.ID_ANY,
71
value = "", size = (-1, 25),
72
style = wx.TE_PROCESS_ENTER)
73
self.search.Bind(wx.EVT_TEXT, self.OnSearchModule)
76
self.searchTip = StaticWrapText(parent = self, id = wx.ID_ANY,
80
self.searchChoice = wx.Choice(parent = self, id = wx.ID_ANY)
82
self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
83
self.searchChoice.Bind(wx.EVT_CHOICE, self.OnSelectModule)
89
sizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
90
gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
92
gridSizer.Add(item = self.searchBy,
93
flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
94
gridSizer.Add(item = self.search,
95
flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (0, 1))
98
gridSizer.Add(item = self.searchTip,
99
flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
103
gridSizer.Add(item = self.searchChoice,
104
flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
106
gridSizer.AddGrowableCol(1)
107
sizer.Add(item = gridSizer, proportion = 1)
112
def GetSelection(self):
113
"""!Get selected element"""
114
selection = self.searchBy.GetStringSelection()
116
return self._searchDict[selection]
118
def SetSelection(self, i):
119
"""!Set selection element"""
120
self.searchBy.SetSelection(i)
122
def OnSearchModule(self, event):
123
"""!Search module by keywords or description"""
124
if not self.cmdPrompt:
128
text = event.GetString()
130
self.cmdPrompt.SetFilter(None)
131
mList = self.cmdPrompt.GetCommandItems()
132
self.searchChoice.SetItems(mList)
134
self.searchTip.SetLabel(_("%d modules found") % len(mList))
140
for module, data in self.cmdPrompt.moduleDesc.iteritems():
142
sel = self.searchBy.GetSelection()
143
if sel == 0: # -> description
144
if text in data['desc']:
146
elif sel == 1: # keywords
147
if text in ','.join(data['keywords']):
150
if module[:len(text)] == text:
156
group, name = module.split('.')
160
if group not in modules:
161
modules[group] = list()
162
modules[group].append(name)
164
self.cmdPrompt.SetFilter(modules)
165
self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
167
self.searchTip.SetLabel(_("%d modules found") % iFound)
171
def OnSelectModule(self, event):
172
"""!Module selected from choice, update command prompt"""
173
cmd = event.GetString().split(' ', 1)[0]
178
self.cmdPrompt.SetText(text)
179
self.cmdPrompt.SetSelectionStart(pos)
180
self.cmdPrompt.SetCurrentPos(pos)
181
self.cmdPrompt.SetFocus()
183
desc = self.cmdPrompt.GetCommandDesc(cmd)
185
self.searchTip.SetLabel(desc)
189
self.searchBy.SetSelection(0)
190
self.search.SetValue('')
192
self.searchTip.SetLabel('')
194
class MenuTreeWindow(wx.Panel):
195
"""!Show menu tree"""
196
def __init__(self, parent, id = wx.ID_ANY, **kwargs):
197
self.parent = parent # LayerManager
199
wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
201
self.dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
202
label = " %s " % _("Menu tree (double-click to run command)"))
204
self.tree = MenuTree(parent = self, data = ManagerData())
208
self.search = SearchModuleWindow(parent = self, showChoice = False)
211
self.btnRun = wx.Button(self, id = wx.ID_OK, label = _("&Run"))
212
self.btnRun.SetToolTipString(_("Run selected command"))
213
self.btnRun.Enable(False)
216
self.btnRun.Bind(wx.EVT_BUTTON, self.OnRun)
217
self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
218
self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnItemSelected)
219
self.search.Bind(wx.EVT_TEXT_ENTER, self.OnShowItem)
220
self.search.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
224
self.search.SetFocus()
227
"""!Do dialog layout"""
228
sizer = wx.BoxSizer(wx.VERTICAL)
231
dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
232
dataSizer.Add(item = self.tree, proportion =1,
236
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
237
btnSizer.Add(item = self.btnRun, proportion = 0)
239
sizer.Add(item = dataSizer, proportion = 1,
240
flag = wx.EXPAND | wx.ALL, border = 5)
242
sizer.Add(item = self.search, proportion = 0,
243
flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
245
sizer.Add(item = btnSizer, proportion = 0,
246
flag = wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border = 5)
249
sizer.SetSizeHints(self)
254
self.SetAutoLayout(True)
257
def OnCloseWindow(self, event):
261
def OnRun(self, event):
262
"""!Run selected command"""
263
if not self.tree.GetSelected():
264
return # should not happen
266
data = self.tree.GetPyData(self.tree.GetSelected())
270
handler = 'self.parent.' + data['handler'].lstrip('self.')
271
if data['handler'] == 'self.OnXTerm':
272
wx.MessageBox(parent = self,
273
message = _('You must run this command from the menu or command line',
274
'This command require an XTerm'),
275
caption = _('Message'), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
276
elif data['command']:
277
eval(handler)(event = None, cmd = data['command'].split())
281
def OnShowItem(self, event):
282
"""!Show selected item"""
283
self.tree.OnShowItem(event)
284
if self.tree.GetSelected():
287
self.btnRun.Enable(False)
289
def OnItemActivated(self, event):
290
"""!Item activated (double-click)"""
291
item = event.GetItem()
292
if not item or not item.IsOk():
295
data = self.tree.GetPyData(item)
296
if not data or 'command' not in data:
299
self.tree.itemSelected = item
303
def OnItemSelected(self, event):
305
item = event.GetItem()
306
if not item or not item.IsOk():
309
data = self.tree.GetPyData(item)
310
if not data or 'command' not in data:
314
label = data['command'] + ' -- ' + data['description']
316
label = data['description']
318
self.parent.SetStatusText(label, 0)
320
def OnUpdateStatusBar(self, event):
321
"""!Update statusbar text"""
322
element = self.search.GetSelection()
323
self.tree.SearchItems(element = element,
324
value = event.GetString())
326
nItems = len(self.tree.itemsMarked)
327
if event.GetString():
328
self.parent.SetStatusText(_("%d modules match") % nItems, 0)
330
self.parent.SetStatusText("", 0)
334
class MenuTree(ItemTree):
335
"""!Menu tree class"""
336
def __init__(self, parent, data, **kwargs):
340
super(MenuTree, self).__init__(parent, **kwargs)
342
def Load(self, data = None):
343
"""!Load menu data tree
345
@param data menu data (None to use self.menudata)
350
self.itemsMarked = [] # list of marked items
351
for eachMenuData in data.GetMenu():
352
for label, items in eachMenuData:
353
item = self.AppendItem(parentId = self.root,
354
text = label.replace('&', ''))
355
self.__AppendItems(item, items)
357
def __AppendItems(self, item, data):
358
"""!Append items into tree (used by Load()
360
@param item tree item (parent)
361
@parent data menu data"""
362
for eachItem in data:
363
if len(eachItem) == 2:
365
itemSub = self.AppendItem(parentId = item,
367
self.__AppendItems(itemSub, eachItem[1])
370
itemNew = self.AppendItem(parentId = item,
373
data = { 'item' : eachItem[0],
374
'description' : eachItem[1],
375
'handler' : eachItem[2],
376
'command' : eachItem[3],
377
'keywords' : eachItem[4] }
379
self.SetPyData(itemNew, data)
381
class AboutWindow(wx.Frame):
382
"""!Create custom About Window
384
def __init__(self, parent, size = (650, 460),
385
title = _('About GRASS GIS'), **kwargs):
386
wx.Frame.__init__(self, parent = parent, id = wx.ID_ANY, title = title, size = size, **kwargs)
388
panel = wx.Panel(parent = self, id = wx.ID_ANY)
391
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
393
# get version and web site
394
vInfo = grass.version()
396
infoTxt = ScrolledPanel(parent = panel)
397
infoTxt.SetupScrolling()
398
infoSizer = wx.BoxSizer(wx.VERTICAL)
399
infoGridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
400
logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass-64x64.png")
401
logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
402
bitmap = wx.Bitmap(name = logo,
403
type = wx.BITMAP_TYPE_PNG))
404
infoSizer.Add(item = logoBitmap, proportion = 0,
405
flag = wx.ALL | wx.ALIGN_CENTER, border = 20)
407
info = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
408
label = 'GRASS GIS ' + vInfo['version'] + '\n\n')
409
info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
410
info.SetForegroundColour(wx.Colour(35, 142, 35))
411
infoSizer.Add(item = info, proportion = 0,
412
flag = wx.BOTTOM | wx.ALIGN_CENTER, border = 1)
415
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
416
label = _('Official GRASS site:')),
418
flag = wx.ALIGN_RIGHT)
420
infoGridSizer.Add(item = HyperLinkCtrl(parent = infoTxt, id = wx.ID_ANY,
421
label = 'http://grass.osgeo.org'),
423
flag = wx.ALIGN_LEFT)
426
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
427
label = '%s:' % _('SVN Revision')),
429
flag = wx.ALIGN_RIGHT)
431
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
432
label = vInfo['revision']),
434
flag = wx.ALIGN_LEFT)
437
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
438
label = '%s:' % _('GIS Library Revision')),
440
flag = wx.ALIGN_RIGHT)
442
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
443
label = vInfo['libgis_revision'] + ' (' +
444
vInfo['libgis_date'].split(' ')[0] + ')'),
446
flag = wx.ALIGN_LEFT)
449
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
452
flag = wx.ALIGN_RIGHT)
454
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
455
label = platform.python_version()),
457
flag = wx.ALIGN_LEFT)
460
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
461
label = 'wxPython:'),
463
flag = wx.ALIGN_RIGHT)
465
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
466
label = wx.__version__),
468
flag = wx.ALIGN_LEFT)
469
infoGridSizer.AddGrowableCol(0)
470
infoGridSizer.AddGrowableCol(1)
472
infoSizer.Add(item = infoGridSizer,
474
flag = wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
477
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
478
label = "%s:" % _('Language')),
480
flag = wx.ALIGN_RIGHT)
481
lang = grass.gisenv().get('LANG', None)
484
loc = locale.getdefaultlocale()
485
if loc == (None, None):
488
lang = u'%s.%s' % (loc[0], loc[1])
489
infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
492
flag = wx.ALIGN_LEFT)
494
# create a flat notebook for displaying information about GRASS
495
aboutNotebook = GNotebook(panel, style = globalvar.FNPageStyle | FN.FNB_NO_X_BUTTON)
496
aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
498
for title, win in ((_("Info"), infoTxt),
499
(_("Copyright"), self._pageCopyright()),
500
(_("License"), self._pageLicense()),
501
(_("Authors"), self._pageCredit()),
502
(_("Contributors"), self._pageContributors()),
503
(_("Extra contributors"), self._pageContributors(extra = True)),
504
(_("Translators"), self._pageTranslators())):
505
aboutNotebook.AddPage(page = win, text = title)
506
wx.CallAfter(aboutNotebook.SetSelection, 0)
509
btnClose = wx.Button(parent = panel, id = wx.ID_CLOSE)
510
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
511
btnSizer.Add(item = btnClose, proportion = 0,
512
flag = wx.ALL | wx.ALIGN_RIGHT,
515
btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
517
infoTxt.SetSizer(infoSizer)
518
infoSizer.Fit(infoTxt)
520
sizer = wx.BoxSizer(wx.VERTICAL)
521
sizer.Add(item = aboutNotebook, proportion = 1,
522
flag = wx.EXPAND | wx.ALL, border = 1)
523
sizer.Add(item = btnSizer, proportion = 0,
524
flag = wx.ALL | wx.ALIGN_RIGHT, border = 1)
525
panel.SetSizer(sizer)
528
self.SetMinSize((400, 400))
530
def _pageCopyright(self):
531
"""Copyright information"""
532
copyfile = os.path.join(os.getenv("GISBASE"), "COPYING")
533
if os.path.exists(copyfile):
534
copyrightFile = open(copyfile, 'r')
535
copytext = copyrightFile.read()
536
copyrightFile.close()
538
copytext = _('%s file missing') % 'COPYING'
540
# put text into a scrolling panel
541
copyrightwin = ScrolledPanel(self)
543
copyrighttxt = wx.StaticText(copyrightwin, id = wx.ID_ANY, label = copytext)
544
copyrightwin.SetAutoLayout(True)
545
copyrightwin.sizer = wx.BoxSizer(wx.VERTICAL)
546
copyrightwin.sizer.Add(item = copyrighttxt, proportion = 1,
547
flag = wx.EXPAND | wx.ALL, border = 3)
548
copyrightwin.SetSizer(copyrightwin.sizer)
549
copyrightwin.Layout()
550
copyrightwin.SetupScrolling()
554
def _pageLicense(self):
556
licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT")
557
if os.path.exists(licfile):
558
licenceFile = open(licfile, 'r')
559
license = ''.join(licenceFile.readlines())
562
license = _('%s file missing') % 'GPL.TXT'
563
# put text into a scrolling panel
564
licensewin = ScrolledPanel(self)
565
licensetxt = wx.StaticText(licensewin, id = wx.ID_ANY, label = license)
566
licensewin.SetAutoLayout(True)
567
licensewin.sizer = wx.BoxSizer(wx.VERTICAL)
568
licensewin.sizer.Add(item = licensetxt, proportion = 1,
569
flag = wx.EXPAND | wx.ALL, border = 3)
570
licensewin.SetSizer(licensewin.sizer)
572
licensewin.SetupScrolling()
576
def _pageCredit(self):
579
authfile = os.path.join(os.getenv("GISBASE"), "AUTHORS")
580
if os.path.exists(authfile):
581
authorsFile = open(authfile, 'r')
582
authors = unicode(''.join(authorsFile.readlines()), "utf-8")
585
authors = _('%s file missing') % 'AUTHORS'
586
authorwin = ScrolledPanel(self)
587
authortxt = wx.StaticText(authorwin, id = wx.ID_ANY, label = authors)
588
authorwin.SetAutoLayout(True)
589
authorwin.SetupScrolling()
590
authorwin.sizer = wx.BoxSizer(wx.VERTICAL)
591
authorwin.sizer.Add(item = authortxt, proportion = 1,
592
flag = wx.EXPAND | wx.ALL, border = 3)
593
authorwin.SetSizer(authorwin.sizer)
598
def _pageContributors(self, extra = False):
599
"""Contributors info"""
601
contribfile = os.path.join(os.getenv("GISBASE"), "contributors_extra.csv")
603
contribfile = os.path.join(os.getenv("GISBASE"), "contributors.csv")
604
if os.path.exists(contribfile):
605
contribFile = codecs.open(contribfile, encoding = 'utf-8', mode = 'r')
608
for line in contribFile.readlines()[1:]:
609
line = line.rstrip('\n')
612
name, email, rfc2_agreed = line.split(',')
614
cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
616
errLines.append(line)
619
contribs.append((name, email))
621
contribs.append((name, email, country, osgeo_id))
626
GError(parent = self,
627
message = _("Error when reading file '%s'.") % contribfile + \
628
"\n\n" + _("Lines:") + " %s" % \
629
os.linesep.join(map(DecodeString, errLines)))
633
contribwin = ScrolledPanel(self)
634
contribwin.SetAutoLayout(True)
635
contribwin.SetupScrolling()
636
contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
639
contribtxt = wx.StaticText(contribwin, id = wx.ID_ANY,
640
label = _('%s file missing') % contribfile)
641
contribwin.sizer.Add(item = contribtxt, proportion = 1,
642
flag = wx.EXPAND | wx.ALL, border = 3)
645
items = (_('Name'), _('E-mail'))
647
items = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
648
contribBox = wx.FlexGridSizer(cols = len(items), vgap = 5, hgap = 5)
650
contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
652
for vals in sorted(contribs, key = lambda x: x[0]):
654
contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
656
contribwin.sizer.Add(item = contribBox, proportion = 1,
657
flag = wx.EXPAND | wx.ALL, border = 3)
659
contribwin.SetSizer(contribwin.sizer)
664
def _pageTranslators(self):
665
"""Translators info"""
666
translatorsfile = os.path.join(os.getenv("GISBASE"), "translators.csv")
667
if os.path.exists(translatorsfile):
668
translatorsFile = open(translatorsfile, 'r')
671
for line in translatorsFile.readlines()[1:]:
672
line = line.rstrip('\n')
674
name, email, languages = line.split(',')
676
errLines.append(line)
678
for language in languages.split(' '):
679
if language not in translators:
680
translators[language] = list()
681
translators[language].append((name, email))
682
translatorsFile.close()
685
GError(parent = self,
686
message = _("Error when reading file '%s'.") % translatorsfile + \
687
"\n\n" + _("Lines:") + " %s" % \
688
os.linesep.join(map(DecodeString, errLines)))
692
translatorswin = ScrolledPanel(self)
693
translatorswin.SetAutoLayout(True)
694
translatorswin.SetupScrolling()
695
translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
698
translatorstxt = wx.StaticText(translatorswin, id = wx.ID_ANY,
699
label = _('%s file missing') % 'translators.csv')
700
translatorswin.sizer.Add(item = translatorstxt, proportion = 1,
701
flag = wx.EXPAND | wx.ALL, border = 3)
703
translatorsBox = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
704
languages = translators.keys()
706
translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
708
translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
709
label = _('E-mail')))
710
translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
711
label = _('Language')))
712
for lang in languages:
713
for translator in translators[lang]:
714
name, email = translator
715
translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
716
label = unicode(name, "utf-8")))
717
translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
719
translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
722
translatorswin.sizer.Add(item = translatorsBox, proportion = 1,
723
flag = wx.EXPAND | wx.ALL, border = 3)
725
translatorswin.SetSizer(translatorswin.sizer)
726
translatorswin.Layout()
728
return translatorswin
730
def OnCloseWindow(self, event):
734
class HelpFrame(wx.Dialog):
735
"""!GRASS Quickstart help window
737
As a base class wx.Dialog is used, because of not working
738
close button with wx.Frame when dialog is called from wizard.
739
If parent is None, application TopLevelWindow is used (wxPython standard behaviour).
741
def __init__(self, parent, id, title, size, file):
742
wx.Dialog.__init__(self, parent = parent, id = id, title = title,
743
size = size, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER | wx.MINIMIZE_BOX)
745
sizer = wx.BoxSizer(wx.VERTICAL)
748
content = HelpPanel(parent = self)
749
content.LoadPage(file)
751
sizer.Add(item = content, proportion = 1, flag = wx.EXPAND)
753
self.SetAutoLayout(True)
758
class HelpWindow(wx.html.HtmlWindow):
759
"""!This panel holds the text from GRASS docs.
761
GISBASE must be set in the environment to find the html docs dir.
762
The SYNOPSIS section is skipped, since this Panel is supposed to
763
be integrated into the cmdPanel and options are obvious there.
765
def __init__(self, parent, grass_command, text, skip_description,
767
"""!If grass_command is given, the corresponding HTML help
768
file will be presented, with all links pointing to absolute
769
paths of local files.
771
If 'skip_description' is True, the HTML corresponding to
772
SYNOPSIS will be skipped, thus only presenting the help file
773
from the DESCRIPTION section onwards.
775
If 'text' is given, it must be the HTML text to be presented
779
if not globalvar.CheckWxVersion([2, 9]):
780
wx.InitAllImageHandlers()
781
wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
783
gisbase = os.getenv("GISBASE")
785
self.history = list()
787
self.fspath = os.path.join(gisbase, "docs", "html")
789
self.SetStandardFonts (size = 10)
794
url = os.path.join(self.fspath, grass_command + ".html")
795
self.fillContentsFromFile(url,
796
skip_description = skip_description)
797
self.history.append(url)
800
### FIXME: calling LoadPage() is strangely time-consuming (only first call)
801
# self.LoadPage(self.fspath + grass_command + ".html")
807
def OnLinkClicked(self, linkinfo):
808
url = linkinfo.GetHref()
809
if url[:4] != 'http':
810
url = os.path.join(self.fspath, url)
811
self.history.append(url)
813
self.parent.OnHistory()
815
super(HelpWindow, self).OnLinkClicked(linkinfo)
817
def fillContentsFromFile(self, htmlFile, skip_description = True):
818
"""!Load content from file"""
819
aLink = re.compile(r'(<a href="?)(.+\.html?["\s]*>)', re.IGNORECASE)
820
imgLink = re.compile(r'(<img src="?)(.+\.[png|gif])', re.IGNORECASE)
824
for l in file(htmlFile, "rb").readlines():
825
if "DESCRIPTION" in l:
828
# do skip the options description if requested
830
skip = skip_description
832
# FIXME: find only first item
833
findALink = aLink.search(l)
834
if findALink is not None:
835
contents.append(aLink.sub(findALink.group(1)+
836
self.fspath+findALink.group(2),l))
837
findImgLink = imgLink.search(l)
838
if findImgLink is not None:
839
contents.append(imgLink.sub(findImgLink.group(1)+
840
self.fspath+findImgLink.group(2),l))
842
if findALink is None and findImgLink is None:
844
self.SetPage("".join(contents))
846
except: # The Manual file was not found
849
class HelpPanel(wx.Panel):
850
def __init__(self, parent, grass_command = "index", text = None,
851
skip_description = False, **kwargs):
852
self.grass_command = grass_command
853
wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
855
self.content = HelpWindow(self, grass_command, text,
858
self.btnNext = wx.Button(parent = self, id = wx.ID_ANY,
860
self.btnNext.Enable(False)
861
self.btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
862
label = _("&Previous"))
863
self.btnPrev.Enable(False)
865
self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext)
866
self.btnPrev.Bind(wx.EVT_BUTTON, self.OnPrev)
872
sizer = wx.BoxSizer(wx.VERTICAL)
873
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
875
btnSizer.Add(item = self.btnPrev, proportion = 0,
876
flag = wx.ALL, border = 5)
877
btnSizer.Add(item = wx.Size(1, 1), proportion = 1)
878
btnSizer.Add(item = self.btnNext, proportion = 0,
879
flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
881
sizer.Add(item = self.content, proportion = 1,
883
sizer.Add(item = btnSizer, proportion = 0,
889
def LoadPage(self, path = None):
892
path = self.GetFile()
893
self.content.history.append(path)
894
self.content.LoadPage(path)
898
fMan = os.path.join(self.content.fspath, self.grass_command + ".html")
899
if os.path.isfile(fMan):
903
aPath = os.getenv('GRASS_ADDON_PATH')
905
for path in aPath.split(os.pathsep):
906
faMan = os.path.join(path, "docs", "html",
907
self.grass_command + ".html")
908
if os.path.isfile(faMan):
914
return self.content.loaded
917
"""!Update buttons"""
918
nH = len(self.content.history)
919
iH = self.content.historyIdx
921
self.btnNext.Enable(False)
923
self.btnNext.Enable(True)
925
self.btnPrev.Enable(False)
927
self.btnPrev.Enable(True)
929
def OnNext(self, event):
931
self.content.historyIdx += 1
932
idx = self.content.historyIdx
933
path = self.content.history[idx]
934
self.content.LoadPage(path)
939
def OnPrev(self, event):
940
"""Load previous page"""
941
self.content.historyIdx -= 1
942
idx = self.content.historyIdx
943
path = self.content.history[idx]
944
self.content.LoadPage(path)