ed_bookmark.py
9.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
###############################################################################
# Name: Cody Precord #
# Purpose: Bookmark Manager window and plugin interface #
# Author: Cody Precord <cprecord@editra.org> #
# Copyright: (c) 2010 Cody Precord <staff@editra.org> #
# License: wxWindows License #
###############################################################################
"""
Bookmark manager
"""
__author__ = "Cody Precord <cprecord@editra.org>"
__svnid__ = "$Id: ed_bookmark.py 69115 2011-09-17 16:51:49Z CJP $"
__revision__ = "$Revision: 69115 $"
#--------------------------------------------------------------------------#
# Imports
import os
import re
import wx
# Editra Libraries
import ed_msg
import iface
import plugin
from profiler import Profile_Get, Profile_Set
import ed_glob
import util
import eclib
import ebmlib
import ed_basewin
from ed_marker import Bookmark
#-----------------------------------------------------------------------------#
# Globals
_ = wx.GetTranslation
#-----------------------------------------------------------------------------#
# Interface Implementation
class EdBookmarks(plugin.Plugin):
"""Shelf interface implementation for the bookmark manager"""
plugin.Implements(iface.ShelfI)
__name__ = u'Bookmarks'
@staticmethod
def AllowMultiple():
"""EdBookmark only allows one instance"""
return False
@staticmethod
def CreateItem(parent):
"""Returns a bookmark panel"""
return BookmarkWindow(parent)
def GetBitmap(self):
"""Get the log viewers tab icon
@return: wx.Bitmap
"""
bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_ADD_BM), wx.ART_MENU)
return bmp
@staticmethod
def GetId():
"""Plugin menu identifier ID"""
return ed_glob.ID_BOOKMARK_MGR
@staticmethod
def GetMenuEntry(menu):
"""Get the menu entry for the bookmark viewer
@param menu: the menu items parent menu
"""
item = wx.MenuItem(menu, ed_glob.ID_BOOKMARK_MGR,
_("Bookmarks"),
_("View all bookmarks"))
bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_ADD_BM), wx.ART_MENU)
item.SetBitmap(bmp)
return item
def GetName(self):
"""Return the name of this control"""
return self.__name__
@staticmethod
def IsStockable():
"""EdBookmark can be saved in the shelf preference stack"""
return True
# Bookmark storage
_marks = list()
@classmethod
def OnStoreBM(cls, msg):
data = msg.GetData()
buf = data.get('stc')
line = data.get('line')
mark = Bookmark()
mark.Filename = buf.GetFileName()
mark.Line = line
if data.get('added', False):
if mark not in cls._marks:
# Store the stc bookmark handle
mark.Handle = data.get('handle', None)
# Store an alias for the bookmark
name = u""
cline = buf.GetCurrentLine()
if line == cline:
name = buf.GetSelectedText()
if not name:
name = buf.GetLine(line)
mark.Name = name.strip()
cls._marks.append(mark)
else:
if mark in cls._marks:
idx = cls._marks.index(mark)
cls._marks.pop(idx)
@classmethod
def GetMarks(cls):
return cls._marks
ed_msg.Subscribe(EdBookmarks.OnStoreBM, ed_msg.EDMSG_UI_STC_BOOKMARK)
#-----------------------------------------------------------------------------#
class BookmarkWindow(ed_basewin.EdBaseCtrlBox):
"""Shelf window for managing bookmarks"""
def __init__(self, parent):
super(BookmarkWindow, self).__init__(parent)
# Attributes
self._list = BookmarkList(self)
#Setup
self.SetWindow(self._list)
ctrlbar = self.CreateControlBar(wx.TOP)
ctrlbar.AddStretchSpacer()
self._delbtn = self.AddPlateButton(_("Delete"), ed_glob.ID_DELETE,
wx.ALIGN_RIGHT)
self._delbtn.ToolTip = wx.ToolTip(_("Delete Bookmark"))
self._delallbtn = self.AddPlateButton(_("Delete All"),
ed_glob.ID_DELETE_ALL,
wx.ALIGN_RIGHT)
self._delallbtn.ToolTip = wx.ToolTip(_("Delete all bookmarks"))
# Message Handlers
ed_msg.Subscribe(self.OnBookmark, ed_msg.EDMSG_UI_STC_BOOKMARK)
# Event Handlers
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy, self)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivate, self._list)
self.Bind(wx.EVT_BUTTON, self.OnDelBm, self._delbtn)
self.Bind(wx.EVT_BUTTON, self.OnDelAllBm, self._delallbtn)
# BUG in wxAUI UpdateUI events not processed when docked
# TODO: renable when switch to agw aui
# self.Bind(wx.EVT_UPDATE_UI,
# lambda evt: evt.Enable(bool(len(self._list.GetSelections()))),
# self._delbtn)
def OnDestroy(self, evt):
"""Unsubscribe message handlers on delete"""
if evt.GetId() == self.GetId():
ed_msg.Unsubscribe(self.OnBookmark)
evt.Skip()
def OnBookmark(self, msg):
"""Bookmark added or removed callback"""
# Update on next iteration to ensure that handler
# in the singleton data store have been updated.
wx.CallAfter(self.DoUpdateListCtrl)
def OnDelAllBm(self, evt):
"""Delete all bookmarks"""
items = range(self._list.ItemCount)
self.DeleteBookmarks(items)
def OnDelBm(self, evt):
"""Remove the selected bookmark(s) from the list and the buffer"""
items = self._list.GetSelections()
self.DeleteBookmarks(items)
def DeleteBookmarks(self, items):
"""Delete the bookmarks from the passed in list
@param items: list of indexes in BookmarkList
"""
assert isinstance(items, list)
if len(items):
items.reverse()
marks = EdBookmarks.GetMarks()
for item in items:
if item < len(marks):
mark = marks.pop(item)
app = wx.GetApp()
mw = app.GetActiveWindow()
if mw:
nb = mw.GetNotebook()
buf = nb.FindBuffer(mark.Filename)
if buf:
buf.MarkerDeleteHandle(mark.Handle)
self.DoUpdateListCtrl()
def DoUpdateListCtrl(self):
"""Update the listctrl for changes in the cache"""
nMarks = len(EdBookmarks.GetMarks())
self._list.SetItemCount(nMarks)
# Refresh everything
# XXX: if optimization is needed only refresh visible items
self._list.RefreshItems(0, nMarks)
self._list.Refresh()
def OnItemActivate(self, evt):
"""Handle double clicks on items to navigate to the
selected bookmark.
"""
index = evt.m_itemIndex
marks = EdBookmarks.GetMarks()
if index < len(marks):
mark = marks[index]
self.GotoBookmark(mark)
def GotoBookmark(self, mark):
"""Goto the bookmark in the editor
@param mark: BookMark
"""
app = wx.GetApp()
mw = app.GetActiveWindow()
if mw:
nb = mw.GetNotebook()
buf = nb.FindBuffer(mark.Filename)
use_handle = True
if not buf:
nb.OpenPage(ebmlib.GetPathName(mark.Filename),
ebmlib.GetFileName(mark.Filename))
buf = nb.GetCurrentPage()
use_handle = False # Handle is invalid so use line number
if buf:
# Ensure the tab is the current one
nb.GotoPage(mark.Filename)
# Jump to the bookmark line
if use_handle:
lnum = buf.MarkerLineFromHandle(mark.Handle)
else:
lnum = mark.Line
buf.GotoLine(lnum)
else:
util.Log("[ed_bookmark][err] Failed to locate mainwindow")
#-----------------------------------------------------------------------------#
class BookmarkList(eclib.EBaseListCtrl):
"""ListCtrl for displaying the bookmarks in"""
BOOKMARK = 0
FILE_NAME = 1
LINE_NUM = 2
def __init__(self, parent):
super(BookmarkList, self).__init__(parent,
style=wx.LC_REPORT|\
wx.LC_EDIT_LABELS|\
wx.LC_VIRTUAL)
# Setup
self._il = wx.ImageList(16,16)
self._idx = self._il.Add(Bookmark().Bitmap)
self.SetImageList(self._il, wx.IMAGE_LIST_SMALL)
self.InsertColumn(BookmarkList.BOOKMARK, _("Bookmark"))
self.InsertColumn(BookmarkList.FILE_NAME, _("File Location"))
self.InsertColumn(BookmarkList.LINE_NUM, _("Line Number"))
self.setResizeColumn(BookmarkList.FILE_NAME+1) #NOTE: +1 bug in mixin
self.SetItemCount(len(EdBookmarks.GetMarks()))
def OnGetItemImage(self, item):
return 0
def OnGetItemText(self, item, column):
"""Override for virtual control"""
marks = EdBookmarks.GetMarks()
val = u""
if item < len(marks):
mark = marks[item]
if column == BookmarkList.BOOKMARK:
val = mark.Name
if not val:
val = _("Bookmark%d") % item
elif column == BookmarkList.FILE_NAME:
val = mark.Filename
elif column == BookmarkList.LINE_NUM:
val = unicode(mark.Line + 1)
return val