the great parser change!

This commit is contained in:
Stephen Dranger 2011-02-13 03:27:12 -06:00
parent aca11bb00e
commit c7987a37aa
23 changed files with 384 additions and 180 deletions

12
TODO
View file

@ -1,17 +1,17 @@
Features:
* Tray doesn't disappear on windows after close
* memo sending from unknown color breaks -- over IRC
* smilies processed before quirks
* More complex quirks: random, spelling, by-sound
* More complex quirks: spelling, by-sound
* random quirk string enter must clear text box and focus input on add
* IRC message limit!!!
* on ban, redirect to memo chooser
* ? time option???
* convert hex tags (<GFFFFFF> or <GFF0000>)
* help menu -- about and forum
* Tray doesn't disappear on windows after close
* memo sending from unknown color breaks -- over IRC??
-- release alpha
* shared buddy lists - changes to the buddy list should refresh it?
multiple clients share buddy list???
* chumList not scaling -- QListView + delegate?
* spell check?
* convo backgrounds -- make them more like http://www.mspaintadventures.com/storyfiles/hs2/02546_2.gif
* help button on quirks menu?
-- release beta
* flashing??

121
convo.py
View file

@ -1,11 +1,12 @@
from string import Template
import re
from copy import copy
from datetime import datetime, timedelta
from PyQt4 import QtGui, QtCore
from dataobjs import PesterProfile, Mood, PesterHistory
from generic import PesterIcon, RightClickList
from parsetools import convertTags
from parsetools import convertTags, lexMessage, mecmd, colorBegin, colorEnd
class PesterTabWindow(QtGui.QFrame):
def __init__(self, mainwindow, parent=None, convo="convo"):
@ -203,74 +204,72 @@ class PesterText(QtGui.QTextEdit):
self.setStyleSheet("QTextEdit { %s } QScrollBar:vertical { %s } QScrollBar::handle:vertical { %s } QScrollBar::add-line:vertical { %s } QScrollBar::sub-line:vertical { %s } QScrollBar:up-arrow:vertical { %s } QScrollBar:down-arrow:vertical { %s }" % (theme["convo/textarea/style"], theme["convo/scrollbar/style"], theme["convo/scrollbar/handle"], theme["convo/scrollbar/downarrow"], theme["convo/scrollbar/uparrow"], theme["convo/scrollbar/uarrowstyle"], theme["convo/scrollbar/darrowstyle"] ))
else:
self.setStyleSheet("QTextEdit { %s }" % (theme["convo/textarea/style"]))
def addMessage(self, text, chum):
color = chum.colorhtml()
def addMessage(self, lexmsg, chum):
if len(lexmsg) == 0:
return
color = chum.colorcmd()
systemColor = QtGui.QColor(self.parent().mainwindow.theme["convo/systemMsgColor"])
initials = chum.initials()
msg = unicode(text)
parent = self.parent()
window = parent.mainwindow
me = window.profile()
quirks = window.userprofile.quirks if parent.applyquirks else None
if msg == "PESTERCHUM:BEGIN":
if lexmsg[0] == "PESTERCHUM:BEGIN":
parent.setChumOpen(True)
msg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
elif msg == "PESTERCHUM:CEASE":
pmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
window.chatlog.log(chum.handle, pmsg)
self.append(convertTags(pmsg))
elif lexmsg[0] == "PESTERCHUM:CEASE":
parent.setChumOpen(False)
msg = chum.pestermsg(me, systemColor, window.theme["convo/text/ceasepester"])
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
elif msg == "PESTERCHUM:BLOCK":
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/blocked'])
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
elif msg == "PESTERCHUM:UNBLOCK":
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/unblocked'])
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
elif msg == "PESTERCHUM:BLOCKED":
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/blockedmsg'])
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
elif msg == "PESTERCHUM:IDLE":
msg = chum.idlemsg(systemColor, window.theme['convo/text/idle'])
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
elif msg[0:3] == "/me" or msg[0:13] == "PESTERCHUM:ME":
if quirks:
msg = quirks.apply(msg)
if msg[0:3] == "/me":
start = 3
else:
start = 13
space = msg.find(" ")
msg = chum.memsg(systemColor, msg[start:space], msg[space:])
pmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/ceasepester"])
window.chatlog.log(chum.handle, pmsg)
self.append(convertTags(pmsg))
elif lexmsg[0] == "PESTERCHUM:BLOCK":
pmsg = chum.pestermsg(me, systemColor, window.theme['convo/text/blocked'])
window.chatlog.log(chum.handle, pmsg)
self.append(convertTags(pmsg))
elif lexmsg[0] == "PESTERCHUM:UNBLOCK":
pmsg = chum.pestermsg(me, systemColor, window.theme['convo/text/unblocked'])
window.chatlog.log(chum.handle, pmsg)
self.append(convertTags(pmsg))
elif lexmsg[0] == "PESTERCHUM:BLOCKED":
pmsg = chum.pestermsg(me, systemColor, window.theme['convo/text/blockedmsg'])
window.chatlog.log(chum.handle, pmsg)
self.append(convertTags(pmsg))
elif lexmsg[0] == "PESTERCHUM:IDLE":
imsg = chum.idlemsg(systemColor, window.theme['convo/text/idle'])
window.chatlog.log(chum.handle, imsg)
self.append(convertTags(imsg))
elif type(lexmsg[0]) is mecmd:
memsg = chum.memsg(systemColor, lexmsg)
if chum is me:
window.chatlog.log(parent.chum.handle, convertTags(msg, "bbcode"))
window.chatlog.log(parent.chum.handle, memsg)
else:
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
self.append(convertTags(msg))
window.chatlog.log(chum.handle, memsg)
self.append(convertTags(memsg))
else:
if not parent.chumopen and chum is not me:
beginmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
parent.setChumOpen(True)
window.chatlog.log(chum.handle, convertTags(beginmsg, "bbcode"))
window.chatlog.log(chum.handle, beginmsg)
self.append(convertTags(beginmsg))
msg = "<c=%s>%s: %s</c>" % (color, initials, msg)
self.append(convertTags(msg, quirkobj=quirks))
lexmsg[0:0] = [colorBegin("<c=%s>" % (color), color),
"%s: " % (initials)]
lexmsg.append(colorEnd("</c>"))
self.append(convertTags(lexmsg))
if chum is me:
window.chatlog.log(parent.chum.handle, convertTags(msg, "bbcode", quirkobj=quirks))
window.chatlog.log(parent.chum.handle, lexmsg)
else:
if window.idle:
if window.idleaction.isChecked():
idlethreshhold = 60
if (not hasattr(self, 'lastmsg')) or \
datetime.now() - self.lastmsg > timedelta(0,60):
datetime.now() - self.lastmsg > timedelta(0,idlethreshhold):
idlemsg = me.idlemsg(systemColor, verb)
self.textArea.append(convertTags(idlemsg))
window.chatlog.log(self.title(), idlemsg)
parent.messageSent.emit("PESTERCHUM:IDLE", parent.title())
self.lastmsg = datetime.now()
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
window.chatlog.log(chum.handle, lexmsg)
def changeTheme(self, theme):
self.initTheme(theme)
sb = self.verticalScrollBar()
@ -303,6 +302,7 @@ class PesterInput(QtGui.QLineEdit):
self.setStyleSheet(theme["convo/input/style"])
def focusInEvent(self, event):
self.parent().clearNewMessage()
self.parent().textArea.textCursor().clearSelection()
QtGui.QLineEdit.focusInEvent(self, event)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Up:
@ -388,7 +388,7 @@ class PesterConvo(QtGui.QFrame):
msg = self.mainwindow.profile().pestermsg(self.chum, QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"]), self.mainwindow.theme["convo/text/beganpester"])
self.setChumOpen(True)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.title(), convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.title(), msg)
self.newmessage = False
self.history = PesterHistory()
@ -403,12 +403,12 @@ class PesterConvo(QtGui.QFrame):
self.mainwindow.ceasesound.play()
msg = self.chum.pestermsg(self.mainwindow.profile(), syscolor, self.mainwindow.theme["convo/text/ceasepester"])
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.title(), convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.title(), msg)
self.chumopen = False
elif old and old.name() != mood.name():
msg = self.chum.moodmsg(mood, syscolor, self.mainwindow.theme)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.title(), convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.title(), msg)
if self.parent():
self.parent().updateMood(self.title(), mood, unblocked)
else:
@ -431,13 +431,17 @@ class PesterConvo(QtGui.QFrame):
def updateColor(self, color):
self.chum.color = color
def addMessage(self, text, me=True):
def addMessage(self, msg, me=True):
if type(msg) in [str, unicode]:
lexmsg = lexMessage(msg)
else:
lexmsg = msg
if me:
chum = self.mainwindow.profile()
else:
chum = self.chum
self.notifyNewMessage()
self.textArea.addMessage(text, chum)
self.textArea.addMessage(lexmsg, chum)
def notifyNewMessage(self):
# first see if this conversation HASS the focus
@ -516,13 +520,16 @@ class PesterConvo(QtGui.QFrame):
if text == "" or text[0:11] == "PESTERCHUM:":
return
self.history.add(text)
self.addMessage(text, True)
quirks = self.mainwindow.userprofile.quirks
lexmsg = lexMessage(text)
if type(lexmsg[0]) is not mecmd and self.applyquirks:
lexmsg = quirks.apply(lexmsg)
serverMsg = copy(lexmsg)
self.addMessage(lexmsg, True)
# if ceased, rebegin
if hasattr(self, 'chumopen') and not self.chumopen:
self.mainwindow.newConvoStarted.emit(QtCore.QString(self.title()), True)
# convert color tags
quirkobj = self.mainwindow.userprofile.quirks if self.applyquirks else None
text = convertTags(text, "ctag", quirkobj)
text = convertTags(serverMsg, "ctag")
self.messageSent.emit(text, self.title())
self.textInput.setText("")

