memos in some semblance of working order

This commit is contained in:
Stephen Dranger 2011-02-05 11:17:33 -06:00
parent 3bafa1e48a
commit a69b72784a
25 changed files with 773 additions and 273 deletions

1
TODO
View file

@ -6,6 +6,7 @@ Features:
* help menu -- about and forum * help menu -- about and forum
* profile switch should say current profile * profile switch should say current profile
* Transparent background? * Transparent background?
* X closes to tray
-- release alpha -- release alpha
* User commands/stop user from sending commands accidentally * User commands/stop user from sending commands accidentally
* shared buddy lists - changes to the buddy list should refresh it? * shared buddy lists - changes to the buddy list should refresh it?

BIN
convo.pyc

Binary file not shown.

View file

@ -100,12 +100,21 @@ class PesterProfile(object):
color = QtGui.QColor("black") color = QtGui.QColor("black")
self.color = color self.color = color
self.mood = mood self.mood = mood
def initials(self): def initials(self, time=None):
handle = self.handle handle = self.handle
caps = [l for l in handle if l.isupper()] caps = [l for l in handle if l.isupper()]
if not caps: if not caps:
caps = [""] caps = [""]
return (handle[0]+caps[0]).upper() initials = (handle[0]+caps[0]).upper()
if hasattr(self, 'time') and time:
if self.time > time:
return "F"+initials
elif self.time < time:
return "P"+initials
else:
return "C"+initials
else:
return (handle[0]+caps[0]).upper()
def colorhtml(self): def colorhtml(self):
return self.color.name() return self.color.name()
def colorcmd(self): def colorcmd(self):
@ -118,11 +127,37 @@ class PesterProfile(object):
def blocked(self, config): def blocked(self, config):
return self.handle in config.getBlocklist() return self.handle in config.getBlocklist()
def memsg(self, syscolor, suffix, msg): def memsg(self, syscolor, suffix, msg, time=None):
uppersuffix = suffix.upper() uppersuffix = suffix.upper()
return "<c=%s>-- %s%s <c=%s>[%s%s]</c> %s --</c>" % (syscolor.name(), self.handle, suffix, self.colorhtml(), self.initials(), uppersuffix, msg) if time is not None:
handle = "%s %s" % (time.temporal, self.handle)
initials = time.pcf+self.initials()+uppersuffix
else:
handle = self.handle
initials = self.initials()+uppersuffix
return "<c=%s>-- %s%s <c=%s>[%s]</c> %s --</c>" % (syscolor.name(), handle, suffix, self.colorhtml(), initials, msg)
def pestermsg(self, otherchum, syscolor, verb): def pestermsg(self, otherchum, syscolor, verb):
return "<c=%s>-- %s <c=%s>[%s]</c> %s %s <c=%s>[%s]</c> at %s --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), verb, otherchum.handle, otherchum.colorhtml(), otherchum.initials(), datetime.now().strftime("%H:%M")) return "<c=%s>-- %s <c=%s>[%s]</c> %s %s <c=%s>[%s]</c> at %s --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), verb, otherchum.handle, otherchum.colorhtml(), otherchum.initials(), datetime.now().strftime("%H:%M"))
def memoclosemsg(self, syscolor, timeGrammar, verb):
return "<c=%s><c=%s>%s%s%s</c> %s.</c>" % (syscolor.name(), self.colorhtml(), timeGrammar.pcf, self.initials(), timeGrammar.number, verb)
def memojoinmsg(self, syscolor, td, timeGrammar, verb):
(temporal, pcf, when) = (timeGrammar.temporal, timeGrammar.pcf, timeGrammar.when)
atd = abs(td)
minutes = (atd.days*86400 + atd.seconds) // 60
hours = minutes // 60
leftoverminutes = minutes % 60
if atd == timedelta(0):
timetext = when
elif atd < timedelta(0,3600):
timetext = "%d MINUTES %s" % (minutes, when)
elif atd < timedelta(0,3600*100):
timetext = "%d:%02d HOURS %s" % (hours, leftoverminutes, when)
else:
timetext = "%d HOURS %s" % (hours, when)
initials = pcf+self.initials()+timeGrammar.number
return "<c=%s><c=%s>%s %s [%s]</c> %s %s." % \
(syscolor.name(), self.colorhtml(), temporal, self.handle,
initials, timetext, verb)
@staticmethod @staticmethod
def checkLength(handle): def checkLength(handle):

Binary file not shown.

View file

@ -1,5 +1,9 @@
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
class PesterList(list):
def __init__(self, l):
self.extend(l)
class PesterIcon(QtGui.QIcon): class PesterIcon(QtGui.QIcon):
def __init__(self, *x, **y): def __init__(self, *x, **y):
QtGui.QIcon.__init__(self, *x, **y) QtGui.QIcon.__init__(self, *x, **y)

Binary file not shown.

211
irc.py Normal file
View file

@ -0,0 +1,211 @@
from PyQt4 import QtGui, QtCore
from oyoyo.client import IRCClient
from oyoyo.cmdhandler import DefaultCommandHandler
from oyoyo import helpers
import logging
from dataobjs import Mood, PesterProfile
from generic import PesterList
logging.basicConfig(level=logging.INFO)
class PesterIRC(QtCore.QObject):
def __init__(self, window):
QtCore.QObject.__init__(self)
self.mainwindow = window
def IRCConnect(self):
self.cli = IRCClient(PesterHandler, host="irc.tymoon.eu", port=6667, nick=self.mainwindow.profile().handle, blocking=True)
self.cli.command_handler.parent = self
self.cli.command_handler.mainwindow = self.mainwindow
self.conn = self.cli.connect()
@QtCore.pyqtSlot(PesterProfile)
def getMood(self, *chums):
self.cli.command_handler.getMood(*chums)
@QtCore.pyqtSlot(PesterList)
def getMoods(self, chums):
self.cli.command_handler.getMood(*chums)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def sendMessage(self, text, handle):
h = unicode(handle)
helpers.msg(self.cli, h, text)
@QtCore.pyqtSlot(QtCore.QString, bool)
def startConvo(self, handle, initiated):
h = unicode(handle)
if initiated:
helpers.msg(self.cli, h, "PESTERCHUM:BEGIN")
helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
@QtCore.pyqtSlot(QtCore.QString)
def endConvo(self, handle):
h = unicode(handle)
helpers.msg(self.cli, h, "PESTERCHUM:CEASE")
@QtCore.pyqtSlot()
def updateProfile(self):
me = self.mainwindow.profile()
handle = me.handle
helpers.nick(self.cli, handle)
self.updateMood()
@QtCore.pyqtSlot()
def updateMood(self):
me = self.mainwindow.profile()
helpers.msg(self.cli, "#pesterchum", "MOOD >%d" % (me.mood.value()))
@QtCore.pyqtSlot()
def updateColor(self):
me = self.mainwindow.profile()
for h in self.mainwindow.convos.keys():
helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
@QtCore.pyqtSlot(QtCore.QString)
def blockedChum(self, handle):
h = unicode(handle)
helpers.msg(self.cli, h, "PESTERCHUM:BLOCK")
@QtCore.pyqtSlot(QtCore.QString)
def unblockedChum(self, handle):
h = unicode(handle)
helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK")
@QtCore.pyqtSlot(QtCore.QString)
def requestNames(self, channel):
c = unicode(channel)
helpers.names(self.cli, c)
@QtCore.pyqtSlot()
def requestChannelList(self):
helpers.channel_list(self.cli)
@QtCore.pyqtSlot(QtCore.QString)
def joinChannel(self, channel):
c = unicode(channel)
helpers.join(self.cli, c)
@QtCore.pyqtSlot(QtCore.QString)
def leftChannel(self, channel):
c = unicode(channel)
helpers.part(self.cli, c)
def updateIRC(self):
self.conn.next()
moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood)
colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor)
messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
memoReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
timeCommand = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
namesReceived = QtCore.pyqtSignal(QtCore.QString, PesterList)
channelListReceived = QtCore.pyqtSignal(PesterList)
nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
connected = QtCore.pyqtSignal()
userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString,
QtCore.QString)
class PesterHandler(DefaultCommandHandler):
def privmsg(self, nick, chan, msg):
# display msg, do other stuff
# silently ignore CTCP
if msg[0] == '\x01':
return
handle = nick[0:nick.find("!")]
logging.info("---> recv \"PRIVMSG %s :%s\"" % (handle, msg))
if chan == "#pesterchum":
# follow instructions
if msg[0:6] == "MOOD >":
try:
mood = Mood(int(msg[6:]))
except ValueError:
mood = Mood(0)
self.parent.moodUpdated.emit(handle, mood)
elif msg[0:7] == "GETMOOD":
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))
elif chan[0] == '#':
if msg[0:16] == "PESTERCHUM:TIME>":
self.parent.timeCommand.emit(chan, handle, msg[16:])
else:
self.parent.memoReceived.emit(chan, handle, msg)
else:
# private message
# silently ignore messages to yourself.
if handle == self.mainwindow.profile().handle:
return
if msg[0:7] == "COLOR >":
colors = msg[7:].split(",")
try:
colors = [int(d) for d in colors]
except ValueError:
colors = [0,0,0]
color = QtGui.QColor(*colors)
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):
newnick = "pesterClient%d" % (random.randint(100,999))
helpers.nick(self.client, newnick)
self.parent.nickCollision.emit(nick, newnick)
def quit(self, nick, reason):
handle = nick[0:nick.find("!")]
self.parent.userPresentUpdate.emit(handle, "", "quit")
self.parent.moodUpdated.emit(handle, Mood("offline"))
def part(self, nick, channel, reason="nanchos"):
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):
handle = nick[0:nick.find("!")]
self.parent.userPresentUpdate.emit(handle, channel, "join")
if channel == "#pesterchum":
self.parent.moodUpdated.emit(handle, Mood("chummy"))
def nick(self, oldnick, newnick):
oldhandle = oldnick[0:oldnick.find("!")]
newchum = PesterProfile(newnick, chumdb=self.mainwindow.chumdb)
self.parent.moodUpdated.emit(oldhandle, Mood("offline"))
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 getMood(self, *chums):
chumglub = "GETMOOD "
for c in chums:
chandle = c.handle
if len(chumglub+chandle) >= 350:
helpers.msg(self.client, "#pesterchum", chumglub)
chumglub = "GETMOOD "
chumglub += chandle
if chumglub != "GETMOOD ":
helpers.msg(self.client, "#pesterchum", chumglub)

