diff --git a/TODO b/TODO index bce54a7..c515bc3 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ Features: -* memo change theme -* 1 MINUTES FROM NOW * memo kicking * user import * Transparent background? diff --git a/convo.pyc b/convo.pyc index afd1769..9fdf065 100644 Binary files a/convo.pyc and b/convo.pyc differ diff --git a/dataobjs.py b/dataobjs.py index 4ff8fec..8be4b37 100644 --- a/dataobjs.py +++ b/dataobjs.py @@ -147,7 +147,11 @@ class PesterProfile(object): initials = pcf+self.initials() return "%s %s %s %s." % \ (syscolor.name(), self.colorhtml(), initials, timetext, verb, channel[1:].upper().replace("_", " ")) - + def memobanmsg(self, opchum, opgrammar, syscolor, timeGrammar): + initials = timeGrammar.pcf+self.initials()+timeGrammar.number + opinit = opgrammar.pcf+opchum.initials()+opgrammar.number + return "%s banned %s from responding to memo." % \ + (opchum.colorhtml(), opinit, self.colorhtml(), initials) def memojoinmsg(self, syscolor, td, timeGrammar, verb): (temporal, pcf, when) = (timeGrammar.temporal, timeGrammar.pcf, timeGrammar.when) timetext = timeDifference(td) diff --git a/dataobjs.pyc b/dataobjs.pyc index da4b76c..a378f29 100644 Binary files a/dataobjs.pyc and b/dataobjs.pyc differ diff --git a/irc.py b/irc.py index 6a54f53..f48289d 100644 --- a/irc.py +++ b/irc.py @@ -3,11 +3,12 @@ from oyoyo.client import IRCClient from oyoyo.cmdhandler import DefaultCommandHandler from oyoyo import helpers import logging +import random from dataobjs import Mood, PesterProfile from generic import PesterList -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=logging.DEBUG) class PesterIRC(QtCore.QObject): def __init__(self, window): @@ -79,6 +80,11 @@ class PesterIRC(QtCore.QObject): def leftChannel(self, channel): c = unicode(channel) helpers.part(self.cli, c) + @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + def kickUser(self, handle, channel): + c = unicode(channel) + h = unicode(handle) + helpers.kick(self.cli, h, c) def updateIRC(self): self.conn.next() @@ -155,7 +161,10 @@ class PesterHandler(DefaultCommandHandler): def quit(self, nick, reason): handle = nick[0:nick.find("!")] self.parent.userPresentUpdate.emit(handle, "", "quit") - self.parent.moodUpdated.emit(handle, Mood("offline")) + self.parent.moodUpdated.emit(handle, Mood("offline")) + def kick(self, opnick, channel, handle, op): + self.parent.userPresentUpdate.emit(handle, channel, "kick:%s" % (op)) + # ok i shouldnt be overloading that but am lazy def part(self, nick, channel, reason="nanchos"): handle = nick[0:nick.find("!")] self.parent.userPresentUpdate.emit(handle, channel, "left") @@ -170,8 +179,7 @@ class PesterHandler(DefaultCommandHandler): oldhandle = oldnick[0:oldnick.find("!")] newchum = PesterProfile(newnick, chumdb=self.mainwindow.chumdb) self.parent.moodUpdated.emit(oldhandle, Mood("offline")) - self.parent.userPresentUpdate.emit(oldhandle, "", "oldnick") - self.parent.userPresentUpdate.emit(newnick, "", "newnick") + self.parent.userPresentUpdate.emit("%s:%s" % (oldhandle, newnick), "", "nick") if newnick in self.mainwindow.chumList.chums: self.getMood(newchum) def namreply(self, server, nick, op, channel, names): diff --git a/irc.pyc b/irc.pyc index bc6e9a6..34d021f 100644 Binary files a/irc.pyc and b/irc.pyc differ diff --git a/memos.py b/memos.py index 582a617..239947e 100644 --- a/memos.py +++ b/memos.py @@ -4,7 +4,7 @@ from PyQt4 import QtGui, QtCore from datetime import time, timedelta, datetime from dataobjs import PesterProfile, Mood -from generic import PesterIcon +from generic import PesterIcon, RightClickList from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow from parsetools import convertTags, escapeBrackets, addTimeInitial, timeProtocol @@ -282,8 +282,17 @@ class PesterMemo(PesterConvo): self.textInput = MemoInput(self.mainwindow.theme, self) self.textInput.setFocus() - self.userlist = QtGui.QListWidget(self) + self.userlist = RightClickList(self) self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding)) + self.userlist.optionsMenu = QtGui.QMenu(self) + self.addchumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) + self.connect(self.addchumAction, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('addChumSlot()')) + self.banuserAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/banuser"], self) + self.connect(self.banuserAction, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('banSelectedUser()')) + self.userlist.optionsMenu.addAction(self.addchumAction) + # ban list added if we are op self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self) self.timeinput = TimeInput(self.timeslider, self) @@ -396,6 +405,8 @@ class PesterMemo(PesterConvo): self.userlist.setStyleSheet(theme["memos/userlist/style"]) self.userlist.setFixedWidth(theme["memos/userlist/width"]) + self.addchumAction.setText(theme["main/menus/rclickchumlist/addchum"]) + self.banuserAction.setText(theme["main/menus/rclickchumlist/banuser"]) self.timeinput.setFixedWidth(theme["memos/time/text/width"]) self.timeinput.setStyleSheet(theme["memos/time/text/style"]) @@ -431,6 +442,7 @@ class PesterMemo(PesterConvo): op = True handle = handle[1:] if handle == self.mainwindow.profile().handle: + self.userlist.optionsMenu.addAction(self.banuserAction) self.op = True item = QtGui.QListWidgetItem(handle) if handle == self.mainwindow.profile().handle: @@ -439,6 +451,8 @@ class PesterMemo(PesterConvo): color = chumdb.getColor(handle, defaultcolor) item.setTextColor(color) self.userlist.addItem(item) + self.userlist + def timeUpdate(self, handle, cmd): window = self.mainwindow @@ -516,32 +530,103 @@ class PesterMemo(PesterConvo): @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString) def userPresentChange(self, handle, channel, update): - if (update in ["join","left"]) and channel != self.channel: - return - chums = self.userlist.findItems(handle, QtCore.Qt.MatchFlags(0)) h = unicode(handle) c = unicode(channel) + update = unicode(update) + if update[0:4] == "kick": # yeah, i'm lazy. + l = update.split(":") + update = l[0] + op = l[1] + if update == "nick": + l = h.split(":") + oldnick = l[0] + newnick = l[1] + h = oldnick + if (update in ["join","left", "kick"]) and channel != self.channel: + return + chums = self.userlist.findItems(h, QtCore.Qt.MatchFlags(0)) systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"]) # print exit - if update == "quit" or update == "left" or update == "oldnick": + if update == "quit" or update == "left" or update == "nick": for c in chums: chum = PesterProfile(h) self.userlist.takeItem(self.userlist.row(c)) if not self.times.has_key(h): - return + self.times[h] = TimeTracker(timedelta(0)) while self.times[h].getTime() is not None: t = self.times[h] grammar = t.getGrammar() self.textArea.append(convertTags(chum.memoclosemsg(systemColor, grammar, self.mainwindow.theme["convo/text/closememo"]))) self.times[h].removeTime(t.getTime()) + if update == "nick": + self.addUser(newnick) + elif update == "kick": + print "KICKING" + if len(chums) == 0: + return + c = chums[0] + chum = PesterProfile(h) + if h == self.mainwindow.profile().handle: + chum = self.mainwindow.profile() + ttracker = self.time + curtime = self.time.getTime() + elif self.times.has_key(h): + ttracker = self.times[h] + else: + ttracker = TimeTracker(timedelta(0)) + while ttracker.getTime() is not None: + grammar = ttracker.getGrammar() + opchum = PesterProfile(op) + if self.times.has_key(op): + opgrammar = self.times[op].getGrammar() + elif op == self.mainwindow.profile().handle: + opgrammar = self.time.getGrammar() + else: + opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW") + self.textArea.append(convertTags(chum.memobanmsg(opchum, opgrammar, systemColor, grammar))) + ttracker.removeTime(ttracker.getTime()) + + if chum is self.mainwindow.profile(): + # are you next? + msgbox = QtGui.QMessageBox() + msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"]) + msgbox.setInformativeText("press 0k to rec0nnect or cancel to absc0nd") + msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + ret = msgbox.exec_() + if ret == QtGui.QMessageBox.Ok: + self.userlist.clear() + self.time = TimeTracker(curtime) + self.resetSlider(curtime) + self.mainwindow.joinChannel.emit(self.channel) + me = self.mainwindow.profile() + self.textArea.append(convertTags(me.memoopenmsg(systemColor, self.time.getTime(), self.time.getGrammar(), self.mainwindow.theme["convo/text/openmemo"], self.channel))) + elif ret == QtGui.QMessageBox.Cancel: + if self.parent(): + i = self.parent().tabIndices[self.channel] + self.parent().tabClose(i) + else: + self.close() + else: + # i warned you about those stairs bro + self.userlist.takeItem(self.userlist.row(c)) elif update == "join": self.addUser(h) time = self.time.getTime() serverText = "PESTERCHUM:TIME>"+delta2txt(time, "server") self.messageSent.emit(serverText, self.title()) - elif update == "newnick": - self.addUser(h) + @QtCore.pyqtSlot() + def addChumSlot(self): + if not self.userlist.currentItem(): + return + currentChum = PesterProfile(unicode(self.userlist.currentItem().text())) + self.mainwindow.addChum(currentChum) + @QtCore.pyqtSlot() + def banSelectedUser(self): + if not self.userlist.currentItem(): + return + currentHandle = unicode(self.userlist.currentItem().text()) + self.mainwindow.kickUser.emit(currentHandle, self.channel) def resetSlider(self, time): self.timeinput.setText(delta2txt(time)) self.timeinput.setSlider() diff --git a/memos.pyc b/memos.pyc index b04b9dc..8e6e6b4 100644 Binary files a/memos.pyc and b/memos.pyc differ diff --git a/oyoyo/helpers.py b/oyoyo/helpers.py index 081e94e..38841b1 100644 --- a/oyoyo/helpers.py +++ b/oyoyo/helpers.py @@ -38,6 +38,9 @@ def names(cli, *channels): def channel_list(cli): cli.send("LIST") +def kick(cli, handle, channel): + cli.send("KICK %s %s" % (channel, handle)) + def msgrandom(cli, choices, dest, user=None): o = "%s: " % user if user else "" o += random.choice(choices) diff --git a/oyoyo/helpers.pyc b/oyoyo/helpers.pyc index 16a01a9..6167088 100644 Binary files a/oyoyo/helpers.pyc and b/oyoyo/helpers.pyc differ diff --git a/parsetools.py b/parsetools.py index b6f7fff..5417607 100644 --- a/parsetools.py +++ b/parsetools.py @@ -121,9 +121,15 @@ def timeDifference(td): if atd == timedelta(0): timetext = "RIGHT NOW" elif atd < timedelta(0,3600): - timetext = "%d MINUTES %s" % (minutes, when) + if minutes == 1: + timetext = "%d MINUTE %s" % (minutes, when) + else: + timetext = "%d MINUTES %s" % (minutes, when) elif atd < timedelta(0,3600*100): - timetext = "%d:%02d HOURS %s" % (hours, leftoverminutes, when) + if hours == 1 and leftoverminutes == 0: + timetext = "%d:%02d HOUR %s" % (hours, leftoverminutes, when) + else: + timetext = "%d:%02d HOURS %s" % (hours, leftoverminutes, when) else: timetext = "%d HOURS %s" % (hours, when) return timetext diff --git a/parsetools.pyc b/parsetools.pyc index fead7da..e63ad4e 100644 Binary files a/parsetools.pyc and b/parsetools.pyc differ diff --git a/pesterchum.js b/pesterchum.js index 9fb7056..2ab9987 100644 --- a/pesterchum.js +++ b/pesterchum.js @@ -1 +1 @@ -{"tabs": true, "chums": ["aquaMarinist", "marineAquist", "unknownTraveler", "tentacleTherapist", "macruralAlchemist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "fireSwallow", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium"], "defaultprofile": "testProfile", "block": []} \ No newline at end of file +{"tabs": false, "chums": ["aquaMarinist", "marineAquist", "unknownTraveler", "tentacleTherapist", "macruralAlchemist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "illuminatedWax"], "defaultprofile": "testProfile", "block": []} \ No newline at end of file diff --git a/pesterchum.py b/pesterchum.py index c26dbd9..d9997d9 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -1037,7 +1037,11 @@ class PesterWindow(MovingWindow): def userPresentUpdate(self, handle, channel, update): c = unicode(channel) n = unicode(handle) - if update == "quit" or update == "oldnick": + if update == "nick": + l = n.split(":") + oldnick = l[0] + newnick = l[1] + if update == "quit": for c in self.namesdb.keys(): try: i = self.namesdb[c].index(n) @@ -1054,14 +1058,16 @@ class PesterWindow(MovingWindow): pass except KeyError: self.namesdb[c] = [] - elif update == "newnick": + elif update == "nick": for c in self.namesdb.keys(): try: - i = self.namesdb[c].index(n) + i = self.namesdb[c].index(oldnick) + self.namesdb[c].pop(i) + self.namesdb[c].append(newnick) except ValueError: - self.namesdb[c].append(n) + pass except KeyError: - self.namesdb[c] = [n] + pass elif update == "join": try: i = self.namesdb[c].index(n) @@ -1406,6 +1412,7 @@ class PesterWindow(MovingWindow): trayIconSignal = QtCore.pyqtSignal(int) blockedChum = QtCore.pyqtSignal(QtCore.QString) unblockedChum = QtCore.pyqtSignal(QtCore.QString) + kickUser = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) joinChannel = QtCore.pyqtSignal(QtCore.QString) leftChannel = QtCore.pyqtSignal(QtCore.QString) @@ -1511,7 +1518,10 @@ def main(): QtCore.SIGNAL('leftChannel(QString)'), irc, QtCore.SLOT('leftChannel(QString)')) - + irc.connect(widget, + QtCore.SIGNAL('kickUser(QString, QString)'), + irc, + QtCore.SLOT('kickUser(QString, QString)')) # IRC --> Main window irc.connect(irc, QtCore.SIGNAL('connected()'), diff --git a/themes/pesterchum/style.js b/themes/pesterchum/style.js index 7a097e3..2bfe997 100644 --- a/themes/pesterchum/style.js +++ b/themes/pesterchum/style.js @@ -30,7 +30,8 @@ "removechum": "REMOVE CHUM", "blockchum": "BLOCK", "addchum": "ADD CHUM", - "unblockchum": "UNBLOCK" + "unblockchum": "UNBLOCK", + "banuser": "BAN USER" } }, "chums": { "style": "border:2px solid yellow; background-color: black;color: white;font: bold;font-family: 'Courier';selection-background-color:#646464; ", @@ -211,7 +212,8 @@ "unblocked": "unblocked", "openmemo": "opened memo on board", "joinmemo": "responded to memo", - "closememo": "ceased responding to memo" + "closememo": "ceased responding to memo", + "kickedmemo": "You have been banned from this memo!" }, "systemMsgColor": "#646464" }, diff --git a/themes/trollian/style.js b/themes/trollian/style.js index ed9af97..b2f397e 100644 --- a/themes/trollian/style.js +++ b/themes/trollian/style.js @@ -30,7 +30,8 @@ "removechum": "Trash", "blockchum": "Block", "addchum": "Add Chump", - "unblockchum": "Mercy"} + "unblockchum": "Mercy", + "banuser": "BAN USER" } }, "chums": { "style": "font-size: 12px; background: white; border:2px solid #c2c2c2; padding: 5px; font-family: 'Arial';selection-background-color:rgb(200,200,200); ", "loc": [475, 89], @@ -259,7 +260,8 @@ "unblocked": "mercifully forgave", "openmemo": "opened memo on board", "joinmemo": "responded to memo", - "closememo": "ceased responding to memo" + "closememo": "ceased responding to memo", + "kickedmemo": "You have been banned from this memo!" }, "systemMsgColor": "#646464" }, @@ -293,8 +295,8 @@ "style": "color: black; font:bold; border:1px solid #c2c2c2; background: white; height: 19px;" }, "slider": { "style": " border:1px solid #c2c2c2;", - "groove": "border-image:url($path/timeslideraqua.png);", - "handle": "image:url($path/aquaicon.png);" + "groove": "border-image:url($path/timeslider.png);", + "handle": "image:url($path/acceptant.png);" }, "buttons": { "style": "border:1px solid #a68168; height: 17px; width: 50px; color: #cd8f9d; font-family: 'Arial'; background: rgb(190, 19, 4); margin-left: 2px;" }, "arrows": { "left": "$path/leftarrow.png",