BIN
convo.pyc

Binary file not shown.

View file

@ -1,9 +1,10 @@
from PyQt4 import QtGui, QtCore
from datetime import *
import re
import random
from generic import PesterIcon
from parsetools import timeDifference
from parsetools import timeDifference, convertTags
class Mood(object):
moods = ["chummy", "rancorous", "offline", "pleasant", "distraught",
@ -37,15 +38,31 @@ class pesterQuirk(object):
raise ValueError("Quirks must be given a dictionary")
self.quirk = quirk
self.type = self.quirk["type"]
def apply(self, string):
def apply(self, string, first=False, last=False):
if self.type == "prefix":
return self.quirk["value"] + string
if self.type == "suffix":
elif self.type == "suffix":
return string + self.quirk["value"]
if self.type == "replace":
elif self.type == "replace":
return string.replace(self.quirk["from"], self.quirk["to"])
if self.type == "regexp":
return re.sub(self.quirk["from"], self.quirk["to"], string)
elif self.type == "regexp":
fr = self.quirk["from"]
if not first and len(fr) > 0 and fr[0] == "^":
return string
if not last and len(fr) > 0 and fr[len(fr)-1] == "$":
return string
return re.sub(fr, self.quirk["to"], string)
elif self.type == "random":
fr = self.quirk["from"]
if not first and len(fr) > 0 and fr[0] == "^":
return string
if not last and len(fr) > 0 and fr[len(fr)-1] == "$":
return string
def randomrep(mo):
choice = random.choice(self.quirk["randomlist"])
return mo.expand(choice)
return re.sub(self.quirk["from"], randomrep, string)
def __str__(self):
if self.type == "prefix":
return "BEGIN WITH: %s" % (self.quirk["value"])
@ -55,6 +72,8 @@ class pesterQuirk(object):
return "REPLACE %s WITH %s" % (self.quirk["from"], self.quirk["to"])
elif self.type == "regexp":
return "REGEXP: %s REPLACED WITH %s" % (self.quirk["from"], self.quirk["to"])
elif self.type == "random":
return "REGEXP: %s RANDOMLY REPLACED WITH %s" % (self.quirk["from"], [str(r) for r in self.quirk["randomlist"]])
class pesterQuirks(object):
def __init__(self, quirklist):
@ -66,25 +85,35 @@ class pesterQuirks(object):
self.quirklist.append(q)
def plainList(self):
return [q.quirk for q in self.quirklist]
def apply(self, string):
# don't quirk /me commands
if string[0:3] == "/me":
space = string.find(" ")
cmd = string[0:space]
string = string[space:]
else:
cmd = ""
presuffix = [q for q in self.quirklist if
q.type=='prefix' or q.type=='suffix']
def apply(self, lexed, first=False, last=False):
prefix = [q for q in self.quirklist if q.type=='prefix']
suffix = [q for q in self.quirklist if q.type=='suffix']
replace = [q for q in self.quirklist if
q.type=='replace' or q.type=='regexp']
for r in replace:
string = r.apply(string)
if not cmd:
for ps in presuffix:
string = ps.apply(string)
string = cmd+string
return string
random = [q for q in self.quirklist if q.type=='random']
firstStr = True
newlist = []
for (i, o) in enumerate(lexed):
if type(o) not in [str, unicode]:
newlist.append(o)
continue
lastStr = (i == len(lexed)-1)
string = o
for r in random:
string = r.apply(string, first=firstStr, last=lastStr)
for r in replace:
string = r.apply(string, first=firstStr, last=lastStr)
if firstStr:
for p in prefix:
string = p.apply(string)
if lastStr:
for s in suffix:
string = s.apply(string)
newlist.append(string)
firstStr = False
return newlist
def __iter__(self):
for q in self.quirklist:
@ -127,7 +156,9 @@ class PesterProfile(object):
def blocked(self, config):
return self.handle in config.getBlocklist()
def memsg(self, syscolor, suffix, msg, time=None):
def memsg(self, syscolor, lexmsg, time=None):
suffix = lexmsg[0].suffix
msg = convertTags(lexmsg[1:], "text")
uppersuffix = suffix.upper()
if time is not None:
handle = "%s %s" % (time.temporal, self.handle)

Binary file not shown.

Binary file not shown.

BIN
irc.pyc

Binary file not shown.

File diff suppressed because one or more lines are too long

View file

@ -1,12 +1,14 @@
from string import Template
import re
from copy import copy
from PyQt4 import QtGui, QtCore
from datetime import time, timedelta, datetime
from dataobjs import PesterProfile, Mood, PesterHistory
from generic import PesterIcon, RightClickList
from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow
from parsetools import convertTags, addTimeInitial, timeProtocol
from parsetools import convertTags, addTimeInitial, timeProtocol, \
lexMessage, colorBegin, colorEnd, mecmd
def delta2txt(d, format="pc"):
if format == "pc":
@ -223,18 +225,20 @@ class MemoText(PesterText):
else:
self.setStyleSheet("QTextEdit { %s }" % theme["memos/textarea/style"])
def addMessage(self, text, chum):
def addMessage(self, msg, chum):
if type(msg) in [str, unicode]:
lexmsg = lexMessage(msg)
else:
lexmsg = msg
parent = self.parent()
window = parent.mainwindow
me = window.profile()
quirks = window.userprofile.quirks if parent.applyquirks else None
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:
if type(lexmsg[0]) is colorBegin: # get color tag
colortag = lexmsg[0]
try:
color = QtGui.QColor(*[int(c) for c in mobj.group(1).split(",")])
color = QtGui.QColor(*[int(c) for c in colortag.color.split(",")])
except ValueError:
color = QtGui.QColor("black")
else:
@ -257,7 +261,7 @@ class MemoText(PesterText):
# new chum! time current
newtime = timedelta(0)
time = TimeTracker(newtime)
parent.times[chum.handle] = time
parent.times[handle] = time
else:
time = parent.time
@ -265,26 +269,16 @@ class MemoText(PesterText):
grammar = time.getGrammar()
joinmsg = chum.memojoinmsg(systemColor, time.getTime(), grammar, window.theme["convo/text/joinmemo"])
self.append(convertTags(joinmsg))
parent.mainwindow.chatlog.log(parent.channel, convertTags(msg, "bbcode"))
parent.mainwindow.chatlog.log(parent.channel, joinmsg)
time.openCurrentTime()
if msg[0:3] == "/me" or msg[0:13] == "PESTERCHUM:ME":
if quirks:
msg = quirks.apply(msg)
if msg[0:3] == "/me":
start = 3
else:
start = 13
space = msg.find(" ")
memsg = chum.memsg(systemColor, msg[start:space], msg[space:], time=time.getGrammar())
window.chatlog.log(parent.channel, convertTags(msg, "bbcode"))
if type(lexmsg[0]) is mecmd:
memsg = chum.memsg(systemColor, lexmsg, time=time.getGrammar())
window.chatlog.log(parent.channel, memsg)
self.append(convertTags(memsg))
else:
if chum is not me:
msg = addTimeInitial(msg, parent.times[chum.handle].getGrammar())
self.append(convertTags(msg, quirksobj=quirks))
window.chatlog.log(parent.channel, convertTags(msg, "bbcode", quirks))
self.append(convertTags(lexmsg))
window.chatlog.log(parent.channel, lexmsg)
def changeTheme(self, theme):
self.initTheme(theme)
@ -398,7 +392,7 @@ class PesterMemo(PesterConvo):
msg = p.memoopenmsg(systemColor, self.time.getTime(), timeGrammar, self.mainwindow.theme["convo/text/openmemo"], self.channel)
self.time.openCurrentTime()
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.channel, msg)
self.op = False
self.newmessage = False
@ -537,7 +531,7 @@ class PesterMemo(PesterConvo):
self.times[handle].removeTime(close)
msg = chum.memoclosemsg(systemColor, grammar, window.theme["convo/text/closememo"])
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.channel, msg)
elif timed not in self.times[handle]:
self.times[handle].addTime(timed)
else:
@ -556,20 +550,26 @@ class PesterMemo(PesterConvo):
if self.time.getTime() == None:
self.sendtime()
grammar = self.time.getGrammar()
if text[0:3] != "/me":
quirks = self.mainwindow.userprofile.quirks
lexmsg = lexMessage(text)
if type(lexmsg[0]) is not mecmd:
if self.applyquirks:
lexmsg = quirks.apply(lexmsg)
initials = self.mainwindow.profile().initials()
colorcmd = self.mainwindow.profile().colorcmd()
clientText = "<c=%s>%s%s%s: %s</c>" % (colorcmd, grammar.pcf, initials, grammar.number, text)
clientMsg = [colorBegin("<c=%s>" % (colorcmd), colorcmd),
"%s%s%s: " % (grammar.pcf, initials, grammar.number)] + lexmsg + [colorEnd("</c>")]
# account for TC's parsing error
serverText = "<c=%s>%s: %s</c> " % (colorcmd, initials, text)
serverMsg = [colorBegin("<c=%s>" % (colorcmd), colorcmd),
"%s: " % (initials)] + lexmsg + [colorEnd("</c>"), " "]
else:
clientText = text
serverText = clientText
self.addMessage(clientText, True)
# convert color tags
quirks = self.mainwindow.userprofile.quirks if self.applyquirks else None
serverText = convertTags(unicode(serverText), "ctag", quirks)
clientMsg = copy(lexmsg)
serverMsg = copy(lexmsg)
self.addMessage(clientMsg, True)
serverText = convertTags(serverMsg, "ctag")
self.messageSent.emit(serverText, self.title())
self.textInput.setText("")
@QtCore.pyqtSlot()
def namesUpdated(self):
@ -611,7 +611,7 @@ class PesterMemo(PesterConvo):
grammar = t.getGrammar()
msg = chum.memoclosemsg(systemColor, grammar, self.mainwindow.theme["convo/text/closememo"])
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.channel, msg)
self.times[h].removeTime(t.getTime())
if update == "nick":
self.addUser(newnick)
@ -639,7 +639,7 @@ class PesterMemo(PesterConvo):
opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
msg = chum.memobanmsg(opchum, opgrammar, systemColor, grammar)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.channel, msg)
ttracker.removeTime(ttracker.getTime())
if chum is self.mainwindow.profile():
@ -658,7 +658,7 @@ class PesterMemo(PesterConvo):
self.time.openCurrentTime()
msg = me.memoopenmsg(systemColor, self.time.getTime(), self.time.getGrammar(), self.mainwindow.theme["convo/text/openmemo"], self.channel)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.channel, msg)
elif ret == QtGui.QMessageBox.Cancel:
if self.parent():
i = self.parent().tabIndices[self.channel]
@ -725,7 +725,7 @@ class PesterMemo(PesterConvo):
systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
msg = me.memoclosemsg(systemColor, grammar, self.mainwindow.theme["convo/text/closememo"])
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, convertTags(msg, "bbcode"))
self.mainwindow.chatlog.log(self.channel, msg)
newtime = self.time.getTime()
if newtime is None:
@ -738,12 +738,13 @@ class PesterMemo(PesterConvo):
time = self.time.prevTime()
self.time.setCurrent(time)
self.resetSlider(time)
self.textInput.setFocus()
@QtCore.pyqtSlot()
def nexttime(self):
time = self.time.nextTime()
self.time.setCurrent(time)
self.resetSlider(time)
self.textInput.setFocus()
def closeEvent(self, event):
self.mainwindow.waitingMessages.messageAnswered(self.channel)
self.windowClosed.emit(self.title())

