~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/help_about_names/gui/wxpython/gui_core/ghelp.py

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""!
2
 
@package gui_core.ghelp
3
 
 
4
 
@brief Help window
5
 
 
6
 
Classes:
7
 
 - ghelp::SearchModuleWindow
8
 
 - ghelp::MenuTreeWindow
9
 
 - ghelp::MenuTree
10
 
 - ghelp::AboutWindow
11
 
 - ghelp::HelpFrame
12
 
 - ghelp::HelpWindow
13
 
 - ghelp::HelpPanel
14
 
 
15
 
(C) 2008-2011 by the GRASS Development Team
16
 
 
17
 
This program is free software under the GNU General Public License
18
 
(>=v2). Read the file COPYING that comes with GRASS for details.
19
 
 
20
 
@author Martin Landa <landa.martin gmail.com>
21
 
"""
22
 
 
23
 
import os
24
 
import sys
25
 
import re
26
 
import codecs
27
 
import platform
28
 
 
29
 
import wx
30
 
from wx.html import HtmlWindow
31
 
try:
32
 
    import wx.lib.agw.customtreectrl as CT
33
 
    from wx.lib.agw.hyperlink import HyperLinkCtrl
34
 
except ImportError:
35
 
    import wx.lib.customtreectrl as CT
36
 
    from wx.lib.hyperlink import HyperLinkCtrl
37
 
import wx.lib.flatnotebook as FN
38
 
 
39
 
import grass.script as grass
40
 
 
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
46
 
 
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
54
 
        
55
 
        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
56
 
        
57
 
        self._searchDict = { _('description') : 'description',
58
 
                             _('command')     : 'command',
59
 
                             _('keywords')    : 'keywords' }
60
 
        
61
 
        self.box = wx.StaticBox(parent = self, id = wx.ID_ANY,
62
 
                                label = " %s " % _("Find module(s)"))
63
 
        
64
 
        self.searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
65
 
                                  choices = [_('description'),
66
 
                                             _('keywords'),
67
 
                                             _('command')])
68
 
        self.searchBy.SetSelection(0)
69
 
        
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)
74
 
        
75
 
        if self.showTip:
76
 
            self.searchTip = StaticWrapText(parent = self, id = wx.ID_ANY,
77
 
                                            size = (-1, 35))
78
 
        
79
 
        if self.showChoice:
80
 
            self.searchChoice = wx.Choice(parent = self, id = wx.ID_ANY)
81
 
            if self.cmdPrompt:
82
 
                self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
83
 
            self.searchChoice.Bind(wx.EVT_CHOICE, self.OnSelectModule)
84
 
        
85
 
        self._layout()
86
 
 
87
 
    def _layout(self):
88
 
        """!Do layout"""
89
 
        sizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
90
 
        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
91
 
        
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))
96
 
        row = 1
97
 
        if self.showTip:
98
 
            gridSizer.Add(item = self.searchTip,
99
 
                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
100
 
            row += 1
101
 
        
102
 
        if self.showChoice:
103
 
            gridSizer.Add(item = self.searchChoice,
104
 
                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
105
 
        
106
 
        gridSizer.AddGrowableCol(1)
107
 
        sizer.Add(item = gridSizer, proportion = 1)
108
 
        
109
 
        self.SetSizer(sizer)
110
 
        sizer.Fit(self)
111
 
 
112
 
    def GetSelection(self):
113
 
        """!Get selected element"""
114
 
        selection = self.searchBy.GetStringSelection()
115
 
        
116
 
        return self._searchDict[selection]
117
 
 
118
 
    def SetSelection(self, i):
119
 
        """!Set selection element"""
120
 
        self.searchBy.SetSelection(i)
121
 
 
122
 
    def OnSearchModule(self, event):
123
 
        """!Search module by keywords or description"""
124
 
        if not self.cmdPrompt:
125
 
            event.Skip()
126
 
            return
127
 
        
128
 
        text = event.GetString()
129
 
        if not text:
130
 
            self.cmdPrompt.SetFilter(None)
131
 
            mList = self.cmdPrompt.GetCommandItems()
132
 
            self.searchChoice.SetItems(mList)
133
 
            if self.showTip:
134
 
                self.searchTip.SetLabel(_("%d modules found") % len(mList))
135
 
            event.Skip()
136
 
            return
137
 
        
138
 
        modules = dict()
139
 
        iFound = 0
140
 
        for module, data in self.cmdPrompt.moduleDesc.iteritems():
141
 
            found = False
142
 
            sel = self.searchBy.GetSelection()
143
 
            if sel == 0: # -> description
144
 
                if text in data['desc']:
145
 
                    found = True
146
 
            elif sel == 1: # keywords
147
 
                if text in ','.join(data['keywords']):
148
 
                    found = True
149
 
            else: # command
150
 
                if module[:len(text)] == text:
151
 
                    found = True
152
 
            
153
 
            if found:
154
 
                iFound += 1
155
 
                try:
156
 
                    group, name = module.split('.')
157
 
                except ValueError:
158
 
                    continue # TODO
159
 
                
160
 
                if group not in modules:
161
 
                    modules[group] = list()
162
 
                modules[group].append(name)
163
 
                
164
 
        self.cmdPrompt.SetFilter(modules)
165
 
        self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
166
 
        if self.showTip:
167
 
            self.searchTip.SetLabel(_("%d modules found") % iFound)
168
 
        
169
 
        event.Skip()
170
 
        
171
 
    def OnSelectModule(self, event):
172
 
        """!Module selected from choice, update command prompt"""
173
 
        cmd  = event.GetString().split(' ', 1)[0]
174
 
        text = cmd + ' '
175
 
        pos = len(text)
176
 
 
177
 
        if self.cmdPrompt:
178
 
            self.cmdPrompt.SetText(text)
179
 
            self.cmdPrompt.SetSelectionStart(pos)
180
 
            self.cmdPrompt.SetCurrentPos(pos)
181
 
            self.cmdPrompt.SetFocus()
182
 
        
183
 
        desc = self.cmdPrompt.GetCommandDesc(cmd)
184
 
        if self.showTip:
185
 
            self.searchTip.SetLabel(desc)
186
 
    
187
 
    def Reset(self):
188
 
        """!Reset widget"""
189
 
        self.searchBy.SetSelection(0)
190
 
        self.search.SetValue('')
191
 
        if self.showTip:
192
 
            self.searchTip.SetLabel('')
193
 
        
194
 
class MenuTreeWindow(wx.Panel):
195
 
    """!Show menu tree"""
196
 
    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
197
 
        self.parent = parent # LayerManager
198
 
        
199
 
        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
200
 
        
201
 
        self.dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
202
 
                                    label = " %s " % _("Menu tree (double-click to run command)"))
203
 
        # tree
204
 
        self.tree = MenuTree(parent = self, data = ManagerData())
205
 
        self.tree.Load()
206
 
 
207
 
        # search widget
208
 
        self.search = SearchModuleWindow(parent = self, showChoice = False)
209
 
        
210
 
        # buttons
211
 
        self.btnRun   = wx.Button(self, id = wx.ID_OK, label = _("&Run"))
212
 
        self.btnRun.SetToolTipString(_("Run selected command"))
213
 
        self.btnRun.Enable(False)
214
 
        
215
 
        # bindings
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)
221
 
        
222
 
        self._layout()
223
 
        
224
 
        self.search.SetFocus()
225
 
        
226
 
    def _layout(self):
227
 
        """!Do dialog layout"""
228
 
        sizer = wx.BoxSizer(wx.VERTICAL)
229
 
        
230
 
        # body
231
 
        dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
232
 
        dataSizer.Add(item = self.tree, proportion =1,
233
 
                      flag = wx.EXPAND)
234
 
        
235
 
        # buttons
236
 
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
237
 
        btnSizer.Add(item = self.btnRun, proportion = 0)
238
 
        
239
 
        sizer.Add(item = dataSizer, proportion = 1,
240
 
                  flag = wx.EXPAND | wx.ALL, border = 5)
241
 
 
242
 
        sizer.Add(item = self.search, proportion = 0,
243
 
                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
244
 
        
245
 
        sizer.Add(item = btnSizer, proportion = 0,
246
 
                  flag = wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border = 5)
247
 
        
248
 
        sizer.Fit(self)
249
 
        sizer.SetSizeHints(self)
250
 
        
251
 
        self.SetSizer(sizer)
252
 
        
253
 
        self.Fit()
254
 
        self.SetAutoLayout(True)        
255
 
        self.Layout()
256
 
        
257
 
    def OnCloseWindow(self, event):
258
 
        """!Close window"""
259
 
        self.Destroy()
260
 
        
261
 
    def OnRun(self, event):
262
 
        """!Run selected command"""
263
 
        if not self.tree.GetSelected():
264
 
            return # should not happen
265
 
        
266
 
        data = self.tree.GetPyData(self.tree.GetSelected())
267
 
        if not data:
268
 
            return
269
 
 
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())
278
 
        else:
279
 
            eval(handler)(None)
280
 
 
281
 
    def OnShowItem(self, event):
282
 
        """!Show selected item"""
283
 
        self.tree.OnShowItem(event)
284
 
        if self.tree.GetSelected():
285
 
            self.btnRun.Enable()
286
 
        else:
287
 
            self.btnRun.Enable(False)
288
 
        
289
 
    def OnItemActivated(self, event):
290
 
        """!Item activated (double-click)"""
291
 
        item = event.GetItem()
292
 
        if not item or not item.IsOk():
293
 
            return
294
 
        
295
 
        data = self.tree.GetPyData(item)
296
 
        if not data or 'command' not in data:
297
 
            return
298
 
        
299
 
        self.tree.itemSelected = item
300
 
        
301
 
        self.OnRun(None)
302
 
        
303
 
    def OnItemSelected(self, event):
304
 
        """!Item selected"""
305
 
        item = event.GetItem()
306
 
        if not item or not item.IsOk():
307
 
            return
308
 
        
309
 
        data = self.tree.GetPyData(item)
310
 
        if not data or 'command' not in data:
311
 
            return
312
 
        
313
 
        if data['command']:
314
 
            label = data['command'] + ' -- ' + data['description']
315
 
        else:
316
 
            label = data['description']
317
 
        
318
 
        self.parent.SetStatusText(label, 0)
319
 
        
320
 
    def OnUpdateStatusBar(self, event):
321
 
        """!Update statusbar text"""
322
 
        element = self.search.GetSelection()
323
 
        self.tree.SearchItems(element = element,
324
 
                              value = event.GetString())
325
 
        
326
 
        nItems = len(self.tree.itemsMarked)
327
 
        if event.GetString():
328
 
            self.parent.SetStatusText(_("%d modules match") % nItems, 0)
329
 
        else:
330
 
            self.parent.SetStatusText("", 0)
331
 
        
332
 
        event.Skip()
333
 
 
334
 
class MenuTree(ItemTree):
335
 
    """!Menu tree class"""
336
 
    def __init__(self, parent, data, **kwargs):
337
 
        self.parent   = parent
338
 
        self.menudata = data
339
 
 
340
 
        super(MenuTree, self).__init__(parent, **kwargs)
341
 
        
342
 
    def Load(self, data = None):
343
 
        """!Load menu data tree
