help.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. """!
  2. @package help.py
  3. @brief Help window
  4. @todo Needs improvements...
  5. Classes:
  6. - HelpWindow
  7. - MenuTreeWindow
  8. (C) 2008-2009 by the GRASS Development Team
  9. This program is free software under the GNU General Public
  10. License (>=v2). Read the file COPYING that comes with GRASS
  11. for details.
  12. @author Martin Landa <landa.martin gmail.com>
  13. """
  14. import wx
  15. import wx.lib.customtreectrl as CT
  16. import menudata
  17. import gcmd
  18. class HelpWindow(wx.Frame):
  19. """!GRASS Quickstart help window"""
  20. def __init__(self, parent, id, title, size, file):
  21. wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
  22. sizer = wx.BoxSizer(wx.VERTICAL)
  23. # text
  24. helpFrame = wx.html.HtmlWindow(parent=self, id=wx.ID_ANY)
  25. helpFrame.SetStandardFonts (size = 10)
  26. helpFrame.SetBorders(10)
  27. wx.InitAllImageHandlers()
  28. helpFrame.LoadFile(file)
  29. self.Ok = True
  30. sizer.Add(item=helpFrame, proportion=1, flag=wx.EXPAND)
  31. self.SetAutoLayout(True)
  32. self.SetSizer(sizer)
  33. # sizer.Fit(self)
  34. # sizer.SetSizeHints(self)
  35. self.Layout()
  36. class MenuTreeWindow(wx.Frame):
  37. """!Show menu tree"""
  38. def __init__(self, parent, id = wx.ID_ANY, title = _("Menu tree window"), **kwargs):
  39. self.parent = parent # LayerManager
  40. wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
  41. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  42. # tree
  43. self.tree = MenuTree(parent = self.panel, data = menudata.Data())
  44. self.tree.Load()
  45. self.searchDict = { _('label') : 'label', # i18n workaround
  46. _('help') : 'help',
  47. _('command') : 'command',
  48. _('keywords') : 'keywords' }
  49. # search
  50. self.searchBy = wx.Choice(parent = self.panel, id = wx.ID_ANY,
  51. choices = [_('label'),
  52. _('help'),
  53. _('command'),
  54. _('keywords')])
  55. self.search = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
  56. value = "", size = (-1, 25),
  57. style = wx.TE_PROCESS_ENTER)
  58. # statusbar
  59. self.statusbar = self.CreateStatusBar(number=1)
  60. # close on run
  61. self.closeOnRun = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  62. label = _("Close dialog on run"))
  63. self.closeOnRun.SetValue(True)
  64. # buttons
  65. self.btnRun = wx.Button(self.panel, id = wx.ID_OK, label = _("Run"))
  66. self.btnRun.SetToolTipString(_("Run selected command"))
  67. self.btnRun.Enable(False)
  68. self.btnClose = wx.Button(self.panel, id = wx.ID_CLOSE)
  69. self.btnClose.SetToolTipString(_("Close dialog"))
  70. # bindings
  71. self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
  72. self.btnRun.Bind(wx.EVT_BUTTON, self.OnRun)
  73. self.search.Bind(wx.EVT_TEXT_ENTER, self.OnShowItem)
  74. self.search.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
  75. self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
  76. self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnItemSelected)
  77. self.__Layout()
  78. self.search.SetFocus()
  79. def __Layout(self):
  80. """!Do dialog layout"""
  81. sizer = wx.BoxSizer(wx.VERTICAL)
  82. # body
  83. dataBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  84. label=" %s " % _("Menu tree (double-click to run command)"))
  85. dataSizer = wx.StaticBoxSizer(dataBox, wx.HORIZONTAL)
  86. dataSizer.Add(item = self.tree, proportion =1,
  87. flag = wx.EXPAND)
  88. # search
  89. searchSizer = wx.BoxSizer(wx.HORIZONTAL)
  90. searchSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  91. label = _("Search:")),
  92. proportion = 0,
  93. flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  94. border = 3)
  95. searchSizer.Add(item = self.searchBy, proportion = 0,
  96. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT,
  97. border = 5)
  98. searchSizer.Add(item = self.search, proportion = 1,
  99. flag = wx.EXPAND | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL,
  100. border = 5)
  101. # buttons
  102. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  103. btnSizer.Add(item = self.btnRun, proportion = 0,
  104. flag = wx.LEFT | wx.RIGHT, border = 5)
  105. btnSizer.Add(item = self.btnClose, proportion = 0,
  106. flag = wx.LEFT | wx.RIGHT, border = 5)
  107. sizer.Add(item = dataSizer, proportion = 1,
  108. flag = wx.EXPAND | wx.ALL, border = 5)
  109. sizer.Add(item = searchSizer, proportion=0,
  110. flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  111. sizer.Add(item = btnSizer, proportion=0,
  112. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  113. sizer.Add(item = self.closeOnRun, proportion=0,
  114. flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  115. self.panel.SetAutoLayout(True)
  116. self.panel.SetSizer(sizer)
  117. sizer.Fit(self.panel)
  118. self.Layout()
  119. self.SetSize((530, 370))
  120. def OnCloseWindow(self, event):
  121. """!Close window"""
  122. self.Destroy()
  123. def OnRun(self, event):
  124. """!Run selected command"""
  125. if not self.tree.GetSelected():
  126. return # should not happen
  127. data = self.tree.GetPyData(self.tree.GetSelected())
  128. if not data or not data.has_key('command'):
  129. return
  130. gcmd.RunCommand(data['command'])
  131. if self.closeOnRun.IsChecked():
  132. self.OnCloseWindow(None)
  133. def OnItemActivated(self, event):
  134. """!Item activated (double-click)"""
  135. item = event.GetItem()
  136. if not item or not item.IsOk():
  137. return
  138. data = self.tree.GetPyData(item)
  139. if not data or not data.has_key('command'):
  140. return
  141. self.tree.itemSelected = item
  142. self.OnRun(None)
  143. def OnItemSelected(self, event):
  144. """!Item selected"""
  145. item = event.GetItem()
  146. if not item or not item.IsOk():
  147. return
  148. data = self.tree.GetPyData(item)
  149. if not data or not data.has_key('command'):
  150. return
  151. self.statusbar.SetStatusText(data['command'] + ' -- ' + data['help'], 0)
  152. def OnShowItem(self, event):
  153. """!Highlight first found item in menu tree"""
  154. if len(self.tree.itemsMarked) > 0:
  155. if self.tree.GetSelected():
  156. self.tree.ToggleItemSelection(self.tree.GetSelected())
  157. idx = self.tree.itemsMarked.index(self.tree.GetSelected()) + 1
  158. else:
  159. idx = 0
  160. try:
  161. self.tree.ToggleItemSelection(self.tree.itemsMarked[idx])
  162. self.tree.itemSelected = self.tree.itemsMarked[idx]
  163. self.tree.EnsureVisible(self.tree.itemsMarked[idx])
  164. except IndexError:
  165. self.tree.ToggleItemSelection(self.tree.itemsMarked[0]) # reselect first item
  166. self.tree.EnsureVisible(self.tree.itemsMarked[0])
  167. self.tree.itemSelected = self.tree.itemsMarked[0]
  168. else:
  169. for item in self.tree.root.GetChildren():
  170. self.tree.Collapse(item)
  171. itemSelected = self.tree.GetSelection()
  172. if itemSelected:
  173. self.tree.ToggleItemSelection(itemSelected)
  174. self.tree.itemSelected = None
  175. def OnUpdateStatusBar(self, event):
  176. """!Update statusbar text"""
  177. element = self.searchDict[self.searchBy.GetStringSelection()]
  178. self.tree.itemsMarked = self.SearchItems(element = element,
  179. value = event.GetString())
  180. self.tree.itemSelected = None
  181. nItems = len(self.tree.itemsMarked)
  182. if event.GetString():
  183. self.statusbar.SetStatusText(_("%d items match") % nItems, 0)
  184. else:
  185. self.statusbar.SetStatusText("", 0)
  186. if nItems > 0:
  187. self.tree.itemSelected = self.tree.itemsMarked[0]
  188. self.btnRun.Enable()
  189. else:
  190. self.btnRun.Enable(False)
  191. event.Skip()
  192. def SearchItems(self, element, value):
  193. """!Search item
  194. @param element element index (see self.searchBy)
  195. @param value
  196. @return list of found tree items
  197. """
  198. items = list()
  199. if not value:
  200. return items
  201. item = self.tree.GetFirstChild(self.tree.root)[0]
  202. self.__ProcessItem(item, element, value, items)
  203. return items
  204. def __ProcessItem(self, item, element, value, listOfItems):
  205. """!Search items (used by SearchItems)
  206. @param item reference item
  207. @param listOfItems list of found items
  208. """
  209. while item and item.IsOk():
  210. subItem = self.tree.GetFirstChild(item)[0]
  211. if subItem:
  212. self.__ProcessItem(subItem, element, value, listOfItems)
  213. data = self.tree.GetPyData(item)
  214. if data and data.has_key(element) and \
  215. value.lower() in data[element].lower():
  216. listOfItems.append(item)
  217. item = self.tree.GetNextSibling(item)
  218. class MenuTree(CT.CustomTreeCtrl):
  219. """!Menu tree class"""
  220. def __init__(self, parent, data, id = wx.ID_ANY,
  221. ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS | \
  222. CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
  223. **kwargs):
  224. self.parent = parent
  225. self.menudata = data
  226. super(MenuTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
  227. self.root = self.AddRoot(_("Menu tree"))
  228. self.itemsMarked = [] # list of marked items
  229. self.itemSelected = None
  230. def Load(self, data = None):
  231. """!Load menu data tree
  232. @param data menu data (None to use self.menudata)
  233. """
  234. if not data:
  235. data = self.menudata
  236. self.itemsMarked = [] # list of marked items
  237. for eachMenuData in data.GetMenu():
  238. for label, items in eachMenuData:
  239. item = self.AppendItem(parentId = self.root,
  240. text = label)
  241. self.__AppendItems(item, items)
  242. def __AppendItems(self, item, data):
  243. """!Append items into tree (used by Load()
  244. @param item tree item (parent)
  245. @parent data menu data"""
  246. for eachItem in data:
  247. if len(eachItem) == 2:
  248. if eachItem[0]:
  249. itemSub = self.AppendItem(parentId = item,
  250. text = eachItem[0])
  251. self.__AppendItems(itemSub, eachItem[1])
  252. else:
  253. if eachItem[0]:
  254. itemNew = self.AppendItem(parentId = item,
  255. text = eachItem[0])
  256. data = { 'label' : eachItem[0],
  257. 'help' : eachItem[1],
  258. 'handler' : eachItem[2],
  259. 'command' : eachItem[3],
  260. 'keywords' : eachItem[4] }
  261. self.SetPyData(itemNew, data)
  262. def GetSelected(self):
  263. """!Get selected item"""
  264. return self.itemSelected