+++ /dev/null
-#----------------------------------------------------------------------------
-# Name: OutlineService.py
-# Purpose: Outline View Service for pydocview
-#
-# Author: Morgan Hua
-#
-# Created: 8/3/04
-# CVS-ID: $Id$
-# Copyright: (c) 2004-2005 ActiveGrid, Inc.
-# License: wxWindows License
-#----------------------------------------------------------------------------
-
-import wx
-import wx.lib.docview
-import wx.lib.pydocview
-import Service
-_ = wx.GetTranslation
-
-
-#----------------------------------------------------------------------------
-# Constants
-#----------------------------------------------------------------------------
-SORT_NONE = 0
-SORT_ASC = 1
-SORT_DESC = 2
-
-class OutlineView(Service.ServiceView):
- """ Reusable Outline View for any document.
- As a default, it uses a modified tree control (OutlineTreeCtrl) that allows sorting.
- Subclass OutlineTreeCtrl to customize the tree control and call SetTreeCtrl to install a customized tree control.
- When an item is selected, the document view is called back (with DoSelectCallback) to highlight and display the corresponding item in the document view.
- """
-
- #----------------------------------------------------------------------------
- # Overridden methods
- #----------------------------------------------------------------------------
-
- def __init__(self, service):
- Service.ServiceView.__init__(self, service)
- self._actionOnSelect = True
-
-
- def _CreateControl(self, parent, id):
- treeCtrl = OutlineTreeCtrl(parent, id)
- wx.EVT_TREE_SEL_CHANGED(treeCtrl, treeCtrl.GetId(), self.DoSelection)
- wx.EVT_SET_FOCUS(treeCtrl, self.DoSelection)
- wx.EVT_ENTER_WINDOW(treeCtrl, treeCtrl.CallDoLoadOutlineCallback)
- wx.EVT_RIGHT_DOWN(treeCtrl, self.OnRightClick)
-
- return treeCtrl
-
-
- #----------------------------------------------------------------------------
- # Service specific methods
- #----------------------------------------------------------------------------
-
- def OnRightClick(self, event):
- menu = wx.Menu()
-
- menu.AppendRadioItem(OutlineService.SORT_NONE, _("Unsorted"), _("Display items in original order"))
- menu.AppendRadioItem(OutlineService.SORT_ASC, _("Sort A-Z"), _("Display items in ascending order"))
- menu.AppendRadioItem(OutlineService.SORT_DESC, _("Sort Z-A"), _("Display items in descending order"))
-
- config = wx.ConfigBase_Get()
- sort = config.ReadInt("OutlineSort", SORT_NONE)
- if sort == SORT_NONE:
- menu.Check(OutlineService.SORT_NONE, True)
- elif sort == SORT_ASC:
- menu.Check(OutlineService.SORT_ASC, True)
- elif sort == SORT_DESC:
- menu.Check(OutlineService.SORT_DESC, True)
-
- self.GetControl().PopupMenu(menu, event.GetPosition())
- menu.Destroy()
-
-
- #----------------------------------------------------------------------------
- # Tree Methods
- #----------------------------------------------------------------------------
-
- def DoSelection(self, event):
- if not self._actionOnSelect:
- return
- item = self.GetControl().GetSelection()
- if item:
- self.GetControl().CallDoSelectCallback(item)
- event.Skip()
-
-
- def ResumeActionOnSelect(self):
- self._actionOnSelect = True
-
-
- def StopActionOnSelect(self):
- self._actionOnSelect = False
-
-
- def SetTreeCtrl(self, tree):
- self.SetControl(tree)
- wx.EVT_TREE_SEL_CHANGED(self.GetControl(), self.GetControl().GetId(), self.DoSelection)
- wx.EVT_ENTER_WINDOW(self.GetControl(), treeCtrl.CallDoLoadOutlineCallback)
- wx.EVT_RIGHT_DOWN(self.GetControl(), self.OnRightClick)
-
-
- def GetTreeCtrl(self):
- return self.GetControl()
-
-
- def OnSort(self, sortOrder):
- treeCtrl = self.GetControl()
- treeCtrl.SetSortOrder(sortOrder)
- treeCtrl.SortAllChildren(treeCtrl.GetRootItem())
-
-
- def ClearTreeCtrl(self):
- if self.GetControl():
- self.GetControl().DeleteAllItems()
-
-
- def GetExpansionState(self):
- expanded = []
-
- treeCtrl = self.GetControl()
- if not treeCtrl:
- return expanded
-
- parentItem = treeCtrl.GetRootItem()
-
- if not parentItem:
- return expanded
-
- if not treeCtrl.IsExpanded(parentItem):
- return expanded
-
- expanded.append(treeCtrl.GetItemText(parentItem))
-
- (child, cookie) = treeCtrl.GetFirstChild(parentItem)
- while child.IsOk():
- if treeCtrl.IsExpanded(child):
- expanded.append(treeCtrl.GetItemText(child))
- (child, cookie) = treeCtrl.GetNextChild(parentItem, cookie)
- return expanded
-
-
- def SetExpansionState(self, expanded):
- if not expanded or len(expanded) == 0:
- return
-
- treeCtrl = self.GetControl()
-
- parentItem = treeCtrl.GetRootItem()
- if not parentItem:
- return
-
- if expanded[0] != treeCtrl.GetItemText(parentItem):
- return
-
- (child, cookie) = treeCtrl.GetFirstChild(parentItem)
- while child.IsOk():
- if treeCtrl.GetItemText(child) in expanded:
- treeCtrl.Expand(child)
- (child, cookie) = treeCtrl.GetNextChild(parentItem, cookie)
-
- treeCtrl.EnsureVisible(parentItem)
-
-
-class OutlineTreeCtrl(wx.TreeCtrl):
- """ Default Tree Control Class for OutlineView.
- This class has the added functionality of sorting by the labels
- """
-
-
- #----------------------------------------------------------------------------
- # Constants
- #----------------------------------------------------------------------------
- ORIG_ORDER = 0
- VIEW = 1
- CALLBACKDATA = 2
-
-
- #----------------------------------------------------------------------------
- # Overridden Methods
- #----------------------------------------------------------------------------
-
- def __init__(self, parent, id, style=wx.TR_HAS_BUTTONS|wx.TR_DEFAULT_STYLE):
- wx.TreeCtrl.__init__(self, parent, id, style = style)
- self._origOrderIndex = 0
- self._sortOrder = SORT_NONE
-
-
- def DeleteAllItems(self):
- self._origOrderIndex = 0
- wx.TreeCtrl.DeleteAllItems(self)
-
-
- #----------------------------------------------------------------------------
- # Sort Methods
- #----------------------------------------------------------------------------
-
- def SetSortOrder(self, sortOrder = SORT_NONE):
- """ Sort Order constants are defined at top of file """
- self._sortOrder = sortOrder
-
-
- def OnCompareItems(self, item1, item2):
- if self._sortOrder == SORT_ASC:
- return cmp(self.GetItemText(item1).lower(), self.GetItemText(item2).lower()) # sort A-Z
- elif self._sortOrder == SORT_DESC:
- return cmp(self.GetItemText(item2).lower(), self.GetItemText(item1).lower()) # sort Z-A
- else:
- return (self.GetPyData(item1)[self.ORIG_ORDER] > self.GetPyData(item2)[self.ORIG_ORDER]) # unsorted
-
-
- def SortAllChildren(self, parentItem):
- if parentItem and self.GetChildrenCount(parentItem, False):
- self.SortChildren(parentItem)
- (child, cookie) = self.GetFirstChild(parentItem)
- while child.IsOk():
- self.SortAllChildren(child)
- (child, cookie) = self.GetNextChild(parentItem, cookie)
-
-
- #----------------------------------------------------------------------------
- # Select Callback Methods
- #----------------------------------------------------------------------------
-
- def CallDoSelectCallback(self, item):
- """ Invoke the DoSelectCallback of the given view to highlight text in the document view
- """
- data = self.GetPyData(item)
- if not data:
- return
-
- view = data[self.VIEW]
- cbdata = data[self.CALLBACKDATA]
- if view:
- view.DoSelectCallback(cbdata)
-
-
- def SelectClosestItem(self, position):
- tree = self
- distances = []
- items = []
- self.FindDistanceToTreeItems(tree.GetRootItem(), position, distances, items)
- mindist = 1000000
- mindex = -1
- for index in range(0, len(distances)):
- if distances[index] <= mindist:
- mindist = distances[index]
- mindex = index
- if mindex != -1:
- item = items[mindex]
- self.EnsureVisible(item)
- os_view = wx.GetApp().GetService(OutlineService).GetView()
- if os_view:
- os_view.StopActionOnSelect()
- self.SelectItem(item)
- if os_view:
- os_view.ResumeActionOnSelect()
-
-
- def FindDistanceToTreeItems(self, item, position, distances, items):
- data = self.GetPyData(item)
- this_dist = 1000000
- if data and data[2]:
- positionTuple = data[2]
- if position >= positionTuple[1]:
- items.append(item)
- distances.append(position - positionTuple[1])
-
- if self.ItemHasChildren(item):
- child, cookie = self.GetFirstChild(item)
- while child.IsOk():
- self.FindDistanceToTreeItems(child, position, distances, items)
- child, cookie = self.GetNextChild(item, cookie)
- return False
-
-
- def SetDoSelectCallback(self, item, view, callbackdata):
- """ When an item in the outline view is selected,
- a method is called to select the respective text in the document view.
- The view must define the method DoSelectCallback(self, data) in order for this to work
- """
- self.SetPyData(item, (self._origOrderIndex, view, callbackdata))
- self._origOrderIndex = self._origOrderIndex + 1
-
-
- def CallDoLoadOutlineCallback(self, event):
- """ Invoke the DoLoadOutlineCallback
- """
- rootItem = self.GetRootItem()
- if rootItem:
- data = self.GetPyData(rootItem)
- if data:
- view = data[self.VIEW]
- if view and view.DoLoadOutlineCallback():
- self.SortAllChildren(self.GetRootItem())
-
-
- def GetCallbackView(self):
- rootItem = self.GetRootItem()
- if rootItem:
- return self.GetPyData(rootItem)[self.VIEW]
- else:
- return None
-
-
-class OutlineService(Service.Service):
-
-
- #----------------------------------------------------------------------------
- # Constants
- #----------------------------------------------------------------------------
- SHOW_WINDOW = wx.NewId() # keep this line for each subclass, need unique ID for each Service
- SORT = wx.NewId()
- SORT_ASC = wx.NewId()
- SORT_DESC = wx.NewId()
- SORT_NONE = wx.NewId()
-
-
- #----------------------------------------------------------------------------
- # Overridden methods
- #----------------------------------------------------------------------------
-
- def __init__(self, serviceName, embeddedWindowLocation = wx.lib.pydocview.EMBEDDED_WINDOW_BOTTOM):
- Service.Service.__init__(self, serviceName, embeddedWindowLocation)
- self._validViewTypes = []
-
-
- def _CreateView(self):
- return OutlineView(self)
-
-
- def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
- Service.Service.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
-
- wx.EVT_MENU(frame, OutlineService.SORT_ASC, frame.ProcessEvent)
- wx.EVT_UPDATE_UI(frame, OutlineService.SORT_ASC, frame.ProcessUpdateUIEvent)
- wx.EVT_MENU(frame, OutlineService.SORT_DESC, frame.ProcessEvent)
- wx.EVT_UPDATE_UI(frame, OutlineService.SORT_DESC, frame.ProcessUpdateUIEvent)
- wx.EVT_MENU(frame, OutlineService.SORT_NONE, frame.ProcessEvent)
- wx.EVT_UPDATE_UI(frame, OutlineService.SORT_NONE, frame.ProcessUpdateUIEvent)
-
-
- if wx.GetApp().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
- return True
-
- viewMenu = menuBar.GetMenu(menuBar.FindMenu(_("&View")))
- self._outlineSortMenu = wx.Menu()
- self._outlineSortMenu.AppendRadioItem(OutlineService.SORT_NONE, _("Unsorted"), _("Display items in original order"))
- self._outlineSortMenu.AppendRadioItem(OutlineService.SORT_ASC, _("Sort A-Z"), _("Display items in ascending order"))
- self._outlineSortMenu.AppendRadioItem(OutlineService.SORT_DESC, _("Sort Z-A"), _("Display items in descending order"))
- viewMenu.AppendMenu(wx.NewId(), _("Outline Sort"), self._outlineSortMenu)
-
- return True
-
-
- #----------------------------------------------------------------------------
- # Event Processing Methods
- #----------------------------------------------------------------------------
-
- def ProcessEvent(self, event):
- if Service.Service.ProcessEvent(self, event):
- return True
-
- id = event.GetId()
- if id == OutlineService.SORT_ASC:
- self.OnSort(event)
- return True
- elif id == OutlineService.SORT_DESC:
- self.OnSort(event)
- return True
- elif id == OutlineService.SORT_NONE:
- self.OnSort(event)
- return True
- else:
- return False
-
-
- def ProcessUpdateUIEvent(self, event):
- if Service.Service.ProcessUpdateUIEvent(self, event):
- return True
-
- id = event.GetId()
- if id == OutlineService.SORT_ASC:
- event.Enable(True)
-
- config = wx.ConfigBase_Get()
- sort = config.ReadInt("OutlineSort", SORT_NONE)
- if sort == SORT_ASC:
- self._outlineSortMenu.Check(OutlineService.SORT_ASC, True)
- else:
- self._outlineSortMenu.Check(OutlineService.SORT_ASC, False)
-
- return True
- elif id == OutlineService.SORT_DESC:
- event.Enable(True)
-
- config = wx.ConfigBase_Get()
- sort = config.ReadInt("OutlineSort", SORT_NONE)
- if sort == SORT_DESC:
- self._outlineSortMenu.Check(OutlineService.SORT_DESC, True)
- else:
- self._outlineSortMenu.Check(OutlineService.SORT_DESC, False)
-
- return True
- elif id == OutlineService.SORT_NONE:
- event.Enable(True)
-
- config = wx.ConfigBase_Get()
- sort = config.ReadInt("OutlineSort", SORT_NONE)
- if sort == SORT_NONE:
- self._outlineSortMenu.Check(OutlineService.SORT_NONE, True)
- else:
- self._outlineSortMenu.Check(OutlineService.SORT_NONE, False)
-
- return True
- else:
- return False
-
-
- def OnSort(self, event):
- id = event.GetId()
- if id == OutlineService.SORT_ASC:
- wx.ConfigBase_Get().WriteInt("OutlineSort", SORT_ASC)
- self.GetView().OnSort(SORT_ASC)
- return True
- elif id == OutlineService.SORT_DESC:
- wx.ConfigBase_Get().WriteInt("OutlineSort", SORT_DESC)
- self.GetView().OnSort(SORT_DESC)
- return True
- elif id == OutlineService.SORT_NONE:
- wx.ConfigBase_Get().WriteInt("OutlineSort", SORT_NONE)
- self.GetView().OnSort(SORT_NONE)
- return True
-
-
- #----------------------------------------------------------------------------
- # Service specific methods
- #----------------------------------------------------------------------------
-
- def LoadOutline(self, view, position=-1, force=False):
- if not self.GetView():
- return
-
- if hasattr(view, "DoLoadOutlineCallback"):
- self.SaveExpansionState()
- if view.DoLoadOutlineCallback(force=force):
- self.GetView().OnSort(wx.ConfigBase_Get().ReadInt("OutlineSort", SORT_NONE))
- self.LoadExpansionState()
- if position >= 0:
- self.SyncToPosition(position)
-
-
- def SyncToPosition(self, position):
- if not self.GetView():
- return
- self.GetView().GetTreeCtrl().SelectClosestItem(position)
-
-
- def OnCloseFrame(self, event):
- Service.Service.OnCloseFrame(self, event)
- self.SaveExpansionState(clear = True)
-
- return True
-
-
- def SaveExpansionState(self, clear = False):
- if clear:
- expanded = []
- elif self.GetView():
- expanded = self.GetView().GetExpansionState()
- wx.ConfigBase_Get().Write("OutlineLastExpanded", expanded.__repr__())
-
-
- def LoadExpansionState(self):
- expanded = wx.ConfigBase_Get().Read("OutlineLastExpanded")
- if expanded:
- self.GetView().SetExpansionState(eval(expanded))
-
-
- #----------------------------------------------------------------------------
- # Timer Methods
- #----------------------------------------------------------------------------
-
- def StartBackgroundTimer(self):
- self._timer = wx.PyTimer(self.DoBackgroundRefresh)
- self._timer.Start(250)
-
-
- def DoBackgroundRefresh(self):
- """ Refresh the outline view periodically """
- self._timer.Stop()
-
- foundRegisteredView = False
- if self.GetView():
- currView = wx.GetApp().GetDocumentManager().GetCurrentView()
- if currView:
- for viewType in self._validViewTypes:
- if isinstance(currView, viewType):
- self.LoadOutline(currView)
- foundRegisteredView = True
- break
-
- if not foundRegisteredView:
- self.GetView().ClearTreeCtrl()
-
- self._timer.Start(1000) # 1 second interval
-
-
- def AddViewTypeForBackgroundHandler(self, viewType):
- self._validViewTypes.append(viewType)
-
-
- def GetViewTypesForBackgroundHandler(self):
- return self._validViewTypes
-
-
- def RemoveViewTypeForBackgroundHandler(self, viewType):
- self._validViewTypes.remove(viewType)
-