BIN
irc.pyc Normal file

Binary file not shown.

View file

@ -1 +1 @@
{"macruralAlchemist": {"color": "#700000", "handle": "macruralAlchemist", "mood": "offline"}, "agogPorphyry": {"color": "#522d80", "handle": "agogPorphyry", "mood": "offline"}, "fireSwallow": {"color": "#80bb9a", "handle": "fireSwallow", "mood": "offline"}, "aquaMarinist": {"color": "#00caca", "handle": "aquaMarinist", "mood": "offline"}, "nitroZealist": {"color": "#ff3737", "handle": "nitroZealist", "mood": "offline"}, "superGhost": {"color": "#800564", "handle": "superGhost", "mood": "offline"}, "tentacleTherapist": {"color": "#cc66ff", "handle": "tentacleTherapist", "mood": "offline"}, "gardenGnostic": {"color": "#00ff00", "handle": "gardenGnostic", "mood": "offline"}, "aquaticMarinist": {"color": "#00caca", "handle": "aquaticMarinist", "mood": "offline"}, "captainCaveman": {"color": "#7c414e", "handle": "captainCaveman", "mood": "offline"}, "greenZephyr": {"color": "#00ca40", "handle": "greenZephyr", "mood": "offline"}, "pesterClient394": {"color": "#ff3737", "handle": "pesterClient394", "mood": "offline"}, "gamblingGenocider": {"color": "#00ff00", "handle": "gamblingGenocider", "mood": "offline"}, "mechanicalSpectacle": {"color": "#0000ff", "handle": "mechanicalSpectacle", "mood": "offline"}, "elegantDiversion": {"color": "#12b40d", "handle": "elegantDiversion", "mood": "offline"}, "absoluteTranquility": {"color": "#000033", "handle": "absoluteTranquility", "mood": "offline"}, "centaursTesticle": {"color": "#000056", "handle": "centaursTesticle", "mood": "offline"}, "schlagzeugGator": {"color": "#61821f", "handle": "schlagzeugGator", "mood": "offline"}, "unknownTraveler": {"color": "#006666", "handle": "unknownTraveler", "mood": "offline"}, "remoteBloodbath": {"color": "#c70000", "handle": "remoteBloodbath", "mood": "offline"}, "marineAquist": {"color": "#00caca", "handle": "marineAquist", "mood": "offline"}} {"macruralAlchemist": {"color": "#700000", "handle": "macruralAlchemist", "mood": "offline"}, "fireSwallow": {"color": "#80bb9a", "handle": "fireSwallow", "mood": "offline"}, "aquaMarinist": {"color": "#00caca", "handle": "aquaMarinist", "mood": "offline"}, "nitroZealist": {"color": "#ff3737", "handle": "nitroZealist", "mood": "offline"}, "masterG": {"color": "#77003c", "handle": "masterG", "mood": "offline"}, "aquaticMarinist": {"color": "#00caca", "handle": "aquaticMarinist", "mood": "offline"}, "iw": {"color": "#ff0000", "handle": "iw", "mood": "offline"}, "pesterClient394": {"color": "#ff3737", "handle": "pesterClient394", "mood": "offline"}, "absoluteTranquility": {"color": "#000033", "handle": "absoluteTranquility", "mood": "offline"}, "centaursTesticle": {"color": "#000056", "handle": "centaursTesticle", "mood": "offline"}, "agogPorphyry": {"color": "#522d80", "handle": "agogPorphyry", "mood": "offline"}, "illuminatedWax": {"color": "#ffff00", "handle": "illuminatedWax", "mood": "offline"}, "gamblingGenocider": {"color": "#00ff00", "handle": "gamblingGenocider", "mood": "offline"}, "elegantDiversion": {"color": "#12b40d", "handle": "elegantDiversion", "mood": "offline"}, "testOut": {"color": "#c760cc", "handle": "testOut", "mood": "offline"}, "superGhost": {"color": "#800564", "handle": "superGhost", "mood": "offline"}, "tentacleTherapist": {"color": "#cc66ff", "handle": "tentacleTherapist", "mood": "offline"}, "captainCaveman": {"color": "#7c414e", "handle": "captainCaveman", "mood": "offline"}, "cuttlefishCuller": {"color": "#77003c", "handle": "cuttlefishCuller", "mood": "offline"}, "mechanicalSpectacle": {"color": "#0000ff", "handle": "mechanicalSpectacle", "mood": "offline"}, "remoteBloodbath": {"color": "#c70000", "handle": "remoteBloodbath", "mood": "offline"}, "rageInducer": {"color": "#00ffff", "handle": "rageInducer", "mood": "offline"}, "gallowsCalibrator": {"color": "#008282", "handle": "gallowsCalibrator", "mood": "offline"}, "greenZephyr": {"color": "#00ca40", "handle": "greenZephyr", "mood": "offline"}, "schlagzeugGator": {"color": "#61821f", "handle": "schlagzeugGator", "mood": "offline"}, "gardenGnostic": {"color": "#00ff00", "handle": "gardenGnostic", "mood": "offline"}, "unknownTraveler": {"color": "#006666", "handle": "unknownTraveler", "mood": "offline"}, "marineAquist": {"color": "#00caca", "handle": "marineAquist", "mood": "offline"}}

