pesterchum/convo.py

752 lines
33 KiB
Python
Raw Normal View History

2011-02-04 16:17:27 -05:00
from string import Template
import re
2011-02-13 21:01:58 -05:00
import platform
2011-02-23 06:06:00 -05:00
import httplib, urllib
from time import strftime
2011-02-13 04:27:12 -05:00
from copy import copy
2011-02-10 20:55:45 -05:00
from datetime import datetime, timedelta
2011-02-04 16:17:27 -05:00
from PyQt4 import QtGui, QtCore
2011-02-09 01:26:23 -05:00
from dataobjs import PesterProfile, Mood, PesterHistory
2011-04-13 02:12:19 -04:00
from generic import PesterIcon
2011-05-03 19:41:40 -04:00
from parsetools import convertTags, lexMessage, splitMessage, mecmd, colorBegin, colorEnd, img2smiley, smiledict
2011-02-04 16:17:27 -05:00
class PesterTabWindow(QtGui.QFrame):
2011-02-04 19:50:56 -05:00
def __init__(self, mainwindow, parent=None, convo="convo"):
2011-02-04 16:17:27 -05:00
QtGui.QFrame.__init__(self, parent)
2011-03-02 18:36:10 -05:00
self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
2011-02-04 16:17:27 -05:00
self.setFocusPolicy(QtCore.Qt.ClickFocus)
self.mainwindow = mainwindow
self.tabs = QtGui.QTabBar(self)
self.tabs.setMovable(True)
2011-02-04 16:17:27 -05:00
self.tabs.setTabsClosable(True)
self.connect(self.tabs, QtCore.SIGNAL('currentChanged(int)'),
self, QtCore.SLOT('changeTab(int)'))
self.connect(self.tabs, QtCore.SIGNAL('tabCloseRequested(int)'),
self, QtCore.SLOT('tabClose(int)'))
self.connect(self.tabs, QtCore.SIGNAL('tabMoved(int, int)'),
self, QtCore.SLOT('tabMoved(int, int)'))
2011-02-04 16:17:27 -05:00
2011-02-16 06:11:09 -05:00
self.initTheme(self.mainwindow.theme)
2011-02-04 16:17:27 -05:00
self.layout = QtGui.QVBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
self.convos = {}
self.tabIndices = {}
self.currentConvo = None
self.changedTab = False
self.softclose = False
2011-02-04 19:50:56 -05:00
self.type = convo
2011-02-04 16:17:27 -05:00
# get default tab color i guess
self.defaultTabTextColor = self.getTabTextColor()
2011-02-04 19:50:56 -05:00
2011-02-04 16:17:27 -05:00
def getTabTextColor(self):
# ugly, ugly hack
self.changedTab = True
i = self.tabs.addTab(".")
c = self.tabs.tabTextColor(i)
self.tabs.removeTab(i)
self.changedTab = False
return c
def addChat(self, convo):
2011-02-04 19:50:56 -05:00
self.convos[convo.title()] = convo
2011-02-04 16:17:27 -05:00
# either addTab or setCurrentIndex will trigger changed()
2011-02-04 19:50:56 -05:00
newindex = self.tabs.addTab(convo.title())
self.tabIndices[convo.title()] = newindex
2011-02-04 16:17:27 -05:00
self.tabs.setCurrentIndex(newindex)
2011-02-04 19:50:56 -05:00
self.tabs.setTabIcon(newindex, convo.icon())
2011-02-04 16:17:27 -05:00
def showChat(self, handle):
tabi = self.tabIndices[handle]
if self.tabs.currentIndex() == tabi:
self.activateWindow()
self.raise_()
self.convos[handle].raiseChat()
else:
self.tabs.setCurrentIndex(tabi)
def convoHasFocus(self, convo):
if ((self.hasFocus() or self.tabs.hasFocus()) and
2011-02-04 19:50:56 -05:00
self.tabs.tabText(self.tabs.currentIndex()) == convo.title()):
2011-02-04 16:17:27 -05:00
return True
2011-02-04 16:17:27 -05:00
def keyPressEvent(self, event):
keypress = event.key()
mods = event.modifiers()
if ((mods & QtCore.Qt.ControlModifier) and
2011-02-04 16:17:27 -05:00
keypress == QtCore.Qt.Key_Tab):
2011-02-10 13:00:06 -05:00
handles = self.convos.keys()
waiting = self.mainwindow.waitingMessages.waitingHandles()
waitinghandles = list(set(handles) & set(waiting))
if len(waitinghandles) > 0:
nexti = self.tabIndices[waitinghandles[0]]
else:
nexti = (self.tabIndices[self.currentConvo.title()] + 1) % self.tabs.count()
2011-02-04 16:17:27 -05:00
self.tabs.setCurrentIndex(nexti)
def closeSoft(self):
self.softclose = True
self.close()
def updateBlocked(self, handle):
i = self.tabIndices[handle]
icon = QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"])
self.tabs.setTabIcon(i, icon)
if self.tabs.currentIndex() == i:
self.setWindowIcon(icon)
def updateMood(self, handle, mood, unblocked=False):
i = self.tabIndices[handle]
if handle in self.mainwindow.config.getBlocklist() and not unblocked:
icon = QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"])
else:
icon = mood.icon(self.mainwindow.theme)
self.tabs.setTabIcon(i, icon)
if self.tabs.currentIndex() == i:
self.setWindowIcon(icon)
def closeEvent(self, event):
if not self.softclose:
while self.tabs.count() > 0:
self.tabClose(0)
self.windowClosed.emit()
def focusInEvent(self, event):
# make sure we're not switching tabs!
i = self.tabs.tabAt(self.mapFromGlobal(QtGui.QCursor.pos()))
if i == -1:
i = self.tabs.currentIndex()
handle = unicode(self.tabs.tabText(i))
self.clearNewMessage(handle)
def convoHasFocus(self, handle):
i = self.tabIndices[handle]
if (self.tabs.currentIndex() == i and
2011-02-04 16:17:27 -05:00
(self.hasFocus() or self.tabs.hasFocus())):
return True
else:
return False
def notifyNewMessage(self, handle):
i = self.tabIndices[handle]
2011-02-04 19:50:56 -05:00
self.tabs.setTabTextColor(i, QtGui.QColor(self.mainwindow.theme["%s/tabs/newmsgcolor" % (self.type)]))
2011-02-04 16:17:27 -05:00
convo = self.convos[handle]
def func():
convo.showChat()
self.mainwindow.waitingMessages.addMessage(handle, func)
# set system tray
def clearNewMessage(self, handle):
try:
i = self.tabIndices[handle]
self.tabs.setTabTextColor(i, self.defaultTabTextColor)
except KeyError:
pass
self.mainwindow.waitingMessages.messageAnswered(handle)
2011-02-16 06:11:09 -05:00
def initTheme(self, theme):
self.resize(*theme["convo/size"])
2011-02-24 20:03:17 -05:00
self.setStyleSheet(theme["convo/tabwindow/style"])
2011-02-16 06:11:09 -05:00
self.tabs.setShape(theme["convo/tabs/tabstyle"])
self.tabs.setStyleSheet("QTabBar::tab{ %s } QTabBar::tab:selected { %s }" % (theme["convo/tabs/style"], theme["convo/tabs/selectedstyle"]))
2011-02-04 19:50:56 -05:00
2011-02-04 16:17:27 -05:00
def changeTheme(self, theme):
2011-02-16 06:11:09 -05:00
self.initTheme(theme)
2011-02-04 16:17:27 -05:00
for c in self.convos.values():
2011-02-05 22:24:10 -05:00
tabi = self.tabIndices[c.title()]
self.tabs.setTabIcon(tabi, c.icon())
2011-02-04 16:17:27 -05:00
currenttabi = self.tabs.currentIndex()
if currenttabi >= 0:
currentHandle = unicode(self.tabs.tabText(self.tabs.currentIndex()))
2011-02-05 22:24:10 -05:00
self.setWindowIcon(self.convos[currentHandle].icon())
2011-02-04 16:17:27 -05:00
self.defaultTabTextColor = self.getTabTextColor()
@QtCore.pyqtSlot(int)
def tabClose(self, i):
handle = unicode(self.tabs.tabText(i))
self.mainwindow.waitingMessages.messageAnswered(handle)
convo = self.convos[handle]
del self.convos[handle]
del self.tabIndices[handle]
self.tabs.removeTab(i)
for (h, j) in self.tabIndices.iteritems():
if j > i:
self.tabIndices[h] = j-1
self.layout.removeWidget(convo)
convo.close()
if self.tabs.count() == 0:
self.close()
return
if self.currentConvo == convo:
currenti = self.tabs.currentIndex()
currenth = unicode(self.tabs.tabText(currenti))
self.currentConvo = self.convos[currenth]
self.currentConvo.raiseChat()
@QtCore.pyqtSlot(int)
def changeTab(self, i):
if i < 0:
return
if self.changedTab:
self.changedTab = False
return
handle = unicode(self.tabs.tabText(i))
convo = self.convos[handle]
if self.currentConvo:
self.layout.removeWidget(self.currentConvo)
self.currentConvo = convo
self.layout.addWidget(convo)
2011-02-04 19:50:56 -05:00
self.setWindowIcon(convo.icon())
self.setWindowTitle(convo.title())
2011-02-04 16:17:27 -05:00
self.activateWindow()
self.raise_()
convo.raiseChat()
@QtCore.pyqtSlot(int, int)
def tabMoved(self, to, fr):
l = self.tabIndices
for i in l:
if l[i] == fr:
oldpos = i
if l[i] == to:
newpos = i
l[oldpos] = to
l[newpos] = fr
2011-02-04 16:17:27 -05:00
windowClosed = QtCore.pyqtSignal()
class PesterText(QtGui.QTextEdit):
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()
2011-02-11 04:07:07 -05:00
self.initTheme(theme)
2011-02-04 16:17:27 -05:00
self.setReadOnly(True)
self.setMouseTracking(True)
2011-02-22 19:49:47 -05:00
self.textSelected = False
self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'),
self, QtCore.SLOT('textReady(bool)'))
2011-05-03 19:41:40 -04:00
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)'))
2011-05-03 19:41:40 -04:00
def addAnimation(self, url, fileName):
movie = QtGui.QMovie(self)
movie.setFileName(fileName)
if movie.frameCount() > 1:
self.urls[movie] = url
self.connect(movie, QtCore.SIGNAL('frameChanged(int)'),
self, QtCore.SLOT('animate(int)'))
#movie.start()
@QtCore.pyqtSlot(int)
def animate(self, frame):
if self.mainwindow.config.animations():
movie = self.sender()
url = self.urls[movie].toString()
html = unicode(self.toHtml())
if html.find(url) != -1:
2011-06-23 03:13:26 -04:00
if self.parent().parent():
i = self.parent().parent().tabIndices[self.parent().title()]
if self.parent().parent().tabs.currentIndex() == i:
self.document().addResource(QtGui.QTextDocument.ImageResource,
self.urls[movie], movie.currentPixmap())
self.setLineWrapColumnOrWidth(self.lineWrapColumnOrWidth())
else:
self.document().addResource(QtGui.QTextDocument.ImageResource,
self.urls[movie], movie.currentPixmap())
self.setLineWrapColumnOrWidth(self.lineWrapColumnOrWidth())
@QtCore.pyqtSlot(bool)
def animateChanged(self, animate):
if animate:
for m in self.urls:
html = unicode(self.toHtml())
if html.find(self.urls[m].toString()) != -1:
if m.frameCount() > 1:
m.start()
else:
for m in self.urls:
html = unicode(self.toHtml())
if html.find(self.urls[m].toString()) != -1:
if m.frameCount() > 1:
m.stop()
2011-05-03 19:41:40 -04:00
2011-02-22 19:49:47 -05:00
@QtCore.pyqtSlot(bool)
def textReady(self, ready):
self.textSelected = ready
2011-02-11 04:07:07 -05:00
def initTheme(self, theme):
if theme.has_key("convo/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["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"]))
2011-02-13 04:27:12 -05:00
def addMessage(self, lexmsg, chum):
if len(lexmsg) == 0:
return
color = chum.colorcmd()
2011-02-04 16:17:27 -05:00
systemColor = QtGui.QColor(self.parent().mainwindow.theme["convo/systemMsgColor"])
initials = chum.initials()
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()
if self.parent().mainwindow.config.showTimeStamps():
if self.parent().mainwindow.config.time12Format():
time = strftime("[%I:%M")
else:
time = strftime("[%H:%M")
if self.parent().mainwindow.config.showSeconds():
time += strftime(":%S] ")
else:
time += "] "
else:
time = ""
2011-02-13 04:27:12 -05:00
if lexmsg[0] == "PESTERCHUM:BEGIN":
2011-02-04 16:17:27 -05:00
parent.setChumOpen(True)
2011-02-13 04:27:12 -05:00
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":
2011-02-04 16:17:27 -05:00
parent.setChumOpen(False)
2011-02-13 04:27:12 -05:00
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)
2011-02-04 16:17:27 -05:00
if chum is me:
2011-02-13 04:27:12 -05:00
window.chatlog.log(parent.chum.handle, memsg)
2011-02-04 16:17:27 -05:00
else:
2011-02-13 04:27:12 -05:00
window.chatlog.log(chum.handle, memsg)
self.append(time + convertTags(memsg))
2011-02-04 16:17:27 -05:00
else:
if not parent.chumopen and chum is not me:
beginmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
parent.setChumOpen(True)
2011-02-13 04:27:12 -05:00
window.chatlog.log(chum.handle, beginmsg)
2011-02-04 16:17:27 -05:00
self.append(convertTags(beginmsg))
lexmsg[0:0] = [colorBegin("<c=%s>" % (color), color),
2011-02-13 04:27:12 -05:00
"%s: " % (initials)]
lexmsg.append(colorEnd("</c>"))
self.append("<span style=\"color:#000000\">" + time + convertTags(lexmsg) + "</span>")
2011-02-04 16:17:27 -05:00
if chum is me:
2011-02-13 04:27:12 -05:00
window.chatlog.log(parent.chum.handle, lexmsg)
2011-02-04 16:17:27 -05:00
else:
2011-02-14 01:28:25 -05:00
if window.idleaction.isChecked() and parent.chumopen:
2011-02-10 20:55:45 -05:00
idlethreshhold = 60
if (not hasattr(self, 'lastmsg')) or \
2011-02-13 04:27:12 -05:00
datetime.now() - self.lastmsg > timedelta(0,idlethreshhold):
2011-02-21 14:07:59 -05:00
verb = window.theme["convo/text/idle"]
2011-02-13 04:27:12 -05:00
idlemsg = me.idlemsg(systemColor, verb)
2011-02-21 14:07:59 -05:00
parent.textArea.append(convertTags(idlemsg))
window.chatlog.log(parent.title(), idlemsg)
2011-02-10 20:55:45 -05:00
parent.messageSent.emit("PESTERCHUM:IDLE", parent.title())
self.lastmsg = datetime.now()
2011-02-13 04:27:12 -05:00
window.chatlog.log(chum.handle, lexmsg)
2011-02-04 16:17:27 -05:00
def changeTheme(self, theme):
2011-02-11 04:07:07 -05:00
self.initTheme(theme)
2011-02-04 16:17:27 -05:00
sb = self.verticalScrollBar()
sb.setValue(sb.maximum())
def focusInEvent(self, event):
self.parent().clearNewMessage()
QtGui.QTextEdit.focusInEvent(self, event)
def keyPressEvent(self, event):
if hasattr(self.parent(), 'textInput'):
if event.key() not in [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown, \
QtCore.Qt.Key_Up, QtCore.Qt.Key_Down]:
self.parent().textInput.keyPressEvent(event)
QtGui.QTextEdit.keyPressEvent(self, event)
2011-02-04 16:17:27 -05:00
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
url = self.anchorAt(event.pos())
if url != "":
if url[0] == "#" and url != "#pesterchum":
self.parent().mainwindow.showMemos(url[1:])
elif url[0] == "@":
handle = unicode(url[1:])
self.parent().mainwindow.newConversation(handle)
else:
if event.modifiers() == QtCore.Qt.ControlModifier:
QtGui.QApplication.clipboard().setText(url)
else:
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
2011-02-04 16:17:27 -05:00
QtGui.QTextEdit.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
QtGui.QTextEdit.mouseMoveEvent(self, event)
if self.anchorAt(event.pos()):
if self.viewport().cursor().shape != QtCore.Qt.PointingHandCursor:
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
else:
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
2011-02-22 19:49:47 -05:00
def contextMenuEvent(self, event):
textMenu = self.createStandardContextMenu()
if self.textSelected:
self.submitLogAction = QtGui.QAction("Submit to Pesterchum QDB", self)
self.connect(self.submitLogAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('submitLog()'))
2011-02-22 19:49:47 -05:00
textMenu.addAction(self.submitLogAction)
textMenu.exec_(event.globalPos())
2011-02-23 06:06:00 -05:00
def submitLogTitle(self):
return "[%s -> %s]" % (self.parent().mainwindow.profile().handle,
self.parent().chum.handle)
2011-02-22 19:49:47 -05:00
@QtCore.pyqtSlot()
def submitLog(self):
mimedata = self.createMimeDataFromSelection()
2011-02-23 06:06:00 -05:00
htmldata = img2smiley(mimedata.data("text/html"))
textdoc = QtGui.QTextDocument()
textdoc.setHtml(htmldata)
2011-02-23 06:27:37 -05:00
logdata = "%s\n%s" % (self.submitLogTitle(), textdoc.toPlainText())
2011-02-23 06:06:00 -05:00
self.sending = QtGui.QDialog(self)
layout = QtGui.QVBoxLayout()
self.sending.sendinglabel = QtGui.QLabel("S3ND1NG...", self.sending)
cancelbutton = QtGui.QPushButton("OK", self.sending)
self.sending.connect(cancelbutton, QtCore.SIGNAL('clicked()'),
self.sending, QtCore.SLOT('close()'))
layout.addWidget(self.sending.sendinglabel)
layout.addWidget(cancelbutton)
self.sending.setLayout(layout)
self.sending.show()
params = urllib.urlencode({'quote': logdata, 'do': "add"})
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
try:
pass
2011-04-10 05:22:06 -04:00
hconn = httplib.HTTPConnection('qdb.pesterchum.net', 80,
2011-02-23 06:06:00 -05:00
timeout=15)
hconn.request("POST", "/index.php", params, headers)
response = hconn.getresponse()
2011-02-24 13:07:37 -05:00
if response.status == 200:
2011-02-23 06:06:00 -05:00
self.sending.sendinglabel.setText("SUCC3SS!")
else:
2011-02-24 13:07:37 -05:00
self.sending.sendinglabel.setText("F41L3D: %s %s" % (response.status, response.reason))
2011-02-23 06:06:00 -05:00
hconn.close()
except Exception, e:
self.sending.sendinglabel.setText("F41L3D: %s" % (e))
del self.sending
2011-02-22 19:49:47 -05:00
2011-02-04 16:17:27 -05:00
class PesterInput(QtGui.QLineEdit):
def __init__(self, theme, parent=None):
QtGui.QLineEdit.__init__(self, parent)
self.setStyleSheet(theme["convo/input/style"])
def changeTheme(self, theme):
self.setStyleSheet(theme["convo/input/style"])
def focusInEvent(self, event):
self.parent().clearNewMessage()
2011-02-13 04:27:12 -05:00
self.parent().textArea.textCursor().clearSelection()
2011-02-04 16:17:27 -05:00
QtGui.QLineEdit.focusInEvent(self, event)
2011-02-09 01:26:23 -05:00
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Up:
text = unicode(self.text())
next = self.parent().history.next(text)
if next is not None:
self.setText(next)
elif event.key() == QtCore.Qt.Key_Down:
prev = self.parent().history.prev()
if prev is not None:
self.setText(prev)
elif event.key() in [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown]:
self.parent().textArea.keyPressEvent(event)
2011-02-10 20:55:45 -05:00
self.parent().mainwindow.idletime = 0
2011-02-09 01:26:23 -05:00
QtGui.QLineEdit.keyPressEvent(self, event)
2011-02-04 16:17:27 -05:00
class PesterConvo(QtGui.QFrame):
def __init__(self, chum, initiated, mainwindow, parent=None):
QtGui.QFrame.__init__(self, parent)
2011-03-02 18:36:10 -05:00
self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
2011-02-11 04:07:07 -05:00
self.setObjectName(chum.handle)
2011-02-04 16:17:27 -05:00
self.setFocusPolicy(QtCore.Qt.ClickFocus)
self.chum = chum
self.mainwindow = mainwindow
2011-02-16 06:11:09 -05:00
theme = self.mainwindow.theme
self.resize(*theme["convo/size"])
2011-02-22 19:49:47 -05:00
self.setStyleSheet("QFrame#%s { %s }" % (chum.handle, theme["convo/style"]))
2011-02-04 19:50:56 -05:00
self.setWindowIcon(self.icon())
self.setWindowTitle(self.title())
2011-02-04 16:17:27 -05:00
t = Template(self.mainwindow.theme["convo/chumlabel/text"])
2011-02-04 16:17:27 -05:00
self.chumLabel = QtGui.QLabel(t.safe_substitute(handle=chum.handle), self)
self.chumLabel.setStyleSheet(self.mainwindow.theme["convo/chumlabel/style"])
self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]])
self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"])
self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"])
2011-02-16 06:11:09 -05:00
self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding))
2011-02-04 16:17:27 -05:00
self.textArea = PesterText(self.mainwindow.theme, self)
self.textInput = PesterInput(self.mainwindow.theme, self)
self.textInput.setFocus()
self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'),
self, QtCore.SLOT('sentMessage()'))
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.chumLabel)
self.layout.addWidget(self.textArea)
self.layout.addWidget(self.textInput)
self.layout.setSpacing(0)
margins = self.mainwindow.theme["convo/margins"]
self.layout.setContentsMargins(margins["left"], margins["top"],
margins["right"], margins["bottom"])
2011-02-04 16:17:27 -05:00
self.setLayout(self.layout)
2011-02-06 19:50:21 -05:00
self.optionsMenu = QtGui.QMenu(self)
self.optionsMenu.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"])
self.addChumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self)
self.connect(self.addChumAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('addThisChum()'))
self.blockAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self)
self.connect(self.blockAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('blockThisChum()'))
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)'))
2011-02-10 20:55:45 -05:00
self.unblockchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self)
self.connect(self.unblockchum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('unblockChumSlot()'))
2011-04-13 02:12:19 -04:00
self.reportchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self)
self.connect(self.reportchum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('reportThisChum()'))
self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self)
self.connect(self.logchum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('openChumLogs()'))
2011-02-10 20:55:45 -05:00
2011-02-06 19:50:21 -05:00
self.optionsMenu.addAction(self.quirksOff)
self.optionsMenu.addAction(self.logchum)
2011-02-06 19:50:21 -05:00
self.optionsMenu.addAction(self.addChumAction)
self.optionsMenu.addAction(self.blockAction)
2011-04-13 02:12:19 -04:00
self.optionsMenu.addAction(self.reportchum)
2011-02-06 19:50:21 -05:00
2011-02-04 16:17:27 -05:00
self.chumopen = False
2011-02-06 19:50:21 -05:00
self.applyquirks = True
2011-02-04 16:17:27 -05:00
if parent:
parent.addChat(self)
if initiated:
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))
2011-02-13 04:27:12 -05:00
self.mainwindow.chatlog.log(self.title(), msg)
2011-02-04 16:17:27 -05:00
self.newmessage = False
2011-02-09 01:26:23 -05:00
self.history = PesterHistory()
2011-02-04 16:17:27 -05:00
2011-02-04 19:50:56 -05:00
def title(self):
return self.chum.handle
def icon(self):
return self.chum.mood.icon(self.mainwindow.theme)
2011-02-23 06:06:00 -05:00
def myUpdateMood(self, mood):
chum = self.mainwindow.profile()
syscolor = QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"])
msg = chum.moodmsg(mood, syscolor, self.mainwindow.theme)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.title(), msg)
2011-02-04 19:50:56 -05:00
2011-02-08 17:47:07 -05:00
def updateMood(self, mood, unblocked=False, old=None):
syscolor = QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"])
2011-02-04 16:17:27 -05:00
if mood.name() == "offline" and self.chumopen == True and not unblocked:
2011-02-10 20:55:45 -05:00
self.mainwindow.ceasesound.play()
2011-02-08 17:47:07 -05:00
msg = self.chum.pestermsg(self.mainwindow.profile(), syscolor, self.mainwindow.theme["convo/text/ceasepester"])
2011-02-04 16:17:27 -05:00
self.textArea.append(convertTags(msg))
2011-02-13 04:27:12 -05:00
self.mainwindow.chatlog.log(self.title(), msg)
2011-02-04 16:17:27 -05:00
self.chumopen = False
2011-02-08 17:47:07 -05:00
elif old and old.name() != mood.name():
2011-02-10 13:00:06 -05:00
msg = self.chum.moodmsg(mood, syscolor, self.mainwindow.theme)
2011-02-08 17:47:07 -05:00
self.textArea.append(convertTags(msg))
2011-02-13 04:27:12 -05:00
self.mainwindow.chatlog.log(self.title(), msg)
2011-02-04 16:17:27 -05:00
if self.parent():
2011-02-04 19:50:56 -05:00
self.parent().updateMood(self.title(), mood, unblocked)
2011-02-04 16:17:27 -05:00
else:
if self.chum.blocked(self.mainwindow.config) and not unblocked:
self.setWindowIcon(QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"]))
2011-02-10 20:55:45 -05:00
self.optionsMenu.addAction(self.unblockchum)
self.optionsMenu.removeAction(self.blockAction)
2011-02-04 16:17:27 -05:00
else:
self.setWindowIcon(mood.icon(self.mainwindow.theme))
2011-02-10 20:55:45 -05:00
self.optionsMenu.removeAction(self.unblockchum)
self.optionsMenu.addAction(self.blockAction)
2011-02-04 16:17:27 -05:00
# print mood update?
def updateBlocked(self):
if self.parent():
2011-02-04 19:50:56 -05:00
self.parent().updateBlocked(self.title())
2011-02-04 16:17:27 -05:00
else:
self.setWindowIcon(QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"]))
2011-02-10 20:55:45 -05:00
self.optionsMenu.addAction(self.unblockchum)
self.optionsMenu.removeAction(self.blockAction)
2011-02-04 16:17:27 -05:00
def updateColor(self, color):
self.chum.color = color
2011-02-13 04:27:12 -05:00
def addMessage(self, msg, me=True):
if type(msg) in [str, unicode]:
lexmsg = lexMessage(msg)
else:
lexmsg = msg
2011-02-04 16:17:27 -05:00
if me:
chum = self.mainwindow.profile()
else:
chum = self.chum
self.notifyNewMessage()
2011-02-13 04:27:12 -05:00
self.textArea.addMessage(lexmsg, chum)
2011-02-04 16:17:27 -05:00
def notifyNewMessage(self):
# first see if this conversation HASS the focus
if not (self.hasFocus() or self.textArea.hasFocus() or
self.textInput.hasFocus() or
2011-02-04 19:50:56 -05:00
(self.parent() and self.parent().convoHasFocus(self.title()))):
2011-02-04 16:17:27 -05:00
# ok if it has a tabconvo parent, send that the notify.
if self.parent():
2011-02-04 19:50:56 -05:00
self.parent().notifyNewMessage(self.title())
2011-06-20 06:34:06 -04:00
self.mainwindow.gainAttention.emit(self.parent())
2011-02-04 16:17:27 -05:00
# if not change the window title and update system tray
else:
self.newmessage = True
2011-02-04 19:50:56 -05:00
self.setWindowTitle(self.title()+"*")
2011-02-04 16:17:27 -05:00
def func():
self.showChat()
2011-02-04 19:50:56 -05:00
self.mainwindow.waitingMessages.addMessage(self.title(), func)
2011-06-20 06:34:06 -04:00
self.mainwindow.gainAttention.emit(self)
2011-02-04 16:17:27 -05:00
def clearNewMessage(self):
if self.parent():
2011-02-04 19:50:56 -05:00
self.parent().clearNewMessage(self.title())
2011-02-04 16:17:27 -05:00
elif self.newmessage:
self.newmessage = False
2011-02-04 19:50:56 -05:00
self.setWindowTitle(self.title())
self.mainwindow.waitingMessages.messageAnswered(self.title())
2011-02-04 16:17:27 -05:00
# reset system tray
def focusInEvent(self, event):
self.clearNewMessage()
self.textInput.setFocus()
2011-02-09 01:26:23 -05:00
2011-02-04 16:17:27 -05:00
def raiseChat(self):
self.activateWindow()
self.raise_()
self.textInput.setFocus()
def showChat(self):
if self.parent():
2011-02-04 19:50:56 -05:00
self.parent().showChat(self.title())
2011-02-04 16:17:27 -05:00
self.raiseChat()
2011-02-06 19:50:21 -05:00
def contextMenuEvent(self, event):
if event.reason() == QtGui.QContextMenuEvent.Mouse:
self.optionsMenu.popup(event.globalPos())
2011-02-04 16:17:27 -05:00
def closeEvent(self, event):
2011-02-04 19:50:56 -05:00
self.mainwindow.waitingMessages.messageAnswered(self.title())
self.windowClosed.emit(self.title())
2011-02-06 19:50:21 -05:00
2011-02-04 16:17:27 -05:00
def setChumOpen(self, o):
self.chumopen = o
def changeTheme(self, theme):
self.resize(*theme["convo/size"])
2011-02-25 05:41:33 -05:00
self.setStyleSheet("QFrame#%s { %s }" % (self.chum.handle, theme["convo/style"]))
2011-02-04 16:17:27 -05:00
margins = theme["convo/margins"]
self.layout.setContentsMargins(margins["left"], margins["top"],
margins["right"], margins["bottom"])
2011-02-04 19:50:56 -05:00
self.setWindowIcon(self.icon())
2011-02-04 16:17:27 -05:00
t = Template(self.mainwindow.theme["convo/chumlabel/text"])
2011-02-04 19:50:56 -05:00
self.chumLabel.setText(t.safe_substitute(handle=self.title()))
2011-02-04 16:17:27 -05:00
self.chumLabel.setStyleSheet(theme["convo/chumlabel/style"])
self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]])
self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"])
self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"])
self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
2011-02-06 19:50:21 -05:00
self.quirksOff.setText(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"])
self.addChumAction.setText(self.mainwindow.theme["main/menus/rclickchumlist/addchum"])
self.blockAction.setText(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"])
2011-02-11 04:07:07 -05:00
self.unblockchum.setText(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"])
self.logchum.setText(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"])
2011-02-06 19:50:21 -05:00
2011-02-04 16:17:27 -05:00
self.textArea.changeTheme(theme)
self.textInput.changeTheme(theme)
2011-02-06 19:50:21 -05:00
2011-02-04 16:17:27 -05:00
@QtCore.pyqtSlot()
def sentMessage(self):
2011-02-08 02:56:30 -05:00
text = unicode(self.textInput.text())
2011-02-10 13:00:06 -05:00
if text == "" or text[0:11] == "PESTERCHUM:":
2011-02-04 16:17:27 -05:00
return
2011-02-09 01:26:23 -05:00
self.history.add(text)
2011-02-13 04:27:12 -05:00
quirks = self.mainwindow.userprofile.quirks
lexmsg = lexMessage(text)
if type(lexmsg[0]) is not mecmd and self.applyquirks:
try:
lexmsg = quirks.apply(lexmsg)
except:
msgbox = QtGui.QMessageBox()
msgbox.setText("Whoa there! There seems to be a problem.")
msgbox.setInformativeText("A quirk seems to be having a problem. (Possibly you're trying to capture a non-existant group?)")
msgbox.exec_()
return
2011-04-10 05:22:06 -04:00
lexmsgs = splitMessage(lexmsg)
for lm in lexmsgs:
serverMsg = copy(lm)
self.addMessage(lm, True)
# if ceased, rebegin
if hasattr(self, 'chumopen') and not self.chumopen:
self.mainwindow.newConvoStarted.emit(QtCore.QString(self.title()), True)
self.setChumOpen(True)
text = convertTags(serverMsg, "ctag")
self.messageSent.emit(text, self.title())
2011-02-08 02:56:30 -05:00
self.textInput.setText("")
2011-02-04 16:17:27 -05:00
2011-02-06 19:50:21 -05:00
@QtCore.pyqtSlot()
def addThisChum(self):
self.mainwindow.addChum(self.chum)
@QtCore.pyqtSlot()
def blockThisChum(self):
self.mainwindow.blockChum(self.chum.handle)
2011-02-10 20:55:45 -05:00
@QtCore.pyqtSlot()
2011-04-13 02:12:19 -04:00
def reportThisChum(self):
self.mainwindow.reportChum(self.chum.handle)
@QtCore.pyqtSlot()
2011-02-10 20:55:45 -05:00
def unblockChumSlot(self):
self.mainwindow.unblockChum(self.chum.handle)
2011-02-06 19:50:21 -05:00
@QtCore.pyqtSlot(bool)
def toggleQuirks(self, toggled):
self.applyquirks = not toggled
@QtCore.pyqtSlot()
def openChumLogs(self):
currentChum = self.chum.handle
self.mainwindow.chumList.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow)
self.connect(self.mainwindow.chumList.pesterlogviewer, QtCore.SIGNAL('rejected()'),
self.mainwindow.chumList, QtCore.SLOT('closeActiveLog()'))
self.mainwindow.chumList.pesterlogviewer.show()
self.mainwindow.chumList.pesterlogviewer.raise_()
self.mainwindow.chumList.pesterlogviewer.activateWindow()
2011-02-06 19:50:21 -05:00
2011-02-04 19:50:56 -05:00
messageSent = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
2011-02-04 16:17:27 -05:00
windowClosed = QtCore.pyqtSignal(QtCore.QString)
aligndict = {"h": {"center": QtCore.Qt.AlignHCenter,
"left": QtCore.Qt.AlignLeft,
"right": QtCore.Qt.AlignRight },
"v": {"center": QtCore.Qt.AlignVCenter,
"top": QtCore.Qt.AlignTop,
"bottom": QtCore.Qt.AlignBottom } }
# the import is way down here to avoid recursive imports
from logviewer import PesterLogViewer