2111 lines
79 KiB
Python
2111 lines
79 KiB
Python
import logging
|
|
import re
|
|
from string import Template
|
|
from datetime import timedelta, datetime
|
|
|
|
try:
|
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
|
from PyQt6.QtGui import QAction
|
|
except ImportError:
|
|
print("PyQt5 fallback (memos.py)")
|
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
from PyQt5.QtWidgets import QAction
|
|
|
|
import parsetools
|
|
from dataobjs import PesterProfile, PesterHistory
|
|
from generic import PesterIcon, RightClickList, mysteryTime
|
|
from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow
|
|
from parsetools import (
|
|
convertTags,
|
|
timeProtocol,
|
|
lexMessage,
|
|
colorBegin,
|
|
mecmd,
|
|
smiledict,
|
|
)
|
|
from logviewer import PesterLogViewer
|
|
|
|
PchumLog = logging.getLogger("pchumLogger")
|
|
|
|
# Python 3
|
|
QString = str
|
|
|
|
|
|
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 td == timedelta(microseconds=1): # Replacement for mysteryTime </3
|
|
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:
|
|
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):
|
|
# mysteryTime breaks stuff now, so, uh
|
|
# I'm replacing it with 1 day...
|
|
if type(time) == mysteryTime:
|
|
time = timedelta(microseconds=1)
|
|
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):
|
|
# mysteryTime </3
|
|
if type(timed) == mysteryTime:
|
|
timed = timedelta(microseconds=1)
|
|
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))
|
|
pcf = pcfGrammar(timed - timedelta(0))[1]
|
|
except TypeError:
|
|
# (temporal, pcf, when) = pcfGrammar(mysteryTime())
|
|
pcf = pcfGrammar(mysteryTime())[1]
|
|
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))
|
|
pcf = pcfGrammar(timed - timedelta(0))[1]
|
|
except TypeError:
|
|
pcf = pcfGrammar(mysteryTime())[1]
|
|
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 time in self.open:
|
|
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(QtWidgets.QLineEdit):
|
|
def __init__(self, timeslider, parent):
|
|
super().__init__(parent)
|
|
self.timeslider = timeslider
|
|
self.setText("+0:00")
|
|
self.timeslider.valueChanged[int].connect(self.setTime)
|
|
self.editingFinished.connect(self.setSlider)
|
|
|
|
@QtCore.pyqtSlot(int)
|
|
def setTime(self, sliderval):
|
|
self.setText(self.timeslider.getTime())
|
|
|
|
@QtCore.pyqtSlot()
|
|
def setSlider(self):
|
|
value = str(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(QtWidgets.QSlider):
|
|
def __init__(self, orientation, parent):
|
|
super().__init__(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):
|
|
super().__init__(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):
|
|
super().__init__(theme, 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.copyAvailable[bool].connect(self.textReady)
|
|
self.urls = {}
|
|
for k in smiledict:
|
|
self.addAnimation(
|
|
QtCore.QUrl("smilies/%s" % (smiledict[k])),
|
|
"smilies/%s" % (smiledict[k]),
|
|
)
|
|
# self.mainwindow.animationSetting[bool].connect(self.animateChanged)
|
|
|
|
def initTheme(self, theme):
|
|
if "memos/scrollbar" in theme:
|
|
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"])
|
|
|
|
# So it doesn't inherit the memo's background image.
|
|
# Fixes floating "PESTERLOG:"
|
|
try:
|
|
self.setStyleSheet(
|
|
self.styleSheet() + ("QMenu{ %s }" % theme["main/defaultwindow/style"])
|
|
)
|
|
except:
|
|
pass
|
|
|
|
def addMessage(self, msg, chum):
|
|
if type(msg) in [str, str]:
|
|
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.MovieState.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 chum.handle in parent.times:
|
|
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[chum.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 _ 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)
|
|
|
|
|
|
class MemoInput(PesterInput):
|
|
stylesheet_path = "memos/input/style"
|
|
# karxi: Because of the use of stylesheet_path, we don't have to rewrite
|
|
# this code.
|
|
# Neat, huh?
|
|
|
|
|
|
class PesterMemo(PesterConvo):
|
|
# TODO: Clean up inheritance between these!! The inits are ugly.
|
|
def __init__(self, channel, timestr, mainwindow, parent=None):
|
|
QtWidgets.QFrame.__init__(self, parent)
|
|
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_QuitOnClose, False)
|
|
self.channel = channel
|
|
self.setObjectName(self.channel)
|
|
self.mainwindow = mainwindow
|
|
self.time = TimeTracker(txt2delta(timestr))
|
|
self.setWindowTitle(channel)
|
|
self.channelLabel = QtWidgets.QLabel(self)
|
|
self.channelLabel.setSizePolicy(
|
|
QtWidgets.QSizePolicy(
|
|
QtWidgets.QSizePolicy.Policy.MinimumExpanding,
|
|
QtWidgets.QSizePolicy.Policy.Expanding,
|
|
)
|
|
)
|
|
|
|
self.textArea = MemoText(self.mainwindow.theme, self)
|
|
self.textInput = MemoInput(self.mainwindow.theme, self)
|
|
self.textInput.setFocus()
|
|
|
|
self.miniUserlist = QtWidgets.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.miniUserlist.clicked.connect(self.toggleUserlist)
|
|
|
|
self.userlist = RightClickList(self)
|
|
self.userlist.setSizePolicy(
|
|
QtWidgets.QSizePolicy(
|
|
QtWidgets.QSizePolicy.Policy.Fixed,
|
|
QtWidgets.QSizePolicy.Policy.Expanding,
|
|
)
|
|
)
|
|
self.userlist.optionsMenu = QtWidgets.QMenu(self)
|
|
self.pesterChumAction = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/pester"], self
|
|
)
|
|
self.pesterChumAction.triggered.connect(self.newPesterSlot)
|
|
self.addchumAction = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self
|
|
)
|
|
self.addchumAction.triggered.connect(self.addChumSlot)
|
|
self.banuserAction = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/banuser"], self
|
|
)
|
|
self.banuserAction.triggered.connect(self.banSelectedUser)
|
|
self.opAction = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/opuser"], self
|
|
)
|
|
self.opAction.triggered.connect(self.opSelectedUser)
|
|
self.voiceAction = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/voiceuser"], self
|
|
)
|
|
self.voiceAction.triggered.connect(self.voiceSelectedUser)
|
|
self.quirkDisableAction = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self
|
|
)
|
|
self.quirkDisableAction.triggered.connect(self.killQuirkUser)
|
|
self.userlist.optionsMenu.addAction(self.pesterChumAction)
|
|
self.userlist.optionsMenu.addAction(self.addchumAction)
|
|
# ban & op list added if we are op
|
|
|
|
self.optionsMenu = QtWidgets.QMenu(self)
|
|
self.optionsMenu.setStyleSheet(
|
|
self.mainwindow.theme["main/defaultwindow/style"]
|
|
) # So it doesn't inherit the memo's background image.
|
|
# Fixes floating "PESTERLOG:"
|
|
self.oocToggle = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self
|
|
)
|
|
self.oocToggle.setCheckable(True)
|
|
self.oocToggle.toggled[bool].connect(self.toggleOOC)
|
|
self.quirksOff = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self
|
|
)
|
|
self.quirksOff.setCheckable(True)
|
|
self.quirksOff.toggled[bool].connect(self.toggleQuirks)
|
|
self.logchum = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self
|
|
)
|
|
self.logchum.triggered.connect(self.openChumLogs)
|
|
self.invitechum = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/invitechum"], self
|
|
)
|
|
self.invitechum.triggered.connect(self.inviteChums)
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/beeponmessage"):
|
|
try:
|
|
self._beepToggle = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/beeponmessage"], self
|
|
)
|
|
except:
|
|
self._beepToggle = QAction("BEEP ON MESSAGE", self)
|
|
self._beepToggle.setCheckable(True)
|
|
self._beepToggle.toggled[bool].connect(self.toggleBeep)
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/flashonmessage"):
|
|
try:
|
|
self._flashToggle = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/flashonmessage"], self
|
|
)
|
|
except:
|
|
self._flashToggle = QAction("FLASH ON MESSAGE", self)
|
|
self._flashToggle.setCheckable(True)
|
|
self._flashToggle.toggled[bool].connect(self.toggleFlash)
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/mutenotifications"):
|
|
try:
|
|
self._muteToggle = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/mutenotifications"],
|
|
self,
|
|
)
|
|
except:
|
|
self._muteToggle = QAction("MUTE NOTIFICATIONS", self)
|
|
self._muteToggle.setCheckable(True)
|
|
self._muteToggle.toggled[bool].connect(self.toggleMute)
|
|
|
|
self.optionsMenu.addAction(self.quirksOff)
|
|
self.optionsMenu.addAction(self.oocToggle)
|
|
|
|
self.optionsMenu.addAction(self._beepToggle)
|
|
self.optionsMenu.addAction(self._flashToggle)
|
|
self.optionsMenu.addAction(self._muteToggle)
|
|
|
|
self.optionsMenu.addAction(self.logchum)
|
|
self.optionsMenu.addAction(self.invitechum)
|
|
|
|
self.chanModeMenu = QtWidgets.QMenu(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/memosetting"], self
|
|
)
|
|
self.chanNoquirks = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/memonoquirk"], self
|
|
)
|
|
self.chanNoquirks.setCheckable(True)
|
|
self.chanNoquirks.toggled[bool].connect(self.noquirksChan)
|
|
self.chanHide = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/memohidden"], self
|
|
)
|
|
self.chanHide.setCheckable(True)
|
|
self.chanHide.toggled[bool].connect(self.hideChan)
|
|
self.chanInvite = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/memoinvite"], self
|
|
)
|
|
self.chanInvite.setCheckable(True)
|
|
self.chanInvite.toggled[bool].connect(self.inviteChan)
|
|
self.chanMod = QAction(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/memomute"], self
|
|
)
|
|
self.chanMod.setCheckable(True)
|
|
self.chanMod.toggled[bool].connect(self.modChan)
|
|
self.chanModeMenu.addAction(self.chanNoquirks)
|
|
self.chanModeMenu.addAction(self.chanHide)
|
|
self.chanModeMenu.addAction(self.chanInvite)
|
|
self.chanModeMenu.addAction(self.chanMod)
|
|
self.chanModeMenu.setStyleSheet(
|
|
self.mainwindow.theme["main/defaultwindow/style"]
|
|
) # BWAH BWAH FLOATING "PESTERLOG:"
|
|
|
|
self.timeslider = TimeSlider(QtCore.Qt.Orientation.Horizontal, self)
|
|
self.timeinput = TimeInput(self.timeslider, self)
|
|
self.timeinput.setText(timestr)
|
|
self.timeinput.setSlider()
|
|
self.timetravel = QtWidgets.QPushButton("GO", self)
|
|
self.timeclose = QtWidgets.QPushButton("CLOSE", self)
|
|
self.timeswitchl = QtWidgets.QPushButton(self)
|
|
self.timeswitchr = QtWidgets.QPushButton(self)
|
|
|
|
self.timetravel.clicked.connect(self.sendtime)
|
|
self.timeclose.clicked.connect(self.smashclock)
|
|
self.timeswitchl.clicked.connect(self.prevtime)
|
|
self.timeswitchr.clicked.connect(self.nexttime)
|
|
|
|
self.times = {}
|
|
|
|
self.initTheme(self.mainwindow.theme)
|
|
|
|
# connect
|
|
self.textInput.returnPressed.connect(self.sentMessage)
|
|
|
|
layout_0 = QtWidgets.QVBoxLayout()
|
|
layout_0.addWidget(self.textArea)
|
|
layout_0.addWidget(self.textInput)
|
|
|
|
layout_1 = QtWidgets.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.AlignmentFlag.AlignHCenter)
|
|
# layout_1.addWidget(self.timeinput, 1, 0, 1, 3)
|
|
layout_2 = QtWidgets.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 = QtWidgets.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
|
|
|
|
self.always_beep = False
|
|
self.always_flash = False
|
|
self.notifications_muted = 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.MatchFlag.MatchExactly)
|
|
for c in chums:
|
|
c.setForeground(QtGui.QBrush(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("QtWidgets.QFrame { %s };" % (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 "main/chums/scrollbar" in theme:
|
|
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 "convo/scrollbar" in theme:
|
|
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(
|
|
"padding: 0px;"
|
|
"margin: 0px;"
|
|
"margin-left: 5px;"
|
|
"width: 10px;"
|
|
"height: 90px;" + borders + theme["memos/userlist/style"]
|
|
)
|
|
|
|
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 }"
|
|
"Slider::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"])
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/beeponmessage"):
|
|
try:
|
|
self._beepToggle.setText(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/beeponmessage"]
|
|
)
|
|
except:
|
|
self._beepToggle.setText("BEEP ON MESSAGE")
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/flashonmessage"):
|
|
try:
|
|
self._flashToggle.setText(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/flashonmessage"]
|
|
)
|
|
except:
|
|
self._flashToggle.setText("FLASH ON MESSAGE")
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/mutenotifications"):
|
|
try:
|
|
self._muteToggle.setText(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/mutenotifications"]
|
|
)
|
|
except:
|
|
self._muteToggle.setText("MUTE NOTIFICATIONS")
|
|
|
|
# if self.mainwindow.theme.has_key("main/menus/rclickchumlist/pester"):
|
|
try:
|
|
self.pesterChumAction.setText(
|
|
self.mainwindow.theme["main/menus/rclickchumlist/pester"]
|
|
)
|
|
except:
|
|
pass
|
|
|
|
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 = QtWidgets.QListWidgetItem(handle)
|
|
if handle == self.mainwindow.profile().handle:
|
|
color = self.mainwindow.profile().color
|
|
else:
|
|
color = chumdb.getColor(handle, defaultcolor)
|
|
item.box = handle == "evacipatedBox"
|
|
item.setForeground(QtGui.QBrush(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 op in self.times:
|
|
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)
|
|
|
|
# New
|
|
if modes.find("C") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-CTCP", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("D") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Join Delayed", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("f") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Flood Protected", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("G") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Censored", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("H") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Remembering Chat History", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("k") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Key-only", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("K") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-Knock", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("L") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Redirecting", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("K") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-Knock", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("l") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum,
|
|
opgrammar,
|
|
systemColor,
|
|
"Limiting maximum amount of users",
|
|
True,
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("M") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Non-Auth muted", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("N") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Handle-locked", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("O") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "An Oper-Only channel", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("P") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Permanent", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("Q") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-kick", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("R") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Registered users only", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("r") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Registered", True
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("z") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Secure-only", 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)
|
|
|
|
# New
|
|
if modes.find("C") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-CTCP", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("D") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Join Delayed", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("f") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Flood Protected", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("G") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Censored", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("H") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum,
|
|
opgrammar,
|
|
systemColor,
|
|
"Remembering Chat History",
|
|
False,
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("k") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Key-only", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("K") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-Knock", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("L") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Redirecting", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("K") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-Knock", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("l") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum,
|
|
opgrammar,
|
|
systemColor,
|
|
"Limiting maximum amount of users",
|
|
False,
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("M") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Non-Auth muted", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("N") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Handle-locked", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("O") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "An Oper-Only channel", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("P") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Permanent", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("Q") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "No-kick", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("R") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Registered users only", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("r") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Registered", False
|
|
)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
if modes.find("z") >= 0:
|
|
if op:
|
|
msg = chum.memomodemsg(
|
|
opchum, opgrammar, systemColor, "Secure-only", 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 OverflowError:
|
|
if secs < 0:
|
|
timed = timedelta.min
|
|
else:
|
|
timed = timedelta.max
|
|
except (OSError, ValueError):
|
|
try:
|
|
if cmd == "i":
|
|
timed = timedelta(0)
|
|
else:
|
|
if cmd[len(cmd) - 1] == "c":
|
|
close = timeProtocol(cmd)
|
|
timed = None
|
|
else:
|
|
timed = timeProtocol(cmd)
|
|
except:
|
|
PchumLog.warning("Invalid PESTERCHUM:TIME> " + str(cmd))
|
|
timed = timedelta(0)
|
|
|
|
if handle in self.times:
|
|
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 = str(self.textInput.text())
|
|
|
|
return parsetools.kxhandleInput(self, text, flavor="memos")
|
|
|
|
@QtCore.pyqtSlot(QString)
|
|
def namesUpdated(self, channel):
|
|
c = str(channel)
|
|
if c.lower() != self.channel.lower():
|
|
return
|
|
# get namesdb (unused)
|
|
# namesdb = self.mainwindow.namesdb
|
|
# reload names
|
|
self.userlist.clear()
|
|
for n in self.mainwindow.namesdb[self.channel]:
|
|
self.addUser(n)
|
|
|
|
@QtCore.pyqtSlot(QString, QString)
|
|
def modesUpdated(self, channel, modes):
|
|
c = str(channel)
|
|
if c.lower() == self.channel.lower():
|
|
self.updateChanModes(modes, None)
|
|
|
|
@QtCore.pyqtSlot(QString)
|
|
def closeInviteOnly(self, channel):
|
|
c = str(channel)
|
|
if c.lower() == self.channel.lower():
|
|
self.mainwindow.inviteOnlyChan["QString"].disconnect(self.closeInviteOnly)
|
|
if self.parent():
|
|
PchumLog.info(self.channel)
|
|
i = self.parent().tabIndices[self.channel]
|
|
self.parent().tabClose(i)
|
|
else:
|
|
self.close()
|
|
msgbox = QtWidgets.QMessageBox()
|
|
msgbox.setStyleSheet(
|
|
"QMessageBox{ %s }" % self.mainwindow.theme["main/defaultwindow/style"]
|
|
)
|
|
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(QtWidgets.QMessageBox.StandardButton.Ok)
|
|
msgbox.exec()
|
|
|
|
@QtCore.pyqtSlot(QString, QString)
|
|
def closeForbidden(self, channel, reason):
|
|
c = str(channel)
|
|
if c.lower() == self.channel.lower():
|
|
self.mainwindow.forbiddenChan["QString", "QString"].disconnect(
|
|
self.closeForbidden
|
|
)
|
|
if self.parent():
|
|
PchumLog.info(self.channel)
|
|
i = self.parent().tabIndices[self.channel]
|
|
self.parent().tabClose(i)
|
|
else:
|
|
self.close()
|
|
msgbox = QtWidgets.QMessageBox()
|
|
msgbox.setStyleSheet(
|
|
"QMessageBox{ %s }" % self.mainwindow.theme["main/defaultwindow/style"]
|
|
)
|
|
msgbox.setText("%s: D: CANT JOIN MEMO!!!" % (c))
|
|
msgbox.setInformativeText(reason)
|
|
msgbox.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Ok)
|
|
msgbox.exec()
|
|
|
|
def quirkDisable(self, op, msg):
|
|
chums = self.userlist.findItems(op, QtCore.Qt.MatchFlag.MatchExactly)
|
|
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 op in self.times:
|
|
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 h in self.times:
|
|
# ttracker = self.times[h]
|
|
# else:
|
|
# ttracker = TimeTracker(timedelta(0))
|
|
opchum = PesterProfile(op)
|
|
PchumLog.debug("op = " + op)
|
|
PchumLog.debug("opchum = " + opchum.handle)
|
|
if op in self.times:
|
|
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):
|
|
# These if attr used to be an if eval("c." + m),
|
|
# better not to use eval() unnecessarily for security reasons though.
|
|
# Hopefully this works fine too.
|
|
if hasattr(c, str(m)):
|
|
if getattr(c, str(m)):
|
|
if m == "box":
|
|
icon = PesterIcon("smilies/box.png")
|
|
else:
|
|
icon = PesterIcon(self.mainwindow.theme[f"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(QString, QString, QString)
|
|
def userPresentChange(self, handle, channel, update):
|
|
# print("handle: %s, channel: %s, update: %s" % (handle, channel, update))
|
|
h = str(handle)
|
|
c = str(channel)
|
|
update = str(update)
|
|
# PchumLog.debug("h=%s\nc=%s\nupdate=%s" % (h,c,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.MatchFlag.MatchExactly)
|
|
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 h not in self.times:
|
|
self.times[h] = TimeTracker(timedelta(0))
|
|
allinitials = []
|
|
while self.times[h].getTime() is not None:
|
|
t = self.times[h]
|
|
grammar = t.getGrammar()
|
|
allinitials.append(
|
|
"{}{}{}".format(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.MatchFlag.MatchExactly
|
|
)
|
|
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 h in self.times:
|
|
ttracker = self.times[h]
|
|
else:
|
|
ttracker = TimeTracker(timedelta(0))
|
|
allinitials = []
|
|
opchum = PesterProfile(op)
|
|
if op in self.times:
|
|
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(
|
|
"{}{}{}".format(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 = QtWidgets.QMessageBox()
|
|
msgbox.setStyleSheet(
|
|
"QMessageBox{ %s }"
|
|
% self.mainwindow.theme["main/defaultwindow/style"]
|
|
)
|
|
msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"])
|
|
|
|
# Add ban(kick) reason
|
|
# l = split update
|
|
kick_msg = "press 0k to rec0nnect or cancel to absc0nd"
|
|
if len(l) >= 3:
|
|
try:
|
|
if (
|
|
l[1] != l[2]
|
|
): # If there's no reason then reason is set to handle
|
|
# Process spare ':' characters (this might not be safe?)
|
|
aggrievocation = l[1] + ": " + l[2]
|
|
if len(l) > 3:
|
|
aggrievocation += ":"
|
|
for x in range(3, len(l)):
|
|
aggrievocation += l[x]
|
|
# Not for last slice
|
|
if x != (len(l) - 1):
|
|
aggrievocation += ":"
|
|
kick_msg = (
|
|
"%s\n\npress 0k to rec0nnect or cancel to absc0nd"
|
|
% aggrievocation
|
|
)
|
|
except IndexError as e:
|
|
# This shouldn't happen
|
|
PchumLog.warning("kickmsg IndexError: %s" % e)
|
|
msgbox.setInformativeText(kick_msg)
|
|
msgbox.setStandardButtons(
|
|
QtWidgets.QMessageBox.StandardButton.Ok
|
|
| QtWidgets.QMessageBox.StandardButton.Cancel
|
|
)
|
|
# Find the OK button and make it default
|
|
for b in msgbox.buttons():
|
|
if (
|
|
msgbox.buttonRole(b)
|
|
== QtWidgets.QMessageBox.ButtonRole.AcceptRole
|
|
):
|
|
# We found the 'OK' button, set it as the default
|
|
b.setDefault(True)
|
|
b.setAutoDefault(True)
|
|
# Actually set it as the selected option, since we're
|
|
# already stealing focus
|
|
b.setFocus()
|
|
break
|
|
ret = msgbox.exec()
|
|
if ret == QtWidgets.QMessageBox.StandardButton.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 == QtWidgets.QMessageBox.StandardButton.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()
|
|
txt_time = delta2txt(time, "server")
|
|
# Only send if time isn't CURRENT, it's very spammy otherwise.
|
|
# CURRENT should be the default already.
|
|
if txt_time != "i":
|
|
serverText = "PESTERCHUM:TIME>" + txt_time
|
|
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)
|
|
# PchumLog.debug("chum.handle = %s\nopchum.handle = %s\nopgrammar = %s\n systemColor = %s\n"
|
|
# % (chum.handle, opchum.handle, opgrammar, systemColor))
|
|
msg = chum.memoopmsg(opchum, opgrammar, systemColor)
|
|
# PchumLog.debug("post memoopmsg")
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
for c in chums:
|
|
c.op = True
|
|
self.iconCrap(c)
|
|
if str(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 str(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 str(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.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
for c in chums:
|
|
c.halfop = False
|
|
self.iconCrap(c)
|
|
if str(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 == "+a":
|
|
for c in chums:
|
|
c.admin = True
|
|
self.iconCrap(c)
|
|
self.sortUsers()
|
|
elif update == "-a":
|
|
for c in chums:
|
|
c.admin = False
|
|
self.iconCrap(c)
|
|
self.sortUsers()
|
|
elif c.lower() == self.channel.lower() and h == "" and update[0] in ["+", "-"]:
|
|
self.updateChanModes(update, op)
|
|
elif update == "+v":
|
|
if self.mainwindow.config.opvoiceMessages():
|
|
(chum, opchum, opgrammar) = self.chumOPstuff(h, op)
|
|
msg = chum.memovoicemsg(opchum, opgrammar, systemColor)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
for c in chums:
|
|
c.voice = True
|
|
self.iconCrap(c)
|
|
self.sortUsers()
|
|
elif update == "-v":
|
|
if self.mainwindow.config.opvoiceMessages():
|
|
(chum, opchum, opgrammar) = self.chumOPstuff(h, op)
|
|
msg = chum.memodevoicemsg(opchum, opgrammar, systemColor)
|
|
self.textArea.append(convertTags(msg))
|
|
self.mainwindow.chatlog.log(self.channel, msg)
|
|
for c in chums:
|
|
c.voice = False
|
|
self.iconCrap(c)
|
|
self.sortUsers()
|
|
elif c.lower() == self.channel.lower() and h == "" and update[0] in ["+", "-"]:
|
|
self.updateChanModes(update, op)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def newPesterSlot(self):
|
|
# We're opening a pester with someone in our user list.
|
|
user = self.userlist.currentItem()
|
|
if not user:
|
|
return
|
|
user = str(user.text())
|
|
self.mainwindow.newConversation(user)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def addChumSlot(self):
|
|
if not self.userlist.currentItem():
|
|
return
|
|
currentChum = PesterProfile(str(self.userlist.currentItem().text()))
|
|
self.mainwindow.addChum(currentChum)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def banSelectedUser(self):
|
|
if not self.userlist.currentItem():
|
|
return
|
|
currentHandle = str(self.userlist.currentItem().text())
|
|
(reason, ok) = QtWidgets.QInputDialog.getText(
|
|
self, "Ban User", "Enter the reason you are banning this user (optional):"
|
|
)
|
|
if ok:
|
|
self.mainwindow.kickUser.emit(currentHandle, reason, self.channel)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def opSelectedUser(self):
|
|
if not self.userlist.currentItem():
|
|
return
|
|
currentHandle = str(self.userlist.currentItem().text())
|
|
self.mainwindow.setChannelMode.emit(self.channel, "+o", currentHandle)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def voiceSelectedUser(self):
|
|
if not self.userlist.currentItem():
|
|
return
|
|
currentHandle = str(self.userlist.currentItem().text())
|
|
self.mainwindow.setChannelMode.emit(self.channel, "+v", currentHandle)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def killQuirkUser(self):
|
|
if not self.userlist.currentItem():
|
|
return
|
|
currentHandle = str(self.userlist.currentItem().text())
|
|
self.mainwindow.killSomeQuirks.emit(self.channel, currentHandle)
|
|
|
|
def resetSlider(self, time, send=True):
|
|
self.timeinput.setText(delta2txt(time))
|
|
self.timeinput.setSlider()
|
|
if send:
|
|
self.sendtime()
|
|
|
|
@QtCore.pyqtSlot()
|
|
def openChumLogs(self):
|
|
currentChum = self.channel
|
|
self.mainwindow.chumList.pesterlogviewer = PesterLogViewer(
|
|
currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow
|
|
)
|
|
self.mainwindow.chumList.pesterlogviewer.rejected.connect(
|
|
self.mainwindow.chumList.closeActiveLog
|
|
)
|
|
self.mainwindow.chumList.pesterlogviewer.show()
|
|
self.mainwindow.chumList.pesterlogviewer.raise_()
|
|
self.mainwindow.chumList.pesterlogviewer.activateWindow()
|
|
|
|
@QtCore.pyqtSlot()
|
|
def inviteChums(self):
|
|
if not hasattr(self, "invitechums"):
|
|
self.invitechums = None
|
|
if not self.invitechums:
|
|
(chum, ok) = QtWidgets.QInputDialog.getText(
|
|
self,
|
|
"Invite to Chat",
|
|
"Enter the chumhandle of the user you'd like to invite:",
|
|
)
|
|
if ok:
|
|
chum = str(chum)
|
|
self.mainwindow.inviteChum.emit(chum, self.channel)
|
|
self.invitechums = None
|
|
|
|
@QtCore.pyqtSlot(bool)
|
|
def noquirksChan(self, on):
|
|
x = ["-", "+"][on]
|
|
self.mainwindow.setChannelMode.emit(self.channel, x + "c", "")
|
|
|
|
@QtCore.pyqtSlot(bool)
|
|
def hideChan(self, on):
|
|
x = ["-", "+"][on]
|
|
self.mainwindow.setChannelMode.emit(self.channel, x + "s", "")
|
|
|
|
@QtCore.pyqtSlot(bool)
|
|
def inviteChan(self, on):
|
|
x = ["-", "+"][on]
|
|
self.mainwindow.setChannelMode.emit(self.channel, x + "i", "")
|
|
|
|
@QtCore.pyqtSlot(bool)
|
|
def modChan(self, on):
|
|
x = ["-", "+"][on]
|
|
self.mainwindow.setChannelMode.emit(self.channel, x + "m", "")
|
|
|
|
@QtCore.pyqtSlot()
|
|
def sendtime(self):
|
|
# me = self.mainwindow.profile()
|
|
# systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
|
|
time = txt2delta(self.timeinput.text())
|
|
# present = self.time.addTime(time)
|
|
self.time.addTime(time)
|
|
|
|
serverText = "PESTERCHUM:TIME>" + delta2txt(time, "server")
|
|
self.messageSent.emit(serverText, self.title())
|
|
|
|
@QtCore.pyqtSlot()
|
|
def smashclock(self):
|
|
me = self.mainwindow.profile()
|
|
time = txt2delta(self.timeinput.text())
|
|
removed = self.time.removeTime(time)
|
|
if removed:
|
|
grammar = self.time.getGrammarTime(time)
|
|
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, msg)
|
|
|
|
newtime = self.time.getTime()
|
|
if newtime is None:
|
|
newtime = timedelta(0)
|
|
self.resetSlider(newtime, send=False)
|
|
else:
|
|
self.resetSlider(newtime)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def prevtime(self):
|
|
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())
|
|
|
|
windowClosed = QtCore.pyqtSignal("QString")
|
|
|
|
|
|
timelist = [
|
|
"0:00",
|
|
"0:01",
|
|
"0:02",
|
|
"0:04",
|
|
"0:06",
|
|
"0:10",
|
|
"0:14",
|
|
"0:22",
|
|
"0:30",
|
|
"0:41",
|
|
"1:00",
|
|
"1:34",
|
|
"2:16",
|
|
"3:14",
|
|
"4:13",
|
|
"4:20",
|
|
"5:25",
|
|
"6:12",
|
|
"7:30",
|
|
"8:44",
|
|
"10:25",
|
|
"11:34",
|
|
"14:13",
|
|
"16:12",
|
|
"17:44",
|
|
"22:22",
|
|
"25:10",
|
|
"33:33",
|
|
"42:00",
|
|
"43:14",
|
|
"50:00",
|
|
"62:12",
|
|
"75:00",
|
|
"88:44",
|
|
"100",
|
|
"133",
|
|
"143",
|
|
"188",
|
|
"200",
|
|
"222",
|
|
"250",
|
|
"314",
|
|
"333",
|
|
"413",
|
|
"420",
|
|
"500",
|
|
"600",
|
|
"612",
|
|
"888",
|
|
"1000",
|
|
"1025",
|
|
]
|
|
|
|
timedlist = [
|
|
timedelta(0),
|
|
timedelta(0, 60),
|
|
timedelta(0, 120),
|
|
timedelta(0, 240),
|
|
timedelta(0, 360),
|
|
timedelta(0, 600),
|
|
timedelta(0, 840),
|
|
timedelta(0, 1320),
|
|
timedelta(0, 1800),
|
|
timedelta(0, 2460),
|
|
timedelta(0, 3600),
|
|
timedelta(0, 5640),
|
|
timedelta(0, 8160),
|
|
timedelta(0, 11640),
|
|
timedelta(0, 15180),
|
|
timedelta(0, 15600),
|
|
timedelta(0, 19500),
|
|
timedelta(0, 22320),
|
|
timedelta(0, 27000),
|
|
timedelta(0, 31440),
|
|
timedelta(0, 37500),
|
|
timedelta(0, 41640),
|
|
timedelta(0, 51180),
|
|
timedelta(0, 58320),
|
|
timedelta(0, 63840),
|
|
timedelta(0, 80520),
|
|
timedelta(1, 4200),
|
|
timedelta(1, 34380),
|
|
timedelta(1, 64800),
|
|
timedelta(1, 69240),
|
|
timedelta(2, 7200),
|
|
timedelta(2, 51120),
|
|
timedelta(3, 10800),
|
|
timedelta(3, 60240),
|
|
timedelta(4, 14400),
|
|
timedelta(5, 46800),
|
|
timedelta(5, 82800),
|
|
timedelta(7, 72000),
|
|
timedelta(8, 28800),
|
|
timedelta(9, 21600),
|
|
timedelta(10, 36000),
|
|
timedelta(13, 7200),
|
|
timedelta(13, 75600),
|
|
timedelta(17, 18000),
|
|
timedelta(17, 43200),
|
|
timedelta(20, 72000),
|
|
timedelta(25),
|
|
timedelta(25, 43200),
|
|
timedelta(37),
|
|
timedelta(41, 57600),
|
|
timedelta(42, 61200),
|
|
]
|