389
memos.py
View file

@ -1,10 +1,170 @@
from string import Template from string import Template
import re import re
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from datetime import time, timedelta, datetime
from dataobjs import PesterProfile, Mood from dataobjs import PesterProfile, Mood
from generic import PesterIcon from generic import PesterIcon
from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow
from parsetools import convertTags, escapeBrackets, addTimeInitial, timeProtocol
def delta2txt(d, format="pc"):
if format == "pc":
sign = "+" if d >= timedelta(0) else "-"
else:
if d == timedelta(0):
return ""
sign = "F" if d >= timedelta(0) else "P"
d = abs(d)
totalminutes = (d.days*86400 + d.seconds) // 60
hours = totalminutes // 60
leftovermins = totalminutes % 60
if hours < 100:
if format == "pc":
return "%s%d:%02d" % (sign, hours, leftovermins)
else:
return "%s%02d:%02d" % (sign, hours, leftovermins)
else:
if format == "pc":
return "%s%d" % (sign, hours)
else:
return "%s%02d:%02d" % (sign, hours, leftovermins)
def txt2delta(txt):
sign = 1
if txt[0] == '+':
txt = txt[1:]
elif txt[0] == '-':
sign = -1
txt = txt[1:]
l = txt.split(":")
try:
h = int(l[0])
m = 0
if len(l) > 1:
m = int(l[1])
timed = timedelta(0, h*3600+m*60)
except ValueError:
timed = timedelta(0)
return sign*timed
def pcfGrammar(td):
if td > timedelta(0):
when = "FROM NOW"
temporal = "FUTURE"
pcf = "F"
elif td < timedelta(0):
when = "AGO"
temporal = "PAST"
pcf = "P"
else:
when = "RIGHT NOW"
temporal = "CURRENT"
pcf = "C"
return (temporal, pcf, when)
class TimeGrammar(object):
def __init__(self, temporal, pcf, when, number="0"):
self.temporal = temporal
self.pcf = pcf
self.when = when
if number == "0" or number == 0:
self.number = ""
else:
self.number = str(number)
class TimeTracker(list):
def __init__(self, time=None):
self.timerecord = {"P": [], "F": []}
if time is not None:
self.append(time)
self.current=0
self.addRecord(time)
else:
self.current=-1
def addTime(self, timed):
try:
i = self.index(timed)
self.current = i
except ValueError:
self.current = len(self)
self.append(timed)
self.addRecord(timed)
def setCurrent(self, timed):
self.current = self.index(timed)
def addRecord(self, timed):
(temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
if pcf == "C":
return
if timed in self.timerecord[pcf]:
return
self.timerecord[pcf].append(timed)
def getRecord(self, timed):
(temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
if pcf == "C":
return 0
if len(self.timerecord[pcf]) > 1:
return self.timerecord[pcf].index(timed)+1
else:
return 0
def removeTime(self, timed):
try:
self.pop(self.index(timed))
self.current = len(self)-1
except ValueError:
pass
def getTime(self):
if self.current >= 0:
return self[self.current]
else:
return None
def getGrammar(self):
timed = self.getTime()
mytime = timedelta(0)
(temporal, pcf, when) = pcfGrammar(timed - mytime)
if timed == mytime:
return TimeGrammar(temporal, pcf, when, 0)
return TimeGrammar(temporal, pcf, when, self.getRecord(timed))
class TimeInput(QtGui.QLineEdit):
def __init__(self, timeslider, parent):
QtGui.QLineEdit.__init__(self, parent)
self.timeslider = timeslider
self.setText("+0:00")
self.connect(self.timeslider, QtCore.SIGNAL('valueChanged(int)'),
self, QtCore.SLOT('setTime(int)'))
self.connect(self, QtCore.SIGNAL('editingFinished()'),
self, QtCore.SLOT('setSlider()'))
@QtCore.pyqtSlot(int)
def setTime(self, sliderval):
self.setText(self.timeslider.getTime())
@QtCore.pyqtSlot()
def setSlider(self):
value = unicode(self.text())
timed = txt2delta(value)
sign = 1 if timed >= timedelta(0) else -1
abstimed = abs(txt2delta(value))
index = 50
for i, td in enumerate(timedlist):
if abstimed < td:
index = i-1
break
self.timeslider.setValue(sign*index)
text = delta2txt(timed)
self.setText(text)
class TimeSlider(QtGui.QSlider):
def __init__(self, orientation, parent):
QtGui.QSlider.__init__(self, orientation, parent)
self.setTracking(True)
self.setMinimum(-50)
self.setMaximum(50)
self.setValue(0)
self.setPageStep(1)
def getTime(self):
time = timelist[abs(self.value())]
sign = "+" if self.value() >= 0 else "-"
return sign+time
class MemoTabWindow(PesterTabWindow): class MemoTabWindow(PesterTabWindow):
def __init__(self, mainwindow, parent=None): def __init__(self, mainwindow, parent=None):
@ -30,10 +190,57 @@ class MemoText(PesterText):
self.setReadOnly(True) self.setReadOnly(True)
self.setMouseTracking(True) self.setMouseTracking(True)
def addMessage(self, text, chum): def addMessage(self, text, chum):
# get chum color from c tag parent = self.parent()
mobj = _ctag_begin.match(text) window = parent.mainwindow
# tinychum sends straight /me with no color. go to chumdb! me = window.profile()
systemColor = QtGui.QColor(self.parent().mainwindow.theme["memo/systemMsgColor"]) msg = unicode(text)
chumdb = window.chumdb
if chum is not me: # SO MUCH WH1T3SP4C3 >:]
mobj = _ctag_begin.match(text) # get color from tag
if mobj:
try:
color = QtGui.QColor(*[int(c) for c in mobj.group(1).split(",")])
except ValueError:
color = QtGui.QColor("black")
else:
chumdb.setColor(chum.handle, color)
parent.updateColor(chum.handle, color)
else:
color = chumdb.getColor(chum.handle)
else:
color = me.color
chum.color = color
systemColor = QtGui.QColor(window.theme["memos/systemMsgColor"])
if chum is not me:
if parent.times.has_key(chum.handle):
time = parent.times[chum.handle]
else:
# new chum! time current
newtime = timedelta(0)
time = TimeTracker(newtime)
parent.times[chum.handle] = time
timeGrammar = time.getGrammar()
self.append(convertTags(chum.memojoinmsg(systemColor, time.getTime(), timeGrammar, window.theme["convo/text/joinmemo"])))
else:
time = parent.time
if msg[0:3] == "/me" or msg[0:13] == "PESTERCHUM:ME":
if msg[0:3] == "/me":
start = 3
else:
start = 13
space = msg.find(" ")
msg = chum.memsg(systemColor, msg[start:space], msg[space:], timegrammar=time.getGrammar())
window.chatlog.log(parent.channel, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
else:
if chum is not me:
msg = addTimeInitial(msg, parent.times[chum.handle].getGrammar())
msg = escapeBrackets(msg)
self.append(convertTags(msg))
window.chatlog.log(parent.channel, convertTags(msg, "bbcode"))
def changeTheme(self): def changeTheme(self):
pass pass
@ -46,10 +253,11 @@ class MemoInput(PesterInput):
self.setStyleSheet(theme["memos/input/style"]) self.setStyleSheet(theme["memos/input/style"])
class PesterMemo(PesterConvo): class PesterMemo(PesterConvo):
def __init__(self, channel, mainwindow, parent=None): def __init__(self, channel, timestr, mainwindow, parent=None):
QtGui.QFrame.__init__(self, parent) QtGui.QFrame.__init__(self, parent)
self.channel = channel self.channel = channel
self.mainwindow = mainwindow self.mainwindow = mainwindow
self.time = TimeTracker(txt2delta(timestr))
self.setWindowTitle(channel) self.setWindowTitle(channel)
self.channelLabel = QtGui.QLabel(self) self.channelLabel = QtGui.QLabel(self)
self.channelLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)) self.channelLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
@ -61,8 +269,13 @@ class PesterMemo(PesterConvo):
self.userlist = QtGui.QListWidget(self) self.userlist = QtGui.QListWidget(self)
self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding)) self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding))
self.timeslider = QtGui.QSlider(QtCore.Qt.Vertical, self) self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self)
self.timeinput = QtGui.QLineEdit(self) self.timeinput = TimeInput(self.timeslider, self)
self.timeinput.setText(timestr)
self.timeinput.setSlider()
self.timetravel = QtGui.QPushButton("GO", self)
self.times = {}
self.initTheme(self.mainwindow.theme) self.initTheme(self.mainwindow.theme)
@ -71,27 +284,36 @@ class PesterMemo(PesterConvo):
self, QtCore.SLOT('sentMessage()')) self, QtCore.SLOT('sentMessage()'))
layout_0 = QtGui.QVBoxLayout() layout_0 = QtGui.QVBoxLayout()
layout_0.addWidget(self.channelLabel)
layout_0.addWidget(self.textArea) layout_0.addWidget(self.textArea)
layout_0.addWidget(self.textInput) layout_0.addWidget(self.textInput)
layout_1 = QtGui.QGridLayout() layout_1 = QtGui.QHBoxLayout()
layout_1.addWidget(self.timeslider, 0, 1, QtCore.Qt.AlignHCenter) layout_1.addLayout(layout_0)
layout_1.addWidget(self.timeinput, 1, 0, 1, 3) layout_1.addWidget(self.userlist)
self.layout = QtGui.QHBoxLayout() # layout_1 = QtGui.QGridLayout()
self.setLayout(self.layout) # layout_1.addWidget(self.timeslider, 0, 1, QtCore.Qt.AlignHCenter)
# layout_1.addWidget(self.timeinput, 1, 0, 1, 3)
layout_2 = QtGui.QHBoxLayout()
layout_2.addWidget(self.timeslider)
layout_2.addWidget(self.timeinput)
layout_2.addWidget(self.timetravel)
self.layout.addLayout(layout_0) self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.userlist)
self.layout.addWidget(self.channelLabel)
self.layout.addLayout(layout_1) self.layout.addLayout(layout_1)
self.layout.addLayout(layout_2)
self.layout.setSpacing(0) self.layout.setSpacing(0)
margins = self.mainwindow.theme["memos/margins"] margins = self.mainwindow.theme["memos/margins"]
self.layout.setContentsMargins(margins["left"], margins["top"], self.layout.setContentsMargins(margins["left"], margins["top"],
margins["right"], margins["bottom"]) margins["right"], margins["bottom"])
self.setLayout(self.layout)
if parent: if parent:
parent.addChat(self) parent.addChat(self)
self.newmessage = False self.newmessage = False
def title(self): def title(self):
@ -99,17 +321,28 @@ class PesterMemo(PesterConvo):
def icon(self): def icon(self):
return PesterIcon(self.mainwindow.theme["memos/memoicon"]) return PesterIcon(self.mainwindow.theme["memos/memoicon"])
def sendTimeInfo(self, newChum=False):
if newChum:
self.messageSent.emit("PESTERCHUM:TIME>%s" % (delta2txt(self.time.getTime(), "server")+"i"),
self.title())
else:
self.messageSent.emit("PESTERCHUM:TIME>%s" % (delta2txt(self.time.getTime(), "server")),
self.title())
def updateMood(self): def updateMood(self):
pass pass
def updateBlocked(self): def updateBlocked(self):
pass pass
def updateColor(self): def updateColor(self, handle, color):
pass chums = self.userlist.findItems(handle, QtCore.Qt.MatchFlags(0))
for c in chums:
c.setTextColor(color)
def addMessage(self, text, handle): def addMessage(self, text, handle):
if type(handle) is bool: if type(handle) is bool:
chum = self.mainwindow.profile() chum = self.mainwindow.profile()
else: else:
chum = PesterProfile(handle) chum = PesterProfile(handle)
self.notifyNewMessage()
self.textArea.addMessage(text, chum) self.textArea.addMessage(text, chum)
def initTheme(self, theme): def initTheme(self, theme):
@ -125,7 +358,7 @@ class PesterMemo(PesterConvo):
self.channelLabel.setMaximumHeight(theme["memos/label/maxheight"]) self.channelLabel.setMaximumHeight(theme["memos/label/maxheight"])
self.channelLabel.setMinimumHeight(theme["memos/label/minheight"]) self.channelLabel.setMinimumHeight(theme["memos/label/minheight"])
self.userlist.setStyleSheet(theme["main/chums/style"]) self.userlist.setStyleSheet(theme["memos/userlist/style"])
self.userlist.setFixedWidth(theme["memos/userlist/width"]) self.userlist.setFixedWidth(theme["memos/userlist/width"])
self.timeinput.setFixedWidth(theme["memos/time/text/width"]) self.timeinput.setFixedWidth(theme["memos/time/text/width"])
@ -137,23 +370,127 @@ class PesterMemo(PesterConvo):
self.initTheme(theme) self.initTheme(theme)
self.textArea.changeTheme(theme) self.textArea.changeTheme(theme)
self.textInput.changeTheme(theme) self.textInput.changeTheme(theme)
margins = theme["memos/margins"]
self.layout.setContentsMargins(margins["left"], margins["top"],
margins["right"], margins["bottom"])
def addUser(self, handle):
chumdb = self.mainwindow.chumdb
defaultcolor = QtGui.QColor("black")
op = False
if handle[0] == '@':
op = True
handle = handle[1:]
item = QtGui.QListWidgetItem(handle)
if handle == self.mainwindow.profile().handle:
color = self.mainwindow.profile().color
else:
color = chumdb.getColor(handle, defaultcolor)
item.setTextColor(color)
self.userlist.addItem(item)
def timeUpdate(self, handle, cmd):
window = self.mainwindow
chum = PesterProfile(handle)
systemColor = QtGui.QColor(window.theme["memos/systemMsgColor"])
close = None
# old TC command?
try:
secs = int(cmd)
time = datetime.fromtimestamp(secs)
timed = time - datetime.now()
s = (timed // 60)*60
timed = timedelta(timed.days, s)
except ValueError:
if cmd == "i":
timed = timedelta(0)
else:
if cmd[len(cmd)-1] == 'c':
close = timeProtocol(cmd)
timed = None
else:
timed = timeProtocol(cmd)
if self.times.has_key(handle):
if close is not None:
if close in self.times[handle]:
self.times[handle].setCurrent(close)
grammar = self.times[handle].getGrammar()
self.times[handle].removeTime(close)
self.textArea.append(convertTags(chum.memoclosemsg(systemColor, grammar, window.theme["convo/text/closememo"])))
elif timed not in self.times[handle]:
self.times[handle].addTime(timed)
grammar = self.times[handle].getGrammar()
self.textArea.append(convertTags(chum.memojoinmsg(systemColor, timed, grammar, window.theme["convo/text/joinmemo"])))
else:
self.times[handle].setCurrent(timed)
else:
if timed is not None:
ttracker = TimeTracker(timed)
grammar = ttracker.getGrammar()
self.textArea.append(convertTags(chum.memojoinmsg(systemColor, timed, grammar, window.theme["convo/text/joinmemo"])))
self.times[handle] = ttracker
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def sentMessage(self): def sentMessage(self):
text = self.textInput.text() text = self.textInput.text()
if text == "": if text == "":
return return
text = "<c=%s>%s</c>" % (self.mainwindow.profile().colorcmd(), text) grammar = self.time.getGrammar()
self.textInput.setText(text) # deal with quirks here
PesterConvo.sentMessage(self) qtext = self.mainwindow.userprofile.quirks.apply(unicode(text))
if qtext[0:3] != "/me":
initials = self.mainwindow.profile().initials()
colorcmd = self.mainwindow.profile().colorcmd()
clientText = "<c=%s>%s%s%s: %s</c>" % (colorcmd, grammar.pcf, initials, grammar.number, qtext)
# account for TC's parsing error
serverText = "<c=%s>%s: %s</c> " % (colorcmd, initials, qtext)
else:
clientText = qtext
serverText = clientText
self.textInput.setText("")
self.addMessage(clientText, True)
# convert color tags
text = convertTags(unicode(serverText), "ctag")
self.messageSent.emit(serverText, self.title())
@QtCore.pyqtSlot()
def namesUpdated(self):
# get namesdb
namesdb = self.mainwindow.namesdb
# reload names
self.userlist.clear()
for n in self.mainwindow.namesdb[self.channel]:
self.addUser(n)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
def userPresentChange(self, handle, channel, update):
if channel != self.channel:
return
chums = self.userlist.findItems(handle, QtCore.Qt.MatchFlags(0))
h = unicode(handle)
c = unicode(channel)
systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
# print exit
if update == "quit" or update == "left":
for c in chums:
chum = PesterProfile(h)
self.userlist.takeItem(self.userlist.row(c))
while self.times[h].getTime() is not None:
t = self.times[h]
grammar = t.getGrammar()
self.textArea.append(convertTags(chum.memoclosemsg(systemColor, grammar, self.mainwindow.theme["convo/text/closememo"])))
self.times[h].removeTime(t.getTime())
elif update == "join":
self.addUser(h)
def closeEvent(self, event): def closeEvent(self, event):
self.mainwindow.waitingMessages.messageAnswered(self.channel) self.mainwindow.waitingMessages.messageAnswered(self.channel)
# self.windowClosed.emit(self.chum.handle) self.windowClosed.emit(self.title())
windowClosed = QtCore.pyqtSignal(QtCore.QString)
# messageSent - signal -> sendMessage -> sendMessage(Memo) timelist = ["0:00", "0:01", "0:02", "0:04", "0:06", "0:10", "0:14", "0:22", "0:30", "0:41", "1:00", "1:34", "2:16", "3:14", "4:13", "4:20", "5:25", "6:12", "7:30", "8:44", "10:25", "11:34", "14:13", "16:12", "17:44", "22:22", "25:10", "33:33", "42:00", "43:14", "50:00", "62:12", "75:00", "88:44", "100", "133", "143", "188", "200", "222", "250", "314", "333", "413", "420", "500", "600", "612", "888", "1000", "1025"]
# windowClosed - signal -> closeMemo
# self.textInput timedlist = [timedelta(0), timedelta(0, 60), timedelta(0, 120), timedelta(0, 240), timedelta(0, 360), timedelta(0, 600), timedelta(0, 840), timedelta(0, 1320), timedelta(0, 1800), timedelta(0, 2460), timedelta(0, 3600), timedelta(0, 5640), timedelta(0, 8160), timedelta(0, 11640), timedelta(0, 15180), timedelta(0, 15600), timedelta(0, 19500), timedelta(0, 22320), timedelta(0, 27000), timedelta(0, 31440), timedelta(0, 37500), timedelta(0, 41640), timedelta(0, 51180), timedelta(0, 58320), timedelta(0, 63840), timedelta(0, 80520), timedelta(1, 4200), timedelta(1, 34380), timedelta(1, 64800), timedelta(1, 69240), timedelta(2, 7200), timedelta(2, 51120), timedelta(3, 10800), timedelta(3, 60240), timedelta(4, 14400), timedelta(5, 46800), timedelta(5, 82800), timedelta(7, 72000), timedelta(8, 28800), timedelta(9, 21600), timedelta(10, 36000), timedelta(13, 7200), timedelta(13, 75600), timedelta(17, 18000), timedelta(17, 43200), timedelta(20, 72000), timedelta(25), timedelta(25, 43200), timedelta(37), timedelta(41, 57600), timedelta(42, 61200)]
# self.textArea

BIN
memos.pyc

Binary file not shown.

View file

@ -3,6 +3,7 @@ import re
from generic import RightClickList, MultiTextDialog from generic import RightClickList, MultiTextDialog
from dataobjs import pesterQuirk, PesterProfile from dataobjs import pesterQuirk, PesterProfile
from memos import TimeSlider, TimeInput
class PesterQuirkItem(QtGui.QListWidgetItem): class PesterQuirkItem(QtGui.QListWidgetItem):
def __init__(self, quirk, parent): def __init__(self, quirk, parent):
@ -407,13 +408,17 @@ class PesterMemoList(QtGui.QDialog):
self.orjoinlabel = QtGui.QLabel("OR MAKE A NEW MEMO:") self.orjoinlabel = QtGui.QLabel("OR MAKE A NEW MEMO:")
self.newmemo = QtGui.QLineEdit(self) self.newmemo = QtGui.QLineEdit(self)
self.timelabel = QtGui.QLabel("TIMEFRAME:")
self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self)
self.timeinput = TimeInput(self.timeslider, self)
self.cancel = QtGui.QPushButton("CANCEL", self) self.cancel = QtGui.QPushButton("CANCEL", self)
self.connect(self.cancel, QtCore.SIGNAL('clicked()'), self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()')) self, QtCore.SLOT('reject()'))
self.join = QtGui.QPushButton("JOIN", self) self.join = QtGui.QPushButton("JOIN", self)
self.join.setDefault(True) self.join.setDefault(True)
self.connect(self.join, QtCore.SIGNAL('clicked()'), self.connect(self.join, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('accept()')) self, QtCore.SLOT('checkEmpty()'))
layout_ok = QtGui.QHBoxLayout() layout_ok = QtGui.QHBoxLayout()
layout_ok.addWidget(self.cancel) layout_ok.addWidget(self.cancel)
layout_ok.addWidget(self.join) layout_ok.addWidget(self.join)
@ -423,6 +428,9 @@ class PesterMemoList(QtGui.QDialog):
layout_0.addWidget(self.channelarea) layout_0.addWidget(self.channelarea)
layout_0.addWidget(self.orjoinlabel) layout_0.addWidget(self.orjoinlabel)
layout_0.addWidget(self.newmemo) layout_0.addWidget(self.newmemo)
layout_0.addWidget(self.timelabel)
layout_0.addWidget(self.timeslider)
layout_0.addWidget(self.timeinput)
layout_0.addLayout(layout_ok) layout_0.addLayout(layout_ok)
self.setLayout(layout_0) self.setLayout(layout_0)
@ -446,6 +454,12 @@ class PesterMemoList(QtGui.QDialog):
item.setTextColor(QtGui.QColor(theme["main/chums/userlistcolor"])) item.setTextColor(QtGui.QColor(theme["main/chums/userlistcolor"]))
item.setIcon(QtGui.QIcon(theme["memos/memoicon"])) item.setIcon(QtGui.QIcon(theme["memos/memoicon"]))
@QtCore.pyqtSlot()
def checkEmpty(self):
newmemo = self.newmemoname()
selectedmemo = self.selectedmemo()
if newmemo or selectedmemo:
self.accept()
@QtCore.pyqtSlot(QtGui.QListWidgetItem) @QtCore.pyqtSlot(QtGui.QListWidgetItem)
def joinActivatedMemo(self, item): def joinActivatedMemo(self, item):
self.channelarea.setCurrentItem(item) self.channelarea.setCurrentItem(item)
@ -460,16 +474,11 @@ class LoadingScreen(QtGui.QDialog):
self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"])
self.loadinglabel = QtGui.QLabel("LO4D1NG") self.loadinglabel = QtGui.QLabel("LO4D1NG")
self.cancel = QtGui.QPushButton("QU1T >:?")
self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()'))
self.layout = QtGui.QVBoxLayout() self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.loadinglabel) self.layout.addWidget(self.loadinglabel)
self.layout.addWidget(self.cancel)
self.setLayout(self.layout) self.setLayout(self.layout)
QtCore.QTimer.singleShot(25000, self, QtCore.SLOT('connectTimeout()'))
@QtCore.pyqtSlot()
def connectTimeout(self):
if hasattr(self, 'failed'):
self.accept()
else:
self.failed = True
self.loadinglabel.setText("F41L3D")
QtCore.QTimer.singleShot(1000, self, QtCore.SLOT('connectTimeout()'))