344
 
 
345
 
        @param data menu data (None to use self.menudata)
346
 
        """
347
 
        if not data:
348
 
            data = self.menudata
349
 
        
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)
356
 
        
357
 
    def __AppendItems(self, item, data):
358
 
        """!Append items into tree (used by Load()
359
 
        
360
 
        @param item tree item (parent)
361
 
        @parent data menu data"""
362
 
        for eachItem in data:
363
 
            if len(eachItem) == 2:
364
 
                if eachItem[0]:
365
 
                    itemSub = self.AppendItem(parentId = item,
366
 
                                    text = eachItem[0])
367
 
                self.__AppendItems(itemSub, eachItem[1])
368
 
            else:
369
 
                if eachItem[0]:
370
 
                    itemNew = self.AppendItem(parentId = item,
371
 
                                              text = eachItem[0])
372
 
                    
373
 
                    data = { 'item'        : eachItem[0],
374
 
                             'description' : eachItem[1],
375
 
                             'handler'  : eachItem[2],
376
 
                             'command'  : eachItem[3],
377
 
                             'keywords' : eachItem[4] }
378
 
                    
379
 
                    self.SetPyData(itemNew, data)
380
 
        
381
 
class AboutWindow(wx.Frame):
382
 
    """!Create custom About Window
383
 
    """
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)
387
 
        
388
 
        panel = wx.Panel(parent = self, id = wx.ID_ANY)
389
 
        
390
 
        # icon
391
 
        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
392
 
        
393
 
        # get version and web site
394
 
        vInfo = grass.version()
395
 
        
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)
406
 
        
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)
413
 
        
414
 
        row = 0
415
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
416
 
                                               label = _('Official GRASS site:')),
417
 
                          pos = (row, 0),
418
 
                          flag = wx.ALIGN_RIGHT)
419
 
 
420
 
        infoGridSizer.Add(item = HyperLinkCtrl(parent = infoTxt, id = wx.ID_ANY,
421
 
                                               label = 'http://grass.osgeo.org'),
422
 
                          pos = (row, 1),
423
 
                          flag = wx.ALIGN_LEFT)
424
 
 
425
 
        row += 2
426
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
427
 
                                               label = '%s:' % _('SVN Revision')),
428
 
                          pos = (row, 0),
429
 
                          flag = wx.ALIGN_RIGHT)
430
 
        
431
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
432
 
                                               label = vInfo['revision']),
433
 
                          pos = (row, 1),
434
 
                          flag = wx.ALIGN_LEFT)
435
 
        
436
 
        row += 1
437
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
438
 
                                               label = '%s:' % _('GIS Library Revision')),
439
 
                          pos = (row, 0),
440
 
                          flag = wx.ALIGN_RIGHT)
441
 
        
442
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
443
 
                                               label = vInfo['libgis_revision'] + ' (' +
444
 
                                               vInfo['libgis_date'].split(' ')[0] + ')'),
445
 
                          pos = (row, 1),
446
 
                          flag = wx.ALIGN_LEFT)
447
 
 
448
 
        row += 2
449
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
450
 
                                               label = 'Python:'),
451
 
                          pos = (row, 0),
452
 
                          flag = wx.ALIGN_RIGHT)
453
 
        
454
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
455
 
                                               label = platform.python_version()),
456
 
                          pos = (row, 1),
457
 
                          flag = wx.ALIGN_LEFT)
458
 
 
459
 
        row += 1
460
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
461
 
                                               label =  'wxPython:'),
462
 
                          pos = (row, 0),
463
 
                          flag = wx.ALIGN_RIGHT)
464
 
        
465
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
466
 
                                               label = wx.__version__),
467
 
                          pos = (row, 1),
468
 
                          flag = wx.ALIGN_LEFT)
469
 
        infoGridSizer.AddGrowableCol(0)
470
 
        infoGridSizer.AddGrowableCol(1)
471
 
        
472
 
        infoSizer.Add(item = infoGridSizer,
473
 
                      proportion = 1,
474
 
                      flag = wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
475
 
        
476
 
        row += 2
477
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
478
 
                                               label = "%s:" % _('Language')),
479
 
                          pos = (row, 0),
480
 
                          flag = wx.ALIGN_RIGHT)
481
 
        lang = grass.gisenv().get('LANG', None)
482
 
        if not lang:
483
 
            import locale
484
 
            loc = locale.getdefaultlocale()
485
 
            if loc == (None, None):
486
 
                lang = _('unknown')
487
 
            else:
488
 
                lang = u'%s.%s' % (loc[0], loc[1]) 
489
 
        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
490
 
                                               label = lang),
491
 
                          pos = (row, 1),
492
 
                          flag = wx.ALIGN_LEFT)        
493
 
        
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)
497
 
        
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)
507
 
        
508
 
        # buttons
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,
513
 
                     border = 5)
514
 
        # bindings
515
 
        btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
516
 
        
517
 
        infoTxt.SetSizer(infoSizer)
518
 
        infoSizer.Fit(infoTxt)
519
 
        
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)
526
 
        
527
 
        self.Layout()
528
 
        self.SetMinSize((400, 400))
529
 
        
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()
537
 
        else:
538
 
            copytext = _('%s file missing') % 'COPYING'
539
 
        
540
 
        # put text into a scrolling panel
541
 
        copyrightwin = ScrolledPanel(self)
542
 
                                     
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()
551
 
        
552
 
        return copyrightwin
553
 
    
554
 
    def _pageLicense(self):
555
 
        """Licence about"""
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())
560
 
            licenceFile.close()
561
 
        else:
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)
571
 
        licensewin.Layout()
572
 
        licensewin.SetupScrolling()
573
 
        
574
 
        return licensewin
575
 
    
576
 
    def _pageCredit(self):
577
 
        """Credit about"""
578
 
                # credits
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")
583
 
            authorsFile.close()
584
 
        else:
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)
594
 
        authorwin.Layout()      
595
 
        
596
 
        return authorwin
597
 
 
598
 
    def _pageContributors(self, extra = False):
599
 
        """Contributors info"""
600
 
        if extra:
601
 
            contribfile = os.path.join(os.getenv("GISBASE"), "contributors_extra.csv")
602
 
        else:
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')
606
 
            contribs = list()
607
 
            errLines = list()
608
 
            for line in contribFile.readlines()[1:]:
609
 
                line = line.rstrip('\n')
610
 
                try:
611
 
                    if extra:
612
 
                        name, email, rfc2_agreed = line.split(',')
613
 
                    else:
614
 
                        cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
615
 
                except ValueError:
616
 
                    errLines.append(line)
617
 
                    continue
618
 
                if extra:
619
 
                    contribs.append((name, email))
620
 
                else:
621
 
                    contribs.append((name, email, country, osgeo_id))
622
 
            
623
 
            contribFile.close()
624
 
            
625
 
            if errLines:
626
 
                GError(parent = self,
627
 
                       message = _("Error when reading file '%s'.") % contribfile + \
628
 
                           "\n\n" + _("Lines:") + " %s" % \
629
 
                           os.linesep.join(map(DecodeString, errLines)))
630
 
        else:
631
 
            contribs = None
632
 
        
633
 
        contribwin = ScrolledPanel(self)
634
 
        contribwin.SetAutoLayout(True)
635
 
        contribwin.SetupScrolling()
636
 
        contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
637
 
        
638
 
        if not contribs:
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)
643
 
        else:
644
 
            if extra:
645
 
                items = (_('Name'), _('E-mail'))
646
 
            else:
647
 
                items = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
648
 
            contribBox = wx.FlexGridSizer(cols = len(items), vgap = 5, hgap = 5)
649
 
            for item in items:
650
 
                contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
651
 
                                                    label = item))
652
 
            for vals in sorted(contribs, key = lambda x: x[0]):
653
 
                for item in vals:
654
 
                    contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
655
 
                                                        label = item))
656
 
            contribwin.sizer.Add(item = contribBox, proportion = 1,
657
 
                                 flag = wx.EXPAND | wx.ALL, border = 3)
658
 
        
659
 
        contribwin.SetSizer(contribwin.sizer)
660
 
        contribwin.Layout()      
661
 
        
662
 
        return contribwin
663
 
 
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')
669
 
            translators = dict()
670
 
            errLines = list()
671
 
            for line in translatorsFile.readlines()[1:]:
672
 
                line = line.rstrip('\n')
673
 
                try:
674
 
                    name, email, languages = line.split(',')
675
 
                except ValueError:
676
 
                    errLines.append(line)
677
 
                    continue
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()
683
 
            
684
 
            if errLines:
685
 
                GError(parent = self,
686
 
                       message = _("Error when reading file '%s'.") % translatorsfile + \
687
 
                           "\n\n" + _("Lines:") + " %s" % \
688
 
                           os.linesep.join(map(DecodeString, errLines)))
689
 
        else:
690
 
            translators = None
691
 
        
692
 
        translatorswin = ScrolledPanel(self)
693
 
        translatorswin.SetAutoLayout(True)
694
 
        translatorswin.SetupScrolling()
695
 
        translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
696
 
        
697
 
        if not translators:
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)
702
 
        else:
703
 
            translatorsBox = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
704
 
            languages = translators.keys()
705
 
            languages.sort()
706
 
            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
707
 
                                                    label = _('Name')))
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,
718
 
                                                            label = email))
719
 
                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
720
 
                                                            label = lang))
721
 
            
722
 
            translatorswin.sizer.Add(item = translatorsBox, proportion = 1,
723
 
                                 flag = wx.EXPAND | wx.ALL, border = 3)
724
 
        
725
 
        translatorswin.SetSizer(translatorswin.sizer)
726
 
        translatorswin.Layout()      
727
 
        
728
 
        return translatorswin
729
 
    
730
 
    def OnCloseWindow(self, event):
731
 
        """!Close window"""
732
 
        self.Close()
733
 
 
734
 
class HelpFrame(wx.Dialog):
735
 
    """!GRASS Quickstart help window
736
 
 
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).
740
 
    """
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)
744
 
        
745
 
        sizer = wx.BoxSizer(wx.VERTICAL)
746
 
        
747
 
        # text
748
 
        content = HelpPanel(parent = self)
749
 
        content.LoadPage(file)
750
 
        
751
 
        sizer.Add(item = content, proportion = 1, flag = wx.EXPAND)
752
 
        
753
 
        self.SetAutoLayout(True)
754
 
        self.SetSizer(sizer)
755
 
        self.Layout()
756
 
 
757
 
 
758
 
class HelpWindow(wx.html.HtmlWindow):
759
 
    """!This panel holds the text from GRASS docs.
