]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/editor.py
Aquire the GIL before raising the NotImplementedError exception
[wxWidgets.git] / wxPython / wx / py / editor.py
1 """PyAlaCarte and PyAlaMode editors."""
2
3 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
4 __cvsid__ = "$Id$"
5 __revision__ = "$Revision$"[11:-2]
6
7 import wx
8
9 from buffer import Buffer
10 import crust
11 import dispatcher
12 import editwindow
13 import frame
14 from shell import Shell
15 import version
16
17 try:
18 True
19 except NameError:
20 True = 1==1
21 False = 1==0
22
23
24 class EditorFrame(frame.Frame):
25 """Frame containing one editor."""
26
27 def __init__(self, parent=None, id=-1, title='PyAlaCarte',
28 pos=wx.DefaultPosition, size=(800, 600),
29 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
30 filename=None):
31 """Create EditorFrame instance."""
32 frame.Frame.__init__(self, parent, id, title, pos, size, style)
33 self.buffers = {}
34 self.buffer = None # Current buffer.
35 self.editor = None
36 self._defaultText = title + ' - the tastiest Python editor.'
37 self._statusText = self._defaultText
38 self.SetStatusText(self._statusText)
39 wx.EVT_IDLE(self, self.OnIdle)
40 self._setup()
41 if filename:
42 self.bufferCreate(filename)
43
44 def _setup(self):
45 """Setup prior to first buffer creation.
46
47 Useful for subclasses."""
48 pass
49
50 def setEditor(self, editor):
51 self.editor = editor
52 self.buffer = self.editor.buffer
53 self.buffers[self.buffer.id] = self.buffer
54
55 def OnAbout(self, event):
56 """Display an About window."""
57 title = 'About PyAlaCarte'
58 text = 'Another fine, flaky program.'
59 dialog = wx.MessageDialog(self, text, title,
60 wx.OK | wx.ICON_INFORMATION)
61 dialog.ShowModal()
62 dialog.Destroy()
63
64 def OnClose(self, event):
65 """Event handler for closing."""
66 for buffer in self.buffers.values():
67 self.buffer = buffer
68 if buffer.hasChanged():
69 cancel = self.bufferSuggestSave()
70 if cancel and event.CanVeto():
71 event.Veto()
72 return
73 self.Destroy()
74
75 def OnIdle(self, event):
76 """Event handler for idle time."""
77 self._updateStatus()
78 if hasattr(self, 'notebook'):
79 self._updateTabText()
80 self._updateTitle()
81 event.Skip()
82
83 def _updateStatus(self):
84 """Show current status information."""
85 if self.editor and hasattr(self.editor, 'getStatus'):
86 status = self.editor.getStatus()
87 text = 'File: %s | Line: %d | Column: %d' % status
88 else:
89 text = self._defaultText
90 if text != self._statusText:
91 self.SetStatusText(text)
92 self._statusText = text
93
94 def _updateTabText(self):
95 """Show current buffer information on notebook tab."""
96 ## suffix = ' **'
97 ## notebook = self.notebook
98 ## selection = notebook.GetSelection()
99 ## if selection == -1:
100 ## return
101 ## text = notebook.GetPageText(selection)
102 ## window = notebook.GetPage(selection)
103 ## if window.editor and window.editor.buffer.hasChanged():
104 ## if text.endswith(suffix):
105 ## pass
106 ## else:
107 ## notebook.SetPageText(selection, text + suffix)
108 ## else:
109 ## if text.endswith(suffix):
110 ## notebook.SetPageText(selection, text[:len(suffix)])
111
112 def _updateTitle(self):
113 """Show current title information."""
114 title = self.GetTitle()
115 if self.bufferHasChanged():
116 if title.startswith('* '):
117 pass
118 else:
119 self.SetTitle('* ' + title)
120 else:
121 if title.startswith('* '):
122 self.SetTitle(title[2:])
123
124 def hasBuffer(self):
125 """Return True if there is a current buffer."""
126 if self.buffer:
127 return True
128 else:
129 return False
130
131 def bufferClose(self):
132 """Close buffer."""
133 if self.bufferHasChanged():
134 cancel = self.bufferSuggestSave()
135 if cancel:
136 return cancel
137 self.bufferDestroy()
138 cancel = False
139 return cancel
140
141 def bufferCreate(self, filename=None):
142 """Create new buffer."""
143 self.bufferDestroy()
144 buffer = Buffer()
145 self.panel = panel = wx.Panel(parent=self, id=-1)
146 wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
147 editor = Editor(parent=panel)
148 panel.editor = editor
149 sizer = wx.BoxSizer(wx.VERTICAL)
150 sizer.Add(editor.window, 1, wx.EXPAND)
151 panel.SetSizer(sizer)
152 panel.SetAutoLayout(True)
153 sizer.Layout()
154 buffer.addEditor(editor)
155 buffer.open(filename)
156 self.setEditor(editor)
157 self.editor.setFocus()
158 self.SendSizeEvent()
159
160
161 def bufferDestroy(self):
162 """Destroy the current buffer."""
163 if self.buffer:
164 for editor in self.buffer.editors.values():
165 editor.destroy()
166 self.editor = None
167 del self.buffers[self.buffer.id]
168 self.buffer = None
169 self.panel.Destroy()
170
171
172 def bufferHasChanged(self):
173 """Return True if buffer has changed since last save."""
174 if self.buffer:
175 return self.buffer.hasChanged()
176 else:
177 return False
178
179 def bufferNew(self):
180 """Create new buffer."""
181 if self.bufferHasChanged():
182 cancel = self.bufferSuggestSave()
183 if cancel:
184 return cancel
185 self.bufferCreate()
186 cancel = False
187 return cancel
188
189 def bufferOpen(self):
190 """Open file in buffer."""
191 if self.bufferHasChanged():
192 cancel = self.bufferSuggestSave()
193 if cancel:
194 return cancel
195 filedir = ''
196 if self.buffer and self.buffer.doc.filedir:
197 filedir = self.buffer.doc.filedir
198 result = openSingle(directory=filedir)
199 if result.path:
200 self.bufferCreate(result.path)
201 cancel = False
202 return cancel
203
204 ## def bufferPrint(self):
205 ## """Print buffer."""
206 ## pass
207
208 ## def bufferRevert(self):
209 ## """Revert buffer to version of file on disk."""
210 ## pass
211
212 def bufferSave(self):
213 """Save buffer to its file."""
214 if self.buffer.doc.filepath:
215 self.buffer.save()
216 cancel = False
217 else:
218 cancel = self.bufferSaveAs()
219 return cancel
220
221 def bufferSaveAs(self):
222 """Save buffer to a new filename."""
223 if self.bufferHasChanged() and self.buffer.doc.filepath:
224 cancel = self.bufferSuggestSave()
225 if cancel:
226 return cancel
227 filedir = ''
228 if self.buffer and self.buffer.doc.filedir:
229 filedir = self.buffer.doc.filedir
230 result = saveSingle(directory=filedir)
231 if result.path:
232 self.buffer.saveAs(result.path)
233 cancel = False
234 else:
235 cancel = True
236 return cancel
237
238 def bufferSuggestSave(self):
239 """Suggest saving changes. Return True if user selected Cancel."""
240 result = messageDialog(parent=None,
241 message='%s has changed.\n'
242 'Would you like to save it first'
243 '?' % self.buffer.name,
244 title='Save current file?')
245 if result.positive:
246 cancel = self.bufferSave()
247 else:
248 cancel = result.text == 'Cancel'
249 return cancel
250
251 def updateNamespace(self):
252 """Update the buffer namespace for autocompletion and calltips."""
253 if self.buffer.updateNamespace():
254 self.SetStatusText('Namespace updated')
255 else:
256 self.SetStatusText('Error executing, unable to update namespace')
257
258
259 class EditorNotebookFrame(EditorFrame):
260 """Frame containing one or more editors in a notebook."""
261
262 def __init__(self, parent=None, id=-1, title='PyAlaMode',
263 pos=wx.DefaultPosition, size=(800, 600),
264 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
265 filename=None):
266 """Create EditorNotebookFrame instance."""
267 self.notebook = None
268 EditorFrame.__init__(self, parent, id, title, pos,
269 size, style, filename)
270 if self.notebook:
271 dispatcher.connect(receiver=self._editorChange,
272 signal='EditorChange', sender=self.notebook)
273
274 def _setup(self):
275 """Setup prior to first buffer creation.
276
277 Called automatically by base class during init."""
278 self.notebook = EditorNotebook(parent=self)
279 intro = 'Py %s' % version.VERSION
280 import imp
281 module = imp.new_module('__main__')
282 import __builtin__
283 module.__dict__['__builtins__'] = __builtin__
284 namespace = module.__dict__.copy()
285 self.crust = crust.Crust(parent=self.notebook, intro=intro, locals=namespace)
286 self.shell = self.crust.shell
287 # Override the filling so that status messages go to the status bar.
288 self.crust.filling.tree.setStatusText = self.SetStatusText
289 # Override the shell so that status messages go to the status bar.
290 self.shell.setStatusText = self.SetStatusText
291 # Fix a problem with the sash shrinking to nothing.
292 self.crust.filling.SetSashPosition(200)
293 self.notebook.AddPage(page=self.crust, text='*Shell*', select=True)
294 self.setEditor(self.crust.editor)
295 self.crust.editor.SetFocus()
296
297 def _editorChange(self, editor):
298 """Editor change signal receiver."""
299 self.setEditor(editor)
300
301 def OnAbout(self, event):
302 """Display an About window."""
303 title = 'About PyAlaMode'
304 text = 'Another fine, flaky program.'
305 dialog = wx.MessageDialog(self, text, title,
306 wx.OK | wx.ICON_INFORMATION)
307 dialog.ShowModal()
308 dialog.Destroy()
309
310 def _updateTitle(self):
311 """Show current title information."""
312 pass
313 ## title = self.GetTitle()
314 ## if self.bufferHasChanged():
315 ## if title.startswith('* '):
316 ## pass
317 ## else:
318 ## self.SetTitle('* ' + title)
319 ## else:
320 ## if title.startswith('* '):
321 ## self.SetTitle(title[2:])
322
323 def bufferCreate(self, filename=None):
324 """Create new buffer."""
325 buffer = Buffer()
326 panel = wx.Panel(parent=self.notebook, id=-1)
327 wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
328 editor = Editor(parent=panel)
329 panel.editor = editor
330 sizer = wx.BoxSizer(wx.VERTICAL)
331 sizer.Add(editor.window, 1, wx.EXPAND)
332 panel.SetSizer(sizer)
333 panel.SetAutoLayout(True)
334 sizer.Layout()
335 buffer.addEditor(editor)
336 buffer.open(filename)
337 self.setEditor(editor)
338 self.notebook.AddPage(page=panel, text=self.buffer.name, select=True)
339 self.editor.setFocus()
340
341 def bufferDestroy(self):
342 """Destroy the current buffer."""
343 selection = self.notebook.GetSelection()
344 ## print "Destroy Selection:", selection
345 if selection > 0: # Don't destroy the PyCrust tab.
346 if self.buffer:
347 del self.buffers[self.buffer.id]
348 self.buffer = None # Do this before DeletePage().
349 self.notebook.DeletePage(selection)
350
351 def bufferNew(self):
352 """Create new buffer."""
353 self.bufferCreate()
354 cancel = False
355 return cancel
356
357 def bufferOpen(self):
358 """Open file in buffer."""
359 filedir = ''
360 if self.buffer and self.buffer.doc.filedir:
361 filedir = self.buffer.doc.filedir
362 result = openMultiple(directory=filedir)
363 for path in result.paths:
364 self.bufferCreate(path)
365 cancel = False
366 return cancel
367
368
369 class EditorNotebook(wx.Notebook):
370 """A notebook containing a page for each editor."""
371
372 def __init__(self, parent):
373 """Create EditorNotebook instance."""
374 wx.Notebook.__init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE)
375 wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(),
376 self.OnPageChanging)
377 wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(),
378 self.OnPageChanged)
379 wx.EVT_IDLE(self, self.OnIdle)
380
381 def OnIdle(self, event):
382 """Event handler for idle time."""
383 self._updateTabText()
384 event.Skip()
385
386 def _updateTabText(self):
387 """Show current buffer display name on all but first tab."""
388 size = 3
389 changed = ' **'
390 unchanged = ' --'
391 selection = self.GetSelection()
392 if selection < 1:
393 return
394 text = self.GetPageText(selection)
395 window = self.GetPage(selection)
396 if not window.editor:
397 return
398 if text.endswith(changed) or text.endswith(unchanged):
399 name = text[:-size]
400 else:
401 name = text
402 if name != window.editor.buffer.name:
403 text = window.editor.buffer.name
404 if window.editor.buffer.hasChanged():
405 if text.endswith(changed):
406 text = None
407 elif text.endswith(unchanged):
408 text = text[:-size] + changed
409 else:
410 text += changed
411 else:
412 if text.endswith(changed):
413 text = text[:-size] + unchanged
414 elif text.endswith(unchanged):
415 text = None
416 else:
417 text += unchanged
418 if text is not None:
419 self.SetPageText(selection, text)
420 self.Refresh() # Needed on Win98.
421
422 def OnPageChanging(self, event):
423 """Page changing event handler."""
424 event.Skip()
425
426 def OnPageChanged(self, event):
427 """Page changed event handler."""
428 new = event.GetSelection()
429 window = self.GetPage(new)
430 dispatcher.send(signal='EditorChange', sender=self,
431 editor=window.editor)
432 window.SetFocus()
433 event.Skip()
434
435
436 class EditorShellNotebookFrame(EditorNotebookFrame):
437 """Frame containing a notebook containing EditorShellNotebooks."""
438
439 def __init__(self, parent=None, id=-1, title='PyAlaModeTest',
440 pos=wx.DefaultPosition, size=(600, 400),
441 style=wx.DEFAULT_FRAME_STYLE,
442 filename=None, singlefile=False):
443 """Create EditorShellNotebookFrame instance."""
444 self._singlefile = singlefile
445 EditorNotebookFrame.__init__(self, parent, id, title, pos,
446 size, style, filename)
447
448 def _setup(self):
449 """Setup prior to first buffer creation.
450
451 Called automatically by base class during init."""
452 if not self._singlefile:
453 self.notebook = EditorNotebook(parent=self)
454
455 def OnAbout(self, event):
456 """Display an About window."""
457 title = 'About PyAlaModePlus'
458 text = 'Another fine, flaky program.'
459 dialog = wx.MessageDialog(self, text, title,
460 wx.OK | wx.ICON_INFORMATION)
461 dialog.ShowModal()
462 dialog.Destroy()
463
464 def bufferCreate(self, filename=None):
465 """Create new buffer."""
466 if self._singlefile:
467 self.bufferDestroy()
468 notebook = EditorShellNotebook(parent=self,
469 filename=filename)
470 self.notebook = notebook
471 else:
472 notebook = EditorShellNotebook(parent=self.notebook,
473 filename=filename)
474 self.setEditor(notebook.editor)
475 if not self._singlefile:
476 self.notebook.AddPage(page=notebook, text=self.buffer.name,
477 select=True)
478 self.editor.setFocus()
479
480 def bufferDestroy(self):
481 """Destroy the current buffer."""
482 if self.buffer:
483 self.editor = None
484 del self.buffers[self.buffer.id]
485 self.buffer = None # Do this before DeletePage().
486 if self._singlefile:
487 self.notebook.Destroy()
488 self.notebook = None
489 else:
490 selection = self.notebook.GetSelection()
491 ## print "Destroy Selection:", selection
492 self.notebook.DeletePage(selection)
493
494 def bufferNew(self):
495 """Create new buffer."""
496 if self._singlefile and self.bufferHasChanged():
497 cancel = self.bufferSuggestSave()
498 if cancel:
499 return cancel
500 self.bufferCreate()
501 cancel = False
502 return cancel
503
504 def bufferOpen(self):
505 """Open file in buffer."""
506 if self._singlefile and self.bufferHasChanged():
507 cancel = self.bufferSuggestSave()
508 if cancel:
509 return cancel
510 filedir = ''
511 if self.buffer and self.buffer.doc.filedir:
512 filedir = self.buffer.doc.filedir
513 if self._singlefile:
514 result = openSingle(directory=filedir)
515 if result.path:
516 self.bufferCreate(result.path)
517 else:
518 result = openMultiple(directory=filedir)
519 for path in result.paths:
520 self.bufferCreate(path)
521 cancel = False
522 return cancel
523
524
525 class EditorShellNotebook(wx.Notebook):
526 """A notebook containing an editor page and a shell page."""
527
528 def __init__(self, parent, filename=None):
529 """Create EditorShellNotebook instance."""
530 wx.Notebook.__init__(self, parent, id=-1)
531 usePanels = True
532 if usePanels:
533 editorparent = editorpanel = wx.Panel(self, -1)
534 shellparent = shellpanel = wx.Panel(self, -1)
535 else:
536 editorparent = self
537 shellparent = self
538 self.buffer = Buffer()
539 self.editor = Editor(parent=editorparent)
540 self.buffer.addEditor(self.editor)
541 self.buffer.open(filename)
542 self.shell = Shell(parent=shellparent, locals=self.buffer.interp.locals,
543 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
544 self.buffer.interp.locals.clear()
545 if usePanels:
546 self.AddPage(page=editorpanel, text='Editor', select=True)
547 self.AddPage(page=shellpanel, text='Shell')
548 # Setup sizers
549 editorsizer = wx.BoxSizer(wx.VERTICAL)
550 editorsizer.Add(self.editor.window, 1, wx.EXPAND)
551 editorpanel.SetSizer(editorsizer)
552 editorpanel.SetAutoLayout(True)
553 shellsizer = wx.BoxSizer(wx.VERTICAL)
554 shellsizer.Add(self.shell, 1, wx.EXPAND)
555 shellpanel.SetSizer(shellsizer)
556 shellpanel.SetAutoLayout(True)
557 else:
558 self.AddPage(page=self.editor.window, text='Editor', select=True)
559 self.AddPage(page=self.shell, text='Shell')
560 self.editor.setFocus()
561 wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
562
563 def OnPageChanged(self, event):
564 """Page changed event handler."""
565 selection = event.GetSelection()
566 if selection == 0:
567 self.editor.setFocus()
568 else:
569 self.shell.SetFocus()
570 event.Skip()
571
572 def SetFocus(self):
573 wx.Notebook.SetFocus(self)
574 selection = self.GetSelection()
575 if selection == 0:
576 self.editor.setFocus()
577 else:
578 self.shell.SetFocus()
579
580
581 class Editor:
582 """Editor having an EditWindow."""
583
584 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
585 size=wx.DefaultSize,
586 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
587 """Create Editor instance."""
588 self.window = EditWindow(self, parent, id, pos, size, style)
589 self.id = self.window.GetId()
590 self.buffer = None
591 # Assign handlers for keyboard events.
592 wx.EVT_CHAR(self.window, self.OnChar)
593 wx.EVT_KEY_DOWN(self.window, self.OnKeyDown)
594
595 def _setBuffer(self, buffer, text):
596 """Set the editor to a buffer. Private callback called by buffer."""
597 self.buffer = buffer
598 self.autoCompleteKeys = buffer.interp.getAutoCompleteKeys()
599 self.clearAll()
600 self.setText(text)
601 self.emptyUndoBuffer()
602 self.setSavePoint()
603
604 def destroy(self):
605 """Destroy all editor objects."""
606 self.window.Destroy()
607
608 def clearAll(self):
609 self.window.ClearAll()
610
611 def emptyUndoBuffer(self):
612 self.window.EmptyUndoBuffer()
613
614 def getStatus(self):
615 """Return (filepath, line, column) status tuple."""
616 pos = self.window.GetCurrentPos()
617 line = self.window.LineFromPosition(pos) + 1
618 col = self.window.GetColumn(pos)
619 if self.buffer:
620 name = self.buffer.doc.filepath or self.buffer.name
621 else:
622 name = ''
623 status = (name, line, col)
624 return status
625
626 def getText(self):
627 """Return contents of editor."""
628 return self.window.GetText()
629
630 def hasChanged(self):
631 """Return True if contents have changed."""
632 return self.window.GetModify()
633
634 def setFocus(self):
635 """Set the input focus to the editor window."""
636 self.window.SetFocus()
637
638 def setSavePoint(self):
639 self.window.SetSavePoint()
640
641 def setText(self, text):
642 """Set contents of editor."""
643 self.window.SetText(text)
644
645 def OnChar(self, event):
646 """Keypress event handler.
647
648 Only receives an event if OnKeyDown calls event.Skip() for the
649 corresponding event."""
650
651 key = event.KeyCode()
652 if key in self.autoCompleteKeys:
653 # Usually the dot (period) key activates auto completion.
654 if self.window.AutoCompActive():
655 self.window.AutoCompCancel()
656 self.window.ReplaceSelection('')
657 self.window.AddText(chr(key))
658 text, pos = self.window.GetCurLine()
659 text = text[:pos]
660 if self.window.autoComplete:
661 self.autoCompleteShow(text)
662 elif key == ord('('):
663 # The left paren activates a call tip and cancels an
664 # active auto completion.
665 if self.window.AutoCompActive():
666 self.window.AutoCompCancel()
667 self.window.ReplaceSelection('')
668 self.window.AddText('(')
669 text, pos = self.window.GetCurLine()
670 text = text[:pos]
671 self.autoCallTipShow(text)
672 else:
673 # Allow the normal event handling to take place.
674 event.Skip()
675
676 def OnKeyDown(self, event):
677 """Key down event handler."""
678
679 key = event.KeyCode()
680 # If the auto-complete window is up let it do its thing.
681 if self.window.AutoCompActive():
682 event.Skip()
683 return
684 controlDown = event.ControlDown()
685 altDown = event.AltDown()
686 shiftDown = event.ShiftDown()
687 # Let Ctrl-Alt-* get handled normally.
688 if controlDown and altDown:
689 event.Skip()
690 # Increase font size.
691 elif controlDown and key in (ord(']'),):
692 dispatcher.send(signal='FontIncrease')
693 # Decrease font size.
694 elif controlDown and key in (ord('['),):
695 dispatcher.send(signal='FontDecrease')
696 # Default font size.
697 elif controlDown and key in (ord('='),):
698 dispatcher.send(signal='FontDefault')
699 else:
700 event.Skip()
701
702 def autoCompleteShow(self, command):
703 """Display auto-completion popup list."""
704 list = self.buffer.interp.getAutoCompleteList(command,
705 includeMagic=self.window.autoCompleteIncludeMagic,
706 includeSingle=self.window.autoCompleteIncludeSingle,
707 includeDouble=self.window.autoCompleteIncludeDouble)
708 if list:
709 options = ' '.join(list)
710 offset = 0
711 self.window.AutoCompShow(offset, options)
712
713 def autoCallTipShow(self, command):
714 """Display argument spec and docstring in a popup window."""
715 if self.window.CallTipActive():
716 self.window.CallTipCancel()
717 (name, argspec, tip) = self.buffer.interp.getCallTip(command)
718 if tip:
719 dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
720 if not self.window.autoCallTip:
721 return
722 if argspec:
723 startpos = self.window.GetCurrentPos()
724 self.window.AddText(argspec + ')')
725 endpos = self.window.GetCurrentPos()
726 self.window.SetSelection(endpos, startpos)
727 if tip:
728 curpos = self.window.GetCurrentPos()
729 size = len(name)
730 tippos = curpos - (size + 1)
731 fallback = curpos - self.window.GetColumn(curpos)
732 # In case there isn't enough room, only go back to the
733 # fallback.
734 tippos = max(tippos, fallback)
735 self.window.CallTipShow(tippos, tip)
736 self.window.CallTipSetHighlight(0, size)
737
738
739 class EditWindow(editwindow.EditWindow):
740 """EditWindow based on StyledTextCtrl."""
741
742 def __init__(self, editor, parent, id=-1, pos=wx.DefaultPosition,
743 size=wx.DefaultSize,
744 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
745 """Create EditWindow instance."""
746 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
747 self.editor = editor
748
749
750 class DialogResults:
751 """DialogResults class."""
752
753 def __init__(self, returned):
754 """Create wrapper for results returned by dialog."""
755 self.returned = returned
756 self.positive = returned in (wx.ID_OK, wx.ID_YES)
757 self.text = self._asString()
758
759
760 def __repr__(self):
761 return str(self.__dict__)
762
763 def _asString(self):
764 returned = self.returned
765 if returned == wx.ID_OK:
766 return "Ok"
767 elif returned == wx.ID_CANCEL:
768 return "Cancel"
769 elif returned == wx.ID_YES:
770 return "Yes"
771 elif returned == wx.ID_NO:
772 return "No"
773
774
775 def fileDialog(parent=None, title='Open', directory='', filename='',
776 wildcard='All Files (*.*)|*.*',
777 style=wx.OPEN | wx.MULTIPLE):
778 """File dialog wrapper function."""
779 dialog = wx.FileDialog(parent, title, directory, filename,
780 wildcard, style)
781 result = DialogResults(dialog.ShowModal())
782 if result.positive:
783 result.paths = dialog.GetPaths()
784 else:
785 result.paths = []
786 dialog.Destroy()
787 return result
788
789
790 def openSingle(parent=None, title='Open', directory='', filename='',
791 wildcard='All Files (*.*)|*.*', style=wx.OPEN):
792 """File dialog wrapper function."""
793 dialog = wx.FileDialog(parent, title, directory, filename,
794 wildcard, style)
795 result = DialogResults(dialog.ShowModal())
796 if result.positive:
797 result.path = dialog.GetPath()
798 else:
799 result.path = None
800 dialog.Destroy()
801 return result
802
803
804 def openMultiple(parent=None, title='Open', directory='', filename='',
805 wildcard='All Files (*.*)|*.*',
806 style=wx.OPEN | wx.MULTIPLE):
807 """File dialog wrapper function."""
808 return fileDialog(parent, title, directory, filename, wildcard, style)
809
810
811 def saveSingle(parent=None, title='Save', directory='', filename='',
812 wildcard='All Files (*.*)|*.*',
813 style=wx.SAVE | wx.HIDE_READONLY | wx.OVERWRITE_PROMPT):
814 """File dialog wrapper function."""
815 dialog = wx.FileDialog(parent, title, directory, filename,
816 wildcard, style)
817 result = DialogResults(dialog.ShowModal())
818 if result.positive:
819 result.path = dialog.GetPath()
820 else:
821 result.path = None
822 dialog.Destroy()
823 return result
824
825
826 def directory(parent=None, message='Choose a directory', path='', style=0,
827 pos=wx.DefaultPosition, size=wx.DefaultSize):
828 """Dir dialog wrapper function."""
829 dialog = wx.DirDialog(parent, message, path, style, pos, size)
830 result = DialogResults(dialog.ShowModal())
831 if result.positive:
832 result.path = dialog.GetPath()
833 else:
834 result.path = None
835 dialog.Destroy()
836 return result
837
838
839 def messageDialog(parent=None, message='', title='Message box',
840 style=wx.YES_NO | wx.CANCEL | wx.CENTRE | wx.ICON_QUESTION,
841 pos=wx.DefaultPosition):
842 """Message dialog wrapper function."""
843 dialog = wx.MessageDialog(parent, message, title, style, pos)
844 result = DialogResults(dialog.ShowModal())
845 dialog.Destroy()
846 return result