]>
Commit | Line | Data |
---|---|---|
2eeaec19 RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: ExtensionService.py | |
3 | # Purpose: Extension Service for IDE | |
4 | # | |
5 | # Author: Peter Yared | |
6 | # | |
7 | # Created: 5/23/05 | |
8 | # CVS-ID: $ID:$ | |
9 | # Copyright: (c) 2005 ActiveGrid, Inc. | |
10 | # License: wxWindows License | |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | import wx | |
14 | import wx.lib.pydocview | |
15 | import MessageService | |
16 | import os | |
17 | import os.path | |
18 | import pickle | |
19 | ||
20 | _ = wx.GetTranslation | |
21 | ||
22 | ||
23 | SPACE = 10 | |
24 | HALF_SPACE = 5 | |
25 | ||
26 | ||
27 | EXTENSIONS_CONFIG_STRING = "Extensions" | |
28 | ||
29 | ||
30 | ||
31 | # TODO: Redo extensions menu on OK, or provide alert that it won't happen until restart | |
32 | ||
33 | ||
34 | #---------------------------------------------------------------------------- | |
35 | # Classes | |
36 | #---------------------------------------------------------------------------- | |
37 | ||
38 | class Extension: | |
39 | ||
40 | ||
41 | def __init__(self, menuItemName): | |
42 | self.menuItemName = menuItemName | |
43 | self.id = 0 | |
44 | self.menuItemDesc = '' | |
45 | self.command = '' | |
46 | self.commandPreArgs = '' | |
47 | self.commandPostArgs = '' | |
48 | self.fileExt = None | |
49 | ||
50 | ||
51 | class ExtensionService(wx.lib.pydocview.DocService): | |
52 | ||
53 | ||
54 | def __init__(self): | |
55 | self.LoadExtensions() | |
56 | ||
57 | ||
58 | def LoadExtensions(self): | |
59 | config = wx.ConfigBase_Get() | |
60 | pickledExtensions = config.Read(EXTENSIONS_CONFIG_STRING) | |
61 | if pickledExtensions: | |
62 | try: | |
63 | self._extensions = pickle.loads(pickledExtensions.encode('ascii')) | |
64 | except: | |
65 | tp, val, tb = sys.exc_info() | |
66 | traceback.print_exception(tp,val,tb) | |
67 | self._extensions = [] | |
68 | else: | |
69 | self._extensions = [] | |
70 | ||
71 | ||
72 | def SaveExtensions(self): | |
73 | config = wx.ConfigBase_Get() | |
74 | config.Write(EXTENSIONS_CONFIG_STRING, pickle.dumps(self._extensions)) | |
75 | ||
76 | ||
77 | def GetExtensions(self): | |
78 | return self._extensions | |
79 | ||
80 | ||
81 | def SetExtensions(self, extensions): | |
82 | self._extensions = extensions | |
83 | ||
84 | ||
85 | def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None): | |
86 | toolsMenuIndex = menuBar.FindMenu(_("&Tools")) | |
87 | if toolsMenuIndex > -1: | |
88 | toolsMenu = menuBar.GetMenu(toolsMenuIndex) | |
89 | else: | |
90 | toolsMenu = wx.Menu() | |
91 | ||
92 | if self._extensions: | |
93 | if toolsMenu.GetMenuItems(): | |
94 | toolsMenu.AppendSeparator() | |
95 | for ext in self._extensions: | |
96 | # Append a tool menu item for each extension | |
97 | ext.id = wx.NewId() | |
98 | toolsMenu.Append(ext.id, ext.menuItemName) | |
99 | wx.EVT_MENU(frame, ext.id, frame.ProcessEvent) | |
100 | wx.EVT_UPDATE_UI(frame, ext.id, frame.ProcessUpdateUIEvent) | |
101 | ||
102 | if toolsMenuIndex == -1: | |
103 | formatMenuIndex = menuBar.FindMenu(_("&Format")) | |
104 | menuBar.Insert(formatMenuIndex + 1, toolsMenu, _("&Tools")) | |
105 | ||
106 | def ProcessEvent(self, event): | |
107 | id = event.GetId() | |
108 | for extension in self._extensions: | |
109 | if id == extension.id: | |
110 | self.OnExecuteExtension(extension) | |
111 | return True | |
112 | return False | |
113 | ||
114 | ||
115 | def ProcessUpdateUIEvent(self, event): | |
116 | id = event.GetId() | |
117 | for extension in self._extensions: | |
118 | if id == extension.id: | |
119 | if extension.fileExt: | |
120 | doc = wx.GetApp().GetDocumentManager().GetCurrentDocument() | |
121 | if doc and '*' in extension.fileExt: | |
122 | event.Enable(True) | |
123 | return True | |
124 | if doc: | |
125 | for fileExt in extension.fileExt: | |
126 | if fileExt in doc.GetDocumentTemplate().GetFileFilter(): | |
127 | event.Enable(True) | |
128 | return True | |
129 | event.Enable(False) | |
130 | return False | |
131 | return False | |
132 | ||
133 | ||
134 | def OnExecuteExtension(self, extension): | |
135 | if extension.fileExt: | |
136 | doc = wx.GetApp().GetDocumentManager().GetCurrentDocument() | |
137 | if not doc: | |
138 | return | |
139 | filename = doc.GetFilename() | |
140 | ext = os.path.splitext(filename)[1] | |
141 | if not '*' in extension.fileExt: | |
142 | if not ext or ext[1:] not in extension.fileExt: | |
143 | return | |
144 | cmds = [extension.command] | |
145 | if extension.commandPreArgs: | |
146 | cmds.append(extension.commandPreArgs) | |
147 | cmds.append(filename) | |
148 | if extension.commandPostArgs: | |
149 | cmds.append(extension.commandPostArgs) | |
150 | os.spawnv(os.P_NOWAIT, extension.command, cmds) | |
151 | ||
152 | else: | |
153 | cmd = extension.command | |
154 | if extension.commandPreArgs: | |
155 | cmd = cmd + ' ' + extension.commandPreArgs | |
156 | if extension.commandPostArgs: | |
157 | cmd = cmd + ' ' + extension.commandPostArgs | |
158 | f = os.popen(cmd) | |
159 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
160 | messageService.ShowWindow() | |
161 | view = messageService.GetView() | |
162 | for line in f.readlines(): | |
163 | view.AddLines(line) | |
164 | view.GetControl().EnsureCaretVisible() | |
165 | f.close() | |
166 | ||
167 | ||
168 | class ExtensionOptionsPanel(wx.Panel): | |
169 | ||
170 | ||
171 | def __init__(self, parent, id): | |
172 | wx.Panel.__init__(self, parent, id) | |
173 | ||
174 | extOptionsPanelBorderSizer = wx.BoxSizer(wx.HORIZONTAL) | |
175 | ||
176 | extOptionsPanelSizer = wx.FlexGridSizer(cols=2, hgap=SPACE, vgap=HALF_SPACE) | |
177 | ||
178 | extCtrlSizer = wx.BoxSizer(wx.VERTICAL) | |
179 | extCtrlSizer.Add(wx.StaticText(self, -1, _("Extensions:")), 0) | |
180 | self._extListBox = wx.ListBox(self, -1, size=(-1,185), style=wx.LB_SINGLE) | |
181 | self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self._extListBox) | |
182 | extCtrlSizer.Add(self._extListBox, 1, wx.TOP | wx.BOTTOM | wx.EXPAND, SPACE) | |
183 | buttonSizer = wx.GridSizer(rows=1, hgap=10, vgap=5) | |
184 | self._moveUpButton = wx.Button(self, -1, _("Move Up")) | |
185 | self.Bind(wx.EVT_BUTTON, self.OnMoveUp, self._moveUpButton) | |
186 | buttonSizer.Add(self._moveUpButton, 0) | |
187 | self._moveDownButton = wx.Button(self, -1, _("Move Down")) | |
188 | self.Bind(wx.EVT_BUTTON, self.OnMoveDown, self._moveDownButton) | |
189 | buttonSizer.Add(self._moveDownButton, 0) | |
190 | extCtrlSizer.Add(buttonSizer, 0, wx.ALIGN_CENTER | wx.BOTTOM, HALF_SPACE) | |
191 | buttonSizer = wx.GridSizer(rows=1, hgap=10, vgap=5) | |
192 | self._addButton = wx.Button(self, -1, _("Add")) | |
193 | self.Bind(wx.EVT_BUTTON, self.OnAdd, self._addButton) | |
194 | buttonSizer.Add(self._addButton, 0) | |
195 | self._deleteButton = wx.Button(self, wx.ID_DELETE) | |
196 | self.Bind(wx.EVT_BUTTON, self.OnDelete, self._deleteButton) | |
197 | buttonSizer.Add(self._deleteButton, 0) | |
198 | extCtrlSizer.Add(buttonSizer, 0, wx.ALIGN_CENTER) | |
199 | extOptionsPanelSizer.Add(extCtrlSizer, 0) | |
200 | ||
201 | self._extDetailPanel = wx.Panel(self) | |
202 | staticBox = wx.StaticBox(self._extDetailPanel, label=_("Selected Extension")) | |
203 | staticBoxSizer = wx.StaticBoxSizer(staticBox) | |
204 | self._extDetailPanel.SetSizer(staticBoxSizer) | |
205 | extDetailSizer = wx.FlexGridSizer(cols=1, hgap=5, vgap=3) | |
206 | staticBoxSizer.AddSizer(extDetailSizer, 0, wx.ALL, 5) | |
207 | ||
208 | extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Name:"))) | |
209 | self._menuItemNameTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) | |
210 | extDetailSizer.Add(self._menuItemNameTextCtrl, 1, wx.EXPAND) | |
211 | self.Bind(wx.EVT_TEXT, self.SaveCurrentItem, self._menuItemNameTextCtrl) | |
212 | ||
213 | extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Description:"))) | |
214 | self._menuItemDescTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) | |
215 | extDetailSizer.Add(self._menuItemDescTextCtrl, 1, wx.EXPAND) | |
216 | ||
217 | extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Path:"))) | |
218 | self._commandTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) | |
219 | findFileButton = wx.Button(self._extDetailPanel, -1, _("Browse...")) | |
220 | def OnBrowseButton(event): | |
221 | fileDlg = wx.FileDialog(self, _("Choose an Executable:"), style=wx.OPEN | wx.HIDE_READONLY) | |
222 | path = self._commandTextCtrl.GetValue() | |
223 | if path: | |
224 | fileDlg.SetPath(path) | |
225 | if fileDlg.ShowModal() == wx.ID_OK: | |
226 | self._commandTextCtrl.SetValue(fileDlg.GetPath()) | |
227 | self._commandTextCtrl.SetInsertionPointEnd() | |
228 | fileDlg.Destroy() | |
229 | wx.EVT_BUTTON(findFileButton, -1, OnBrowseButton) | |
230 | hsizer = wx.BoxSizer(wx.HORIZONTAL) | |
231 | hsizer.Add(self._commandTextCtrl, 1, wx.EXPAND) | |
232 | hsizer.Add(findFileButton, 0, wx.LEFT, HALF_SPACE) | |
233 | extDetailSizer.Add(hsizer, 0) | |
234 | ||
235 | extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Pre Arguments:"))) | |
236 | self._commandPreArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) | |
237 | extDetailSizer.Add(self._commandPreArgsTextCtrl, 1, wx.EXPAND) | |
238 | ||
239 | extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Post Arguments:"))) | |
240 | self._commandPostArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) | |
241 | extDetailSizer.Add(self._commandPostArgsTextCtrl, 1, wx.EXPAND) | |
242 | ||
243 | extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("File Extensions (Comma Separated):"))) | |
244 | self._fileExtTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) | |
245 | self._fileExtTextCtrl.SetToolTipString(_("""For example: "txt, text" or "*" for all files""")) | |
246 | extDetailSizer.Add(self._fileExtTextCtrl, 1, wx.EXPAND) | |
247 | ||
248 | extOptionsPanelSizer.Add(self._extDetailPanel, 0) | |
249 | ||
250 | extOptionsPanelBorderSizer.Add(extOptionsPanelSizer, 0, wx.ALL | wx.EXPAND, SPACE) | |
251 | self.SetSizer(extOptionsPanelBorderSizer) | |
252 | self.Layout() | |
253 | parent.AddPage(self, _("Extensions")) | |
254 | ||
255 | if self.PopulateItems(): | |
256 | self._extListBox.SetSelection(0) | |
257 | self.OnListBoxSelect(None) | |
258 | ||
259 | ||
260 | def OnOK(self, optionsDialog): | |
261 | self.SaveCurrentItem() | |
262 | extensionsService = wx.GetApp().GetService(ExtensionService) | |
263 | oldExtensions = extensionsService.GetExtensions() | |
264 | extensionsService.SetExtensions(self._extensions) | |
265 | extensionsService.SaveExtensions() | |
266 | if oldExtensions.__repr__() != self._extensions.__repr__(): | |
267 | msgTitle = wx.GetApp().GetAppName() | |
268 | if not msgTitle: | |
269 | msgTitle = _("Document Options") | |
270 | wx.MessageBox(_("Extension changes will not appear until the application is restarted."), | |
271 | msgTitle, | |
272 | wx.OK | wx.ICON_INFORMATION, | |
273 | self.GetParent()) | |
274 | ||
275 | ||
276 | def PopulateItems(self): | |
277 | extensionsService = wx.GetApp().GetService(ExtensionService) | |
278 | import copy | |
279 | self._extensions = copy.deepcopy(extensionsService.GetExtensions()) | |
280 | for extension in self._extensions: | |
281 | self._extListBox.Append(extension.menuItemName, extension) | |
282 | self._currentItem = None | |
283 | self._currentItemIndex = -1 | |
284 | return len(self._extensions) | |
285 | ||
286 | ||
287 | def OnListBoxSelect(self, event): | |
288 | self.SaveCurrentItem() | |
289 | if not self._extListBox.GetSelections(): | |
290 | self._currentItemIndex = -1 | |
291 | self._currentItem = None | |
292 | self._deleteButton.Enable(False) | |
293 | self._moveUpButton.Enable(False) | |
294 | self._moveDownButton.Enable(False) | |
295 | else: | |
296 | self._currentItemIndex = self._extListBox.GetSelection() | |
297 | self._currentItem = self._extListBox.GetClientData(self._currentItemIndex) | |
298 | self._deleteButton.Enable() | |
299 | self._moveUpButton.Enable(self._extListBox.GetCount() > 1 and self._currentItemIndex > 0) | |
300 | self._moveDownButton.Enable(self._extListBox.GetCount() > 1 and self._currentItemIndex < self._extListBox.GetCount() - 1) | |
301 | self.LoadItem(self._currentItem) | |
302 | ||
303 | ||
304 | def SaveCurrentItem(self, event=None): | |
305 | extension = self._currentItem | |
306 | if extension: | |
307 | if extension.menuItemName != self._menuItemNameTextCtrl.GetValue(): | |
308 | extension.menuItemName = self._menuItemNameTextCtrl.GetValue() | |
309 | self._extListBox.SetString(self._currentItemIndex, extension.menuItemName) | |
310 | extension.menuItemDesc = self._menuItemDescTextCtrl.GetValue() | |
311 | extension.command = self._commandTextCtrl.GetValue() | |
312 | extension.commandPreArgs = self._commandPreArgsTextCtrl.GetValue() | |
313 | extension.commandPostArgs = self._commandPostArgsTextCtrl.GetValue() | |
314 | fileExt = self._fileExtTextCtrl.GetValue().replace(' ','') | |
315 | if not fileExt: | |
316 | extension.fileExt = None | |
317 | else: | |
318 | extension.fileExt = fileExt.split(',') | |
319 | ||
320 | ||
321 | def LoadItem(self, extension): | |
322 | if extension: | |
323 | self._menuItemDescTextCtrl.SetValue(extension.menuItemDesc or '') | |
324 | self._commandTextCtrl.SetValue(extension.command or '') | |
325 | self._commandPreArgsTextCtrl.SetValue(extension.commandPreArgs or '') | |
326 | self._commandPostArgsTextCtrl.SetValue(extension.commandPostArgs or '') | |
327 | if extension.fileExt: | |
328 | self._fileExtTextCtrl.SetValue(extension.fileExt.__repr__()[1:-1].replace("'","")) # Make the list a string, strip the brakcet on either side | |
329 | else: | |
330 | self._fileExtTextCtrl.SetValue('') | |
331 | self._menuItemNameTextCtrl.SetValue(extension.menuItemName or '') # Do the name last since it triggers the write event that updates the entire item | |
332 | self._extDetailPanel.Enable() | |
333 | else: | |
334 | self._menuItemNameTextCtrl.SetValue('') | |
335 | self._menuItemDescTextCtrl.SetValue('') | |
336 | self._commandTextCtrl.SetValue('') | |
337 | self._commandPreArgsTextCtrl.SetValue('') | |
338 | self._commandPostArgsTextCtrl.SetValue('') | |
339 | self._fileExtTextCtrl.SetValue('') | |
340 | self._extDetailPanel.Enable(False) | |
341 | ||
342 | ||
343 | def OnAdd(self, event): | |
344 | self.SaveCurrentItem() | |
345 | extensionNames = map(lambda extension: extension.menuItemName, self._extensions) | |
346 | name = _("Untitled") | |
347 | count = 1 | |
348 | while name in extensionNames: | |
349 | count = count + 1 | |
350 | name = _("Untitled %s") % count | |
351 | extension = Extension(name) | |
352 | self._extensions.append(extension) | |
353 | self._extListBox.Append(extension.menuItemName, extension) | |
354 | self._extListBox.SetSelection(self._extListBox.GetCount() - 1) | |
355 | self.OnListBoxSelect(None) | |
356 | self._menuItemNameTextCtrl.SetFocus() | |
357 | self._menuItemNameTextCtrl.SetSelection(-1, -1) | |
358 | ||
359 | ||
360 | def OnDelete(self, event): | |
361 | self._extListBox.Delete(self._currentItemIndex) | |
362 | self._extensions.remove(self._currentItem) | |
363 | self._currentItemIndex = min(self._currentItemIndex, self._extListBox.GetCount() - 1) | |
364 | if self._currentItemIndex > -1: | |
365 | self._extListBox.SetSelection(self._currentItemIndex) | |
366 | self._currentItem = None # Don't update it since it no longer exists | |
367 | self.OnListBoxSelect(None) | |
368 | ||
369 | ||
370 | def OnMoveUp(self, event): | |
371 | itemAboveString = self._extListBox.GetString(self._currentItemIndex - 1) | |
372 | itemAboveData = self._extListBox.GetClientData(self._currentItemIndex - 1) | |
373 | self._extListBox.Delete(self._currentItemIndex - 1) | |
374 | self._extListBox.Insert(itemAboveString, self._currentItemIndex) | |
375 | self._extListBox.SetClientData(self._currentItemIndex, itemAboveData) | |
376 | self._currentItemIndex = self._currentItemIndex - 1 | |
377 | self.OnListBoxSelect(None) # Reset buttons | |
378 | ||
379 | ||
380 | def OnMoveDown(self, event): | |
381 | itemBelowString = self._extListBox.GetString(self._currentItemIndex + 1) | |
382 | itemBelowData = self._extListBox.GetClientData(self._currentItemIndex + 1) | |
383 | self._extListBox.Delete(self._currentItemIndex + 1) | |
384 | self._extListBox.Insert(itemBelowString, self._currentItemIndex) | |
385 | self._extListBox.SetClientData(self._currentItemIndex, itemBelowData) | |
386 | self._currentItemIndex = self._currentItemIndex + 1 | |
387 | self.OnListBoxSelect(None) # Reset buttons |