1 #----------------------------------------------------------------------------
2 # Name: ExtensionService.py
3 # Purpose: Extension Service for IDE
9 # Copyright: (c) 2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
14 import wx
.lib
.pydocview
27 EXTENSIONS_CONFIG_STRING
= "Extensions"
31 # TODO: Redo extensions menu on OK, or provide alert that it won't happen until restart
34 #----------------------------------------------------------------------------
36 #----------------------------------------------------------------------------
41 def __init__(self
, menuItemName
):
42 self
.menuItemName
= menuItemName
44 self
.menuItemDesc
= ''
46 self
.commandPreArgs
= ''
47 self
.commandPostArgs
= ''
51 class ExtensionService(wx
.lib
.pydocview
.DocService
):
58 def LoadExtensions(self
):
59 config
= wx
.ConfigBase_Get()
60 pickledExtensions
= config
.Read(EXTENSIONS_CONFIG_STRING
)
63 self
._extensions
= pickle
.loads(pickledExtensions
.encode('ascii'))
65 tp
, val
, tb
= sys
.exc_info()
66 traceback
.print_exception(tp
,val
,tb
)
72 def SaveExtensions(self
):
73 config
= wx
.ConfigBase_Get()
74 config
.Write(EXTENSIONS_CONFIG_STRING
, pickle
.dumps(self
._extensions
))
77 def GetExtensions(self
):
78 return self
._extensions
81 def SetExtensions(self
, extensions
):
82 self
._extensions
= extensions
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
)
93 if toolsMenu
.GetMenuItems():
94 toolsMenu
.AppendSeparator()
95 for ext
in self
._extensions
:
96 # Append a tool menu item for each extension
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
)
102 if toolsMenuIndex
== -1:
103 formatMenuIndex
= menuBar
.FindMenu(_("&Format"))
104 menuBar
.Insert(formatMenuIndex
+ 1, toolsMenu
, _("&Tools"))
106 def ProcessEvent(self
, event
):
108 for extension
in self
._extensions
:
109 if id == extension
.id:
110 self
.OnExecuteExtension(extension
)
115 def ProcessUpdateUIEvent(self
, event
):
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
:
125 for fileExt
in extension
.fileExt
:
126 if fileExt
in doc
.GetDocumentTemplate().GetFileFilter():
134 def OnExecuteExtension(self
, extension
):
135 if extension
.fileExt
:
136 doc
= wx
.GetApp().GetDocumentManager().GetCurrentDocument()
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
:
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
)
153 cmd
= extension
.command
154 if extension
.commandPreArgs
:
155 cmd
= cmd
+ ' ' + extension
.commandPreArgs
156 if extension
.commandPostArgs
:
157 cmd
= cmd
+ ' ' + extension
.commandPostArgs
159 messageService
= wx
.GetApp().GetService(MessageService
.MessageService
)
160 messageService
.ShowWindow()
161 view
= messageService
.GetView()
162 for line
in f
.readlines():
164 view
.GetControl().EnsureCaretVisible()
168 class ExtensionOptionsPanel(wx
.Panel
):
171 def __init__(self
, parent
, id):
172 wx
.Panel
.__init
__(self
, parent
, id)
174 extOptionsPanelBorderSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
176 extOptionsPanelSizer
= wx
.FlexGridSizer(cols
=2, hgap
=SPACE
, vgap
=HALF_SPACE
)
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)
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)
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
)
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
)
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()
224 fileDlg
.SetPath(path
)
225 if fileDlg
.ShowModal() == wx
.ID_OK
:
226 self
._commandTextCtrl
.SetValue(fileDlg
.GetPath())
227 self
._commandTextCtrl
.SetInsertionPointEnd()
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)
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
)
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
)
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
)
248 extOptionsPanelSizer
.Add(self
._extDetailPanel
, 0)
250 extOptionsPanelBorderSizer
.Add(extOptionsPanelSizer
, 0, wx
.ALL | wx
.EXPAND
, SPACE
)
251 self
.SetSizer(extOptionsPanelBorderSizer
)
253 parent
.AddPage(self
, _("Extensions"))
255 if self
.PopulateItems():
256 self
._extListBox
.SetSelection(0)
257 self
.OnListBoxSelect(None)
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()
269 msgTitle
= _("Document Options")
270 wx
.MessageBox(_("Extension changes will not appear until the application is restarted."),
272 wx
.OK | wx
.ICON_INFORMATION
,
276 def PopulateItems(self
):
277 extensionsService
= wx
.GetApp().GetService(ExtensionService
)
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
)
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)
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
)
304 def SaveCurrentItem(self
, event
=None):
305 extension
= self
._currentItem
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(' ','')
316 extension
.fileExt
= None
318 extension
.fileExt
= fileExt
.split(',')
321 def LoadItem(self
, 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
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()
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)
343 def OnAdd(self
, event
):
344 self
.SaveCurrentItem()
345 extensionNames
= map(lambda extension
: extension
.menuItemName
, self
._extensions
)
348 while name
in extensionNames
:
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)
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)
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
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