BIN
menus.pyc

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,5 @@
import re import re
from datetime import timedelta
from PyQt4 import QtGui from PyQt4 import QtGui
_ctag_begin = re.compile(r'<c=(.*?)>') _ctag_begin = re.compile(r'<c=(.*?)>')
@ -87,3 +88,23 @@ def escapeBrackets(string):
for i in range(0, btlen-etlen): for i in range(0, btlen-etlen):
retval += "</c>" retval += "</c>"
return retval return retval
def addTimeInitial(string, grammar):
endofi = string.find(":")
endoftag = string.find(">")
if endoftag < 0 or endoftag > 16 or endofi > 17:
return string
return string[0:endoftag+1]+grammar.pcf+string[endoftag+1:endofi]+grammar.number+string[endofi:]
def timeProtocol(cmd):
dir = cmd[0]
cmd = cmd[1:]
cmd = re.sub("[^0-9:]", "", cmd)
try:
l = [int(x) for x in cmd.split(":")]
except ValueError:
l = [0,0]
timed = timedelta(0, l[0]*3600+l[1]*60)
if dir == "P":
timed = timed*-1
return timed

Binary file not shown.

View file

@ -1 +1 @@
{"tabs": false, "chums": ["aquaMarinist", "marineAquist", "unknownTraveler", "tentacleTherapist", "macruralAlchemist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "fireSwallow", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador"], "defaultprofile": "testProfile", "block": []} {"tabs": true, "chums": ["aquaMarinist", "marineAquist", "unknownTraveler", "tentacleTherapist", "macruralAlchemist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "fireSwallow", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium"], "defaultprofile": "testProfile", "block": []}