760
 
    
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.
764
 
    """
765
 
    def __init__(self, parent, grass_command, text, skip_description,
766
 
                 **kwargs):
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.
770
 
 
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.
774
 
 
775
 
        If 'text' is given, it must be the HTML text to be presented
776
 
        in the Panel.
777
 
        """
778
 
        self.parent = parent
779
 
        if not globalvar.CheckWxVersion([2, 9]):
780
 
            wx.InitAllImageHandlers()
781
 
        wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
782
 
        
783
 
        gisbase = os.getenv("GISBASE")
784
 
        self.loaded = False
785
 
        self.history = list()
786
 
        self.historyIdx = 0
787
 
        self.fspath = os.path.join(gisbase, "docs", "html")
788
 
        
789
 
        self.SetStandardFonts (size = 10)
790
 
        self.SetBorders(10)
791
 
        
792
 
        if text is None:
793
 
            if skip_description:
794
 
                url = os.path.join(self.fspath, grass_command + ".html")
795
 
                self.fillContentsFromFile(url,
796
 
                                          skip_description = skip_description)
797
 
                self.history.append(url)
798
 
                self.loaded = True
799
 
            else:
800
 
                ### FIXME: calling LoadPage() is strangely time-consuming (only first call)
801
 
                # self.LoadPage(self.fspath + grass_command + ".html")
