# Twisted, the Framework of Your Internet
# Copyright (C) 2001 Matthew W. Lefkowitz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os, re
from twisted.python import reflect
from twisted.python import util
from twisted.manhole.ui.pywidgets import isCursorOnFirstLine, isCursorOnLastLine
import string
import gtk
from libglade import GladeXML
GLADE_FILE = util.sibpath(__file__, "instancemessenger.glade")
SETTINGS_FILE = os.path.expanduser("~/.InstanceMessenger")
OFFLINE = 0
ONLINE = 1
AWAY = 2
True = gtk.TRUE
False = gtk.FALSE
class InputOutputWindow:
def __init__(self, rootName, inputName, outputName):
self.xml = openGlade(GLADE_FILE, root=rootName)
wid = self.xml.get_widget
self.entry = wid(inputName)
#self.entry.set_word_wrap(gtk.TRUE)
self.output = wid(outputName)
#self.output.set_word_wrap(gtk.TRUE)
self.widget = wid(rootName)
self.history = []
self.histpos = 0
self.linemode = True
self.currentlyVisible = 0
self.win = None
autoConnectMethods(self)
def show(self):
if not self.currentlyVisible:
self.win = w = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL)
self.connectid = w.connect("destroy", self.hidden)
w.add(self.widget)
w.set_title(self.getTitle())
w.show_all()
self.entry.grab_focus()
self.currentlyVisible = 1
def hidden(self, w):
self.win = None
w.remove(self.widget)
self.currentlyVisible = 0
def hide(self):
if self.currentlyVisible:
self.win.remove(self.widget)
self.currentlyVisible = 0
self.win.disconnect(self.connectid)
self.win.destroy()
def handle_key_press_event(self, entry, event):
stopSignal = False
# ASSUMPTION: Assume Meta == mod4
isMeta = event.state & gtk.GDK.MOD4_MASK
##
# Return handling
##
if event.keyval == gtk.GDK.Return:
isShift = event.state & gtk.GDK.SHIFT_MASK
if isShift:
self.linemode = True
entry.insert_defaults('\n')
else:
stopSignal = True
text = entry.get_chars(0,-1)
if not text:
return
self.entry.delete_text(0, -1)
self.linemode = False
self.sendText(text)
self.history.append(text)
self.histpos = len(self.history)
##
# History handling
##
elif ((event.keyval == gtk.GDK.Up and isCursorOnFirstLine(entry))
or (isMeta and event.string == 'p')):
print "history up"
self.historyUp()
stopSignal = True
elif ((event.keyval == gtk.GDK.Down and isCursorOnLastLine(entry))
or (isMeta and event.string == 'n')):
print "history down"
self.historyDown()
stopSignal = True
##
# Tab Completion
##
elif event.keyval == gtk.GDK.Tab:
oldpos = entry.get_point()
word, pos = self.getCurrentWord(entry)
result = self.tabComplete(word)
#If there are multiple potential matches, then we spit
#them out and don't insert a tab, so the user can type
#a couple more characters and try completing again.
if len(result) > 1:
for nick in result:
self.output.insert_defaults(nick + " ")
self.output.insert_defaults('\n')
stopSignal = True
elif result: #only happens when len(result) == 1
entry.freeze()
entry.delete_text(*pos)
entry.set_position(pos[0])
entry.insert_defaults(result[0])
entry.set_position(oldpos+len(result[0])-len(word))
entry.thaw()
stopSignal = True
if stopSignal:
entry.emit_stop_by_name("key_press_event")
return True
def tabComplete(self, word):
"""Override me to implement tab completion for your window,
I should return a list of potential matches."""
return []
def getCurrentWord(self, entry):
i = entry.get_point()
text = entry.get_chars(0,-1)
word = re.split(r'\s', text)[-1]
start = string.rfind(text, word)
end = start+len(word)
return (word, (start, end))
def historyUp(self):
if self.histpos > 0:
self.entry.delete_text(0, -1)
self.histpos = self.histpos - 1
self.entry.insert_defaults(self.history[self.histpos])
self.entry.set_position(0)
def historyDown(self):
if self.histpos < len(self.history) - 1:
self.histpos = self.histpos + 1
self.entry.delete_text(0, -1)
self.entry.insert_defaults(self.history[self.histpos])
elif self.histpos == len(self.history) - 1:
self.histpos = self.histpos + 1
self.entry.delete_text(0, -1)
def createMethodDict(o, d=None):
if d is None:
d = {}
for base in reflect.allYourBase(o.__class__) + [o.__class__]:
for n in dir(base):
m = getattr(o, n)
#print 'd[%s] = %s' % (n, m)
d[n] = m
#print d
return d
def autoConnectMethods(*objs):
o = {}
for obj in objs:
createMethodDict(obj, o)
# print 'connecting', o
objs[0].xml.signal_autoconnect(o)
def openGlade(*args, **kwargs):
# print "opening glade file"
r = GladeXML(*args, **kwargs)
if r._o:
return r
else:
raise IOError("Couldn't open Glade XML: %s; %s" % (args, kwargs))
syntax highlighted by Code2HTML, v. 0.9.1