2 @package gui_core.ghelp
7 - ghelp::SearchModuleWindow
13 (C) 2008-2011 by the GRASS Development Team
15 This program is free software under the GNU General Public License
16 (>=v2). Read the file COPYING that comes with GRASS for details.
18 @author Martin Landa <landa.martin gmail.com>
28 from wx.html
import HtmlWindow
30 import wx.lib.agw.customtreectrl
as CT
31 from wx.lib.agw.hyperlink
import HyperLinkCtrl
33 import wx.lib.customtreectrl
as CT
34 from wx.lib.hyperlink
import HyperLinkCtrl
35 import wx.lib.flatnotebook
as FN
39 from core
import globalvar
40 from core
import utils
41 from core.gcmd import GError, DecodeString
46 """!Search module window (used in MenuTreeWindow)"""
47 def __init__(self, parent, id = wx.ID_ANY, cmdPrompt = None,
48 showChoice =
True, showTip =
False, **kwargs):
53 wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
55 self.
_searchDict = { _(
'description') :
'description',
56 _(
'command') :
'command',
57 _(
'keywords') :
'keywords' }
59 self.
box = wx.StaticBox(parent = self, id = wx.ID_ANY,
60 label =
" %s " % _(
"Find module - (press Enter for next match)"))
62 self.
searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
63 choices = [_(
'description'),
66 self.searchBy.SetSelection(0)
68 self.
search = wx.SearchCtrl(parent = self, id = wx.ID_ANY,
69 size = (-1, 25), style = wx.TE_PROCESS_ENTER)
74 self.
searchTip = StaticWrapText(parent = self, id = wx.ID_ANY,
80 self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
87 sizer = wx.StaticBoxSizer(self.
box, wx.HORIZONTAL)
88 gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
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))
97 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
101 flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
104 gridSizer.AddGrowableCol(1)
105 sizer.Add(item = gridSizer, proportion = 1)
111 """!Get SearchCtrl widget"""
115 """!Get selected element"""
116 selection = self.searchBy.GetStringSelection()
121 """!Set selection element"""
122 self.searchBy.SetSelection(i)
125 """!Search module by keywords or description"""
131 if self.cmdPrompt.AutoCompActive():
132 self.cmdPrompt.AutoCompCancel()
134 text = event.GetEventObject().
GetValue()
136 self.cmdPrompt.SetFilter(
None)
137 mList = self.cmdPrompt.GetCommandItems()
138 self.searchChoice.SetItems(mList)
140 self.searchTip.SetLabel(_(
"%d modules found") % len(mList))
146 for module, data
in self.cmdPrompt.moduleDesc.iteritems():
148 sel = self.searchBy.GetSelection()
150 if text
in data[
'desc']:
153 if text
in ','.join(data[
'keywords']):
156 if module[:len(text)] == text:
162 group, name = module.split(
'.')
166 if group
not in modules:
167 modules[group] = list()
168 modules[group].append(name)
170 self.cmdPrompt.SetFilter(modules)
171 self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
172 self.searchChoice.SetSelection(0)
174 self.searchTip.SetLabel(_(
"%d modules match") % iFound)
179 """!Module selected from choice, update command prompt"""
180 cmd = event.GetString().
split(
' ', 1)[0]
185 self.cmdPrompt.SetText(text)
186 self.cmdPrompt.SetSelectionStart(pos)
187 self.cmdPrompt.SetCurrentPos(pos)
188 self.cmdPrompt.SetFocus()
190 desc = self.cmdPrompt.GetCommandDesc(cmd)
192 self.searchTip.SetLabel(desc)
196 self.searchBy.SetSelection(0)
197 self.search.SetValue(
'')
199 self.searchTip.SetLabel(
'')
202 """!Create custom About Window
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)
208 panel = wx.Panel(parent = self, id = wx.ID_ANY)
211 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
214 vInfo = grass.version()
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)
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)
235 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
236 label = _(
'Official GRASS site:')),
238 flag = wx.ALIGN_RIGHT)
240 infoGridSizer.Add(item = HyperLinkCtrl(parent = infoTxt, id = wx.ID_ANY,
241 label =
'http://grass.osgeo.org'),
243 flag = wx.ALIGN_LEFT)
246 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
247 label =
'%s:' % _(
'SVN Revision')),
249 flag = wx.ALIGN_RIGHT)
251 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
252 label = vInfo[
'revision']),
254 flag = wx.ALIGN_LEFT)
257 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
258 label =
'%s:' % _(
'GIS Library Revision')),
260 flag = wx.ALIGN_RIGHT)
262 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
263 label = vInfo[
'libgis_revision'] +
' (' +
264 vInfo[
'libgis_date'].
split(
' ')[0] +
')'),
266 flag = wx.ALIGN_LEFT)
269 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
272 flag = wx.ALIGN_RIGHT)
274 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
275 label = platform.python_version()),
277 flag = wx.ALIGN_LEFT)
280 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
281 label =
'wxPython:'),
283 flag = wx.ALIGN_RIGHT)
285 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
286 label = wx.__version__),
288 flag = wx.ALIGN_LEFT)
289 infoGridSizer.AddGrowableCol(0)
290 infoGridSizer.AddGrowableCol(1)
292 infoSizer.Add(item = infoGridSizer,
294 flag = wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
297 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
298 label =
"%s:" % _(
'Language')),
300 flag = wx.ALIGN_RIGHT)
301 lang = grass.gisenv().get(
'LANG',
None)
304 loc = locale.getdefaultlocale()
305 if loc == (
None,
None):
308 lang =
u'%s.%s' % (loc[0], loc[1])
309 infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
312 flag = wx.ALIGN_LEFT)
315 aboutNotebook = GNotebook(panel, style = globalvar.FNPageStyle | FN.FNB_NO_X_BUTTON)
316 aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
318 for title, win
in ((_(
"Info"), infoTxt),
325 aboutNotebook.AddPage(page = win, text = title)
326 wx.CallAfter(aboutNotebook.SetSelection, 0)
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,
337 infoTxt.SetSizer(infoSizer)
338 infoSizer.Fit(infoTxt)
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)
348 self.SetMinSize((400, 400))
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()
358 copytext = _(
'%s file missing') %
'COPYING'
361 copyrightwin = ScrolledPanel(self)
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()
374 def _pageLicense(self):
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())
382 license = _(
'%s file missing') %
'GPL.TXT'
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)
392 licensewin.SetupScrolling()
396 def _pageCredit(self):
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")
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)
418 def _pageContributors(self, extra = False):
419 """Contributors info"""
421 contribfile = os.path.join(os.getenv(
"GISBASE"),
"contributors_extra.csv")
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')
428 for line
in contribFile.readlines()[1:]:
429 line = line.rstrip(
'\n')
432 name, email, country, rfc2_agreed = line.split(
',')
434 cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(
',')
436 errLines.append(line)
439 contribs.append((name, email))
441 contribs.append((name, email, country, osgeo_id))
446 GError(parent = self,
447 message = _(
"Error when reading file '%s'.") % contribfile + \
448 "\n\n" + _(
"Lines:") +
" %s" % \
449 os.linesep.join(map(DecodeString, errLines)))
453 contribwin = ScrolledPanel(self)
454 contribwin.SetAutoLayout(
True)
455 contribwin.SetupScrolling()
456 contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
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)
465 items = (_(
'Name'), _(
'E-mail'))
467 items = (_(
'Name'), _(
'E-mail'), _(
'Country'), _(
'OSGeo_ID'))
468 contribBox = wx.FlexGridSizer(cols = len(items), vgap = 5, hgap = 5)
470 contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
472 for vals
in sorted(contribs, key =
lambda x: x[0]):
474 contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
476 contribwin.sizer.Add(item = contribBox, proportion = 1,
477 flag = wx.EXPAND | wx.ALL, border = 3)
479 contribwin.SetSizer(contribwin.sizer)
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')
491 for line
in translatorsFile.readlines()[1:]:
492 line = line.rstrip(
'\n')
494 name, email, languages = line.split(
',')
496 errLines.append(line)
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()
505 GError(parent = self,
506 message = _(
"Error when reading file '%s'.") % translatorsfile + \
507 "\n\n" + _(
"Lines:") +
" %s" % \
508 os.linesep.join(map(DecodeString, errLines)))
512 translatorswin = ScrolledPanel(self)
513 translatorswin.SetAutoLayout(
True)
514 translatorswin.SetupScrolling()
515 translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
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)
523 translatorsBox = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
524 languages = translators.keys()
526 translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
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,
539 translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
542 translatorswin.sizer.Add(item = translatorsBox, proportion = 1,
543 flag = wx.EXPAND | wx.ALL, border = 3)
545 translatorswin.SetSizer(translatorswin.sizer)
546 translatorswin.Layout()
548 return translatorswin
555 """!GRASS Quickstart help window
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).
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)
565 sizer = wx.BoxSizer(wx.VERTICAL)
569 content.LoadPage(file)
571 sizer.Add(item = content, proportion = 1, flag = wx.EXPAND)
573 self.SetAutoLayout(
True)
579 """!This panel holds the text from GRASS docs.
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.
585 def __init__(self, parent, command, text, skipDescription,
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.
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.
595 If 'text' is given, it must be the HTML text to be presented
600 wx.InitAllImageHandlers()
601 wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
606 self.
fspath = os.path.join(os.getenv(
"GISBASE"),
"docs",
"html")
608 self.SetStandardFonts (size = 10)
613 url = os.path.join(self.
fspath, command +
".html")
615 skipDescription = skipDescription)
616 self.history.append(url)
627 url = linkinfo.GetHref()
628 if url[:4] !=
'http':
629 url = os.path.join(self.
fspath, url)
630 self.history.append(url)
632 self.parent.OnHistory()
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)
643 for l
in file(htmlFile,
"rb").readlines():
644 if "DESCRIPTION" in l:
649 skip = skipDescription
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))
661 if findALink
is None and findImgLink
is None:
663 self.SetPage(
"".join(contents))
669 def __init__(self, parent, command = "index", text = None,
670 skipDescription =
False, **kwargs):
672 wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
676 self.
btnNext = wx.Button(parent = self, id = wx.ID_ANY,
678 self.btnNext.Enable(
False)
679 self.
btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
680 label = _(
"&Previous"))
681 self.btnPrev.Enable(
False)
683 self.btnNext.Bind(wx.EVT_BUTTON, self.
OnNext)
684 self.btnPrev.Bind(wx.EVT_BUTTON, self.
OnPrev)
690 sizer = wx.BoxSizer(wx.VERTICAL)
691 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
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)
699 sizer.Add(item = self.
content, proportion = 1,
701 sizer.Add(item = btnSizer, proportion = 0,
711 self.content.history.append(path)
712 self.content.LoadPage(path)
716 fMan = os.path.join(self.content.fspath, self.
command +
".html")
717 if os.path.isfile(fMan):
721 aPath = os.getenv(
'GRASS_ADDON_PATH')
723 for path
in aPath.split(os.pathsep):
724 faMan = os.path.join(path,
"docs",
"html",
726 if os.path.isfile(faMan):
732 return self.content.loaded
735 """!Update buttons"""
736 nH = len(self.content.history)
737 iH = self.content.historyIdx
739 self.btnNext.Enable(
False)
741 self.btnNext.Enable(
True)
743 self.btnPrev.Enable(
False)
745 self.btnPrev.Enable(
True)
749 self.content.historyIdx += 1
750 idx = self.content.historyIdx
751 path = self.content.history[idx]
752 self.content.LoadPage(path)
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)
Search module window (used in MenuTreeWindow)
def CheckWxVersion
Check wx version.
def GetFile
Get HTML file.
def OnHistory
Update buttons.
def split
Platform spefic shlex.split.
def GetCtrl
Get SearchCtrl widget.
Create custom About Window.
loaded
FIXME: calling LoadPage() is strangely time-consuming (only first call) self.LoadPage(self.fspath + command + ".html")
This panel holds the text from GRASS docs.
def SetSelection
Set selection element.
def OnCloseWindow
Close window.
def OnSearchModule
Search module by keywords or description.
GRASS Quickstart help window.
def fillContentsFromFile
Load content from file.
def OnSelectModule
Module selected from choice, update command prompt.
def __init__
If command is given, the corresponding HTML help file will be presented, with all links pointing to a...
def GetSelection
Get selected element.