802
 
                self.loaded = False
803
 
        else:
804
 
            self.SetPage(text)
805
 
            self.loaded = True
806
 
        
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)
812
 
        self.historyIdx += 1
813
 
        self.parent.OnHistory()
814
 
        
815
 
        super(HelpWindow, self).OnLinkClicked(linkinfo)
816
 
        
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)
821
 
        try:
822
 
            contents = []
823
 
            skip = False
824
 
            for l in file(htmlFile, "rb").readlines():
825
 
                if "DESCRIPTION" in l:
826
 
                    skip = False
827
 
                if not skip:
828
 
                    # do skip the options description if requested
829
 
                    if "SYNOPSIS" in l:
830
 
                        skip = skip_description
831
 
                    else:
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))
841
 
                        
842
 
                        if findALink is None and findImgLink is None:
843
 
                            contents.append(l)
844
 
            self.SetPage("".join(contents))
845
 
            self.loaded = True
846
 
        except: # The Manual file was not found
847
 
            self.loaded = False
848
 
        
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)
854
 
        
855
 
        self.content = HelpWindow(self, grass_command, text,
856
 
                                  skip_description)
857
 
        
858
 
        self.btnNext = wx.Button(parent = self, id = wx.ID_ANY,
859
 
                                 label = _("&Next"))