BIN
memos.pyc

Binary file not shown.

107
menus.py
View file

@ -30,7 +30,7 @@ class PesterQuirkList(QtGui.QListWidget):
for q in mainwindow.userprofile.quirks:
item = PesterQuirkItem(q, self)
self.addItem(item)
self.sortItems()
#self.sortItems()
@QtCore.pyqtSlot()
def removeCurrent(self):
@ -38,6 +38,77 @@ class PesterQuirkList(QtGui.QListWidget):
if i >= 0:
self.takeItem(i)
class RandomQuirkDialog(MultiTextDialog):
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle("RANDOM QUIRK")
self.inputs = {}
layout_1 = QtGui.QHBoxLayout()
regexpl = QtGui.QLabel("REGEXP:", self)
self.regexp = QtGui.QLineEdit(self)
layout_1.addWidget(regexpl)
layout_1.addWidget(self.regexp)
replacewithl = QtGui.QLabel("REPLACE WITH:", self)
layout_2 = QtGui.QVBoxLayout()
layout_3 = QtGui.QHBoxLayout()
self.replacelist = QtGui.QListWidget(self)
self.replaceinput = QtGui.QLineEdit(self)
addbutton = QtGui.QPushButton("ADD", self)
self.connect(addbutton, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('addRandomString()'))
removebutton = QtGui.QPushButton("REMOVE", self)
self.connect(removebutton, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('removeRandomString()'))
layout_3.addWidget(addbutton)
layout_3.addWidget(removebutton)
layout_2.addWidget(self.replacelist)
layout_2.addWidget(self.replaceinput)
layout_2.addLayout(layout_3)
layout_1.addLayout(layout_2)
self.ok = QtGui.QPushButton("OK", self)
self.ok.setDefault(True)
self.connect(self.ok, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('accept()'))
self.cancel = QtGui.QPushButton("CANCEL", self)
self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()'))
layout_ok = QtGui.QHBoxLayout()
layout_ok.addWidget(self.cancel)
layout_ok.addWidget(self.ok)
layout_0 = QtGui.QVBoxLayout()
layout_0.addLayout(layout_1)
layout_0.addLayout(layout_ok)
self.setLayout(layout_0)
def getText(self):
r = self.exec_()
if r == QtGui.QDialog.Accepted:
randomlist = [unicode(self.replacelist.item(i).text())
for i in range(0,self.replacelist.count())]
retval = {"from": unicode(self.regexp.text()),
"randomlist": randomlist }
return retval
else:
return None
@QtCore.pyqtSlot()
def addRandomString(self):
text = unicode(self.replaceinput.text())
item = QtGui.QListWidgetItem(text, self.replacelist)
self.replaceinput.setText("")
@QtCore.pyqtSlot()
def removeRandomString(self):
if not self.replacelist.currentItem():
return
else:
self.replacelist.takeItem(self.currentRow())
self.replaceinput.setFocus()
class PesterChooseQuirks(QtGui.QDialog):
def __init__(self, config, theme, parent):
QtGui.QDialog.__init__(self, parent)
@ -62,11 +133,17 @@ class PesterChooseQuirks(QtGui.QDialog):
self.addRegexpReplaceButton = QtGui.QPushButton("REGEXP REPLACE", self)
self.connect(self.addRegexpReplaceButton, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('addRegexpDialog()'))
self.addRandomReplaceButton = QtGui.QPushButton("RANDOM REPLACE", self)
self.connect(self.addRandomReplaceButton, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('addRandomDialog()'))
layout_1 = QtGui.QHBoxLayout()
layout_1.addWidget(self.addPrefixButton)
layout_1.addWidget(self.addSuffixButton)
layout_1.addWidget(self.addSimpleReplaceButton)
layout_1.addWidget(self.addRegexpReplaceButton)
layout_2 = QtGui.QHBoxLayout()
layout_2.addWidget(self.addRegexpReplaceButton)
layout_2.addWidget(self.addRandomReplaceButton)
self.removeSelectedButton = QtGui.QPushButton("REMOVE", self)
self.connect(self.removeSelectedButton, QtCore.SIGNAL('clicked()'),
@ -86,6 +163,7 @@ class PesterChooseQuirks(QtGui.QDialog):
layout_0 = QtGui.QVBoxLayout()
layout_0.addWidget(self.quirkList)
layout_0.addLayout(layout_1)
layout_0.addLayout(layout_2)
layout_0.addWidget(self.removeSelectedButton)
layout_0.addLayout(layout_ok)
self.setLayout(layout_0)
@ -94,7 +172,6 @@ class PesterChooseQuirks(QtGui.QDialog):
return [self.quirkList.item(i).quirk for i in
range(0,self.quirkList.count())]
@QtCore.pyqtSlot()
def addPrefixDialog(self):
pdict = MultiTextDialog("ENTER PREFIX", self, {"label": "Value:", "inputname": "value"}).getText()
@ -102,7 +179,7 @@ class PesterChooseQuirks(QtGui.QDialog):
prefix = pesterQuirk(pdict)
pitem = PesterQuirkItem(prefix, self.quirkList)
self.quirkList.addItem(pitem)
self.quirkList.sortItems()
#self.quirkList.sortItems()
@QtCore.pyqtSlot()
def addSuffixDialog(self):
vdict = MultiTextDialog("ENTER SUFFIX", self, {"label": "Value:", "inputname": "value"}).getText()
@ -110,7 +187,7 @@ class PesterChooseQuirks(QtGui.QDialog):
quirk = pesterQuirk(vdict)
item = PesterQuirkItem(quirk, self.quirkList)
self.quirkList.addItem(item)
self.quirkList.sortItems()
#self.quirkList.sortItems()
@QtCore.pyqtSlot()
def addSimpleReplaceDialog(self):
vdict = MultiTextDialog("REPLACE", self, {"label": "Replace:", "inputname": "from"}, {"label": "With:", "inputname": "to"}).getText()
@ -118,7 +195,7 @@ class PesterChooseQuirks(QtGui.QDialog):
quirk = pesterQuirk(vdict)
item = PesterQuirkItem(quirk, self.quirkList)
self.quirkList.addItem(item)
self.quirkList.sortItems()
#self.quirkList.sortItems()
@QtCore.pyqtSlot()
def addRegexpDialog(self):
vdict = MultiTextDialog("REGEXP REPLACE", self, {"label": "Regexp:", "inputname": "from"}, {"label": "Replace With:", "inputname": "to"}).getText()
@ -135,7 +212,23 @@ class PesterChooseQuirks(QtGui.QDialog):
quirk = pesterQuirk(vdict)
item = PesterQuirkItem(quirk, self.quirkList)
self.quirkList.addItem(item)
self.quirkList.sortItems()
#self.quirkList.sortItems()
@QtCore.pyqtSlot()
def addRandomDialog(self):
vdict = RandomQuirkDialog(self).getText()
vdict["type"] = "random"
try:
re.compile(vdict["from"])
except re.error, e:
quirkWarning = QtGui.QMessageBox(self)
quirkWarning.setText("Not a valid regular expression!")
quirkWarning.setInformativeText("H3R3S WHY DUMP4SS: %s" % (e))
quirkWarning.exec_()
return
quirk = pesterQuirk(vdict)
item = PesterQuirkItem(quirk, self.quirkList)
self.quirkList.addItem(item)
#self.quirkList.sortItems()
class PesterChooseTheme(QtGui.QDialog):
def __init__(self, config, theme, parent):

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

@ -4,10 +4,13 @@ from datetime import timedelta
from PyQt4 import QtGui
_ctag_begin = re.compile(r'(?i)<c=(.*?)>')
_gtag_begin = re.compile(r'(?i)<g[a-f]>')
_ctag_end = re.compile(r'(?i)</c>')
_ctag_rgb = re.compile(r'\d+,\d+,\d+')
_urlre = re.compile(r"(?i)http://[^\s]+")
_memore = re.compile(r" (#[A-Za-z0-9_]+)")
_memore = re.compile(r"(\s|^)(#[A-Za-z0-9_]+)")
_imgre = re.compile(r"""(?i)<img src=['"](\S+)['"]\s*/>""")
_mecmdre = re.compile(r"^/me(\S*)")
def lexer(string, objlist):
"""objlist is a list: [(objecttype, re),...] list is in order of preference"""
@ -38,6 +41,8 @@ class colorBegin(object):
self.color = color
def convert(self, format):
color = self.color
if format == "text":
return ""
if _ctag_rgb.match(color) is not None:
if format=='ctag':
return "<c=%s>" % (color)
@ -64,6 +69,8 @@ class colorEnd(object):
return "</span>"
elif format == "bbcode":
return "[/color]"
elif format == "text":
return ""
else:
return self.string
class hyperlink(object):
@ -76,6 +83,30 @@ class hyperlink(object):
return "[url]%s[/url]" % (self.string)
else:
return self.string
class imagelink(object):
def __init__(self, string, img):
self.string = string
self.img = img
def convert(self, format):
if format == "html":
return self.string
elif format == "bbcode":
if self.img[0:7] == "http://":
return "[img]%s[/img]" % (img)
else:
return ""
else:
return ""
class memolex(object):
def __init__(self, string, space, channel):
self.string = string
self.space = space
self.channel = channel
def convert(self, format):
if format == "html":
return "%s<a href='%s'>%s</a>" % (self.space, self.channel, self.channel)
else:
return self.string
class smiley(object):
def __init__(self, string):
self.string = string
@ -84,15 +115,22 @@ class smiley(object):
return "<img src='smilies/%s' />" % (smiledict[self.string])
else:
return self.string
class mecmd(object):
def __init__(self, string, suffix):
self.string = string
self.suffix = suffix
def convert(self, format):
return self.string
def convertTags(string, format="html", quirkobj=None):
if format not in ["html", "bbcode", "ctag"]:
raise ValueError("Color format not recognized")
lexlist = [(colorBegin, _ctag_begin), (colorEnd, _ctag_end),
(hyperlink, _urlre), (hyperlink, _memore),
def lexMessage(string):
lexlist = [(mecmd, _mecmdre),
(colorBegin, _ctag_begin), (colorBegin, _gtag_begin),
(colorEnd, _ctag_end), (imagelink, _imgre),
(hyperlink, _urlre), (memolex, _memore),
(smiley, _smilere)]
lexed = lexer(string, lexlist)
lexed = lexer(unicode(string), lexlist)
balanced = []
beginc = 0
endc = 0
@ -111,25 +149,35 @@ def convertTags(string, format="html", quirkobj=None):
if beginc > endc:
for i in range(0, beginc-endc):
balanced.append(colorEnd("</c>"))
if type(balanced[len(balanced)-1]) not in [str, unicode]:
balanced.append("")
return balanced
def convertTags(lexed, format="html"):
if format not in ["html", "bbcode", "ctag", "text"]:
raise ValueError("Color format not recognized")
if type(lexed) in [str, unicode]:
lexed = lexMessage(lexed)
escaped = ""
for o in balanced:
firststr = True
for (i, o) in enumerate(lexed):
if type(o) in [str, unicode]:
if quirkobj:
o = quirkobj.apply(o)
if format == "html":
escaped += o.replace("&", "&amp;").replace(">", "&gt;").replace("<","&lt;")
else:
escaped += o
else:
escaped += o.convert(format)
return escaped
def addTimeInitial(string, grammar):
endofi = string.find(":")
endoftag = string.find(">")
if endoftag < 0 or endoftag > 16 or endofi > 17:
# support Doc Scratch mode
if (endoftag < 0 or endoftag > 16) or (endofi < 0 or endofi > 17):
return string
return string[0:endoftag+1]+grammar.pcf+string[endoftag+1:endofi]+grammar.number+string[endofi:]

Binary file not shown.

View file

@ -1 +1 @@
{"tabs": false, "soundon": true, "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", "maxiumumFatness", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "confusedTransient", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist"], "defaultprofile": "ghostDunk", "block": []}
{"tabs": true, "soundon": true, "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"], "defaultprofile": "ghostDunk", "block": []}

View file

@ -19,8 +19,8 @@ from menus import PesterChooseQuirks, PesterChooseTheme, \
from dataobjs import PesterProfile, Mood, pesterQuirk, pesterQuirks
from generic import PesterIcon, RightClickList, MultiTextDialog, PesterList
from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo
from parsetools import convertTags
from memos import PesterMemo, MemoTabWindow
from parsetools import convertTags, addTimeInitial
from memos import PesterMemo, MemoTabWindow, TimeTracker
from irc import PesterIRC
class waitingMessageHolder(object):
@ -59,27 +59,35 @@ class PesterLog(object):
self.handle = handle
self.convos = {}
def log(self, handle, msg):
bbcodemsg = convertTags(msg, "bbcode")
html = convertTags(msg, "html")
msg = convertTags(msg, "text")
modes = {"bbcode": bbcodemsg, "html": html, "text": msg}
if not self.convos.has_key(handle):
if not os.path.exists("logs/%s" % (self.handle)):
os.mkdir("logs/%s" % (self.handle))
time = datetime.now().strftime("%Y-%m-%d.%H.%M.txt")
if not os.path.exists("logs/%s/%s" % (self.handle, handle)):
os.mkdir("logs/%s/%s" % (self.handle, handle))
fp = codecs.open("logs/%s/%s/%s.%s" % (self.handle, handle, handle, time), encoding='utf-8', mode='a')
self.convos[handle] = fp
if platform.system() == "Windows":
self.convos[handle].write(msg+"\r\n")
else:
self.convos[handle].write(msg+"\n")
self.convos[handle].flush()
time = datetime.now().strftime("%Y-%m-%d.%H.%M")
self.convos[handle] = {}
for (format, t) in modes.iteritems():
if not os.path.exists("logs/%s/%s/%s" % (self.handle, handle, format)):
os.makedirs("logs/%s/%s/%s" % (self.handle, handle, format))
fp = codecs.open("logs/%s/%s/%s/%s.%s.txt" % (self.handle, handle, format, handle, time), encoding='utf-8', mode='a')
self.convos[handle][format] = fp
for (format, t) in modes.iteritems():
f = self.convos[handle][format]
if platform.system() == "Windows":
f.write(t+"\r\n")
else:
f.write(t+"\r\n")
f.flush()
def finish(self, handle):
if not self.convos.has_key(handle):
return
self.convos[handle].close()
for f in self.convos[handle].values():
f.close()
del self.convos[handle]
def close(self):
for h in self.convos.keys():
self.convos[h].close()
for f in self.convos[h].values():
f.close()
class PesterProfileDB(dict):
def __init__(self):
@ -668,6 +676,10 @@ class PesterWindow(MovingWindow):
self.importaction = QtGui.QAction(self.theme["main/menus/client/import"], self)
self.connect(self.importaction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('importExternalConfig()'))
self.idleaction = QtGui.QAction(self.theme["main/menus/client/idle"], self)
self.idleaction.setCheckable(True)
self.connect(self.idleaction, QtCore.SIGNAL('toggled(bool)'),
self, QtCore.SLOT('toggleIdle(bool)'))
self.menu = QtGui.QMenuBar(self)
@ -676,6 +688,7 @@ class PesterWindow(MovingWindow):
filemenu.addAction(opts)
filemenu.addAction(memoaction)
filemenu.addAction(userlistaction)
filemenu.addAction(self.idleaction)
filemenu.addAction(self.importaction)
filemenu.addAction(exitaction)
@ -769,7 +782,7 @@ class PesterWindow(MovingWindow):
self.waitingMessages = waitingMessageHolder(self)
self.idle = False
self.autoidle = False
self.idlethreshold = 600
self.idletimer = QtCore.QTimer(self)
self.idleposition = QtGui.QCursor.pos()
@ -843,6 +856,14 @@ class PesterWindow(MovingWindow):
# silently ignore in case we forgot to /part
return
memo = self.memos[chan]
msg = unicode(msg)
if not memo.times.has_key(handle):
# new chum! time current
newtime = timedelta(0)
time = TimeTracker(newtime)
memo.times[handle] = time
if msg[0:3] != "/me" and msg[0:13] != "PESTERCHUM:ME":
msg = addTimeInitial(msg, memo.times[handle].getGrammar())
memo.addMessage(msg, handle)
self.alarm.play()
@ -963,6 +984,7 @@ class PesterWindow(MovingWindow):
self.userlistaction.setText(theme["main/menus/client/userlist"])
self.memoaction.setText(theme["main/menus/client/memos"])
self.importaction.setText(theme["main/menus/client/import"])
self.idleaction.setText(theme["main/menus/client/idle"])
self.filemenu.setTitle(theme["main/menus/client/_name"])
self.changetheme.setText(theme["main/menus/profile/theme"])
self.changequirks.setText(theme["main/menus/profile/quirks"])
@ -1116,7 +1138,7 @@ class PesterWindow(MovingWindow):
chum = self.convos[h].chum
chumopen = self.convos[h].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, self.profile().pestermsg(chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/ceasepester"]))
self.convoClosed.emit(handle)
self.chatlog.finish(h)
del self.convos[h]
@ -1242,7 +1264,7 @@ class PesterWindow(MovingWindow):
convo = self.convos[h]
msg = self.profile().pestermsg(convo.chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/blocked"])
convo.textArea.append(convertTags(msg))
self.chatlog.log(convo.chum.handle, convertTags(msg, "bbcode"))
self.chatlog.log(convo.chum.handle, msg)
convo.updateBlocked()
self.chumList.removeChum(h)
if hasattr(self, 'trollslum') and self.trollslum:
@ -1259,7 +1281,7 @@ class PesterWindow(MovingWindow):
convo = self.convos[h]
msg = self.profile().pestermsg(convo.chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/unblocked"])
convo.textArea.append(convertTags(msg))
self.chatlog.log(convo.chum.handle, convertTags(msg, "bbcode"))
self.chatlog.log(convo.chum.handle, msg)
convo.updateMood(convo.chum.mood, unblocked=True)
chum = PesterProfile(h, chumdb=self.chumdb)
if hasattr(self, 'trollslum') and self.trollslum:
@ -1271,18 +1293,16 @@ class PesterWindow(MovingWindow):
@QtCore.pyqtSlot(bool)
def toggleIdle(self, idle):
if self.idle and not idle:
self.idle = False
elif idle and not self.idle:
self.idle = True
if idle:
sysColor = QtGui.QColor(self.theme["convo/systemMsgColor"])
verb = self.theme["convo/text/idle"]
for (h, convo) in self.convos.iteritems():
msg = self.profile().idlemsg(sysColor, verb)
convo.textArea.append(convertTags(msg))
self.chatlog.log(h, convertTags(msg, "bbcode"))
self.chatlog.log(h, msg)
self.sendMessage.emit("PESTERCHUM:IDLE", h)
else:
self.idletime = 0
@QtCore.pyqtSlot()
def checkIdle(self):
newpos = QtGui.QCursor.pos()
@ -1291,9 +1311,14 @@ class PesterWindow(MovingWindow):
else:
self.idletime = 0
if self.idletime >= self.idlethreshold:
self.toggleIdle(True)
if not self.idleaction.isChecked():
self.idleaction.toggle()
self.autoidle = True
else:
self.toggleIdle(False)
if self.autoidle:
if self.idleaction.isChecked():
self.idleaction.toggle()
self.autoidle = False
self.idleposition = newpos
@QtCore.pyqtSlot()
def importExternalConfig(self):
@ -1801,10 +1826,9 @@ class MainProgram(QtCore.QObject):
self.widget.loadingscreen = LoadingScreen(self.widget)
self.connect(self.widget.loadingscreen, QtCore.SIGNAL('rejected()'),
self.widget, QtCore.SLOT('close()'))
self.widget.loadingscreen = None
#status = self.widget.loadingscreen.exec_()
#if status == QtGui.QDialog.Rejected:
# sys.exit(0)
status = self.widget.loadingscreen.exec_()
if status == QtGui.QDialog.Rejected:
sys.exit(0)
os._exit(self.app.exec_())
pesterchum = MainProgram()

View file

@ -1 +1 @@
{"color": "#ff00ff", "theme": "pesterchum", "quirks": [{"to": "7", "from": "t", "type": "replace"}], "handle": "ghostDunk"}
{"color": "#ff00ff", "theme": "pesterchum", "quirks": [], "handle": "ghostDunk"}