View file

@ -1,7 +1,4 @@
# pesterchum # pesterchum
from oyoyo.client import IRCClient
from oyoyo.cmdhandler import DefaultCommandHandler
from oyoyo import helpers
import logging import logging
import os, sys import os, sys
import os.path import os.path
@ -17,12 +14,11 @@ from menus import PesterChooseQuirks, PesterChooseTheme, \
PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \ PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \
LoadingScreen LoadingScreen
from dataobjs import PesterProfile, Mood, pesterQuirk, pesterQuirks from dataobjs import PesterProfile, Mood, pesterQuirk, pesterQuirks
from generic import PesterIcon, RightClickList, MultiTextDialog from generic import PesterIcon, RightClickList, MultiTextDialog, PesterList
from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo
from parsetools import convertTags from parsetools import convertTags
from memos import PesterMemo, MemoTabWindow from memos import PesterMemo, MemoTabWindow
from irc import PesterIRC
logging.basicConfig(level=logging.INFO)
class waitingMessageHolder(object): class waitingMessageHolder(object):
def __init__(self, mainwindow, **msgfuncs): def __init__(self, mainwindow, **msgfuncs):
@ -110,10 +106,6 @@ class PesterProfileDB(dict):
dict.__setitem__(self, key, val) dict.__setitem__(self, key, val)
self.save() self.save()
class PesterList(list):
def __init__(self, l):
self.extend(l)
class pesterTheme(dict): class pesterTheme(dict):
def __init__(self, name): def __init__(self, name):
self.path = "themes/%s" % (name) self.path = "themes/%s" % (name)
@ -708,6 +700,8 @@ class PesterWindow(MovingWindow):
if not self.config.defaultprofile(): if not self.config.defaultprofile():
self.changeProfile() self.changeProfile()
self.loadingscreen = LoadingScreen(self) self.loadingscreen = LoadingScreen(self)
self.connect(self.loadingscreen, QtCore.SIGNAL('rejected()'),
self, QtCore.SLOT('close()'))
def profile(self): def profile(self):
return self.userprofile.chat return self.userprofile.chat
@ -756,6 +750,7 @@ class PesterWindow(MovingWindow):
return return
memo = self.memos[chan] memo = self.memos[chan]
memo.addMessage(msg, handle) memo.addMessage(msg, handle)
self.alarm.play()
def changeColor(self, handle, color): def changeColor(self, handle, color):
# pesterconvo and chumlist # pesterconvo and chumlist
@ -798,28 +793,34 @@ class PesterWindow(MovingWindow):
self.connect(self.tabmemo, QtCore.SIGNAL('windowClosed()'), self.connect(self.tabmemo, QtCore.SIGNAL('windowClosed()'),
self, QtCore.SLOT('memoTabsClosed()')) self, QtCore.SLOT('memoTabsClosed()'))
def newMemo(self, channel): def newMemo(self, channel, timestr):
if channel == "#pesterchum": if channel == "#pesterchum":
return return
if self.memos.has_key(channel): if self.memos.has_key(channel):
# load memo self.memos[channel].showChat()
return return
# do slider dialog then set # do slider dialog then set
if self.config.tabs(): if self.config.tabs():
if not self.tabmemo: if not self.tabmemo:
self.createMemoTabWindow() self.createMemoTabWindow()
memoWindow = PesterMemo(channel, self, self.tabmemo) memoWindow = PesterMemo(channel, timestr, self, self.tabmemo)
self.tabmemo.show() self.tabmemo.show()
else: else:
memoWindow = PesterMemo(channel, self, None) memoWindow = PesterMemo(channel, timestr, self, None)
# connect signals # connect signals
self.connect(memoWindow, QtCore.SIGNAL('messageSent(QString, QString)'), self.connect(memoWindow, QtCore.SIGNAL('messageSent(QString, QString)'),
self, QtCore.SIGNAL('sendMessage(QString, QString)')) self, QtCore.SIGNAL('sendMessage(QString, QString)'))
# self.connect(memoWindow, QtCore.SIGNAL('windowClosed(QString)'), self.connect(memoWindow, QtCore.SIGNAL('windowClosed(QString)'),
# self, QtCore.SLOT('closeConvo(QString)')) self, QtCore.SLOT('closeMemo(QString)'))
self.connect(self, QtCore.SIGNAL('namesUpdated()'),
memoWindow, QtCore.SLOT('namesUpdated()'))
self.connect(self,
QtCore.SIGNAL('userPresentSignal(QString, QString, QString)'),
memoWindow, QtCore.SLOT('userPresentChange(QString, QString, QString)'))
# chat client send memo open # chat client send memo open
self.memos[channel] = memoWindow self.memos[channel] = memoWindow
self.joinChannel.emit(channel) self.joinChannel.emit(channel) # race condition?
memoWindow.sendTimeInfo()
memoWindow.show() memoWindow.show()
def addChum(self, chum): def addChum(self, chum):
@ -859,6 +860,7 @@ class PesterWindow(MovingWindow):
self.opts.setText(theme["main/menus/client/options"]) self.opts.setText(theme["main/menus/client/options"])
self.exitaction.setText(theme["main/menus/client/exit"]) self.exitaction.setText(theme["main/menus/client/exit"])
self.userlistaction.setText(theme["main/menus/client/userlist"]) self.userlistaction.setText(theme["main/menus/client/userlist"])
self.memoaction.setText(theme["main/menus/client/memos"])
self.filemenu.setTitle(theme["main/menus/client/_name"]) self.filemenu.setTitle(theme["main/menus/client/_name"])
self.changetheme.setText(theme["main/menus/profile/theme"]) self.changetheme.setText(theme["main/menus/profile/theme"])
self.changequirks.setText(theme["main/menus/profile/quirks"]) self.changequirks.setText(theme["main/menus/profile/quirks"])
@ -949,7 +951,7 @@ class PesterWindow(MovingWindow):
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def connected(self): def connected(self):
if self.loadingscreen: if self.loadingscreen:
self.loadingscreen.close() self.loadingscreen.accept()
self.loadingscreen = None self.loadingscreen = None
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def blockSelectedChum(self): def blockSelectedChum(self):
@ -977,9 +979,15 @@ class PesterWindow(MovingWindow):
chumopen = self.convos[h].chumopen chumopen = self.convos[h].chumopen
if chumopen: if chumopen:
self.chatlog.log(chum.handle, convertTags(self.profile().pestermsg(chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/ceasepester"]), "bbcode")) self.chatlog.log(chum.handle, convertTags(self.profile().pestermsg(chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/ceasepester"]), "bbcode"))
self.chatlog.finish(h)
self.convoClosed.emit(handle) self.convoClosed.emit(handle)
self.chatlog.finish(h)
del self.convos[h] del self.convos[h]
@QtCore.pyqtSlot(QtCore.QString)
def closeMemo(self, channel):
c = unicode(channel)
self.chatlog.finish(c)
self.leftChannel.emit(channel)
del self.memos[c]
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def tabsClosed(self): def tabsClosed(self):
del self.tabconvo del self.tabconvo
@ -1008,6 +1016,11 @@ class PesterWindow(MovingWindow):
def deliverMemo(self, chan, handle, msg): def deliverMemo(self, chan, handle, msg):
(c, h, m) = (unicode(chan), unicode(handle), unicode(msg)) (c, h, m) = (unicode(chan), unicode(handle), unicode(msg))
self.newMemoMsg(c,h,m) self.newMemoMsg(c,h,m)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
def timeCommand(self, chan, handle, command):
(c, h, cmd) = (unicode(chan), unicode(handle), unicode(command))
if self.memos[c]:
self.memos[c].timeUpdate(h, cmd)
@QtCore.pyqtSlot(QtCore.QString, PesterList) @QtCore.pyqtSlot(QtCore.QString, PesterList)
def updateNames(self, channel, names): def updateNames(self, channel, names):
@ -1121,12 +1134,13 @@ class PesterWindow(MovingWindow):
def joinSelectedMemo(self): def joinSelectedMemo(self):
newmemo = self.memochooser.newmemoname() newmemo = self.memochooser.newmemoname()
selectedmemo = self.memochooser.selectedmemo() selectedmemo = self.memochooser.selectedmemo()
time = unicode(self.memochooser.timeinput.text())
if newmemo: if newmemo:
channel = "#"+unicode(newmemo) channel = "#"+unicode(newmemo)
self.newMemo(channel) self.newMemo(channel, time)
elif selectedmemo: elif selectedmemo:
channel = "#"+unicode(selectedmemo.text()) channel = "#"+unicode(selectedmemo.text())
self.newMemo(channel) self.newMemo(channel, time)
self.memochooser = None self.memochooser = None
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def memoChooserClose(self): def memoChooserClose(self):
@ -1208,13 +1222,20 @@ class PesterWindow(MovingWindow):
tabsetting = self.optionmenu.tabcheck.isChecked() tabsetting = self.optionmenu.tabcheck.isChecked()
if curtab and not tabsetting: if curtab and not tabsetting:
# split tabs into windows # split tabs into windows
windows = []
if self.tabconvo: if self.tabconvo:
windows = list(self.tabconvo.convos.values()) windows = list(self.tabconvo.convos.values())
for w in windows: if self.tabmemo:
w.setParent(None) windows += list(self.tabmemo.convos.values())
w.show()
w.raiseChat() for w in windows:
w.setParent(None)
w.show()
w.raiseChat()
if self.tabconvo:
self.tabconvo.closeSoft() self.tabconvo.closeSoft()
if self.tabmemo:
self.tabmemo.closeSoft()
# save options # save options
self.config.set("tabs", tabsetting) self.config.set("tabs", tabsetting)
elif tabsetting and not curtab: elif tabsetting and not curtab:
@ -1227,6 +1248,14 @@ class PesterWindow(MovingWindow):
self.tabconvo.show() self.tabconvo.show()
newconvos[h] = c newconvos[h] = c
self.convos = newconvos self.convos = newconvos
newmemos = {}
self.createMemoTabWindow()
for (h,m) in self.memos.iteritems():
m.setParent(self.tabmemo)
self.tabmemo.addChat(m)
self.tabmemo.show()
newmemos[h] = m
self.memos = newmemos
# save options # save options
self.config.set("tabs", tabsetting) self.config.set("tabs", tabsetting)
self.optionmenu = None self.optionmenu = None
@ -1366,203 +1395,7 @@ class PesterWindow(MovingWindow):
blockedChum = QtCore.pyqtSignal(QtCore.QString) blockedChum = QtCore.pyqtSignal(QtCore.QString)
unblockedChum = QtCore.pyqtSignal(QtCore.QString) unblockedChum = QtCore.pyqtSignal(QtCore.QString)
joinChannel = QtCore.pyqtSignal(QtCore.QString) joinChannel = QtCore.pyqtSignal(QtCore.QString)
leftChannel = QtCore.pyqtSignal(QtCore.QString)
class PesterIRC(QtCore.QObject):
def __init__(self, window):
QtCore.QObject.__init__(self)
self.mainwindow = window
def IRCConnect(self):
self.cli = IRCClient(PesterHandler, host="irc.tymoon.eu", port=6667, nick=self.mainwindow.profile().handle, blocking=True)
self.cli.command_handler.parent = self
self.cli.command_handler.mainwindow = self.mainwindow
self.conn = self.cli.connect()
@QtCore.pyqtSlot(PesterProfile)
def getMood(self, *chums):
self.cli.command_handler.getMood(*chums)
@QtCore.pyqtSlot(PesterList)
def getMoods(self, chums):
self.cli.command_handler.getMood(*chums)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def sendMessage(self, text, handle):
h = unicode(handle)
helpers.msg(self.cli, h, text)
@QtCore.pyqtSlot(QtCore.QString, bool)
def startConvo(self, handle, initiated):
h = unicode(handle)
if initiated:
helpers.msg(self.cli, h, "PESTERCHUM:BEGIN")
helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
@QtCore.pyqtSlot(QtCore.QString)
def endConvo(self, handle):
h = unicode(handle)
helpers.msg(self.cli, h, "PESTERCHUM:CEASE")
@QtCore.pyqtSlot()
def updateProfile(self):
me = self.mainwindow.profile()
handle = me.handle
helpers.nick(self.cli, handle)
self.updateMood()
@QtCore.pyqtSlot()
def updateMood(self):
me = self.mainwindow.profile()
helpers.msg(self.cli, "#pesterchum", "MOOD >%d" % (me.mood.value()))
@QtCore.pyqtSlot()
def updateColor(self):
me = self.mainwindow.profile()
for h in self.mainwindow.convos.keys():
helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
@QtCore.pyqtSlot(QtCore.QString)
def blockedChum(self, handle):
h = unicode(handle)
helpers.msg(self.cli, h, "PESTERCHUM:BLOCK")
@QtCore.pyqtSlot(QtCore.QString)
def unblockedChum(self, handle):
h = unicode(handle)
helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK")
@QtCore.pyqtSlot(QtCore.QString)
def requestNames(self, channel):
c = unicode(channel)
helpers.names(self.cli, c)
@QtCore.pyqtSlot()
def requestChannelList(self):
helpers.channel_list(self.cli)
@QtCore.pyqtSlot(QtCore.QString)
def joinChannel(self, channel):
c = unicode(channel)
helpers.join(self.cli, c)
def updateIRC(self):
self.conn.next()
moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood)
colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor)
messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
memoReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
namesReceived = QtCore.pyqtSignal(QtCore.QString, PesterList)
channelListReceived = QtCore.pyqtSignal(PesterList)
nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
connected = QtCore.pyqtSignal()
userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString,
QtCore.QString)
class PesterHandler(DefaultCommandHandler):
def privmsg(self, nick, chan, msg):
# display msg, do other stuff
# silently ignore CTCP
if msg[0] == '\x01':
return
handle = nick[0:nick.find("!")]
logging.info("---> recv \"PRIVMSG %s :%s\"" % (handle, msg))
if chan == "#pesterchum":
# follow instructions
if msg[0:6] == "MOOD >":
try:
mood = Mood(int(msg[6:]))
except ValueError:
mood = Mood(0)
self.parent.moodUpdated.emit(handle, mood)
elif msg[0:7] == "GETMOOD":
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))
elif chan[0] == '#':
if msg[0:16] == "PESTERCHUM:TIME>":
# send time msg
pass
else:
self.parent.memoReceived.emit(chan, handle, msg)
else:
# private message
# silently ignore messages to yourself.
if handle == self.mainwindow.profile().handle:
return
if msg[0:7] == "COLOR >":
colors = msg[7:].split(",")
try:
colors = [int(d) for d in colors]
except ValueError:
colors = [0,0,0]
color = QtGui.QColor(*colors)
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):
newnick = "pesterClient%d" % (random.randint(100,999))
helpers.nick(self.client, newnick)
self.parent.nickCollision.emit(nick, newnick)
def quit(self, nick, reason):
handle = nick[0:nick.find("!")]
self.parent.userPresentUpdate.emit(handle, "", "quit")
self.parent.moodUpdated.emit(handle, Mood("offline"))
def part(self, nick, channel, reason="nanchos"):
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):
handle = nick[0:nick.find("!")]
self.parent.userPresentUpdate.emit(handle, channel, "join")
if channel == "#pesterchum":
self.parent.moodUpdated.emit(handle, Mood("chummy"))
def nick(self, oldnick, newnick):
oldhandle = oldnick[0:oldnick.find("!")]
newchum = PesterProfile(newnick, chumdb=self.mainwindow.chumdb)
self.parent.moodUpdated.emit(oldhandle, Mood("offline"))
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 getMood(self, *chums):
chumglub = "GETMOOD "
for c in chums:
chandle = c.handle
if len(chumglub+chandle) >= 350:
helpers.msg(self.client, "#pesterchum", chumglub)
chumglub = "GETMOOD "
chumglub += chandle
if chumglub != "GETMOOD ":
helpers.msg(self.client, "#pesterchum", chumglub)
class IRCThread(QtCore.QThread): class IRCThread(QtCore.QThread):
def __init__(self, ircobj): def __init__(self, ircobj):
@ -1662,6 +1495,11 @@ def main():
QtCore.SIGNAL('joinChannel(QString)'), QtCore.SIGNAL('joinChannel(QString)'),
irc, irc,
QtCore.SLOT('joinChannel(QString)')) QtCore.SLOT('joinChannel(QString)'))
irc.connect(widget,
QtCore.SIGNAL('leftChannel(QString)'),
irc,
QtCore.SLOT('leftChannel(QString)'))
# IRC --> Main window # IRC --> Main window
irc.connect(irc, QtCore.SIGNAL('connected()'), irc.connect(irc, QtCore.SIGNAL('connected()'),
@ -1698,10 +1536,16 @@ def main():
QtCore.SIGNAL('channelListReceived(PyQt_PyObject)'), QtCore.SIGNAL('channelListReceived(PyQt_PyObject)'),
widget, widget,
QtCore.SLOT('updateChannelList(PyQt_PyObject)')) QtCore.SLOT('updateChannelList(PyQt_PyObject)'))
irc.connect(irc,
QtCore.SIGNAL('timeCommand(QString, QString, QString)'),
widget,
QtCore.SLOT('timeCommand(QString, QString, QString)'))
ircapp = IRCThread(irc) ircapp = IRCThread(irc)
ircapp.start() ircapp.start()
widget.loadingscreen.exec_() status = widget.loadingscreen.exec_()
if status == QtGui.QDialog.Rejected:
sys.exit(0)
sys.exit(app.exec_()) sys.exit(app.exec_())
main() main()