860
 
        self.btnNext.Enable(False)
861
 
        self.btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
862
 
                                 label = _("&Previous"))
863
 
        self.btnPrev.Enable(False)
864
 
        
865
 
        self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext)
866
 
        self.btnPrev.Bind(wx.EVT_BUTTON, self.OnPrev)
867
 
        
868
 
        self._layout()
869
 
 
870
 
    def _layout(self):
871
 
        """!Do layout"""
872
 
        sizer = wx.BoxSizer(wx.VERTICAL)
873
 
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
874
 
        
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)
880
 
        
881
 
        sizer.Add(item = self.content, proportion = 1,
882
 
                  flag = wx.EXPAND)
883
 
        sizer.Add(item = btnSizer, proportion = 0,
884
 
                  flag = wx.EXPAND)
885
 
        
886
 
        self.SetSizer(sizer)
887
 
        sizer.Fit(self)
888
 
 
889
 
    def LoadPage(self, path = None):
890
 
        """!Load page"""
891
 
        if not path:
892
 
            path = self.GetFile()
893
 
        self.content.history.append(path)
894
 
        self.content.LoadPage(path)
895
 
        
896
 
    def GetFile(self):
897
 
        """!Get HTML file"""
898
 
        fMan = os.path.join(self.content.fspath, self.grass_command + ".html")
