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