/memos.py
Python | 1289 lines | 1239 code | 44 blank | 6 comment | 74 complexity | bcb62b3bba861b4aa0e3a809abb35cb3 MD5 | raw file
Possible License(s): GPL-3.0, Cube
Large files files are truncated, but you can click here to view the full file
- from string import Template
- import re
- from copy import copy
- from PyQt4 import QtGui, QtCore
- from datetime import time, timedelta, datetime
- from mood import Mood
- from dataobjs import PesterProfile, PesterHistory
- from generic import PesterIcon, RightClickList, mysteryTime
- from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow
- from parsetools import convertTags, addTimeInitial, timeProtocol, \
- lexMessage, colorBegin, colorEnd, mecmd, smiledict, oocre
- from logviewer import PesterLogViewer
- def delta2txt(d, format="pc"):
- if type(d) is mysteryTime:
- return "?"
- if format == "pc":
- sign = "+" if d >= timedelta(0) else "-"
- else:
- if d == timedelta(0):
- return "i"
- 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] == '?':
- return mysteryTime()
- 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)
- except OverflowError:
- if sign < 0:
- return timedelta(min)
- else:
- return timedelta(max)
- return sign*timed
- def pcfGrammar(td):
- if type(td) is mysteryTime:
- when = "???"
- temporal = "???"
- pcf = "?"
- elif 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": []}
- self.open = {}
- if time is not None:
- self.append(time)
- self.current=0
- self.addRecord(time)
- self.open[time] = False
- else:
- self.current=-1
- def addTime(self, timed):
- try:
- i = self.index(timed)
- self.current = i
- return True
- except ValueError:
- self.current = len(self)
- self.append(timed)
- self.open[timed] = False
- self.addRecord(timed)
- return False
- def prevTime(self):
- i = self.current
- i = (i - 1) % len(self)
- return self[i]
- def nextTime(self):
- i = self.current
- i = (i + 1) % len(self)
- return self[i]
- def setCurrent(self, timed):
- self.current = self.index(timed)
- def addRecord(self, timed):
- try:
- (temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
- except TypeError:
- (temporal, pcf, when) = pcfGrammar(mysteryTime())
- if pcf == "C" or pcf == "?":
- return
- if timed in self.timerecord[pcf]:
- return
- self.timerecord[pcf].append(timed)
- def getRecord(self, timed):
- try:
- (temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
- except TypeError:
- (temporal, pcf, when) = pcfGrammar(mysteryTime())
- if pcf == "C" or pcf == "?":
- 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
- del self.open[timed]
- return True
- except ValueError:
- return None
- def openTime(self, time):
- if self.open.has_key(time):
- self.open[time] = True
- def openCurrentTime(self):
- timed = self.getTime()
- self.openTime(timed)
- def isFirstTime(self):
- timed = self.getTime()
- return not self.open[timed]
- def getTime(self):
- if self.current >= 0:
- return self[self.current]
- else:
- return None
- def getGrammar(self):
- timed = self.getTime()
- return self.getGrammarTime(timed)
- def getGrammarTime(self, timed):
- mytime = timedelta(0)
- try:
- (temporal, pcf, when) = pcfGrammar(timed - mytime)
- except TypeError:
- (temporal, pcf, when) = pcfGrammar(mysteryTime())
- 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)
- if type(timed) is mysteryTime:
- self.timeslider.setValue(0)
- self.setText("?")
- return
- 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
- def mouseDoubleClickEvent(self, event):
- self.setValue(0)
- class MemoTabWindow(PesterTabWindow):
- def __init__(self, mainwindow, parent=None):
- PesterTabWindow.__init__(self, mainwindow, parent, "memos")
- def addChat(self, convo):
- self.convos[convo.channel] = convo
- # either addTab or setCurrentIndex will trigger changed()
- newindex = self.tabs.addTab(convo.channel)
- self.tabIndices[convo.channel] = newindex
- self.tabs.setCurrentIndex(newindex)
- self.tabs.setTabIcon(newindex, PesterIcon(self.mainwindow.theme["memos/memoicon"]))
- def updateBlocked(self):
- pass
- def updateMood(self):
- pass
- _ctag_begin = re.compile(r'<c=(.*?)>')
- class MemoText(PesterText):
- def __init__(self, theme, parent=None):
- QtGui.QTextEdit.__init__(self, parent)
- if hasattr(self.parent(), 'mainwindow'):
- self.mainwindow = self.parent().mainwindow
- else:
- self.mainwindow = self.parent()
- if type(parent.parent()) is PesterTabWindow:
- self.tabobject = parent.parent()
- self.hasTabs = True
- else:
- self.hasTabs = False
- self.initTheme(theme)
- self.setReadOnly(True)
- self.setMouseTracking(True)
- self.textSelected = False
- self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'),
- self, QtCore.SLOT('textReady(bool)'))
- self.urls = {}
- for k in smiledict:
- self.addAnimation(QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k]))
- self.connect(self.mainwindow, QtCore.SIGNAL('animationSetting(bool)'),
- self, QtCore.SLOT('animateChanged(bool)'))
- def initTheme(self, theme):
- if theme.has_key("memos/scrollbar"):
- 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["memos/textarea/style"], theme["memos/scrollbar/style"], theme["memos/scrollbar/handle"], theme["memos/scrollbar/downarrow"], theme["memos/scrollbar/uparrow"], theme["memos/scrollbar/uarrowstyle"], theme["memos/scrollbar/darrowstyle"] ))
- else:
- self.setStyleSheet("QTextEdit { %s }" % theme["memos/textarea/style"])
- 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()
- if self.mainwindow.config.animations():
- for m in self.urls:
- if convertTags(lexmsg).find(self.urls[m].toString()) != -1:
- if m.state() == QtGui.QMovie.NotRunning:
- m.start()
- chumdb = window.chumdb
- if chum is not me: # SO MUCH WH1T3SP4C3 >:]
- if type(lexmsg[0]) is colorBegin: # get color tag
- colortag = lexmsg[0]
- try:
- color = QtGui.QColor(*[int(c) for c in colortag.color.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]
- if time.getTime() is None:
- # MY WAY OR THE HIGHWAY
- time.addTime(timedelta(0))
- else:
- # new chum! time current
- newtime = timedelta(0)
- time = TimeTracker(newtime)
- parent.times[handle] = time
- else:
- time = parent.time
- if time.isFirstTime():
- 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, joinmsg)
- time.openCurrentTime()
- def makeSafe(msg):
- if msg.count("<c") > msg.count("</c>"):
- for i in range(msg.count("<c") - msg.count("</c>")):
- msg = msg + "</c>"
- return "<span style=\"color:#000000\">" + msg + "</span>"
- 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:
- self.append(makeSafe(convertTags(lexmsg)))
- window.chatlog.log(parent.channel, lexmsg)
- def changeTheme(self, theme):
- self.initTheme(theme)
- def submitLogTitle(self):
- return "[%s]" % (self.parent().title())
- class MemoInput(PesterInput):
- def __init__(self, theme, parent=None):
- QtGui.QLineEdit.__init__(self, parent)
- self.setStyleSheet(theme["memos/input/style"])
- def changeTheme(self, theme):
- self.setStyleSheet(theme["memos/input/style"])
- class PesterMemo(PesterConvo):
- def __init__(self, channel, timestr, mainwindow, parent=None):
- QtGui.QFrame.__init__(self, parent)
- self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
- self.channel = channel
- self.setObjectName(self.channel)
- self.mainwindow = mainwindow
- self.time = TimeTracker(txt2delta(timestr))
- self.setWindowTitle(channel)
- self.channelLabel = QtGui.QLabel(self)
- self.channelLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
- self.textArea = MemoText(self.mainwindow.theme, self)
- self.textInput = MemoInput(self.mainwindow.theme, self)
- self.textInput.setFocus()
- self.miniUserlist = QtGui.QPushButton(">\n>", self)
- #self.miniUserlist.setStyleSheet("border:1px solid #a68168; border-width: 2px 0px 2px 2px; height: 90px; width: 10px; color: #cd8f9d; font-family: 'Arial'; background: white; margin-left: 2px;")
- self.connect(self.miniUserlist, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('toggleUserlist()'))
- self.userlist = RightClickList(self)
- self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding))
- self.userlist.optionsMenu = QtGui.QMenu(self)
- self.addchumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self)
- self.connect(self.addchumAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('addChumSlot()'))
- self.banuserAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/banuser"], self)
- self.connect(self.banuserAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('banSelectedUser()'))
- self.opAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/opuser"], self)
- self.connect(self.opAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('opSelectedUser()'))
- self.voiceAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/voiceuser"], self)
- self.connect(self.voiceAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('voiceSelectedUser()'))
- self.quirkDisableAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self)
- self.connect(self.quirkDisableAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('killQuirkUser()'))
- self.userlist.optionsMenu.addAction(self.addchumAction)
- # ban & op list added if we are op
- self.optionsMenu = QtGui.QMenu(self)
- self.oocToggle = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self)
- self.oocToggle.setCheckable(True)
- self.connect(self.oocToggle, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('toggleOOC(bool)'))
- self.quirksOff = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self)
- self.quirksOff.setCheckable(True)
- self.connect(self.quirksOff, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('toggleQuirks(bool)'))
- self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self)
- self.connect(self.logchum, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('openChumLogs()'))
- self.invitechum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/invitechum"], self)
- self.connect(self.invitechum, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('inviteChums()'))
- self.optionsMenu.addAction(self.quirksOff)
- self.optionsMenu.addAction(self.oocToggle)
- self.optionsMenu.addAction(self.logchum)
- self.optionsMenu.addAction(self.invitechum)
- self.chanModeMenu = QtGui.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/memosetting"], self)
- self.chanNoquirks = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memonoquirk"], self)
- self.chanNoquirks.setCheckable(True)
- self.connect(self.chanNoquirks, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('noquirksChan(bool)'))
- self.chanHide = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memohidden"], self)
- self.chanHide.setCheckable(True)
- self.connect(self.chanHide, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('hideChan(bool)'))
- self.chanInvite = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memoinvite"], self)
- self.chanInvite.setCheckable(True)
- self.connect(self.chanInvite, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('inviteChan(bool)'))
- self.chanMod = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memomute"], self)
- self.chanMod.setCheckable(True)
- self.connect(self.chanMod, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('modChan(bool)'))
- self.chanModeMenu.addAction(self.chanNoquirks)
- self.chanModeMenu.addAction(self.chanHide)
- self.chanModeMenu.addAction(self.chanInvite)
- self.chanModeMenu.addAction(self.chanMod)
- self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self)
- self.timeinput = TimeInput(self.timeslider, self)
- self.timeinput.setText(timestr)
- self.timeinput.setSlider()
- self.timetravel = QtGui.QPushButton("GO", self)
- self.timeclose = QtGui.QPushButton("CLOSE", self)
- self.timeswitchl = QtGui.QPushButton(self)
- self.timeswitchr = QtGui.QPushButton(self)
- self.connect(self.timetravel, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('sendtime()'))
- self.connect(self.timeclose, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('smashclock()'))
- self.connect(self.timeswitchl, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('prevtime()'))
- self.connect(self.timeswitchr, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('nexttime()'))
- self.times = {}
- self.initTheme(self.mainwindow.theme)
- # connect
- self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'),
- self, QtCore.SLOT('sentMessage()'))
- layout_0 = QtGui.QVBoxLayout()
- layout_0.addWidget(self.textArea)
- layout_0.addWidget(self.textInput)
- layout_1 = QtGui.QHBoxLayout()
- layout_1.addLayout(layout_0)
- layout_1.addWidget(self.miniUserlist)
- layout_1.addWidget(self.userlist)
- # layout_1 = QtGui.QGridLayout()
- # 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)
- layout_2.addWidget(self.timeclose)
- layout_2.addWidget(self.timeswitchl)
- layout_2.addWidget(self.timeswitchr)
- self.layout = QtGui.QVBoxLayout()
- self.layout.addWidget(self.channelLabel)
- self.layout.addLayout(layout_1)
- self.layout.addLayout(layout_2)
- self.layout.setSpacing(0)
- margins = self.mainwindow.theme["memos/margins"]
- self.layout.setContentsMargins(margins["left"], margins["top"],
- margins["right"], margins["bottom"])
- self.setLayout(self.layout)
- if parent:
- parent.addChat(self)
- p = self.mainwindow.profile()
- timeGrammar = self.time.getGrammar()
- systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
- 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, msg)
- self.op = False
- self.newmessage = False
- self.history = PesterHistory()
- self.applyquirks = True
- self.ooc = False
- @QtCore.pyqtSlot()
- def toggleUserlist(self):
- if self.userlist.isHidden():
- self.userlist.show()
- self.miniUserlist.setText(">\n>")
- self.miniUserlist.setStyleSheet("%s border-width: 2px 0px 2px 2px;" % self.miniUserlist.styleSheet())
- else:
- self.userlist.hide()
- self.miniUserlist.setText("<\n<")
- self.miniUserlist.setStyleSheet("%s border-width: 2px;" % self.miniUserlist.styleSheet())
- def title(self):
- return self.channel
- def icon(self):
- 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):
- pass
- def updateBlocked(self):
- pass
- def updateColor(self, handle, color):
- chums = self.userlist.findItems(handle, QtCore.Qt.MatchFlags(0))
- for c in chums:
- c.setTextColor(color)
- def addMessage(self, text, handle):
- if type(handle) is bool:
- chum = self.mainwindow.profile()
- else:
- chum = PesterProfile(handle)
- self.notifyNewMessage()
- self.textArea.addMessage(text, chum)
- def initTheme(self, theme):
- self.resize(*theme["memos/size"])
- self.setStyleSheet("QFrame#%s { %s }" % (self.channel, theme["memos/style"]))
- self.setWindowIcon(PesterIcon(theme["memos/memoicon"]))
- t = Template(theme["memos/label/text"])
- if self.mainwindow.advanced and hasattr(self, 'modes'):
- self.channelLabel.setText(t.safe_substitute(channel=self.channel) + "(%s)" % (self.modes))
- else:
- self.channelLabel.setText(t.safe_substitute(channel=self.channel))
- self.channelLabel.setStyleSheet(theme["memos/label/style"])
- self.channelLabel.setAlignment(self.aligndict["h"][theme["memos/label/align/h"]] | self.aligndict["v"][theme["memos/label/align/v"]])
- self.channelLabel.setMaximumHeight(theme["memos/label/maxheight"])
- self.channelLabel.setMinimumHeight(theme["memos/label/minheight"])
- self.userlist.optionsMenu.setStyleSheet(theme["main/defaultwindow/style"])
- scrolls = "width: 12px; height: 12px; border: 0; padding: 0;"
- if theme.has_key("main/chums/scrollbar"):
- self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["main/chums/scrollbar/style"] + scrolls, theme["main/chums/scrollbar/handle"], theme["main/chums/scrollbar/downarrow"], theme["main/chums/scrollbar/uparrow"], theme["main/chums/scrollbar/uarrowstyle"], theme["main/chums/scrollbar/darrowstyle"] ))
- elif theme.has_key("convo/scrollbar"):
- self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["convo/scrollbar/style"] + scrolls, theme["convo/scrollbar/handle"], "display:none;", "display:none;", "display:none;", "display:none;" ))
- else:
- self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s }" % (theme["memos/userlist/style"], scrolls, "background-color: black;"))
- self.userlist.setFixedWidth(theme["memos/userlist/width"])
- if self.userlist.isHidden():
- borders = "border-width: 2px;"
- else:
- borders = "border-width: 2px 0px 2px 2px;"
- self.miniUserlist.setStyleSheet("%s padding: 0px; margin: 0px; margin-left: 5px; width: 10px; height: 90px; %s" % (theme["memos/userlist/style"], borders))
- self.addchumAction.setText(theme["main/menus/rclickchumlist/addchum"])
- self.banuserAction.setText(theme["main/menus/rclickchumlist/banuser"])
- self.opAction.setText(theme["main/menus/rclickchumlist/opuser"])
- self.voiceAction.setText(theme["main/menus/rclickchumlist/voiceuser"])
- self.quirkDisableAction.setText(theme["main/menus/rclickchumlist/quirkkill"])
- self.quirksOff.setText(theme["main/menus/rclickchumlist/quirksoff"])
- self.logchum.setText(theme["main/menus/rclickchumlist/viewlog"])
- self.invitechum.setText(theme["main/menus/rclickchumlist/invitechum"])
- self.chanModeMenu.setTitle(theme["main/menus/rclickchumlist/memosetting"])
- self.chanNoquirks.setText(theme["main/menus/rclickchumlist/memonoquirk"])
- self.chanHide.setText(theme["main/menus/rclickchumlist/memohidden"])
- self.chanInvite.setText(theme["main/menus/rclickchumlist/memoinvite"])
- self.chanMod.setText(theme["main/menus/rclickchumlist/memomute"])
- self.timeinput.setFixedWidth(theme["memos/time/text/width"])
- self.timeinput.setStyleSheet(theme["memos/time/text/style"])
- slidercss = "QSlider { %s } QSlider::groove { %s } QSlider::handle { %s }" % (theme["memos/time/slider/style"], theme["memos/time/slider/groove"], theme["memos/time/slider/handle"])
- self.timeslider.setStyleSheet(slidercss)
- larrow = PesterIcon(self.mainwindow.theme["memos/time/arrows/left"])
- self.timeswitchl.setIcon(larrow)
- self.timeswitchl.setIconSize(larrow.realsize())
- self.timeswitchl.setStyleSheet(self.mainwindow.theme["memos/time/arrows/style"])
- self.timetravel.setStyleSheet(self.mainwindow.theme["memos/time/buttons/style"])
- self.timeclose.setStyleSheet(self.mainwindow.theme["memos/time/buttons/style"])
- rarrow = PesterIcon(self.mainwindow.theme["memos/time/arrows/right"])
- self.timeswitchr.setIcon(rarrow)
- self.timeswitchr.setIconSize(rarrow.realsize())
- self.timeswitchr.setStyleSheet(self.mainwindow.theme["memos/time/arrows/style"])
- def changeTheme(self, theme):
- self.initTheme(theme)
- self.textArea.changeTheme(theme)
- self.textInput.changeTheme(theme)
- margins = theme["memos/margins"]
- self.layout.setContentsMargins(margins["left"], margins["top"],
- margins["right"], margins["bottom"])
- for item in [self.userlist.item(i) for i in range(0,self.userlist.count())]:
- self.iconCrap(item)
- def addUser(self, handle):
- chumdb = self.mainwindow.chumdb
- defaultcolor = QtGui.QColor("black")
- founder = False
- op = False
- halfop = False
- admin = False
- voice = False
- if handle[0] == '@':
- op = True
- handle = handle[1:]
- if handle == self.mainwindow.profile().handle:
- self.userlist.optionsMenu.addAction(self.opAction)
- self.userlist.optionsMenu.addAction(self.banuserAction)
- self.optionsMenu.addMenu(self.chanModeMenu)
- self.op = True
- elif handle[0] == '%':
- halfop = True
- handle = handle[1:]
- if handle == self.mainwindow.profile().handle:
- self.userlist.optionsMenu.addAction(self.opAction)
- self.userlist.optionsMenu.addAction(self.banuserAction)
- self.optionsMenu.addMenu(self.chanModeMenu)
- self.halfop = True
- elif handle[0] == '+':
- voice = True
- handle = handle[1:]
- elif handle[0] == '~':
- founder = True
- handle = handle[1:]
- elif handle[0] == '&':
- admin = 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.box = (handle == "evacipatedBox")
- item.setTextColor(color)
- item.founder = founder
- item.op = op
- item.halfop = halfop
- item.admin = admin
- item.voice = voice
- self.umodes = ["box", "founder", "admin", "op", "halfop", "voice"]
- self.iconCrap(item)
- self.userlist.addItem(item)
- self.sortUsers()
- def sortUsers(self):
- users = []
- listing = self.userlist.item(0)
- while listing is not None:
- users.append(self.userlist.takeItem(0))
- listing = self.userlist.item(0)
- users.sort(key=lambda x: ((-1 if x.box else (0 if x.founder else (1 if x.admin else (2 if x.op else (3 if x.halfop else (4 if x.voice else 5)))))), x.text()))
- for u in users:
- self.userlist.addItem(u)
- def updateChanModes(self, modes, op):
- if not hasattr(self, 'modes'): self.modes = ""
- chanmodes = list(str(self.modes))
- if chanmodes and chanmodes[0] == "+": chanmodes = chanmodes[1:]
- modes = str(modes)
- if op:
- systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
- chum = self.mainwindow.profile()
- opchum = PesterProfile(op)
- if self.times.has_key(op):
- opgrammar = self.times[op].getGrammar()
- elif op == self.mainwindow.profile().handle:
- opgrammar = self.time.getGrammar()
- else:
- opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
- if modes[0] == "+":
- for m in modes[1:]:
- if m not in chanmodes:
- chanmodes.extend(m)
- # Make +c (disable ANSI colours) disable quirks.
- if modes.find("c") >= 0:
- self.chanNoquirks.setChecked(True)
- self.quirksOff.setChecked(True)
- self.applyquirks = False
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "A No-Quirk zone", True)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if modes.find("s") >= 0:
- self.chanHide.setChecked(True)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Secret", True)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if modes.find("i") >= 0:
- self.chanInvite.setChecked(True)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Invite-Only", True)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if modes.find("m") >= 0:
- self.chanMod.setChecked(True)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Muted", True)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- elif modes[0] == "-":
- for i in modes[1:]:
- try:
- chanmodes.remove(i)
- except ValueError:
- pass
- if modes.find("c") >= 0:
- self.chanNoquirks.setChecked(False)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "A No-Quirk zone", False)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if modes.find("s") >= 0:
- self.chanHide.setChecked(False)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Secret", False)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if modes.find("i") >= 0:
- self.chanInvite.setChecked(False)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Invite-Only", False)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if modes.find("m") >= 0:
- self.chanMod.setChecked(False)
- if op:
- msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Muted", False)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- chanmodes.sort()
- self.modes = "+" + "".join(chanmodes)
- if self.mainwindow.advanced:
- t = Template(self.mainwindow.theme["memos/label/text"])
- self.channelLabel.setText(t.safe_substitute(channel=self.channel) + "(%s)" % (self.modes))
- 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.seconds // 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)
- msg = chum.memoclosemsg(systemColor, grammar, window.theme["convo/text/closememo"])
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- elif timed not in self.times[handle]:
- self.times[handle].addTime(timed)
- else:
- self.times[handle].setCurrent(timed)
- else:
- if timed is not None:
- ttracker = TimeTracker(timed)
- self.times[handle] = ttracker
- @QtCore.pyqtSlot()
- def sentMessage(self):
- text = unicode(self.textInput.text())
- if text == "" or text[0:11] == "PESTERCHUM:":
- return
- oocDetected = oocre.match(text.strip())
- if self.ooc and not oocDetected:
- text = "(( %s ))" % (text)
- self.history.add(text)
- if self.time.getTime() == None:
- self.sendtime()
- grammar = self.time.getGrammar()
- quirks = self.mainwindow.userprofile.quirks
- lexmsg = lexMessage(text)
- if type(lexmsg[0]) is not mecmd:
- if self.applyquirks and not (self.ooc or oocDetected):
- lexmsg = quirks.apply(lexmsg)
- initials = self.mainwindow.profile().initials()
- colorcmd = self.mainwindow.profile().colorcmd()
- clientMsg = [colorBegin("<c=%s>" % (colorcmd), colorcmd),
- "%s%s%s: " % (grammar.pcf, initials, grammar.number)] + lexmsg + [colorEnd("</c>")]
- # account for TC's parsing error
- serverMsg = [colorBegin("<c=%s>" % (colorcmd), colorcmd),
- "%s: " % (initials)] + lexmsg + [colorEnd("</c>"), " "]
- else:
- 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(QtCore.QString)
- def namesUpdated(self, channel):
- c = unicode(channel)
- if c.lower() != self.channel.lower(): return
- # 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)
- def modesUpdated(self, channel, modes):
- c = unicode(channel)
- if c.lower() == self.channel.lower():
- self.updateChanModes(modes, None)
- @QtCore.pyqtSlot(QtCore.QString)
- def closeInviteOnly(self, channel):
- c = unicode(channel)
- if c.lower() == self.channel.lower():
- self.disconnect(self.mainwindow, QtCore.SIGNAL('inviteOnlyChan(QString)'),
- self, QtCore.SLOT('closeInviteOnly(QString)'))
- if self.parent():
- print self.channel
- i = self.parent().tabIndices[self.channel]
- self.parent().tabClose(i)
- else:
- self.close()
- msgbox = QtGui.QMessageBox()
- msgbox.setText("%s: Invites only!" % (c))
- msgbox.setInformativeText("This channel is invite-only. You must get an invitation from someone on the inside before entering.")
- msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
- ret = msgbox.exec_()
- def quirkDisable(self, op, msg):
- chums = self.userlist.findItems(op, QtCore.Qt.MatchFlags(0))
- for c in chums:
- if c.op:
- if msg == self.mainwindow.profile().handle:
- self.quirksOff.setChecked(True)
- self.applyquirks = False
- systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
- chum = self.mainwindow.profile()
- opchum = PesterProfile(op)
- if self.times.has_key(op):
- opgrammar = self.times[op].getGrammar()
- elif op == self.mainwindow.profile().handle:
- opgrammar = self.time.getGrammar()
- else:
- opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
- msg = chum.memoquirkkillmsg(opchum, opgrammar, systemColor)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- def chumOPstuff(self, h, op):
- chum = PesterProfile(h)
- if h == self.mainwindow.profile().handle:
- chum = self.mainwindow.profile()
- ttracker = self.time
- curtime = self.time.getTime()
- elif self.times.has_key(h):
- ttracker = self.times[h]
- else:
- ttracker = TimeTracker(timedelta(0))
- opchum = PesterProfile(op)
- if self.times.has_key(op):
- opgrammar = self.times[op].getGrammar()
- elif op == self.mainwindow.profile().handle:
- opgrammar = self.time.getGrammar()
- else:
- opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
- return (chum, opchum, opgrammar)
- def iconCrap(self, c, down=True):
- for m in (self.umodes if down else reversed(self.umodes)):
- if eval("c."+m):
- if m == "box":
- icon = PesterIcon("smilies/box.png")
- else:
- icon = PesterIcon(self.mainwindow.theme["memos/"+m+"/icon"])
- c.setIcon(icon)
- return
- icon = QtGui.QIcon()
- c.setIcon(icon)
- @QtCore.pyqtSlot()
- def dumpNetsplit(self):
- if (len(self.netsplit) > 0):
- chum = self.mainwindow.profile()
- systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
- msg = chum.memonetsplitmsg(systemColor, self.netsplit)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- del self.netsplit
- @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
- def userPresentChange(self, handle, channel, update):
- h = unicode(handle)
- c = unicode(channel)
- update = unicode(update)
- if update[0:4] == "kick": # yeah, i'm lazy.
- l = update.split(":")
- update = l[0]
- op = l[1]
- reason = ":".join(l[2:])
- if update == "nick":
- l = h.split(":")
- oldnick = l[0]
- newnick = l[1]
- h = oldnick
- if update[0:1] in ["+", "-"]:
- l = update.split(":")
- update = l[0]
- op = l[1]
- if (update in ["join","left", "kick", \
- "+q", "-q", "+o", "-o", "+h", "-h", \
- "+a", "-a", "+v", "-v"]) \
- and c.lower() != self.channel.lower():
- return
- chums = self.userlist.findItems(h, QtCore.Qt.MatchFlags(0))
- systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
- # print exit
- if update in ("quit", "left", "nick", "netsplit"):
- if update == "netsplit":
- if not hasattr(self, "netsplit"):
- self.netsplit = []
- QtCore.QTimer.singleShot(1500, self, QtCore.SLOT('dumpNetsplit()'))
- for c in chums:
- chum = PesterProfile(h)
- self.userlist.takeItem(self.userlist.row(c))
- if not self.times.has_key(h):
- self.times[h] = TimeTracker(timedelta(0))
- allinitials = []
- while self.times[h].getTime() is not None:
- t = self.times[h]
- grammar = t.getGrammar()
- allinitials.append("%s%s%s" % (grammar.pcf, chum.initials(), grammar.number))
- self.times[h].removeTime(t.getTime())
- if update == "netsplit":
- self.netsplit.extend(allinitials)
- else:
- msg = chum.memoclosemsg(systemColor, allinitials, self.mainwindow.theme["convo/text/closememo"])
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if update == "nick":
- self.addUser(newnick)
- newchums = self.userlist.findItems(newnick, QtCore.Qt.MatchFlags(0))
- for nc in newchums:
- for c in chums:
- nc.founder = c.founder
- nc.op = c.op
- nc.halfop = c.halfop
- nc.admin = c.admin
- self.iconCrap(nc)
- self.sortUsers()
- elif update == "kick":
- if len(chums) == 0:
- return
- c = chums[0]
- chum = PesterProfile(h)
- if h == self.mainwindow.profile().handle:
- chum = self.mainwindow.profile()
- ttracker = self.time
- curtime = self.time.getTime()
- elif self.times.has_key(h):
- ttracker = self.times[h]
- else:
- ttracker = TimeTracker(timedelta(0))
- allinitials = []
- opchum = PesterProfile(op)
- if self.times.has_key(op):
- opgrammar = self.times[op].getGrammar()
- elif op == self.mainwindow.profile().handle:
- opgrammar = self.time.getGrammar()
- else:
- opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
- while ttracker.getTime() is not None:
- grammar = ttracker.getGrammar()
- allinitials.append("%s%s%s" % (grammar.pcf, chum.initials(), grammar.number))
- ttracker.removeTime(ttracker.getTime())
- msg = chum.memobanmsg(opchum, opgrammar, systemColor, allinitials, reason)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- if chum is self.mainwindow.profile():
- # are you next?
- msgbox = QtGui.QMessageBox()
- msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"])
- msgbox.setInformativeText("press 0k to rec0nnect or cancel to absc0nd")
- msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
- ret = msgbox.exec_()
- if ret == QtGui.QMessageBox.Ok:
- self.userlist.clear()
- self.time = TimeTracker(curtime)
- self.resetSlider(curtime)
- self.mainwindow.joinChannel.emit(self.channel)
- me = self.mainwindow.profile()
- 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, msg)
- elif ret == QtGui.QMessageBox.Cancel:
- if self.parent():
- i = self.parent().tabIndices[self.channel]
- self.parent().tabClose(i)
- else:
- self.close()
- else:
- # i warned you about those stairs bro
- self.userlist.takeItem(self.userlist.row(c))
- elif update == "join":
- self.addUser(h)
- time = self.time.getTime()
- serverText = "PESTERCHUM:TIME>"+delta2txt(time, "server")
- self.messageSent.emit(serverText, self.title())
- elif update == "+q":
- for c in chums:
- c.founder = True
- self.iconCrap(c)
- self.sortUsers()
- elif update == "-q":
- for c in chums:
- c.founder = False
- self.iconCrap(c)
- self.sortUsers()
- elif update == "+o":
- if self.mainwindow.config.opvoiceMessages():
- (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
- msg = chum.memoopmsg(opchum, opgrammar, systemColor)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- for c in chums:
- c.op = True
- self.iconCrap(c)
- if unicode(c.text()) == self.mainwindow.profile().handle:
- self.userlist.optionsMenu.addAction(self.opAction)
- self.userlist.optionsMenu.addAction(self.voiceAction)
- self.userlist.optionsMenu.addAction(self.banuserAction)
- self.userlist.optionsMenu.addAction(self.quirkDisableAction)
- self.optionsMenu.addMenu(self.chanModeMenu)
- self.sortUsers()
- elif update == "-o":
- self.mainwindow.channelNames.emit(self.channel)
- if self.mainwindow.config.opvoiceMessages():
- (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
- msg = chum.memodeopmsg(opchum, opgrammar, systemColor)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- for c in chums:
- c.op = False
- self.iconCrap(c)
- if unicode(c.text()) == self.mainwindow.profile().handle:
- self.userlist.optionsMenu.removeAction(self.opAction)
- self.userlist.optionsMenu.removeAction(self.voiceAction)
- self.userlist.optionsMenu.removeAction(self.banuserAction)
- self.userlist.optionsMenu.removeAction(self.quirkDisableAction)
- self.optionsMenu.removeAction(self.chanModeMenu.menuAction())
- self.sortUsers()
- elif update == "+h":
- if self.mainwindow.config.opvoiceMessages():
- (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
- msg = chum.memoopmsg(opchum, opgrammar, systemColor)
- self.textArea.append(convertTags(msg))
- self.mainwindow.chatlog.log(self.channel, msg)
- for c in chums:
- c.halfop = True
- self.iconCrap(c)
- if unicode(c.text()) == self.mainwindow.profile().handle:
- self.userlist.optionsMenu.addAction(self.opAction)
- self.userlist.optionsMenu.addAction(self.voiceAction)
- self.userlist.optionsMenu.addAction(self.banuserAction)
- self.userlist.optionsMenu.addAction(self.quirkDisableAction)
- self.optionsMenu.addMenu(self.chanModeMenu)
- self.sortUsers()
- elif update == "-h":
- self.mainwindow.channelNames.emit(self.channel)
- if self.mainwindow.config.opvoiceMessages():
- (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
- msg = chum.memodeopmsg(opchum, opgrammar, systemColor)
- self.textArea.ap…
Large files files are truncated, but you can click here to view the full file