View file

@ -208,7 +208,10 @@
"beganpester": "began pestering", "beganpester": "began pestering",
"ceasepester": "ceased pestering", "ceasepester": "ceased pestering",
"blocked": "blocked", "blocked": "blocked",
"unblocked": "unblocked" "unblocked": "unblocked",
"openmemo": "opened memo on board",
"joinmemo": "responded to memo",
"closememo": "ceased responding to memo"
}, },
"systemMsgColor": "#646464" "systemMsgColor": "#646464"
}, },
@ -231,11 +234,14 @@
"input": { "style": "background: white; border:2px solid #c48a00;margin-top:5px;" }, "input": { "style": "background: white; border:2px solid #c48a00;margin-top:5px;" },
"textarea": { "style": "background: white; font:bold; border:2px solid #c48a00;text-align:center;" }, "textarea": { "style": "background: white; font:bold; border:2px solid #c48a00;text-align:center;" },
"margins": {"top": 0, "bottom": 0, "left": 0, "right": 0 }, "margins": {"top": 0, "bottom": 0, "left": 0, "right": 0 },
"userlist": { "width": 150 }, "userlist": { "width": 150,
"style": "border:2px solid yellow; background: white;font: bold;font-family: 'Courier';selection-background-color:#646464; "
},
"time": { "text": { "width": 75, "style": "" }, "time": { "text": { "width": 75, "style": "" },
"slider": { "style": "", "slider": { "style": "",
"groove": "", "groove": "",
"handle": "" } "handle": ""
}
}, },
"systemMsgColor": "#646464" "systemMsgColor": "#646464"
} }

