From 5de02c65b59af7b7c74a19f2bad03c3f5b1bd5b1 Mon Sep 17 00:00:00 2001 From: Stephen Dranger Date: Tue, 15 Feb 2011 03:44:33 -0600 Subject: [PATCH] failed twisted integration....just stick w/oyoyo for now --- TODO | 1 + convo.pyc | Bin 25647 -> 25647 bytes dataobjs.pyc | Bin 14331 -> 14331 bytes generic.pyc | Bin 4285 -> 4285 bytes irc.py | 299 +++++++++-------- irc.pyc | Bin 14119 -> 14194 bytes memos.pyc | Bin 32063 -> 32063 bytes menus.py | 2 +- menus.pyc | Bin 25563 -> 25570 bytes mispeller.pyc | Bin 2929 -> 2929 bytes oyoyo/__init__.pyc | Bin 333 -> 333 bytes oyoyo/client.py | 2 + oyoyo/client.pyc | Bin 9913 -> 9938 bytes oyoyo/cmdhandler.pyc | Bin 8312 -> 8312 bytes oyoyo/helpers.pyc | Bin 5020 -> 5020 bytes oyoyo/ircevents.pyc | Bin 5693 -> 5693 bytes oyoyo/parse.pyc | Bin 2869 -> 2869 bytes parsetools.pyc | Bin 11107 -> 11107 bytes pesterchum.js | 2 +- pesterchum.py | 29 +- qt4reactor/.gitignore | 9 + qt4reactor/LICENSE | 57 ++++ qt4reactor/README | 55 ++++ qt4reactor/__init__.py | 0 qt4reactor/bin/gtrial | 24 ++ qt4reactor/ghtTests/buttonStress.py | 57 ++++ qt4reactor/ghtTests/fakeAppButtonStress.py | 51 +++ qt4reactor/ghtTests/ircClient.py | 106 ++++++ qt4reactor/ghtTests/testIterate.py | 37 +++ qt4reactor/ghtTests/trivialscript.py | 25 ++ qt4reactor/gtrial.py | 41 +++ qt4reactor/qt4reactor.py | 359 +++++++++++++++++++++ qt4reactor/twisted/plugins/qt4.py | 9 + 33 files changed, 984 insertions(+), 181 deletions(-) create mode 100644 qt4reactor/.gitignore create mode 100644 qt4reactor/LICENSE create mode 100644 qt4reactor/README create mode 100644 qt4reactor/__init__.py create mode 100755 qt4reactor/bin/gtrial create mode 100755 qt4reactor/ghtTests/buttonStress.py create mode 100755 qt4reactor/ghtTests/fakeAppButtonStress.py create mode 100644 qt4reactor/ghtTests/ircClient.py create mode 100755 qt4reactor/ghtTests/testIterate.py create mode 100755 qt4reactor/ghtTests/trivialscript.py create mode 100755 qt4reactor/gtrial.py create mode 100644 qt4reactor/qt4reactor.py create mode 100644 qt4reactor/twisted/plugins/qt4.py diff --git a/TODO b/TODO index be2733d..38c46ad 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ Bugs: +* memos need to test for max time * color swatch text doesnt disappear * X and _ buttons move around all crazy like diff --git a/convo.pyc b/convo.pyc index af9073ea576deba20ba47d0ae426e87422d61748..c2f68040b7088f519ff8a879f7638fc37c61c48d 100644 GIT binary patch delta 17 ZcmZ2~f^q!`Mz)Kec)1>&-pHnz0su;62fzRT delta 17 ZcmZ2~f^q!`Mz)Kec)3(+H?nD_002aG2DShI diff --git a/dataobjs.pyc b/dataobjs.pyc index c5afea25e7d62106d70338547217dc59678ce37d..34f0c15496f03275f1600ade1b28fe7f798fcf8d 100644 GIT binary patch delta 15 XcmeyJ|2v=U;wN6N2d6i(eKiLFMw19b delta 15 WcmeyJ|2v=U;wN4%mD-JLU(EqPr3X0x diff --git a/generic.pyc b/generic.pyc index c06f5283724144688355a5fd6ea4ed4f99559070..7851495b9d25a65cd69e78c27c02ee688d7a308c 100644 GIT binary patch delta 15 Xcmdn1xL1+w;wN6N2d6i(Z5IFlH#`Q$ delta 15 Wcmdn1xL1+w;wN4%mD-JL+XVnIP6fOG diff --git a/irc.py b/irc.py index dc6ae08..1a87048 100644 --- a/irc.py +++ b/irc.py @@ -1,10 +1,9 @@ from PyQt4 import QtGui, QtCore -from oyoyo.client import IRCClient -from oyoyo.cmdhandler import DefaultCommandHandler -from oyoyo import helpers +from twisted.internet.protocol import ClientFactory +from twisted.words.protocols.irc import IRCClient +from twisted.internet import reactor import logging import random -import socket from dataobjs import Mood, PesterProfile from generic import PesterList @@ -18,31 +17,32 @@ class PesterIRC(QtCore.QObject): self.config = config def IRCConnect(self): server = self.config.server() - port = self.config.port() - self.cli = IRCClient(PesterHandler, host=server, port=int(port), nick=self.mainwindow.profile().handle, real_name='pcc30', blocking=True) - self.cli.command_handler.parent = self - self.cli.command_handler.mainwindow = self.mainwindow - self.conn = self.cli.connect() - self.brokenConnection = False + port = int(self.config.port()) + nick = self.mainwindow.profile() + self.cli = PesterIRCFactory(nick, self) + logging.info("---> Logging on...") + reactor.connectTCP(server, port, self.cli) + reactor.run() def closeConnection(self): - self.cli.close() - def setConnectionBroken(self, broken=True): - self.brokenConnection = True + #logging.info("---> Logging on...") + # self.cli.close() + pass @QtCore.pyqtSlot(PesterProfile) def getMood(self, *chums): - self.cli.command_handler.getMood(*chums) + self.cli.getMood(*chums) @QtCore.pyqtSlot(PesterList) def getMoods(self, chums): - self.cli.command_handler.getMood(*chums) + self.cli.getMood(*chums) @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) def sendMessage(self, text, handle): h = unicode(handle) textl = [unicode(text)] + CMD_LENGTH = 450 def splittext(l): - if len(l[0]) > 400: - space = l[0].rfind(" ", 0,400) + if len(l[0]) > CMD_LENGTH: + space = l[0].rfind(" ", 0,CMD_LENGTH) if space == -1: - space = 400 + space = CMD_LENGTH a = l[0][0:space] b = l[0][space:] if len(b) > 0: @@ -52,117 +52,72 @@ class PesterIRC(QtCore.QObject): else: return l textl = splittext(textl) - try: - for t in textl: - helpers.msg(self.cli, h, t) - except socket.error: - self.setConnectionBroken() + for t in textl: + self.cli.msg(h, t) @QtCore.pyqtSlot(QtCore.QString, bool) def startConvo(self, handle, initiated): h = unicode(handle) - try: - if initiated: - helpers.msg(self.cli, h, "PESTERCHUM:BEGIN") - helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd())) - except socket.error: - self.setConnectionBroken() + if initiated: + self.cli.msg(h, "PESTERCHUM:BEGIN") + self.cli.msg(h, "COLOR >%s" % (self.mainwindow.profile().colorcmd())) @QtCore.pyqtSlot(QtCore.QString) def endConvo(self, handle): h = unicode(handle) - try: - helpers.msg(self.cli, h, "PESTERCHUM:CEASE") - except socket.error: - self.setConnectionBroken() + self.cli.msg(h, "PESTERCHUM:CEASE") @QtCore.pyqtSlot() def updateProfile(self): me = self.mainwindow.profile() handle = me.handle - try: - helpers.nick(self.cli, handle) - except socket.error: - self.setConnectionBroken() + self.cli.setNick(handle) self.updateMood() @QtCore.pyqtSlot() def updateMood(self): me = self.mainwindow.profile() - try: - helpers.msg(self.cli, "#pesterchum", "MOOD >%d" % (me.mood.value())) - except socket.error: - self.setConnectionBroken() + self.cli.msg("#pesterchum", "MOOD >%d" % (me.mood.value())) @QtCore.pyqtSlot() def updateColor(self): me = self.mainwindow.profile() for h in self.mainwindow.convos.keys(): - try: - helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd())) - except socket.error: - self.setConnectionBroken() + self.cli.msg(h, "COLOR >%s" % (self.mainwindow.profile().colorcmd())) @QtCore.pyqtSlot(QtCore.QString) def blockedChum(self, handle): h = unicode(handle) - try: - helpers.msg(self.cli, h, "PESTERCHUM:BLOCK") - except socket.error: - self.setConnectionBroken() + self.cli.msg(h, "PESTERCHUM:BLOCK") @QtCore.pyqtSlot(QtCore.QString) def unblockedChum(self, handle): h = unicode(handle) - try: - helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK") - except socket.error: - self.setConnectionBroken() + self.cli.msg(h, "PESTERCHUM:UNBLOCK") @QtCore.pyqtSlot(QtCore.QString) def requestNames(self, channel): c = unicode(channel) - try: - helpers.names(self.cli, c) - except socket.error: - self.setConnectionBroken() + self.cli.sendMessage("NAMES", c) @QtCore.pyqtSlot() def requestChannelList(self): - try: - helpers.channel_list(self.cli) - except socket.error: - self.setConnectionBroken() + self.cli.sendMessage("LIST") @QtCore.pyqtSlot(QtCore.QString) def joinChannel(self, channel): c = unicode(channel) - try: - helpers.join(self.cli, c) - except socket.error: - self.setConnectionBroken() + self.cli.join(c) @QtCore.pyqtSlot(QtCore.QString) def leftChannel(self, channel): c = unicode(channel) - try: - helpers.part(self.cli, c) - except socket.error: - self.setConnectionBroken() + self.cli.leave(c) @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) def kickUser(self, handle, channel): c = unicode(channel) h = unicode(handle) - try: - helpers.kick(self.cli, h, c) - except socket.error: - self.setConnectionBroken() + self.cli.kick(h, c) @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) def setChannelMode(self, channel, mode, command): c = unicode(channel) - m = unicode(mode) + m = unicode(mode).replace("+", "") cmd = unicode(command) if cmd == "": cmd = None - try: - helpers.mode(self.cli, c, m, cmd) - except socket.error: - self.setConnectionBroken() + self.cli.mode(c, True, m, cmd) @QtCore.pyqtSlot() def reconnectIRC(self): - self.setConnectionBroken() - - def updateIRC(self): - self.conn.next() + pass moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood) colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor) @@ -174,10 +129,48 @@ class PesterIRC(QtCore.QObject): nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) connected = QtCore.pyqtSignal() userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, - QtCore.QString) + QtCore.QString) + + +class PesterIRCClient(IRCClient): + realname = "pcc30" + username = "pcc30" + + def __init__(self, nick, qobj): + self.nickname = nick + self.parent = qobj + self.mainwindow = qobj.mainwindow + qobj.irc = self + + def msg(self, user, message): + logging.info("---> send PRIVMSG %s %s" % (user, message)) + IRCClient.msg(self, user, message) + + def signedOn(self): + logging.info("---> recv WELCOME") + self.parent.connected.emit() + self.join("#pesterchum") + mychumhandle = self.mainwindow.profile().handle + mymood = self.mainwindow.profile().mood.value() + self.msg("#pesterchum", "MOOD >%d" % (mymood)) + + chums = self.mainwindow.chumList.chums + self.getMood(*chums) + + def getMood(self, *chums): + chumglub = "GETMOOD " + for c in chums: + chandle = c.handle + if len(chumglub+chandle) >= 350: + self.msg("#pesterchum", chumglub) + chumglub = "GETMOOD " + chumglub += chandle + if chumglub != "GETMOOD ": + self.msg("#pesterchum", chumglub) -class PesterHandler(DefaultCommandHandler): def privmsg(self, nick, chan, msg): + # do we still need this? + #msg = msg.decode("utf-8") # display msg, do other stuff if len(msg) == 0: return @@ -185,7 +178,7 @@ class PesterHandler(DefaultCommandHandler): if msg[0] == '\x01': return handle = nick[0:nick.find("!")] - logging.info("---> recv \"PRIVMSG %s :%s\"" % (handle, msg)) + logging.info("---> recv PRIVMSG %s :%s" % (handle, msg)) if chan == "#pesterchum": # follow instructions if msg[0:6] == "MOOD >": @@ -198,8 +191,7 @@ class PesterHandler(DefaultCommandHandler): mychumhandle = self.mainwindow.profile().handle mymood = self.mainwindow.profile().mood.value() if msg.find(mychumhandle, 8) != -1: - helpers.msg(self.client, "#pesterchum", - "MOOD >%d" % (mymood)) + self.msg("#pesterchum", "MOOD >%d" % (mymood)) elif chan[0] == '#': if msg[0:16] == "PESTERCHUM:TIME>": self.parent.timeCommand.emit(chan, handle, msg[16:]) @@ -220,89 +212,88 @@ class PesterHandler(DefaultCommandHandler): self.parent.colorUpdated.emit(handle, color) else: self.parent.messageReceived.emit(handle, msg) - - - def welcome(self, server, nick, msg): - self.parent.connected.emit() - helpers.join(self.client, "#pesterchum") - mychumhandle = self.mainwindow.profile().handle - mymood = self.mainwindow.profile().mood.value() - helpers.msg(self.client, "#pesterchum", "MOOD >%d" % (mymood)) - - chums = self.mainwindow.chumList.chums - self.getMood(*chums) - - def nicknameinuse(self, server, cmd, nick, msg): + + def irc_ERR_NICKNAMEINUSE(self, prefix, params): + logging.info("---> recv NICKINUSE %s %s" % (prefix, params)) newnick = "pesterClient%d" % (random.randint(100,999)) - helpers.nick(self.client, newnick) + self.setNick(newnick) self.parent.nickCollision.emit(nick, newnick) - def quit(self, nick, reason): + def userQuit(self, nick, reason): + logging.info("---> recv QUIT %s %s" % (nick, reason)) handle = nick[0:nick.find("!")] self.parent.userPresentUpdate.emit(handle, "", "quit") self.parent.moodUpdated.emit(handle, Mood("offline")) - def kick(self, opnick, channel, handle, op): - self.parent.userPresentUpdate.emit(handle, channel, "kick:%s" % (op)) + def userKicked(self, kickee, channel, kicker, msg): + logging.info("---> recv KICK %s %s %s %s" % (kickee, channel, kicker, msg)) + self.parent.userPresentUpdate.emit(kickee, channel, "kick:%s" % (op)) # ok i shouldnt be overloading that but am lazy - def part(self, nick, channel, reason="nanchos"): + def userLeft(self, nick, channel, reason="nanchos"): + logging.info("---> recv LEFT %s %s" % (nick, channel)) handle = nick[0:nick.find("!")] self.parent.userPresentUpdate.emit(handle, channel, "left") if channel == "#pesterchum": self.parent.moodUpdated.emit(handle, Mood("offline")) - def join(self, nick, channel): + def userJoined(self, nick, channel): + logging.info("---> recv JOIN %s %s" % (nick, channel)) handle = nick[0:nick.find("!")] self.parent.userPresentUpdate.emit(handle, channel, "join") if channel == "#pesterchum": self.parent.moodUpdated.emit(handle, Mood("chummy")) - def mode(self, op, channel, mode, handle=""): + def modeChannel(self, op, channel, set, modes, args): + logging.info("---> recv MODE %s %s %s %s %s" % (op, channel, set, modes, args)) + if set: + modes += "+" + else: + modes += "-" + handle = "" + print args self.parent.userPresentUpdate.emit(handle, channel, mode) - def nick(self, oldnick, newnick): - oldhandle = oldnick[0:oldnick.find("!")] + def userRenamed(self, oldnick, newnick): + logging.info("---> recv RENAME %s %s" % (oldnick, newnick)) newchum = PesterProfile(newnick, chumdb=self.mainwindow.chumdb) - self.parent.moodUpdated.emit(oldhandle, Mood("offline")) - self.parent.userPresentUpdate.emit("%s:%s" % (oldhandle, newnick), "", "nick") + self.parent.moodUpdated.emit(oldnick, Mood("offline")) + self.parent.userPresentUpdate.emit("%s:%s" % (oldnick, newnick), "", "nick") if newnick in self.mainwindow.chumList.chums: self.getMood(newchum) - def namreply(self, server, nick, op, channel, names): - namelist = names.split(" ") - logging.info("---> recv \"NAMES %s: %d names\"" % (channel, len(namelist))) - if not hasattr(self, 'channelnames'): - self.channelnames = {} - if not self.channelnames.has_key(channel): - self.channelnames[channel] = [] - self.channelnames[channel].extend(namelist) - def endofnames(self, server, nick, channel, msg): - namelist = self.channelnames[channel] - pl = PesterList(namelist) - del self.channelnames[channel] - self.parent.namesReceived.emit(channel, pl) - - def liststart(self, server, handle, *info): - self.channel_list = [] - info = list(info) - self.channel_field = info.index("Channel") # dunno if this is protocol - def list(self, server, handle, *info): - channel = info[self.channel_field] - if channel not in self.channel_list and channel != "#pesterchum": - self.channel_list.append(channel) - def listend(self, server, handle, msg): - pl = PesterList(self.channel_list) - self.parent.channelListReceived.emit(pl) - self.channel_list = [] + def irc_RPL_NAMREPLY(self, prefix, params): + logging.info("---> recv NAMREPLY %s %s" % (prefix, params)) + # namelist = names.split(" ") + # logging.info("---> recv \"NAMES %s: %d names\"" % (channel, len(namelist))) + # if not hasattr(self, 'channelnames'): + # self.channelnames = {} + # if not self.channelnames.has_key(channel): + # self.channelnames[channel] = [] + # self.channelnames[channel].extend(namelist) + def irc_RPL_ENDOFNAMES(self, prefix, params): + logging.info("---> recv ENDOFNAMES %s %s" % (prefix, params)) + # namelist = self.channelnames[channel] + # pl = PesterList(namelist) + # del self.channelnames[channel] + # self.parent.namesReceived.emit(channel, pl) + def irc_RPL_LISTSTART(self, prefix, params): + logging.info("---> recv LISTSTART %s %s" % (prefix, params)) + # self.channel_list = [] + # info = list(info) + # self.channel_field = info.index("Channel") # dunno if this is protocol + def irc_RPL_LIST(self, prefix, params): + logging.info("---> recv LIST %s %s" % (prefix, params)) + # channel = info[self.channel_field] + # if channel not in self.channel_list and channel != "#pesterchum": + # self.channel_list.append(channel) + def irc_RPL_LISTEND(self, prefix, params): + logging.info("---> recv LISTEND %s %s" % (prefix, params)) + # pl = PesterList(self.channel_list) + # self.parent.channelListReceived.emit(pl) + # self.channel_list = [] - def getMood(self, *chums): - chumglub = "GETMOOD " - for c in chums: - chandle = c.handle - if len(chumglub+chandle) >= 350: - try: - helpers.msg(self.client, "#pesterchum", chumglub) - except socket.error: - self.parent.setConnectionBroken() - chumglub = "GETMOOD " - chumglub += chandle - if chumglub != "GETMOOD ": - try: - helpers.msg(self.client, "#pesterchum", chumglub) - except socket.error: - self.parent.setConnectionBroken() - +class PesterIRCFactory(ClientFactory): + protocol = PesterIRCClient + + def __init__(self, nick, qobj): + self.irc = self.protocol(nick, qobj) + def buildProtocol(self, addr=None): + return self.irc + def clientConnectionLost(self, conn, reason): + conn.connect() + def clientConnectionFailed(self, conn, reason): + conn.connect() diff --git a/irc.pyc b/irc.pyc index 09faee387f2e0febb6bf5b59780fe7ac76e2e3a3..a7a711649de4e26496e6d430e1fa25e01f134bb4 100644 GIT binary patch literal 14194 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 literal 14119 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 delta 17 Zcmdo0i*f%iMz)Kec)3(-H?mpQ0su@;2V?*M diff --git a/menus.py b/menus.py index 7e221a8..c6be3a1 100644 --- a/menus.py +++ b/menus.py @@ -649,6 +649,6 @@ class LoadingScreen(QtGui.QDialog): class AboutPesterchum(QtGui.QMessageBox): def __init__(self, parent=None): QtGui.QMessageBox.__init__(self, parent) - self.setText("P3ST3RCHUM V. 0.1.2") + self.setText("P3ST3RCHUM V. 3.14 alpha 4") self.setInformativeText("Programming by illuminatedwax (ghostDunk), art by Grimlive (aquaMarinist)") self.mainwindow = parent diff --git a/menus.pyc b/menus.pyc index 0b97e7b3cd0c8b74402cfde36d3c60378606fde9..8a86c4c53026c2a0a4186fabc5c49b127742422b 100644 GIT binary patch delta 53 zcmcb8obl0dMz)Kec)4DG+{jjtC@00hzz|>@9AX^g>=Ej#5T>VKtY>JVkeE}Dk*Hv@ Jxi`^|2>=t`5t{%2 delta 46 zcmaEKobmQ?Mz)Kec)8SSH?kEZiVHI^Fa#I}hZqMrdxZKbgy|_5=o#u6ZJv_o#{>X$ Cwhjsa diff --git a/mispeller.pyc b/mispeller.pyc index e86c8b3dd79ff462dbd3ca1a8a32f482c27b0711..db7bf43aaf17eabd222cbcc8c112293e53cfacd7 100644 GIT binary patch delta 15 Xcmew;_EC)O;wN6N2d6i(Wpe`nJ23{w delta 15 Wcmew;_EC)O;wN4%wc3qr+1vm%PX)gK diff --git a/oyoyo/__init__.pyc b/oyoyo/__init__.pyc index f10874552d2edcbedfec17785e7dae545156da02..cef76db7937cee5c726fa0799affa98df5d1caa0 100644 GIT binary patch delta 15 XcmX@hbe4(j;wN6N2d6i(xibO)H0K5> delta 15 WcmX@hbe4(j;wN4%wc3qr?u-C01qC4h diff --git a/oyoyo/client.py b/oyoyo/client.py index 6c5fff2..fa60fa1 100644 --- a/oyoyo/client.py +++ b/oyoyo/client.py @@ -29,6 +29,8 @@ from oyoyo.parse import * from oyoyo import helpers from oyoyo.cmdhandler import CommandError +from datetime import * + # Python < 3 compatibility if sys.version_info < (3,): class bytes(object): diff --git a/oyoyo/client.pyc b/oyoyo/client.pyc index d3a6ea9192bc596edad5ee9aeb44e1be78aff23b..f289bd05b4d34627cbf00bf16839959826db0dbe 100644 GIT binary patch delta 333 zcmZ9FKTASU7{;IHn032d?U-e9RfzmUQZ0RgwkBJ0v8_5cvZ#i{)gT9l2;%6_*XT?Q z2`$wSM1o_`6b%j07qCNwL(j|03%?&P&rPXUO1*qXTzpkZJNS#Vch&BRdzrdwC_o7u zL{Sa|s*_Mr>;uO>s74V;>=J4WP2dcuY{qazYa9eqzh-=B;!rM>{ht`3X($g$LPdsX z28!5Nh}rt;z-HYPnIZFfP1KpwUD09DltYgWS4_rhhpEhU%nh@tZxelXwVrKo*~F7c z!3VwM@9|!D{5L+Cda5PZGlNW8@YST}o-AECz;rDF((AHilGw zhBQWo6n2Id28Lz^hR7%ZhCD`~3(@1PG$i{ KDONES;VA%jTS-R% diff --git a/oyoyo/cmdhandler.pyc b/oyoyo/cmdhandler.pyc index 57d62ba916276ac9e806ac26c5c24258294e0348..d14d14b1654bf1390ed627f59bfe254475d39ee3 100644 GIT binary patch delta 15 Xcmez2@WX-a;wN6N2d6i(6)6A!KwJk! delta 15 Wcmez2@WX-a;wN4%wc3qrMG62qdImiJ diff --git a/oyoyo/helpers.pyc b/oyoyo/helpers.pyc index 8a68fc5bbaa2ed41e6d66a09946982b20dde3bf4..fbe204694315f2399ea2125d51d5148af5852bab 100644 GIT binary patch delta 15 XcmbQEK1ZGH;wN6N2d6i(O%nzHGyMi~ delta 15 WcmbQEK1ZGH;wN4%wc3qr(}V#o8wF|r diff --git a/oyoyo/ircevents.pyc b/oyoyo/ircevents.pyc index 51fd3418d38d855a302b6ac575a6eb79b92bb159..da861f173655eafbbaa16d5dae3f6859efa4d390 100644 GIT binary patch delta 15 Xcmdn1vsZ`h;wN6N2d6i(nTr7cH(&;0 delta 15 Wcmdn1vsZ`h;wN4%wc3qr=3)Rbeg#?p diff --git a/oyoyo/parse.pyc b/oyoyo/parse.pyc index 79ddf4499bc6cbeb126190cde91c5329c1da6c32..718e1da16d21d5860378d790ad0629aa455e224e 100644 GIT binary patch delta 15 XcmdlgwpEPn;wN6N2d6i(>2m`BG${rX delta 15 WcmdlgwpEPn;wN4%wc3qr`rH66M+FN2 diff --git a/parsetools.pyc b/parsetools.pyc index 97122b334305d9163a965ca50f47fcf650b286ac..47037b132c94f0aa532e62dcab6d18531b40e180 100644 GIT binary patch delta 15 XcmaDH_Bf2~;wN6N2d6i(#cBfpKrIJ7 delta 15 WcmaDH_Bf2~;wN4%^UjTIvDyGS?FLc+ diff --git a/pesterchum.js b/pesterchum.js index aaa058c..185587d 100644 --- a/pesterchum.js +++ b/pesterchum.js @@ -1 +1 @@ -{"tabs": true, "soundon": true, "server": "irc.tymoon.eu", "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "confusedTransient", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "obliviousCrafter", "ircMonster"], "defaultprofile": "ghostDunk", "block": []} \ No newline at end of file +{"tabs": true, "soundon": true, "server": "irc.tymoon.eu", "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "confusedTransient", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "obliviousCrafter", "ircMonster"], "defaultprofile": "testProfile", "block": []} \ No newline at end of file diff --git a/pesterchum.py b/pesterchum.py index f645fd5..c887918 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -21,7 +21,6 @@ from generic import PesterIcon, RightClickList, MultiTextDialog, PesterList from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo from parsetools import convertTags, addTimeInitial from memos import PesterMemo, MemoTabWindow, TimeTracker -from irc import PesterIRC class waitingMessageHolder(object): def __init__(self, mainwindow, **msgfuncs): @@ -1657,26 +1656,6 @@ class PesterWindow(MovingWindow): closeSignal = QtCore.pyqtSignal() reconnectIRC = QtCore.pyqtSignal() -class IRCThread(QtCore.QThread): - def __init__(self, ircobj): - QtCore.QThread.__init__(self) - self.irc = ircobj - def run(self): - irc = self.irc - irc.IRCConnect() - while 1: - if irc.brokenConnection: - irc.brokenConnection = False - self.restartIRC.emit() - irc.closeConnection() - irc.IRCConnect() - try: - irc.updateIRC() - except socket.error: - irc.setConnectionBroken() - - restartIRC = QtCore.pyqtSignal() - class PesterTray(QtGui.QSystemTrayIcon): def __init__(self, icon, mainwindow, parent): QtGui.QSystemTrayIcon.__init__(self, icon, parent) @@ -1696,6 +1675,9 @@ class MainProgram(QtCore.QObject): def __init__(self): QtCore.QObject.__init__(self) self.app = QtGui.QApplication(sys.argv) + from qt4reactor import qt4reactor + qt4reactor.install() + from irc import PesterIRC if pygame.mixer: # we could set the frequency higher but i love how cheesy it sounds try: @@ -1744,9 +1726,7 @@ class MainProgram(QtCore.QObject): self.irc = PesterIRC(self.widget.config, self.widget) self.connectWidgets(self.irc, self.widget) - self.ircapp = IRCThread(self.irc) - self.connect(self.ircapp, QtCore.SIGNAL('restartIRC()'), - self, QtCore.SLOT('restartIRC()')) + self.irc.IRCConnect() def connectWidgets(self, irc, widget): irc.connect(widget, QtCore.SIGNAL('sendMessage(QString, QString)'), @@ -1866,7 +1846,6 @@ class MainProgram(QtCore.QObject): sys.exit(0) def run(self): - self.ircapp.start() self.widget.loadingscreen = LoadingScreen(self.widget) self.connect(self.widget.loadingscreen, QtCore.SIGNAL('rejected()'), self.widget, QtCore.SLOT('close()')) diff --git a/qt4reactor/.gitignore b/qt4reactor/.gitignore new file mode 100644 index 0000000..e1fb410 --- /dev/null +++ b/qt4reactor/.gitignore @@ -0,0 +1,9 @@ +*.[oa] +*~ +*.pyc +*.pyo +*.class +.project +.pydevproject +*.cache +_trial_temp diff --git a/qt4reactor/LICENSE b/qt4reactor/LICENSE new file mode 100644 index 0000000..5fc7ac7 --- /dev/null +++ b/qt4reactor/LICENSE @@ -0,0 +1,57 @@ +Copyright (c) 2001-2010 +Allen Short +Andy Gayton +Andrew Bennetts +Antoine Pitrou +Apple Computer, Inc. +Benjamin Bruheim +Bob Ippolito +Canonical Limited +Christopher Armstrong +David Reid +Donovan Preston +Eric Mangold +Eyal Lotem +Itamar Shtull-Trauring +James Knight +Jason A. Mobarak +Jean-Paul Calderone +Jessica McKellar +Jonathan Jacobs +Jonathan Lange +Jonathan D. Simms +Jürgen Hermann +Kevin Horn +Kevin Turner +Mary Gardiner +Matthew Lefkowitz +Massachusetts Institute of Technology +Moshe Zadka +Paul Swartz +Pavel Pergamenshchik +Ralph Meijer +Sean Riley +Software Freedom Conservancy +Travis B. Hartwell +Thijs Triemstra +Thomas Herve +Timothy Allen + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/qt4reactor/README b/qt4reactor/README new file mode 100644 index 0000000..e6b5fec --- /dev/null +++ b/qt4reactor/README @@ -0,0 +1,55 @@ +Unpack this directory into your PYTHONPATH. + +test with: + +trial --reactor=qt4 twisted (or twisted.test or twisted.test.test_internet) + += Contributors = + +Many thanks to Darren Dale who provided the patch to fix the reactor for Qt4.4 + += Using the Qt4Reactor = + +In your own code, BEFORE you import the reactor... + +app = QApplication(sys.argv) +import qt4reactor +qt4reactor.install() + += Gui = + +There is a way to run trial using a gui... in bin, there is a routine +gtrial. Put that in the same directory as trial and it pops up a +trivial gui... hit the buton and it all runs the same... don't use the +--reactor option when calling gtrial... but all the other options +appear to work. This was just to make sure there wasn't anything +strange with guis which there doesn't appear to be + +If you're writing a conventional Qt application and just want twisted +as an addon, you can get that by calling reactor.runReturn() instead +of run(). This call needs to occur after your installation of of the +reactor and after QApplication.exec_() (or QCoreApplication.exec_() +whichever you are using. + +reactor.run() will also work as expected in a typical twisted application + +more docs in qt4reactor.py + +Note that if a QApplication or QCoreApplication instance isn't +constructed prior to calling reactor run, an internally owned +QCoreApplication is created and destroyed. This won't work if you call +runReturn instead of run unless you take responsibility for wacking +QCoreApplication yourself... + +However, most users want this reactor to do gui stuff so this +shouldn't be an issue. + +Performance impact of Qt has been reduced by minimizing use of +signaling which is expensive. 186s for qt4reactor vs 180s for select +for entire twisted trial suite. + +-glenn + +-- +Glenn H. Tarbox, PhD +glenn@tarbox.org diff --git a/qt4reactor/__init__.py b/qt4reactor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/qt4reactor/bin/gtrial b/qt4reactor/bin/gtrial new file mode 100755 index 0000000..e0d899e --- /dev/null +++ b/qt4reactor/bin/gtrial @@ -0,0 +1,24 @@ +#!/usr/bin/python + +# Twisted, the Framework of Your Internet +# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# See LICENSE for details. + + + +### Twisted Preamble +# This makes sure that users don't have to set up their environment +# specially in order to run these programs from bin/. +import sys, os, string +if string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') != -1: + sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))) +if hasattr(os, "getuid") and os.getuid() != 0: + sys.path.insert(0, os.curdir) +### end of preamble + +# begin chdir armor +sys.path[:] = map(os.path.abspath, sys.path) +# end chdir armor + +from gtrial import run +run() diff --git a/qt4reactor/ghtTests/buttonStress.py b/qt4reactor/ghtTests/buttonStress.py new file mode 100755 index 0000000..7b4ec54 --- /dev/null +++ b/qt4reactor/ghtTests/buttonStress.py @@ -0,0 +1,57 @@ +import sys +from PySide import QtGui, QtScript +from PySide.QtCore import QTimer, SIGNAL, QObject +import qt4reactor + +app = QtGui.QApplication(sys.argv) +qt4reactor.install() + +from twisted.internet import reactor, task +from twisted.python import log +log.startLogging(sys.stdout) + +class doNothing(QObject): + def __init__(self): + self.count = 0 + self.looping=False + task.LoopingCall(self.printStat).start(1.0) + QObject.__init__(self) + + def doSomething(self): + if not self.looping: return + self.count += 1 + reactor.callLater(0.003,self.doSomething) + + def buttonClick(self): + if self.looping: + self.looping=False + log.msg('looping stopped....') + else: + self.looping=True + self.doSomething() + log.msg('looping started....') + + def printStat(self): + log.msg(' c: ' + str(self.count) + + ' st: ' + str(reactor._doSomethingCount)) + + +t=doNothing() + +engine = QtScript.QScriptEngine() + +button = QtGui.QPushButton() +scriptButton = engine.newQObject(button) +engine.globalObject().setProperty("button", scriptButton) + +app.connect(button, SIGNAL("clicked()"), t.buttonClick) + +engine.evaluate("button.text = 'Hello World!'") +engine.evaluate("button.styleSheet = 'font-style: italic'") +engine.evaluate("button.show()") + +reactor.runReturn() +app.exec_() +log.msg('fell off the bottom?...') + + diff --git a/qt4reactor/ghtTests/fakeAppButtonStress.py b/qt4reactor/ghtTests/fakeAppButtonStress.py new file mode 100755 index 0000000..d5a2977 --- /dev/null +++ b/qt4reactor/ghtTests/fakeAppButtonStress.py @@ -0,0 +1,51 @@ +import sys +from PySide import QtGui, QtScript +from PySide.QtCore import QTimer, SIGNAL, QEventLoop +import qt4reactor + +app = QtGui.QApplication(sys.argv) + +qt4reactor.install() + +from twisted.internet import reactor, task + +class doNothing(object): + def __init__(self): + self.count = 0 + self.running=False + task.LoopingCall(self.printStat).start(1.0) + + + def buttonClick(self): + if self.running: + self.running=False + print 'CLICK: calling reactor stop...' + reactor.stop() + print 'reactor stop called....' + else: + self.running=True + print 'CLICK: entering run' + reactor.run() + print 'reactor run returned...' + + def printStat(self): + print 'tick...' + +t=doNothing() + +engine = QtScript.QScriptEngine() + +button = QtGui.QPushButton() +scriptButton = engine.newQObject(button) +engine.globalObject().setProperty("button", scriptButton) + +app.connect(button, SIGNAL("clicked()"), t.buttonClick) + +engine.evaluate("button.text = 'Hello World!'") +engine.evaluate("button.styleSheet = 'font-style: italic'") +engine.evaluate("button.show()") + +app.exec_() +print 'fell off the bottom?...' + + diff --git a/qt4reactor/ghtTests/ircClient.py b/qt4reactor/ghtTests/ircClient.py new file mode 100644 index 0000000..9e6fdfb --- /dev/null +++ b/qt4reactor/ghtTests/ircClient.py @@ -0,0 +1,106 @@ +from PySide.QtCore import * +from PySide.QtGui import * +import sys, qt4reactor + +app = QApplication(sys.argv) +qt4reactor.install() + +from twisted.words.protocols import irc +from twisted.internet import reactor, protocol +from twisted.python import log + +import time, sys + +class IRCCore(irc.IRCClient): + nickname = 'dosdsdssd' + def connectionMade(self): + self.nickname = self.factory.window.nickName.text().encode('ascii') + self.factory.window.protocol = self + irc.IRCClient.connectionMade(self) + self.log('connected!!') + def connectionLost(self, reason): + self.log('disconnected... :( %s'%reason) + def signedOn(self): + chanName = self.factory.window.channelName.text().encode('ascii') + self.join(chanName) + def joined(self, channel): + self.log('joined %s'%channel) + def privmsg(self, user, channel, msg): + self.log('%s %s %s'%(user, channel, msg)) + def action(self, user, channel, msg): + self.log('action: %s %s %s'%(user, channel, msg)) + def log(self, str): + self.factory.window.view.addItem(str) + +class IRCCoreFactory(protocol.ClientFactory): + protocol = IRCCore + def __init__(self, window): + self.window = window + def clientConnectionLost(self, connector, reason): + # reconnect to server if lose connection + connector.connect() + def clientConnectionFailed(self, connector, reason): + print('connection failed! :(', reason) + reactor.stop() + +class MainWindow(QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + connectLayout = QHBoxLayout() + connectLayout.addWidget(QLabel('Server:')) + self.serverName = QLineEdit('irc.freenode.org') + connectLayout.addWidget(self.serverName) + connectLayout.addWidget(QLabel('Channel:')) + self.channelName = QLineEdit('#pangaea') + connectLayout.addWidget(self.channelName) + connectLayout.addWidget(QLabel('Nick:')) + self.nickName = QLineEdit('ceruleanwave9832') + connectLayout.addWidget(self.nickName) + self.connectButton = QPushButton('Connect!') + connectLayout.addWidget(self.connectButton) + self.connectButton.clicked.connect(self.connectIRC) + + self.view = QListWidget() + self.entry = QLineEdit() + self.entry.returnPressed.connect(self.sendMessage) + irc = QWidget(self) + vbox = QVBoxLayout() + vbox.addLayout(connectLayout) + vbox.addWidget(self.view) + vbox.addWidget(self.entry) + irc.setLayout(vbox) + self.setCentralWidget(irc) + self.setWindowTitle('IRC') + self.setUnifiedTitleAndToolBarOnMac(True) + self.showMaximized() + + self.protocol = None + def connectIRC(self): + self.connectButton.setDisabled(True) + self.channelName.setDisabled(True) + self.nickName.setDisabled(True) + self.serverName.setDisabled(True) + ircCoreFactory = IRCCoreFactory(self) + serverName = self.serverName.text().encode('ascii') + reactor.connectTCP(serverName, 6667, ircCoreFactory) + #reactor.runReturn() + #app.exit() + #app.exit() + reactor.run() + def sendMessage(self): + if self.protocol: + chanName = self.channelName.text().encode('ascii') + message = self.entry.text().encode('ascii') + self.protocol.msg(chanName, message) + self.view.addItem('%s <%s> %s'%(chanName, self.protocol.nickname, message)) + else: + self.view.addItem('Not connected.') + self.entry.setText('') + def closeEvent(self, event): + print('Attempting to close the main window!') + reactor.stop() + event.accept() + +if __name__ == '__main__': + mainWin = MainWindow() + sys.exit(app.exec_()) diff --git a/qt4reactor/ghtTests/testIterate.py b/qt4reactor/ghtTests/testIterate.py new file mode 100755 index 0000000..261155b --- /dev/null +++ b/qt4reactor/ghtTests/testIterate.py @@ -0,0 +1,37 @@ +import sys +from PySide import QtGui, QtScript +from PySide.QtCore import QTimer, SIGNAL +import qt4reactor + +app = QtGui.QApplication(sys.argv) +qt4reactor.install() + +from twisted.internet import reactor, task +from twisted.python import log +log.startLogging(sys.stdout) + +def testReactor(): + print 'tick...' + +def buttonClick(): + print 'click...' + reactor.iterate(5.0) + print 'click return' + +engine = QtScript.QScriptEngine() + +button = QtGui.QPushButton() +scriptButton = engine.newQObject(button) +engine.globalObject().setProperty("button", scriptButton) + +app.connect(button, SIGNAL("clicked()"), buttonClick) + +engine.evaluate("button.text = 'Hello World!'") +engine.evaluate("button.styleSheet = 'font-style: italic'") +engine.evaluate("button.show()") + +task.LoopingCall(testReactor).start(1.0) +reactor.run() +log.msg('fell off the bottom?...') + + diff --git a/qt4reactor/ghtTests/trivialscript.py b/qt4reactor/ghtTests/trivialscript.py new file mode 100755 index 0000000..2c015cc --- /dev/null +++ b/qt4reactor/ghtTests/trivialscript.py @@ -0,0 +1,25 @@ +import sys + +from twisted.application import reactors +import qt4reactor +qt4reactor.install() +#reactors.installReactor('qt4') + +from twisted.internet import reactor, task +from twisted.python import log +log.startLogging(sys.stdout) + +def testReactor(): + print 'tick...' + +def doit(): + task.LoopingCall(testReactor).start(1.0) + reactor.callLater(15.0,reactor.stop) + +reactor.callWhenRunning(doit) +log.msg('calling reactor.run()') +reactor.run() +log.msg('fell off the bottom?...') + +#sys.exit(app.exec_()) + diff --git a/qt4reactor/gtrial.py b/qt4reactor/gtrial.py new file mode 100755 index 0000000..704a2f4 --- /dev/null +++ b/qt4reactor/gtrial.py @@ -0,0 +1,41 @@ +import sys +from PyQt4 import QtGui, QtScript +from PyQt4.QtCore import QTimer, SIGNAL, QEventLoop +import qt4reactor + +app = QtGui.QApplication(sys.argv) + +qt4reactor.install() + +from twisted.internet import reactor, task + +class doNothing(object): + def __init__(self): + self.count = 0 + self.running=False + + def buttonClick(self): + if not self.running: + from twisted.scripts import trial + trial.run() + +def run(): + + t=doNothing() + + engine = QtScript.QScriptEngine() + + button = QtGui.QPushButton() + scriptButton = engine.newQObject(button) + engine.globalObject().setProperty("button", scriptButton) + + app.connect(button, SIGNAL("clicked()"), t.buttonClick) + + engine.evaluate("button.text = 'Do Twisted Gui Trial'") + engine.evaluate("button.styleSheet = 'font-style: italic'") + engine.evaluate("button.show()") + + app.exec_() + print 'fell off the bottom?...' + + diff --git a/qt4reactor/qt4reactor.py b/qt4reactor/qt4reactor.py new file mode 100644 index 0000000..eff7e2e --- /dev/null +++ b/qt4reactor/qt4reactor.py @@ -0,0 +1,359 @@ +# Copyright (c) 2001-2011 Twisted Matrix Laboratories. +# See LICENSE for details. + + +""" +This module provides support for Twisted to be driven by the Qt mainloop. + +In order to use this support, simply do the following:: + | app = QApplication(sys.argv) # your code to init Qt + | import qt4reactor + | qt4reactor.install() + +alternatively: + + | from twisted.application import reactors + | reactors.installReactor('qt4') + +Then use twisted.internet APIs as usual. The other methods here are not +intended to be called directly. + +If you don't instantiate a QApplication or QCoreApplication prior to +installing the reactor, a QCoreApplication will be constructed +by the reactor. QCoreApplication does not require a GUI so trial testing +can occur normally. + +Twisted can be initialized after QApplication.exec_() with a call to +reactor.runReturn(). calling reactor.stop() will unhook twisted but +leave your Qt application running + +API Stability: stable + +Maintainer: U{Glenn H Tarbox, PhD} + +Previous maintainer: U{Itamar Shtull-Trauring} +Original port to QT4: U{Gabe Rudy} +Subsequent port by therve +""" + +import sys +import time +from zope.interface import implements +from twisted.internet.interfaces import IReactorFDSet +from twisted.python import log, runtime +from twisted.internet import posixbase +from twisted.python.runtime import platformType, platform + +try: + from PyQt4.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication + from PyQt4.QtCore import QEventLoop +except ImportError: + from PySide.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication + from PySide.QtCore import QEventLoop + + +class TwistedSocketNotifier(QObject): + """ + Connection between an fd event and reader/writer callbacks. + """ + + def __init__(self, parent, reactor, watcher, socketType): + QObject.__init__(self, parent) + self.reactor = reactor + self.watcher = watcher + fd = watcher.fileno() + self.notifier = QSocketNotifier(fd, socketType, parent) + self.notifier.setEnabled(True) + if socketType == QSocketNotifier.Read: + self.fn = self.read + else: + self.fn = self.write + QObject.connect(self.notifier, SIGNAL("activated(int)"), self.fn) + + + def shutdown(self): + self.notifier.setEnabled(False) + self.disconnect(self.notifier, SIGNAL("activated(int)"), self.fn) + self.fn = self.watcher = None + self.notifier.deleteLater() + self.deleteLater() + + + def read(self, fd): + if not self.watcher: + return + w = self.watcher + # doRead can cause self.shutdown to be called so keep a reference to self.watcher + def _read(): + #Don't call me again, until the data has been read + self.notifier.setEnabled(False) + why = None + try: + why = w.doRead() + inRead = True + except: + inRead = False + log.err() + why = sys.exc_info()[1] + if why: + self.reactor._disconnectSelectable(w, why, inRead) + elif self.watcher: + self.notifier.setEnabled(True) # Re enable notification following sucessfull read + self.reactor._iterate(fromqt=True) + log.callWithLogger(w, _read) + + def write(self, sock): + if not self.watcher: + return + w = self.watcher + def _write(): + why = None + self.notifier.setEnabled(False) + + try: + why = w.doWrite() + except: + log.err() + why = sys.exc_info()[1] + if why: + self.reactor._disconnectSelectable(w, why, False) + elif self.watcher: + self.notifier.setEnabled(True) + self.reactor._iterate(fromqt=True) + log.callWithLogger(w, _write) + + + +class QtReactor(posixbase.PosixReactorBase): + implements(IReactorFDSet) + + def __init__(self): + self._reads = {} + self._writes = {} + self._notifiers = {} + self._timer = QTimer() + self._timer.setSingleShot(True) + QObject.connect(self._timer, SIGNAL("timeout()"), self.iterate) + + if QCoreApplication.startingUp(): + # Application Object has not been started yet + self.qApp=QCoreApplication([]) + self._ownApp=True + else: + self.qApp = QCoreApplication.instance() + self._ownApp=False + self._blockApp = None + posixbase.PosixReactorBase.__init__(self) + + + def _add(self, xer, primary, type): + """ + Private method for adding a descriptor from the event loop. + + It takes care of adding it if new or modifying it if already added + for another state (read -> read/write for example). + """ + if xer not in primary: + primary[xer] = TwistedSocketNotifier(None, self, xer, type) + + + def addReader(self, reader): + """ + Add a FileDescriptor for notification of data available to read. + """ + self._add(reader, self._reads, QSocketNotifier.Read) + + + def addWriter(self, writer): + """ + Add a FileDescriptor for notification of data available to write. + """ + self._add(writer, self._writes, QSocketNotifier.Write) + + + def _remove(self, xer, primary): + """ + Private method for removing a descriptor from the event loop. + + It does the inverse job of _add, and also add a check in case of the fd + has gone away. + """ + if xer in primary: + notifier = primary.pop(xer) + notifier.shutdown() + + + def removeReader(self, reader): + """ + Remove a Selectable for notification of data available to read. + """ + self._remove(reader, self._reads) + + + def removeWriter(self, writer): + """ + Remove a Selectable for notification of data available to write. + """ + self._remove(writer, self._writes) + + + def removeAll(self): + """ + Remove all selectables, and return a list of them. + """ + rv = self._removeAll(self._reads, self._writes) + return rv + + + def getReaders(self): + return self._reads.keys() + + + def getWriters(self): + return self._writes.keys() + + + def callLater(self,howlong, *args, **kargs): + rval = super(QtReactor,self).callLater(howlong, *args, **kargs) + self.reactorInvocation() + return rval + + + def reactorInvocation(self): + self._timer.stop() + self._timer.setInterval(0) + self._timer.start() + + + def _iterate(self, delay=None, fromqt=False): + """See twisted.internet.interfaces.IReactorCore.iterate. + """ + self.runUntilCurrent() + self.doIteration(delay, fromqt) + + iterate = _iterate + + def doIteration(self, delay=None, fromqt=False): + 'This method is called by a Qt timer or by network activity on a file descriptor' + + if not self.running and self._blockApp: + self._blockApp.quit() + self._timer.stop() + delay = max(delay, 1) + if not fromqt: + self.qApp.processEvents(QEventLoop.AllEvents, delay * 1000) + if self.timeout() is None: + timeout = 0.1 + elif self.timeout() == 0: + timeout = 0 + else: + timeout = self.timeout() + self._timer.setInterval(timeout * 1000) + self._timer.start() + + + def runReturn(self, installSignalHandlers=True): + self.startRunning(installSignalHandlers=installSignalHandlers) + self.reactorInvocation() + + + def run(self, installSignalHandlers=True): + if self._ownApp: + self._blockApp = self.qApp + else: + self._blockApp = QEventLoop() + self.runReturn() + self._blockApp.exec_() + + +class QtEventReactor(QtReactor): + def __init__(self, *args, **kwargs): + self._events = {} + super(QtEventReactor, self).__init__() + + + def addEvent(self, event, fd, action): + """ + Add a new win32 event to the event loop. + """ + self._events[event] = (fd, action) + + + def removeEvent(self, event): + """ + Remove an event. + """ + if event in self._events: + del self._events[event] + + + def doEvents(self): + handles = self._events.keys() + if len(handles) > 0: + val = None + while val != WAIT_TIMEOUT: + val = MsgWaitForMultipleObjects(handles, 0, 0, QS_ALLINPUT | QS_ALLEVENTS) + if val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles): + event_id = handles[val - WAIT_OBJECT_0] + if event_id in self._events: + fd, action = self._events[event_id] + log.callWithLogger(fd, self._runAction, action, fd) + elif val == WAIT_TIMEOUT: + pass + else: + #print 'Got an unexpected return of %r' % val + return + + + def _runAction(self, action, fd): + try: + closed = getattr(fd, action)() + except: + closed = sys.exc_info()[1] + log.deferr() + + if closed: + self._disconnectSelectable(fd, closed, action == 'doRead') + + + def timeout(self): + t = super(QtEventReactor, self).timeout() + return min(t, 0.01) + + + def iterate(self, delay=None): + """See twisted.internet.interfaces.IReactorCore.iterate. + """ + self.runUntilCurrent() + self.doEvents() + self.doIteration(delay) + + +def posixinstall(): + """ + Install the Qt reactor. + """ + p = QtReactor() + from twisted.internet.main import installReactor + installReactor(p) + + +def win32install(): + """ + Install the Qt reactor. + """ + p = QtEventReactor() + from twisted.internet.main import installReactor + installReactor(p) + + +if runtime.platform.getType() == 'win32': + from win32event import CreateEvent, MsgWaitForMultipleObjects + from win32event import WAIT_OBJECT_0, WAIT_TIMEOUT, QS_ALLINPUT, QS_ALLEVENTS + install = win32install +else: + install = posixinstall + + +__all__ = ["install"] + diff --git a/qt4reactor/twisted/plugins/qt4.py b/qt4reactor/twisted/plugins/qt4.py new file mode 100644 index 0000000..0f380b5 --- /dev/null +++ b/qt4reactor/twisted/plugins/qt4.py @@ -0,0 +1,9 @@ +# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# see LICENSE for details + + +from twisted.application.reactors import Reactor + +qt4 = Reactor('qt4', 'qt4reactor', 'Qt4 integration reactor') +qt4bad = Reactor('qt4bad', 'qt4reactor_bad', 'Qt4 broken reactor') +