blob: 14312d5f3fc5999913685eff6a88d33353ee4566 [file] [log] [blame]
import W
import Wkeys
from Carbon import Fm
import WASTEconst
from types import *
from Carbon import Events
import string
import sys
import traceback
import MacOS
import MacPrefs
from Carbon import Qd
import EasyDialogs
import PyInteractive
if not hasattr(sys, 'ps1'):
sys.ps1 = '>>> '
if not hasattr(sys, 'ps2'):
sys.ps2 = '... '
def inspect(foo): # JJS 1/25/99
"Launch the browser on the given object. This is a general built-in function."
import PyBrowser
PyBrowser.Browser(foo)
class ConsoleTextWidget(W.EditText):
def __init__(self, *args, **kwargs):
W.EditText.__init__(self, *args, **kwargs)
self._inputstart = 0
self._buf = ''
self.pyinteractive = PyInteractive.PyInteractive()
import __main__
self._namespace = __main__.__dict__
self._namespace['inspect'] = inspect # JJS 1/25/99
def insert(self, text):
self.checkselection()
self.ted.WEInsert(text, None, None)
self.changed = 1
self.selchanged = 1
def set_namespace(self, dict):
if type(dict) <> DictionaryType:
raise TypeError, "The namespace needs to be a dictionary"
if 'inspect' not in dict.keys(): dict['inspect'] = inspect # JJS 1/25/99
self._namespace = dict
def open(self):
import __main__
W.EditText.open(self)
self.write('Python %s\n' % sys.version)
self.write('Type "copyright", "credits" or "license" for more information.\n')
self.write('MacPython IDE %s\n' % __main__.__version__)
self.write(sys.ps1)
self.flush()
def key(self, char, event):
(what, message, when, where, modifiers) = event
if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
if char not in Wkeys.navigationkeys:
self.checkselection()
if char == Wkeys.enterkey:
char = Wkeys.returnkey
selstart, selend = self.getselection()
if char == Wkeys.backspacekey:
if selstart <= (self._inputstart - (selstart <> selend)):
return
self.ted.WEKey(ord(char), modifiers)
if char not in Wkeys.navigationkeys:
self.changed = 1
if char not in Wkeys.scrollkeys:
self.selchanged = 1
self.updatescrollbars()
if char == Wkeys.returnkey:
text = self.get()[self._inputstart:selstart]
text = string.join(string.split(text, "\r"), "\n")
if hasattr(MacOS, 'EnableAppswitch'):
saveyield = MacOS.EnableAppswitch(0)
self._scriptDone = False
if sys.platform == "darwin":
# see identical construct in PyEdit.py
from threading import Thread
t = Thread(target=self._userCancelledMonitor,
name="UserCancelledMonitor")
t.start()
try:
self.pyinteractive.executeline(text, self, self._namespace)
finally:
self._scriptDone = True
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(saveyield)
selstart, selend = self.getselection()
self._inputstart = selstart
def _userCancelledMonitor(self):
# XXX duplicate code from PyEdit.py
import time, os
from signal import SIGINT
from Carbon import Evt
while not self._scriptDone:
if Evt.CheckEventQueueForUserCancel():
# Send a SIGINT signal to ourselves.
# This gets delivered to the main thread,
# cancelling the running script.
os.kill(os.getpid(), SIGINT)
break
time.sleep(0.25)
def domenu_save_as(self, *args):
filename = EasyDialogs.AskFileForSave(message='Save console text as:',
savedFileName='console.txt')
if not filename:
return
f = open(filename, 'wb')
f.write(self.get())
f.close()
MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
def write(self, text):
self._buf = self._buf + text
if '\n' in self._buf:
self.flush()
def flush(self):
stuff = string.split(self._buf, '\n')
stuff = string.join(stuff, '\r')
self.setselection_at_end()
try:
self.ted.WEInsert(stuff, None, None)
finally:
self._buf = ""
selstart, selend = self.getselection()
self._inputstart = selstart
self.ted.WEClearUndo()
self.updatescrollbars()
if self._parentwindow.wid.GetWindowPort().QDIsPortBuffered():
self._parentwindow.wid.GetWindowPort().QDFlushPortBuffer(None)
def selection_ok(self):
selstart, selend = self.getselection()
return not (selstart < self._inputstart or selend < self._inputstart)
def checkselection(self):
if not self.selection_ok():
self.setselection_at_end()
def setselection_at_end(self):
end = self.ted.WEGetTextLength()
self.setselection(end, end)
self.updatescrollbars()
def domenu_cut(self, *args):
if not self.selection_ok():
return
W.EditText.domenu_cut(self)
def domenu_paste(self, *args):
if not self.selection_ok():
self.setselection_at_end()
W.EditText.domenu_paste(self)
def domenu_clear(self, *args):
if not self.selection_ok():
return
W.EditText.domenu_clear(self)
class PyConsole(W.Window):
def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)),
tabsettings = (32, 0), unclosable = 0):
W.Window.__init__(self,
bounds,
"Python Interactive",
minsize = (200, 100),
tabbable = 0,
show = show)
self._unclosable = unclosable
consoletext = ConsoleTextWidget((-1, -1, -14, 1), inset = (6, 5),
fontsettings = fontsettings, tabsettings = tabsettings)
self._bary = W.Scrollbar((-15, 14, 16, -14), consoletext.vscroll, max = 32767)
self.consoletext = consoletext
self.namespacemenu = W.PopupMenu((-15, -1, 16, 16), [], self.consoletext.set_namespace)
self.namespacemenu.bind('<click>', self.makenamespacemenu)
self.open()
def makenamespacemenu(self, *args):
W.SetCursor('watch')
namespacelist = self.getnamespacelist()
self.namespacemenu.set([("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings),
["Namespace"] + namespacelist, ("Browse namespace\xc9", self.browsenamespace)])
currentname = self.consoletext._namespace["__name__"]
for i in range(len(namespacelist)):
if namespacelist[i][0] == currentname:
break
else:
return
# XXX this functionality should be generally available in Wmenus
submenuid = self.namespacemenu.menu.menu.GetItemMark(3)
menu = self.namespacemenu.menu.bar.menus[submenuid]
menu.menu.CheckMenuItem(i + 1, 1)
def browsenamespace(self):
import PyBrowser, W
W.SetCursor('watch')
PyBrowser.Browser(self.consoletext._namespace, self.consoletext._namespace["__name__"])
def clearbuffer(self):
from Carbon import Res
self.consoletext.ted.WEUseText(Res.Resource(''))
self.consoletext.write(sys.ps1)
self.consoletext.flush()
def getnamespacelist(self):
import os
import __main__
editors = filter(lambda x: x.__class__.__name__ == "Editor", self.parent._windows.values())
namespaces = [ ("__main__",__main__.__dict__) ]
for ed in editors:
modname = os.path.splitext(ed.title)[0]
if sys.modules.has_key(modname):
module = sys.modules[modname]
namespaces.append((modname, module.__dict__))
else:
if ed.title[-3:] == '.py':
modname = ed.title[:-3]
else:
modname = ed.title
ed.globals["__name__"] = modname
namespaces.append((modname, ed.globals))
return namespaces
def dofontsettings(self):
import FontSettings
settings = FontSettings.FontDialog(self.consoletext.getfontsettings(),
self.consoletext.gettabsettings())
if settings:
fontsettings, tabsettings = settings
self.consoletext.setfontsettings(fontsettings)
self.consoletext.settabsettings(tabsettings)
def show(self, onoff = 1):
W.Window.show(self, onoff)
if onoff:
self.select()
def close(self):
if self._unclosable:
self.show(0)
return -1
W.Window.close(self)
def writeprefs(self):
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
prefs.console.show = self.isvisible()
prefs.console.windowbounds = self.getbounds()
prefs.console.fontsettings = self.consoletext.getfontsettings()
prefs.console.tabsettings = self.consoletext.gettabsettings()
prefs.save()
def getselectedtext(self):
return self.consoletext.getselectedtext()
class OutputTextWidget(W.EditText):
def domenu_save_as(self, *args):
title = self._parentwindow.gettitle()
filename = EasyDialogs.AskFileForSave(message='Save %s text as:' % title,
savedFileName=title + '.txt')
if not filename:
return
f = open(filename, 'wb')
f.write(self.get())
f.close()
MacOS.SetCreatorAndType(filename, W._signature, 'TEXT')
def domenu_cut(self, *args):
self.domenu_copy(*args)
def domenu_clear(self, *args):
self.set('')
class PyOutput:
def __init__(self, bounds, show = 1, fontsettings = ("Monaco", 0, 9, (0, 0, 0)), tabsettings = (32, 0)):
self.bounds = bounds
self.fontsettings = fontsettings
self.tabsettings = tabsettings
self.w = None
self.closed = 1
self._buf = ''
# should be able to set this
self.savestdout, self.savestderr = sys.stdout, sys.stderr
sys.stderr = sys.stdout = self
if show:
self.show()
def setupwidgets(self):
self.w = W.Window(self.bounds, "Output",
minsize = (200, 100),
tabbable = 0)
self.w.outputtext = OutputTextWidget((-1, -1, -14, 1), inset = (6, 5),
fontsettings = self.fontsettings, tabsettings = self.tabsettings, readonly = 1)
menuitems = [("Clear window", self.clearbuffer), ("Font settings\xc9", self.dofontsettings)]
self.w.popupmenu = W.PopupMenu((-15, -1, 16, 16), menuitems)
self.w._bary = W.Scrollbar((-15, 14, 16, -14), self.w.outputtext.vscroll, max = 32767)
self.w.bind("<close>", self.close)
self.w.bind("<activate>", self.activate)
def write(self, text):
if hasattr(MacOS, 'EnableAppswitch'):
oldyield = MacOS.EnableAppswitch(-1)
try:
self._buf = self._buf + text
if '\n' in self._buf:
self.flush()
finally:
if hasattr(MacOS, 'EnableAppswitch'):
MacOS.EnableAppswitch(oldyield)
def flush(self):
self.show()
stuff = string.split(self._buf, '\n')
stuff = string.join(stuff, '\r')
end = self.w.outputtext.ted.WEGetTextLength()
self.w.outputtext.setselection(end, end)
self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
try:
self.w.outputtext.ted.WEInsert(stuff, None, None)
finally:
self._buf = ""
self.w.outputtext.updatescrollbars()
self.w.outputtext.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
if self.w.wid.GetWindowPort().QDIsPortBuffered():
self.w.wid.GetWindowPort().QDFlushPortBuffer(None)
def show(self):
if self.closed:
if not self.w:
self.setupwidgets()
self.w.open()
self.w.outputtext.updatescrollbars()
self.closed = 0
else:
self.w.show(1)
self.closed = 0
self.w.select()
def writeprefs(self):
if self.w is not None:
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
prefs.output.show = self.w.isvisible()
prefs.output.windowbounds = self.w.getbounds()
prefs.output.fontsettings = self.w.outputtext.getfontsettings()
prefs.output.tabsettings = self.w.outputtext.gettabsettings()
prefs.save()
def dofontsettings(self):
import FontSettings
settings = FontSettings.FontDialog(self.w.outputtext.getfontsettings(),
self.w.outputtext.gettabsettings())
if settings:
fontsettings, tabsettings = settings
self.w.outputtext.setfontsettings(fontsettings)
self.w.outputtext.settabsettings(tabsettings)
def clearbuffer(self):
from Carbon import Res
self.w.outputtext.set('')
def activate(self, onoff):
if onoff:
self.closed = 0
def close(self):
self.w.show(0)
self.closed = 1
return -1
class SimpleStdin:
def readline(self):
import EasyDialogs
# A trick to make the input dialog box a bit more palatable
if hasattr(sys.stdout, '_buf'):
prompt = sys.stdout._buf
else:
prompt = ""
if not prompt:
prompt = "Stdin input:"
sys.stdout.flush()
rv = EasyDialogs.AskString(prompt)
if rv is None:
return ""
rv = rv + "\n" # readline should include line terminator
sys.stdout.write(rv) # echo user's reply
return rv
def installconsole(defaultshow = 1):
global console
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
if not prefs.console or not hasattr(prefs.console, 'show'):
prefs.console.show = defaultshow
if not hasattr(prefs.console, "windowbounds"):
prefs.console.windowbounds = (450, 250)
if not hasattr(prefs.console, "fontsettings"):
prefs.console.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
if not hasattr(prefs.console, "tabsettings"):
prefs.console.tabsettings = (32, 0)
console = PyConsole(prefs.console.windowbounds, prefs.console.show,
prefs.console.fontsettings, prefs.console.tabsettings, 1)
def installoutput(defaultshow = 0, OutPutWindow = PyOutput):
global output
# quick 'n' dirty std in emulation
sys.stdin = SimpleStdin()
prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
if not prefs.output or not hasattr(prefs.output, 'show'):
prefs.output.show = defaultshow
if not hasattr(prefs.output, "windowbounds"):
prefs.output.windowbounds = (450, 250)
if not hasattr(prefs.output, "fontsettings"):
prefs.output.fontsettings = ("Monaco", 0, 9, (0, 0, 0))
if not hasattr(prefs.output, "tabsettings"):
prefs.output.tabsettings = (32, 0)
output = OutPutWindow(prefs.output.windowbounds, prefs.output.show,
prefs.output.fontsettings, prefs.output.tabsettings)