View file

@ -256,13 +256,45 @@
"beganpester": "began trolling", "beganpester": "began trolling",
"ceasepester": "gave up trolling", "ceasepester": "gave up trolling",
"blocked": "blocked", "blocked": "blocked",
"unblocked": "mercifully forgave" "unblocked": "mercifully forgave",
"openmemo": "opened memo on board",
"joinmemo": "responded to memo",
"closememo": "ceased responding to memo"
}, },
"systemMsgColor": "#646464" "systemMsgColor": "#646464"
}, },
"memos": "memos":
{"memoicon": "$path/memo.png" {"memoicon": "$path/memo.png",
"style": "background: rgb(190, 19, 4); font-family: 'Arial';",
} "size": [600,300],
"tabs": {
"style": "",
"selectedstyle": "",
"newmsgcolor": "red",
"tabstyle": 0
},
"label": { "text": "$channel",
"style": "background: rgb(255, 38, 18); color: white; padding: 2px; border:1px solid #c2c2c2;",
"align": { "h": "center", "v": "center" },
"minheight": 30,
"maxheight": 50
},
"textarea": {
"style": "background: white; border:2px solid #c2c2c2; font-size: 12px; margin-top: 4px;"
},
"input": {
"style": "background: white;margin-top:5px; border:1px solid #c2c2c2; margin-right: 54px; font-size: 12px;"
},
"margins": {"top": 0, "bottom": 0, "left": 0, "right": 0 },
"userlist": { "width": 150,
"style": "font-size: 12px; background: white; border:2px solid #c2c2c2; padding: 5px; font-family: 'Arial';selection-background-color:rgb(200,200,200);"
},
"time": { "text": { "width": 75, "style": "" },
"slider": { "style": "",
"groove": "",
"handle": ""
}
},
"systemMsgColor": "#646464"
}
} }