899
 
        if os.path.isfile(fMan):
900
 
            return fMan
901
 
        
902
 
        # check also addons
903
 
        aPath = os.getenv('GRASS_ADDON_PATH')
904
 
        if aPath:
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):
909
 
                    return faMan
910
 
        
911
 
        return None
912
 
 
913
 
    def IsLoaded(self):
914
 
        return self.content.loaded
915
 
 
916
 
    def OnHistory(self):
917
 
        """!Update buttons"""
918
 
        nH = len(self.content.history)
919
 
        iH = self.content.historyIdx
920
 
        if iH == nH - 1:
921
 
            self.btnNext.Enable(False)
922
 
        elif iH > -1:
923
 
            self.btnNext.Enable(True)
924
 
        if iH < 1:
925
 
            self.btnPrev.Enable(False)
926
 
        else:
927
 
            self.btnPrev.Enable(True)
928
 
 
929
 
    def OnNext(self, event):
930
 
        """Load next page"""
931
 
        self.content.historyIdx += 1
932
 
        idx = self.content.historyIdx
933
 
        path = self.content.history[idx]
934
 
        self.content.LoadPage(path)
935
 
        self.OnHistory()
936
 
        
937
 
        event.Skip()
938
 
        
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)
945
 
        self.OnHistory()
946
 
        
947
 
        event.Skip()