From b2e5841469e20af01354179f3b5595727688aa2a Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Fri, 11 Mar 2011 23:44:07 -0800 Subject: [PATCH 01/13] Added a scramle() function for scrambling text in regexp replaces. (Works like the upper() function). --- dataobjs.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dataobjs.py b/dataobjs.py index 4449292..c154228 100644 --- a/dataobjs.py +++ b/dataobjs.py @@ -8,10 +8,11 @@ from parsetools import timeDifference, convertTags, lexMessage from mispeller import mispeller _upperre = re.compile(r"upper\(([\w\\]+)\)") +_scramblere = re.compile(r"scramble\(([\w\\]+)\)") class Mood(object): - moods = ["chummy", "rancorous", "offline", "pleasant", "distraught", - "pranky", "smooth", "ecstatic", "relaxed", "discontent", + moods = ["chummy", "rancorous", "offline", "pleasant", "distraught", + "pranky", "smooth", "ecstatic", "relaxed", "discontent", "devious", "sleek", "detestful", "mirthful", "manipulative", "vigorous", "perky", "acceptant", "protective", "mystified", "amazed", "insolent", "bemused" ] @@ -62,7 +63,10 @@ class pesterQuirk(object): to = self.quirk["to"] def upperrep(m): return mo.expand(m.group(1)).upper() + def scramblerep(m): + return "".join(random.sample(mo.expand(m.group(1)), len(mo.expand(m.group(1))))) to = _upperre.sub(upperrep, to) + to = _scramblere.sub(scramblerep, to) return mo.expand(to) return re.sub(fr, regexprep, string) elif self.type == "random": @@ -77,6 +81,9 @@ class pesterQuirk(object): choice = random.choice(self.quirk["randomlist"]) def upperrep(m): return mo.expand(m.group(1)).upper() + def scramblerep(m): + return "".join(random.sample(mo.expand(m.group(1)), len(mo.expand(m.group(1))))) + choice = _upperre.sub(upperrep, choice) choice = _upperre.sub(upperrep, choice) return mo.expand(choice) return re.sub(self.quirk["from"], randomrep, string) @@ -125,7 +132,7 @@ class pesterQuirks(object): q.type=='replace' or q.type=='regexp'] randomrep = [q for q in self.quirklist if q.type=='random'] spelling = [q for q in self.quirklist if q.type=='spelling'] - + newlist = [] for (i, o) in enumerate(lexed): if type(o) not in [str, unicode]: @@ -190,7 +197,7 @@ class PesterProfile(object): else: return "C"+initials else: - return (handle[0]+caps[0]).upper() + return (handle[0]+caps[0]).upper() def colorhtml(self): if self.color: return self.color.name() From 06bcad0ca0734de6a7c76c03675a92541191dac6 Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Fri, 11 Mar 2011 23:44:59 -0800 Subject: [PATCH 02/13] Timestamps for conversations and logs. Options for turning timestamps on/off, 12/24 hour time, seconds/no seconds. --- convo.py | 42 ++++++++++++++++---------- menus.py | 49 ++++++++++++++++++++---------- pesterchum.py | 82 +++++++++++++++++++++++++++++++++------------------ 3 files changed, 114 insertions(+), 59 deletions(-) diff --git a/convo.py b/convo.py index 3d51320..2a6ddac 100644 --- a/convo.py +++ b/convo.py @@ -2,6 +2,7 @@ from string import Template import re import platform import httplib, urllib +from time import strftime from copy import copy from datetime import datetime, timedelta from PyQt4 import QtGui, QtCore @@ -65,14 +66,14 @@ class PesterTabWindow(QtGui.QFrame): self.tabs.setCurrentIndex(tabi) def convoHasFocus(self, convo): - if ((self.hasFocus() or self.tabs.hasFocus()) and + if ((self.hasFocus() or self.tabs.hasFocus()) and self.tabs.tabText(self.tabs.currentIndex()) == convo.title()): return True - + def keyPressEvent(self, event): keypress = event.key() mods = event.modifiers() - if ((mods & QtCore.Qt.ControlModifier) and + if ((mods & QtCore.Qt.ControlModifier) and keypress == QtCore.Qt.Key_Tab): handles = self.convos.keys() waiting = self.mainwindow.waitingMessages.waitingHandles() @@ -115,7 +116,7 @@ class PesterTabWindow(QtGui.QFrame): self.clearNewMessage(handle) def convoHasFocus(self, handle): i = self.tabIndices[handle] - if (self.tabs.currentIndex() == i and + if (self.tabs.currentIndex() == i and (self.hasFocus() or self.tabs.hasFocus())): return True else: @@ -221,6 +222,17 @@ class PesterText(QtGui.QTextEdit): parent = self.parent() window = parent.mainwindow me = window.profile() + 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 = "" if lexmsg[0] == "PESTERCHUM:BEGIN": parent.setChumOpen(True) pmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"]) @@ -253,7 +265,7 @@ class PesterText(QtGui.QTextEdit): window.chatlog.log(parent.chum.handle, memsg) else: window.chatlog.log(chum.handle, memsg) - self.append(convertTags(memsg)) + self.append(time + convertTags(memsg)) else: if not parent.chumopen and chum is not me: beginmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"]) @@ -261,10 +273,10 @@ class PesterText(QtGui.QTextEdit): window.chatlog.log(chum.handle, beginmsg) self.append(convertTags(beginmsg)) - lexmsg[0:0] = [colorBegin("" % (color), color), + lexmsg[0:0] = [colorBegin("" % (color), color), "%s: " % (initials)] lexmsg.append(colorEnd("")) - self.append(convertTags(lexmsg)) + self.append(time + convertTags(lexmsg)) if chum is me: window.chatlog.log(parent.chum.handle, lexmsg) else: @@ -308,7 +320,7 @@ class PesterText(QtGui.QTextEdit): if self.textSelected: self.submitLogAction = QtGui.QAction("Submit to Pesterchum QDB", self) self.connect(self.submitLogAction, QtCore.SIGNAL('triggered()'), - self, QtCore.SLOT('submitLog()')) + self, QtCore.SLOT('submitLog()')) textMenu.addAction(self.submitLogAction) textMenu.exec_(event.globalPos()) @@ -338,7 +350,7 @@ class PesterText(QtGui.QTextEdit): "Accept": "text/plain"} try: pass - hconn = httplib.HTTPConnection('luke.violentlemon.com', 80, + hconn = httplib.HTTPConnection('luke.violentlemon.com', 80, timeout=15) hconn.request("POST", "/index.php", params, headers) response = hconn.getresponse() @@ -391,7 +403,7 @@ class PesterConvo(QtGui.QFrame): self.setWindowTitle(self.title()) t = Template(self.mainwindow.theme["convo/chumlabel/text"]) - + 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"]]) @@ -413,7 +425,7 @@ class PesterConvo(QtGui.QFrame): margins = self.mainwindow.theme["convo/margins"] self.layout.setContentsMargins(margins["left"], margins["top"], margins["right"], margins["bottom"]) - + self.setLayout(self.layout) self.optionsMenu = QtGui.QMenu(self) @@ -508,8 +520,8 @@ class PesterConvo(QtGui.QFrame): def notifyNewMessage(self): # first see if this conversation HASS the focus - if not (self.hasFocus() or self.textArea.hasFocus() or - self.textInput.hasFocus() or + if not (self.hasFocus() or self.textArea.hasFocus() or + self.textInput.hasFocus() or (self.parent() and self.parent().convoHasFocus(self.title()))): # ok if it has a tabconvo parent, send that the notify. if self.parent(): @@ -521,7 +533,7 @@ class PesterConvo(QtGui.QFrame): def func(): self.showChat() self.mainwindow.waitingMessages.addMessage(self.title(), func) - + def clearNewMessage(self): if self.parent(): self.parent().clearNewMessage(self.title()) @@ -555,7 +567,7 @@ class PesterConvo(QtGui.QFrame): def changeTheme(self, theme): self.resize(*theme["convo/size"]) self.setStyleSheet("QFrame#%s { %s }" % (self.chum.handle, theme["convo/style"])) - + margins = theme["convo/margins"] self.layout.setContentsMargins(margins["left"], margins["top"], margins["right"], margins["bottom"]) diff --git a/menus.py b/menus.py index 8343983..e97c06a 100644 --- a/menus.py +++ b/menus.py @@ -21,7 +21,7 @@ class PesterQuirkItem(QtGui.QListWidgetItem): return True else: return False - + class PesterQuirkList(QtGui.QListWidget): def __init__(self, mainwindow, parent): QtGui.QListWidget.__init__(self, parent) @@ -93,7 +93,7 @@ class RandomQuirkDialog(MultiTextDialog): layout_1.addWidget(regexpl) layout_1.addWidget(self.regexp) replacewithl = QtGui.QLabel("REPLACE WITH:", self) - + layout_2 = QtGui.QVBoxLayout() layout_3 = QtGui.QHBoxLayout() self.replacelist = QtGui.QListWidget(self) @@ -141,7 +141,7 @@ class RandomQuirkDialog(MultiTextDialog): else: return None - + @QtCore.pyqtSlot() def addRandomString(self): text = unicode(self.replaceinput.text()) @@ -167,7 +167,7 @@ class PesterChooseQuirks(QtGui.QDialog): self.setWindowTitle("Set Quirks") self.quirkList = PesterQuirkList(self.mainwindow, self) - + self.addPrefixButton = QtGui.QPushButton("ADD PREFIX", self) self.connect(self.addPrefixButton, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('addPrefixDialog()')) @@ -206,7 +206,7 @@ class PesterChooseQuirks(QtGui.QDialog): layout_3 = QtGui.QHBoxLayout() layout_3.addWidget(self.editSelectedButton) layout_3.addWidget(self.removeSelectedButton) - + self.ok = QtGui.QPushButton("OK", self) self.ok.setDefault(True) self.connect(self.ok, QtCore.SIGNAL('clicked()'), @@ -227,7 +227,7 @@ class PesterChooseQuirks(QtGui.QDialog): self.setLayout(layout_0) def quirks(self): - return [self.quirkList.item(i).quirk for i in + return [self.quirkList.item(i).quirk for i in range(0,self.quirkList.count())] @QtCore.pyqtSlot() @@ -317,7 +317,7 @@ class PesterChooseQuirks(QtGui.QDialog): quirkWarning.setInformativeText("H3R3S WHY DUMP4SS: %s" % (e)) quirkWarning.exec_() return - + newquirk = pesterQuirk(vdict) if qitem is None: item = PesterQuirkItem(newquirk, self.quirkList) @@ -444,7 +444,7 @@ class PesterChooseProfile(QtGui.QDialog): layout_2 = QtGui.QHBoxLayout() layout_2.addWidget(self.defaultlabel) layout_2.addWidget(self.defaultcheck) - + self.ok = QtGui.QPushButton("OK", self) self.ok.setDefault(True) self.connect(self.ok, QtCore.SIGNAL('clicked()'), @@ -517,6 +517,22 @@ class PesterOptions(QtGui.QDialog): self.soundcheck = QtGui.QCheckBox("Sounds On", self) if self.config.soundOn(): self.soundcheck.setChecked(True) + + self.timestampcheck = QtGui.QCheckBox("Time Stamps", self) + if self.config.showTimeStamps(): + self.timestampcheck.setChecked(True) + + self.timestampBox = QtGui.QComboBox(self) + self.timestampBox.addItem("12 hour") + self.timestampBox.addItem("24 hour") + if self.config.time12Format(): + self.timestampBox.setCurrentIndex(0) + else: + self.timestampBox.setCurrentIndex(1) + self.secondscheck = QtGui.QCheckBox("Show Seconds", self) + if self.config.showSeconds(): + self.secondscheck.setChecked(True) + self.ok = QtGui.QPushButton("OK", self) self.ok.setDefault(True) self.connect(self.ok, QtCore.SIGNAL('clicked()'), @@ -532,6 +548,9 @@ class PesterOptions(QtGui.QDialog): layout_0.addWidget(self.tabcheck) layout_0.addWidget(self.soundcheck) layout_0.addWidget(self.hideOffline) + layout_0.addWidget(self.timestampcheck) + layout_0.addWidget(self.timestampBox) + layout_0.addWidget(self.secondscheck) layout_0.addLayout(layout_2) self.setLayout(layout_0) @@ -565,15 +584,15 @@ class PesterUserlist(QtGui.QDialog): layout_0.addWidget(self.label) layout_0.addWidget(self.userarea) layout_0.addWidget(self.ok) - + self.setLayout(layout_0) self.connect(self.mainwindow, QtCore.SIGNAL('namesUpdated()'), self, QtCore.SLOT('updateUsers()')) - self.connect(self.mainwindow, + self.connect(self.mainwindow, QtCore.SIGNAL('userPresentSignal(QString, QString, QString)'), - self, + self, QtCore.SLOT('updateUserPresent(QString, QString, QString)')) self.updateUsers() @QtCore.pyqtSlot() @@ -635,7 +654,7 @@ class PesterMemoList(QtGui.QDialog): self.channelarea = RightClickList(self) self.channelarea.setStyleSheet(self.theme["main/chums/style"]) self.channelarea.optionsMenu = QtGui.QMenu(self) - self.connect(self.channelarea, + self.connect(self.channelarea, QtCore.SIGNAL('itemActivated(QListWidgetItem *)'), self, QtCore.SLOT('joinActivatedMemo(QListWidgetItem *)')) @@ -668,7 +687,7 @@ class PesterMemoList(QtGui.QDialog): layout_0.addWidget(self.timeslider) layout_0.addWidget(self.timeinput) layout_0.addLayout(layout_ok) - + self.setLayout(layout_0) def newmemoname(self): @@ -689,7 +708,7 @@ class PesterMemoList(QtGui.QDialog): for item in [self.userarea.item(i) for i in range(0, self.channelarea.count())]: item.setTextColor(QtGui.QColor(theme["main/chums/userlistcolor"])) item.setIcon(QtGui.QIcon(theme["memos/memoicon"])) - + @QtCore.pyqtSlot() def checkEmpty(self): newmemo = self.newmemoname() @@ -704,7 +723,7 @@ class PesterMemoList(QtGui.QDialog): class LoadingScreen(QtGui.QDialog): def __init__(self, parent=None): - QtGui.QDialog.__init__(self, parent, flags=(QtCore.Qt.CustomizeWindowHint | + QtGui.QDialog.__init__(self, parent, flags=(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint)) self.mainwindow = parent self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) diff --git a/pesterchum.py b/pesterchum.py index fa15c1a..d09b3d0 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -12,6 +12,7 @@ import socket import platform from PyQt4 import QtGui, QtCore import pygame +from time import strftime from menus import PesterChooseQuirks, PesterChooseTheme, \ PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \ @@ -76,9 +77,10 @@ class PesterLog(object): self.logpath = _datadir+"logs" def log(self, handle, msg): - bbcodemsg = convertTags(msg, "bbcode") - html = convertTags(msg, "html")+"
" - msg = convertTags(msg, "text") + time = strftime("[%H:%M:%S] ") + bbcodemsg = time + convertTags(msg, "bbcode") + html = time + convertTags(msg, "html")+"
" + msg = time + convertTags(msg, "text") modes = {"bbcode": bbcodemsg, "html": html, "text": msg} if not self.convos.has_key(handle): time = datetime.now().strftime("%Y-%m-%d.%H.%M") @@ -127,7 +129,7 @@ class PesterProfileDB(dict): fp = open("%s/chums.js" % (self.logpath), 'w') json.dump(chumdict, fp) fp.close() - + converted = dict([(handle, PesterProfile(handle, color=QtGui.QColor(c['color']), mood=Mood(c['mood']))) for (handle, c) in chumdict.iteritems()]) self.update(converted) @@ -179,7 +181,7 @@ class pesterTheme(dict): if hasattr(self, 'defaultTheme'): return self.defaultTheme[key] else: - raise e + raise e for k in keys: try: v = v[k] @@ -225,7 +227,7 @@ class pesterTheme(dict): class userConfig(object): def __init__(self): - if sys.platform != "darwin": + if sys.platform != "darwin": self.filename = "pesterchum.js" else: self.filename = _datadir+"pesterchum.js" @@ -249,6 +251,18 @@ class userConfig(object): return None def tabs(self): return self.config.get("tabs", True) + def showTimeStamps(self): + if not self.config.has_key('showTimeStamps'): + self.set("showTimeStamps", True) + return self.config.get('showTimeStamps', True) + def time12Format(self): + if not self.config.has_key('time12Format'): + self.set("time12Format", True) + return self.config.get('time12Format', True) + def showSeconds(self): + if not self.config.has_key('showSeconds'): + self.set("showSeconds", False) + return self.config.get('showSeconds', False) def addChum(self, chum): if chum.handle not in self.chums(): fp = open(self.filename) # what if we have two clients open?? @@ -311,7 +325,7 @@ class userConfig(object): return [userProfile(p) for p in profs] class userProfile(object): def __init__(self, user): - if sys.platform != "darwin": + if sys.platform != "darwin": self.profiledir = "profiles" else: self.profiledir = _datadir+"profiles" @@ -450,7 +464,7 @@ class chumArea(RightClickList): if len([c for c in self.chums if c.handle == chum.handle]) != 0: return self.chums.append(chum) - if not (self.mainwindow.config.hideOfflineChums() and + if not (self.mainwindow.config.hideOfflineChums() and chum.mood.name() == "offline"): chumLabel = chumListing(chum, self.mainwindow) self.addItem(chumLabel) @@ -459,7 +473,7 @@ class chumArea(RightClickList): def getChums(self, handle): chums = self.findItems(handle, QtCore.Qt.MatchFlags(0)) return chums - + def showAllChums(self): for c in self.chums: chandle = c.handle @@ -753,8 +767,8 @@ class MovingWindow(QtGui.QFrame): class PesterWindow(MovingWindow): def __init__(self, parent=None): - MovingWindow.__init__(self, parent, - flags=(QtCore.Qt.CustomizeWindowHint | + MovingWindow.__init__(self, parent, + flags=(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint)) self.convos = {} @@ -804,7 +818,7 @@ class PesterWindow(MovingWindow): self, QtCore.SIGNAL('reconnectIRC()')) self.menu = QtGui.QMenuBar(self) - + filemenu = self.menu.addMenu(self.theme["main/menus/client/_name"]) self.filemenu = filemenu filemenu.addAction(opts) @@ -856,7 +870,7 @@ class PesterWindow(MovingWindow): self.helpmenu = helpmenu self.helpmenu.addAction(self.helpAction) self.helpmenu.addAction(self.aboutAction) - + self.closeButton = WMButton(PesterIcon(self.theme["main/close/image"]), self) self.connect(self.closeButton, QtCore.SIGNAL('clicked()'), @@ -870,9 +884,9 @@ class PesterWindow(MovingWindow): chums = [PesterProfile(c, chumdb=self.chumdb) for c in set(self.config.chums())] self.chumList = chumArea(chums, self) - self.connect(self.chumList, + self.connect(self.chumList, QtCore.SIGNAL('itemActivated(QListWidgetItem *)'), - self, + self, QtCore.SLOT('newConversationWindow(QListWidgetItem *)')) self.connect(self.chumList, QtCore.SIGNAL('removeChumSignal(QListWidgetItem *)'), @@ -882,7 +896,7 @@ class PesterWindow(MovingWindow): QtCore.SIGNAL('blockChumSignal(QString)'), self, QtCore.SLOT('blockChum(QString)')) - + self.addChumButton = QtGui.QPushButton(self.theme["main/addchum/text"], self) self.connect(self.addChumButton, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('addChumWindow()')) @@ -1041,7 +1055,7 @@ class PesterWindow(MovingWindow): if self.memos.has_key(channel): self.memos[channel].showChat() return - # do slider dialog then set + # do slider dialog then set if self.config.tabs(): if not self.tabmemo: self.createMemoTabWindow() @@ -1056,7 +1070,7 @@ class PesterWindow(MovingWindow): self, QtCore.SLOT('closeMemo(QString)')) self.connect(self, QtCore.SIGNAL('namesUpdated()'), memoWindow, QtCore.SLOT('namesUpdated()')) - self.connect(self, + self.connect(self, QtCore.SIGNAL('userPresentSignal(QString, QString, QString)'), memoWindow, QtCore.SLOT('userPresentChange(QString, QString, QString)')) # chat client send memo open @@ -1131,7 +1145,7 @@ class PesterWindow(MovingWindow): if hasattr(self, 'moods'): self.moods.removeButtons() mood_list = theme["main/moods"] - mood_list = [dict([(str(k),v) for (k,v) in d.iteritems()]) + mood_list = [dict([(str(k),v) for (k,v) in d.iteritems()]) for d in mood_list] self.moods = PesterMoodHandler(self, *[PesterMoodButton(self, **d) for d in mood_list]) self.moods.showButtons() @@ -1182,7 +1196,7 @@ class PesterWindow(MovingWindow): self.currentMoodIcon.hide() self.currentMoodIcon = None - + if theme["main/mychumhandle/colorswatch/text"]: self.mychumcolor.setText(theme["main/mychumhandle/colorswatch/text"]) else: @@ -1199,7 +1213,7 @@ class PesterWindow(MovingWindow): except Exception, e: self.alarm = NoneSound() self.ceasesound = NoneSound() - + def changeTheme(self, theme): self.theme = theme # do self @@ -1293,7 +1307,7 @@ class PesterWindow(MovingWindow): def memoTabsClosed(self): del self.tabmemo self.tabmemo = None - + @QtCore.pyqtSlot(QtCore.QString, Mood) def updateMoodSlot(self, handle, mood): h = unicode(handle) @@ -1613,7 +1627,7 @@ class PesterWindow(MovingWindow): windows = list(self.tabconvo.convos.values()) if self.tabmemo: windows += list(self.tabmemo.convos.values()) - + for w in windows: w.setParent(None) w.show() @@ -1655,6 +1669,16 @@ class PesterWindow(MovingWindow): # sound soundsetting = self.optionmenu.soundcheck.isChecked() self.config.set("soundon", soundsetting) + # timestamps + timestampsetting = self.optionmenu.timestampcheck.isChecked() + self.config.set("showTimeStamps", timestampsetting) + timeformatsetting = unicode(self.optionmenu.timestampBox.currentText()) + if timeformatsetting == "12 hour": + self.config.set("time12Format", True) + else: + self.config.set("time12Format", False) + secondssetting = self.optionmenu.secondscheck.isChecked() + self.config.set("showSeconds", secondssetting) self.optionmenu = None @QtCore.pyqtSlot() @@ -1717,7 +1741,7 @@ class PesterWindow(MovingWindow): self.trollslum = TrollSlumWindow(trolls, self) self.connect(self.trollslum, QtCore.SIGNAL('blockChumSignal(QString)'), self, QtCore.SLOT('blockChum(QString)')) - self.connect(self.trollslum, + self.connect(self.trollslum, QtCore.SIGNAL('unblockChumSignal(QString)'), self, QtCore.SLOT('unblockChum(QString)')) self.moodsRequest.emit(PesterList(trolls)) @@ -1874,7 +1898,7 @@ class MainProgram(QtCore.QObject): self.trayicon.setContextMenu(self.traymenu) self.trayicon.show() - self.trayicon.connect(self.trayicon, + self.trayicon.connect(self.trayicon, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self.widget, QtCore.SLOT('systemTrayActivated(QSystemTrayIcon::ActivationReason)')) @@ -1896,7 +1920,7 @@ class MainProgram(QtCore.QObject): self.irc = PesterIRC(self.widget.config, self.widget) self.connectWidgets(self.irc, self.widget) - widget2irc = [('sendMessage(QString, QString)', + widget2irc = [('sendMessage(QString, QString)', 'sendMessage(QString, QString)'), ('newConvoStarted(QString, bool)', 'startConvo(QString, bool)'), @@ -1916,15 +1940,15 @@ class MainProgram(QtCore.QObject): ('requestChannelList()', 'requestChannelList()'), ('joinChannel(QString)', 'joinChannel(QString)'), ('leftChannel(QString)', 'leftChannel(QString)'), - ('kickUser(QString, QString)', + ('kickUser(QString, QString)', 'kickUser(QString, QString)'), ('setChannelMode(QString, QString, QString)', 'setChannelMode(QString, QString, QString)'), - ('reconnectIRC()', 'reconnectIRC()') + ('reconnectIRC()', 'reconnectIRC()') ] # IRC --> Main window irc2widget = [('connected()', 'connected()'), - ('moodUpdated(QString, PyQt_PyObject)', + ('moodUpdated(QString, PyQt_PyObject)', 'updateMoodSlot(QString, PyQt_PyObject)'), ('colorUpdated(QString, QColor)', 'updateColorSlot(QString, QColor)'), From fbbcd8d923733efb2370f2626c8ed431c7517c2f Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Sun, 13 Mar 2011 23:29:45 -0700 Subject: [PATCH 03/13] Log viewer, complete with all pesterlogs, memo logs, colors, images, etc. --- logviewer.py | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++ pesterchum.py | 44 ++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 logviewer.py diff --git a/logviewer.py b/logviewer.py new file mode 100644 index 0000000..f96c99b --- /dev/null +++ b/logviewer.py @@ -0,0 +1,194 @@ +import os, sys +import codecs +import re +from time import strftime, strptime +from PyQt4 import QtGui, QtCore +from generic import RightClickList +from parsetools import convertTags + +class PesterLogUserSelect(QtGui.QDialog): + def __init__(self, config, theme, parent): + QtGui.QDialog.__init__(self, parent) + self.setModal(False) + self.config = config + self.theme = theme + self.parent = parent + self.handle = parent.profile().handle + if sys.platform != "darwin": + self.logpath = "logs" + else: + self.logpath = _datadir+"logs" + + self.setStyleSheet(self.theme["main/defaultwindow/style"]) + self.setWindowTitle("Pesterlogs") + + instructions = QtGui.QLabel("Pick a memo or chumhandle:") + + if os.path.exists("%s/%s" % (self.logpath, self.handle)): + chumMemoList = os.listdir("%s/%s/" % (self.logpath, self.handle)) + else: + chumMemoList = [] + chumslist = config.chums() + for c in chumslist: + if not c in chumMemoList: + chumMemoList.append(c) + chumMemoList.sort() + + self.chumsBox = RightClickList(self) + self.chumsBox.setStyleSheet(self.theme["main/chums/style"]) + self.chumsBox.optionsMenu = QtGui.QMenu(self) + + for (i, t) in enumerate(chumMemoList): + item = QtGui.QListWidgetItem(t) + item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"])) + self.chumsBox.addItem(item) + + self.cancel = QtGui.QPushButton("CANCEL", self) + self.connect(self.cancel, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('reject()')) + self.ok = QtGui.QPushButton("OK", self) + self.ok.setDefault(True) + self.connect(self.ok, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('viewActivatedLog()')) + layout_ok = QtGui.QHBoxLayout() + layout_ok.addWidget(self.cancel) + layout_ok.addWidget(self.ok) + + layout_0 = QtGui.QVBoxLayout() + layout_0.addWidget(instructions) + layout_0.addWidget(self.chumsBox) + layout_0.addLayout(layout_ok) + + self.setLayout(layout_0) + + def selectedchum(self): + return self.chumsBox.currentItem() + + @QtCore.pyqtSlot() + def viewActivatedLog(self): + selectedchum = self.selectedchum().text() + if not hasattr(self, 'pesterlogviewer'): + self.pesterlogviewer = None + if not self.pesterlogviewer: + self.pesterlogviewer = PesterLogViewer(selectedchum, self.config, self.theme, self.parent) + self.connect(self.pesterlogviewer, QtCore.SIGNAL('rejected()'), + self, QtCore.SLOT('closeActiveLog()')) + self.pesterlogviewer.show() + self.pesterlogviewer.raise_() + self.pesterlogviewer.activateWindow() + self.accept() + + @QtCore.pyqtSlot() + def closeActiveLog(self): + self.pesterlogviewer.close() + self.pesterlogviewer = None + +class PesterLogViewer(QtGui.QDialog): + def __init__(self, chum, config, theme, parent): + QtGui.QDialog.__init__(self, parent) + self.setModal(False) + self.config = config + self.theme = theme + self.parent = parent + global _datadir + self.handle = parent.profile().handle + self.chum = chum + self.convos = {} + if sys.platform != "darwin": + self.logpath = "logs" + else: + self.logpath = _datadir+"logs" + + self.setStyleSheet(self.theme["main/defaultwindow/style"]) + self.setWindowTitle("Pesterlogs with " + self.chum) + + self.format = "bbcode" + if os.path.exists("%s/%s/%s/%s" % (self.logpath, self.handle, chum, self.format)): + self.logList = os.listdir("%s/%s/%s/%s/" % (self.logpath, self.handle, self.chum, self.format)) + else: + self.logList = [] + + if not os.path.exists("%s/%s/%s/%s" % (self.logpath, self.handle, chum, self.format)) or len(self.logList) == 0: + instructions = QtGui.QLabel("No Pesterlogs were found") + + self.ok = QtGui.QPushButton("CLOSE", self) + self.ok.setDefault(True) + self.connect(self.ok, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('reject()')) + layout_ok = QtGui.QHBoxLayout() + layout_ok.addWidget(self.ok) + + layout_0 = QtGui.QVBoxLayout() + layout_0.addWidget(instructions) + layout_0.addLayout(layout_ok) + + self.setLayout(layout_0) + else: + self.instructions = QtGui.QLabel("Pesterlog with " +self.chum+ " on") + + self.logsBox = RightClickList(self) + self.logsBox.setFixedSize(220, 300) + self.logsBox.setStyleSheet(self.theme["main/chums/style"]) + self.connect(self.logsBox, QtCore.SIGNAL('itemSelectionChanged()'), + self, QtCore.SLOT('loadSelectedLog()')) + self.logsBox.optionsMenu = QtGui.QMenu(self) + + self.textArea = QtGui.QTextEdit(self) + self.textArea.setReadOnly(True) + self.textArea.setFixedWidth(600) + if theme.has_key("convo/scrollbar"): + self.textArea.setStyleSheet("QTextEdit { width:500px; %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.textArea.setStyleSheet("QTextEdit { width:500px; %s }" % (theme["convo/textarea/style"])) + + self.logList.sort() + self.logList.reverse() + + for l in self.logList: + item = QtGui.QListWidgetItem(self.fileToTime(l)) + item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"])) + self.logsBox.addItem(item) + + if len(self.logList) > 0: self.loadLog(self.logList[0]) + + self.ok = QtGui.QPushButton("CLOSE", self) + self.ok.setDefault(True) + self.ok.setFixedWidth(80) + self.connect(self.ok, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('reject()')) + layout_ok = QtGui.QHBoxLayout() + layout_ok.addWidget(self.ok) + layout_ok.setAlignment(self.ok, QtCore.Qt.AlignRight) + + layout_logs = QtGui.QHBoxLayout() + layout_logs.addWidget(self.logsBox) + layout_logs.addWidget(self.textArea) + + layout_0 = QtGui.QVBoxLayout() + layout_0.addWidget(self.instructions) + layout_0.addLayout(layout_logs) + layout_0.addLayout(layout_ok) + + self.setLayout(layout_0) + + @QtCore.pyqtSlot() + def loadSelectedLog(self): + self.loadLog(self.timeToFile(self.logsBox.currentItem().text())) + + def loadLog(self, fname): + fp = codecs.open("%s/%s/%s/%s/%s" % (self.logpath, self.handle, self.chum, self.format, fname), encoding='utf-8', mode='r') + self.textArea.clear() + for line in fp: + cline = line.replace("\r\n", "").replace("[/color]","") + cline = re.sub("\[color=(#.{6})]", r"", cline) + self.textArea.append(convertTags(cline)) + textCur = self.textArea.textCursor() + textCur.movePosition(1) + self.textArea.setTextCursor(textCur) + self.instructions.setText("Pesterlog with " +self.chum+ " on " + self.fileToTime(str(fname))) + + def fileToTime(self, fname): + timestr = fname[(fname.index(".")+1):fname.index(".txt")] + return strftime("%a %d %b %Y %H %M", strptime(timestr, "%Y-%m-%d.%H.%M")) + def timeToFile(self, time): + return self.chum + strftime(".%Y-%m-%d.%H.%M.txt", strptime(str(time), "%a %d %b %Y %H %M")) diff --git a/pesterchum.py b/pesterchum.py index d09b3d0..df9c5c3 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -23,6 +23,7 @@ from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo from parsetools import convertTags, addTimeInitial from memos import PesterMemo, MemoTabWindow, TimeTracker from irc import PesterIRC +from logviewer import PesterLogUserSelect, PesterLogViewer _datadir = QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.DataLocation)+"Pesterchum/" @@ -454,7 +455,11 @@ class chumArea(RightClickList): self.blockchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self) self.connect(self.blockchum, QtCore.SIGNAL('triggered()'), self, QtCore.SLOT('blockChum()')) + self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) + self.connect(self.logchum, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('openChumLogs()')) self.optionsMenu.addAction(self.pester) + self.optionsMenu.addAction(self.logchum) self.optionsMenu.addAction(self.blockchum) self.optionsMenu.addAction(self.removechum) @@ -526,6 +531,7 @@ class chumArea(RightClickList): self.pester.setText(theme["main/menus/rclickchumlist/pester"]) self.removechum.setText(theme["main/menus/rclickchumlist/removechum"]) self.blockchum.setText(theme["main/menus/rclickchumlist/blockchum"]) + self.logchum.setText(theme["main/menus/rclickchumlist/viewlog"]) def changeTheme(self, theme): self.initTheme(theme) chumlistings = [self.item(i) for i in range(0, self.count())] @@ -553,6 +559,21 @@ class chumArea(RightClickList): if not currentChum: return self.blockChumSignal.emit(self.currentItem().chum.handle) + @QtCore.pyqtSlot() + def openChumLogs(self): + currentChum = self.currentItem().text() + if not currentChum: + return + self.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow) + self.connect(self.pesterlogviewer, QtCore.SIGNAL('rejected()'), + self, QtCore.SLOT('closeActiveLog()')) + self.pesterlogviewer.show() + self.pesterlogviewer.raise_() + self.pesterlogviewer.activateWindow() + @QtCore.pyqtSlot() + def closeActiveLog(self): + self.pesterlogviewer.close() + self.pesterlogviewer = None removeChumSignal = QtCore.pyqtSignal(QtGui.QListWidgetItem) blockChumSignal = QtCore.pyqtSignal(QtCore.QString) @@ -790,6 +811,10 @@ class PesterWindow(MovingWindow): self.move(100, 100) + logv = QtGui.QAction(self.theme["main/menus/client/logviewer"], self) + self.logv = logv + self.connect(logv, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('openLogv()')) opts = QtGui.QAction(self.theme["main/menus/client/options"], self) self.opts = opts self.connect(opts, QtCore.SIGNAL('triggered()'), @@ -823,6 +848,7 @@ class PesterWindow(MovingWindow): self.filemenu = filemenu filemenu.addAction(opts) filemenu.addAction(memoaction) + filemenu.addAction(logv) filemenu.addAction(userlistaction) filemenu.addAction(self.idleaction) filemenu.addAction(self.importaction) @@ -1120,6 +1146,7 @@ class PesterWindow(MovingWindow): self.miniButton.move(*theme["main/minimize/loc"]) # menus self.menu.move(*theme["main/menu/loc"]) + self.logv.setText(theme["main/menus/client/logviewer"]) self.opts.setText(theme["main/menus/client/options"]) self.exitaction.setText(theme["main/menus/client/exit"]) self.userlistaction.setText(theme["main/menus/client/userlist"]) @@ -1599,6 +1626,23 @@ class PesterWindow(MovingWindow): def closeQuirks(self): self.quirkmenu = None @QtCore.pyqtSlot() + def openLogv(self): + if not hasattr(self, 'logusermenu'): + self.logusermenu = None + if not self.logusermenu: + self.logusermenu = PesterLogUserSelect(self.config, self.theme, self) + self.connect(self.logusermenu, QtCore.SIGNAL('accepted()'), + self, QtCore.SLOT('closeLogUsers()')) + self.connect(self.logusermenu, QtCore.SIGNAL('rejected()'), + self, QtCore.SLOT('closeLogUsers()')) + self.logusermenu.show() + self.logusermenu.raise_() + self.logusermenu.activateWindow() + @QtCore.pyqtSlot() + def closeLogUsers(self): + self.logusermenu.close() + self.logusermenu = None + @QtCore.pyqtSlot() def openOpts(self): if not hasattr(self, 'optionmenu'): self.optionmenu = None From 600fe5e2c4679f2fbb47190cfa9a360309d5713a Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Sun, 13 Mar 2011 23:30:39 -0700 Subject: [PATCH 04/13] Updated all themes to have pesterlog menu items --- themes/enamel/style.js | 2 ++ themes/gold/style.js | 2 ++ themes/pesterchum/style.js | 2 ++ themes/trollian/style.js | 2 ++ themes/typewriter/style.js | 2 ++ 5 files changed, 10 insertions(+) diff --git a/themes/enamel/style.js b/themes/enamel/style.js index 0f9054b..07f8b06 100644 --- a/themes/enamel/style.js +++ b/themes/enamel/style.js @@ -18,6 +18,7 @@ "menus": {"client": {"_name": "Client", "options": "Options", "memos": "Memos", + "logviewer": "Pesterlogs", "userlist": "Userlist", "import": "Import", "reconnect": "Reconnect", @@ -35,6 +36,7 @@ "removechum": "Remove Chum", "blockchum": "Block", "addchum": "Add Chum", + "viewlog": "View Pesterlog", "unblockchum": "Unblock", "banuser": "Ban User", "opuser": "Make OP", diff --git a/themes/gold/style.js b/themes/gold/style.js index f46a1ea..c7fb706 100644 --- a/themes/gold/style.js +++ b/themes/gold/style.js @@ -20,6 +20,7 @@ "menus": {"client": {"_name": "Client", "options": "Options", "memos": "Memos", + "logviewer": "Pesterlogs", "userlist": "Userlist", "import": "Import", "reconnect": "Reconnect", @@ -37,6 +38,7 @@ "removechum": "Remove Chum", "blockchum": "Block", "addchum": "Add Chum", + "viewlog": "View Pesterlog", "unblockchum": "Unblock", "banuser": "Ban User", "opuser": "Make OP", diff --git a/themes/pesterchum/style.js b/themes/pesterchum/style.js index cdd21da..eb6e9db 100644 --- a/themes/pesterchum/style.js +++ b/themes/pesterchum/style.js @@ -20,6 +20,7 @@ "menus": {"client": {"_name": "CLIENT", "options": "OPTIONS", "memos": "MEMOS", + "logviewer": "PESTERLOGS", "userlist": "USERLIST", "import": "IMPORT", "reconnect": "RECONNECT", @@ -37,6 +38,7 @@ "removechum": "REMOVE CHUM", "blockchum": "BLOCK", "addchum": "ADD CHUM", + "viewlog": "VIEW PESTERLOG", "unblockchum": "UNBLOCK", "banuser": "BAN USER", "opuser": "MAKE OP", diff --git a/themes/trollian/style.js b/themes/trollian/style.js index 365505d..0ec8137 100644 --- a/themes/trollian/style.js +++ b/themes/trollian/style.js @@ -19,6 +19,7 @@ "menus": {"client": {"_name": "Trollian", "options": "Options", "memos": "Memos", + "logviewer": "Pesterlogs", "userlist": "Fresh Targets", "import": "import U2;", "idle": "Idle", @@ -35,6 +36,7 @@ "removechum": "Trash", "blockchum": "Block", "addchum": "Add Chump", + "viewlog": "View Pesterlog", "unblockchum": "Mercy", "banuser": "Ban", "opuser": "Promote", diff --git a/themes/typewriter/style.js b/themes/typewriter/style.js index 32b07cc..d141d74 100644 --- a/themes/typewriter/style.js +++ b/themes/typewriter/style.js @@ -20,6 +20,7 @@ "menus": {"client": {"_name": "Typewriter", "options": "Preferences", "memos": "Bulletin Boards", + "logviewer": "Pesterlogs", "userlist": "Userlist", "import": "Import", "idle": "Idle", @@ -37,6 +38,7 @@ "removechum": "Erase User", "blockchum": "Condemn", "addchum": "Add User", + "viewlog": "View Pesterlog", "unblockchum": "Forgive", "banuser": "Expel User", "opuser": "Promote", From e331014ebe8a070b5d888d75d4f1dfb103ede4cb Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Sun, 13 Mar 2011 23:31:07 -0700 Subject: [PATCH 05/13] Removed time stamps and log viewer from TODO (they're done) --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 6bb52af..37f539e 100644 --- a/TODO +++ b/TODO @@ -17,8 +17,6 @@ Features: * help button on quirks menu? * chum list groups * More complex quirks: by-sound -* log viewer -* time codes * Theme checking * Spy mode * Animated From f01874bcfa9d5ba13c74b5899f34553496034bdf Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Tue, 15 Mar 2011 21:33:17 -0700 Subject: [PATCH 06/13] Changed list of logs to tree --- logviewer.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/logviewer.py b/logviewer.py index f96c99b..0ae70fa 100644 --- a/logviewer.py +++ b/logviewer.py @@ -126,13 +126,6 @@ class PesterLogViewer(QtGui.QDialog): else: self.instructions = QtGui.QLabel("Pesterlog with " +self.chum+ " on") - self.logsBox = RightClickList(self) - self.logsBox.setFixedSize(220, 300) - self.logsBox.setStyleSheet(self.theme["main/chums/style"]) - self.connect(self.logsBox, QtCore.SIGNAL('itemSelectionChanged()'), - self, QtCore.SLOT('loadSelectedLog()')) - self.logsBox.optionsMenu = QtGui.QMenu(self) - self.textArea = QtGui.QTextEdit(self) self.textArea.setReadOnly(True) self.textArea.setFixedWidth(600) @@ -144,10 +137,27 @@ class PesterLogViewer(QtGui.QDialog): self.logList.sort() self.logList.reverse() - for l in self.logList: - item = QtGui.QListWidgetItem(self.fileToTime(l)) - item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"])) - self.logsBox.addItem(item) + self.tree = QtGui.QTreeWidget() + self.tree.setFixedSize(260, 300) + self.tree.header().hide() + if theme.has_key("convo/scrollbar"): + self.tree.setStyleSheet("QTreeWidget { %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.tree.setStyleSheet("%s" % (theme["convo/textarea/style"])) + self.connect(self.tree, QtCore.SIGNAL('itemSelectionChanged()'), + self, QtCore.SLOT('loadSelectedLog()')) + self.tree.setSortingEnabled(False) + child_1 = None + last = ["",""] + for (i,l) in enumerate(self.logList): + my = self.fileToMonthYear(l) + if my[0] != last[0]: + child_1 = QtGui.QTreeWidgetItem(["%s %s" % (my[0], my[1])]) + self.tree.addTopLevelItem(child_1) + if i == 0: + child_1.setExpanded(True) + child_1.addChild(QtGui.QTreeWidgetItem([self.fileToTime(l)])) + last = self.fileToMonthYear(l) if len(self.logList) > 0: self.loadLog(self.logList[0]) @@ -161,7 +171,7 @@ class PesterLogViewer(QtGui.QDialog): layout_ok.setAlignment(self.ok, QtCore.Qt.AlignRight) layout_logs = QtGui.QHBoxLayout() - layout_logs.addWidget(self.logsBox) + layout_logs.addWidget(self.tree) layout_logs.addWidget(self.textArea) layout_0 = QtGui.QVBoxLayout() @@ -173,7 +183,8 @@ class PesterLogViewer(QtGui.QDialog): @QtCore.pyqtSlot() def loadSelectedLog(self): - self.loadLog(self.timeToFile(self.logsBox.currentItem().text())) + if len(self.tree.currentItem().text(0)) > len("September 2011"): + self.loadLog(self.timeToFile(self.tree.currentItem().text(0))) def loadLog(self, fname): fp = codecs.open("%s/%s/%s/%s/%s" % (self.logpath, self.handle, self.chum, self.format, fname), encoding='utf-8', mode='r') @@ -187,6 +198,9 @@ class PesterLogViewer(QtGui.QDialog): self.textArea.setTextCursor(textCur) self.instructions.setText("Pesterlog with " +self.chum+ " on " + self.fileToTime(str(fname))) + def fileToMonthYear(self, fname): + time = strptime(fname[(fname.index(".")+1):fname.index(".txt")], "%Y-%m-%d.%H.%M") + return [strftime("%B", time), strftime("%Y", time)] def fileToTime(self, fname): timestr = fname[(fname.index(".")+1):fname.index(".txt")] return strftime("%a %d %b %Y %H %M", strptime(timestr, "%Y-%m-%d.%H.%M")) From 3f1f874e6ef08a65a6398e8504498974aa403fbc Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Thu, 17 Mar 2011 16:57:13 -0700 Subject: [PATCH 07/13] Fix chumroll bugs, can now actually remove and pester chums from right-click menu. --- pesterchum.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pesterchum.py b/pesterchum.py index df9c5c3..ae172a9 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -550,7 +550,7 @@ class chumArea(RightClickList): return currentChum = self.currentItem().chum self.chums = [c for c in self.chums if c.handle != currentChum.handle] - self.removeChumSignal.emit(self.currentItem()) + self.removeChumSignal.emit(self.currentItem().chum.handle) oldlist = self.takeItem(self.currentRow()) del oldlist @QtCore.pyqtSlot() @@ -575,7 +575,7 @@ class chumArea(RightClickList): self.pesterlogviewer.close() self.pesterlogviewer = None - removeChumSignal = QtCore.pyqtSignal(QtGui.QListWidgetItem) + removeChumSignal = QtCore.pyqtSignal(QtCore.QString) blockChumSignal = QtCore.pyqtSignal(QtCore.QString) class trollSlum(chumArea): @@ -913,11 +913,11 @@ class PesterWindow(MovingWindow): self.connect(self.chumList, QtCore.SIGNAL('itemActivated(QListWidgetItem *)'), self, - QtCore.SLOT('newConversationWindow(QListWidgetItem *)')) + QtCore.SLOT('pesterSelectedChum()')) self.connect(self.chumList, - QtCore.SIGNAL('removeChumSignal(QListWidgetItem *)'), + QtCore.SIGNAL('removeChumSignal(QString)'), self, - QtCore.SLOT('removeChum(QListWidgetItem *)')) + QtCore.SLOT('removeChum(QString)')) self.connect(self.chumList, QtCore.SIGNAL('blockChumSignal(QString)'), self, @@ -1430,9 +1430,9 @@ class PesterWindow(MovingWindow): chum = PesterProfile(handle, chumdb=self.chumdb) self.addChum(chum) self.addchumdialog = None - @QtCore.pyqtSlot(QtGui.QListWidgetItem) + @QtCore.pyqtSlot(QtCore.QString) def removeChum(self, chumlisting): - self.config.removeChum(chumlisting.chum) + self.config.removeChum(chumlisting) @QtCore.pyqtSlot(QtCore.QString) def blockChum(self, handle): h = unicode(handle) From b81c2517c34da1a5f1bb436118aaf9bbdf91f77f Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Thu, 17 Mar 2011 18:26:35 -0700 Subject: [PATCH 08/13] Handle urls and memos correctly in logviewer. --- logviewer.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/logviewer.py b/logviewer.py index 0ae70fa..b1c9474 100644 --- a/logviewer.py +++ b/logviewer.py @@ -5,6 +5,7 @@ from time import strftime, strptime from PyQt4 import QtGui, QtCore from generic import RightClickList from parsetools import convertTags +from convo import PesterText class PesterLogUserSelect(QtGui.QDialog): def __init__(self, config, theme, parent): @@ -126,7 +127,7 @@ class PesterLogViewer(QtGui.QDialog): else: self.instructions = QtGui.QLabel("Pesterlog with " +self.chum+ " on") - self.textArea = QtGui.QTextEdit(self) + self.textArea = PesterLogText(theme, self.parent) self.textArea.setReadOnly(True) self.textArea.setFixedWidth(600) if theme.has_key("convo/scrollbar"): @@ -190,7 +191,7 @@ class PesterLogViewer(QtGui.QDialog): fp = codecs.open("%s/%s/%s/%s/%s" % (self.logpath, self.handle, self.chum, self.format, fname), encoding='utf-8', mode='r') self.textArea.clear() for line in fp: - cline = line.replace("\r\n", "").replace("[/color]","") + cline = line.replace("\r\n", "").replace("[/color]","").replace("[url]","").replace("[/url]","") cline = re.sub("\[color=(#.{6})]", r"", cline) self.textArea.append(convertTags(cline)) textCur = self.textArea.textCursor() @@ -206,3 +207,25 @@ class PesterLogViewer(QtGui.QDialog): return strftime("%a %d %b %Y %H %M", strptime(timestr, "%Y-%m-%d.%H.%M")) def timeToFile(self, time): return self.chum + strftime(".%Y-%m-%d.%H.%M.txt", strptime(str(time), "%a %d %b %Y %H %M")) + +class PesterLogText(PesterText): + def __init__(self, theme, parent=None): + PesterText.__init__(self, theme, parent) + + def focusInEvent(self, event): + QtGui.QTextEdit.focusInEvent(self, event) + def mousePressEvent(self, event): + url = self.anchorAt(event.pos()) + if url != "": + if url[0] != "#": + QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode)) + 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: + url = self.anchorAt(event.pos()) + if url != "" and url[0] != "#": + self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + else: + self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) From a5cce9acfcdc2bf7640ed7d8186694f596823dfc Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Tue, 29 Mar 2011 00:02:05 -0700 Subject: [PATCH 09/13] Chum groups! --- TODO | 1 - dataobjs.py | 11 +- generic.py | 7 + logviewer.py | 6 +- menus.py | 13 ++ parsetools.py | 6 +- pesterchum.py | 387 +++++++++++++++++++++++++++++++++---- themes/enamel/style.js | 186 +++++++++--------- themes/gold/style.js | 206 ++++++++++---------- themes/pesterchum/style.js | 160 +++++++-------- themes/trollian/style.js | 69 ++++--- themes/typewriter/style.js | 78 ++++---- 12 files changed, 748 insertions(+), 382 deletions(-) diff --git a/TODO b/TODO index 37f539e..6561c8f 100644 --- a/TODO +++ b/TODO @@ -15,7 +15,6 @@ SS: and the arrows next to the time thing overlap the CLOSE button Features: * copy quirks between profiles? * help button on quirks menu? -* chum list groups * More complex quirks: by-sound * Theme checking * Spy mode diff --git a/dataobjs.py b/dataobjs.py index c154228..d6e215d 100644 --- a/dataobjs.py +++ b/dataobjs.py @@ -174,7 +174,7 @@ class pesterQuirks(object): yield q class PesterProfile(object): - def __init__(self, handle, color=None, mood=Mood("offline"), chumdb=None): + def __init__(self, handle, color=None, mood=Mood("offline"), group=None, chumdb=None): self.handle = handle if color is None: if chumdb: @@ -183,6 +183,12 @@ class PesterProfile(object): color = QtGui.QColor("black") self.color = color self.mood = mood + if group is None: + if chumdb: + group = chumdb.getGroup(handle, "Chums") + else: + group = "Chums" + self.group = group def initials(self, time=None): handle = self.handle caps = [l for l in handle if l.isupper()] @@ -212,7 +218,8 @@ class PesterProfile(object): def plaindict(self): return (self.handle, {"handle": self.handle, "mood": self.mood.name(), - "color": unicode(self.color.name())}) + "color": unicode(self.color.name()), + "group": unicode(self.group)}) def blocked(self, config): return self.handle in config.getBlocklist() diff --git a/generic.py b/generic.py index fd77ad6..2c0f265 100644 --- a/generic.py +++ b/generic.py @@ -37,6 +37,13 @@ class RightClickList(QtGui.QListWidget): self.setCurrentItem(listing) self.optionsMenu.popup(event.globalPos()) +class RightClickTree(QtGui.QTreeWidget): + def contextMenuEvent(self, event): + if event.reason() == QtGui.QContextMenuEvent.Mouse: + listing = self.itemAt(event.pos()) + self.setCurrentItem(listing) + self.optionsMenu.popup(event.globalPos()) + class MultiTextDialog(QtGui.QDialog): def __init__(self, title, parent, *queries): QtGui.QDialog.__init__(self, parent) diff --git a/logviewer.py b/logviewer.py index b1c9474..b543731 100644 --- a/logviewer.py +++ b/logviewer.py @@ -3,7 +3,7 @@ import codecs import re from time import strftime, strptime from PyQt4 import QtGui, QtCore -from generic import RightClickList +from generic import RightClickList, RightClickTree from parsetools import convertTags from convo import PesterText @@ -138,7 +138,8 @@ class PesterLogViewer(QtGui.QDialog): self.logList.sort() self.logList.reverse() - self.tree = QtGui.QTreeWidget() + self.tree = RightClickTree() + self.tree.optionsMenu = QtGui.QMenu(self) self.tree.setFixedSize(260, 300) self.tree.header().hide() if theme.has_key("convo/scrollbar"): @@ -148,6 +149,7 @@ class PesterLogViewer(QtGui.QDialog): self.connect(self.tree, QtCore.SIGNAL('itemSelectionChanged()'), self, QtCore.SLOT('loadSelectedLog()')) self.tree.setSortingEnabled(False) + child_1 = None last = ["",""] for (i,l) in enumerate(self.logList): diff --git a/menus.py b/menus.py index e97c06a..514af57 100644 --- a/menus.py +++ b/menus.py @@ -507,6 +507,10 @@ class PesterOptions(QtGui.QDialog): self.theme = theme self.setStyleSheet(self.theme["main/defaultwindow/style"]) + hr = QtGui.QFrame() + hr.setFrameShape(QtGui.QFrame.HLine) + hr.setFrameShadow(QtGui.QFrame.Sunken) + self.tabcheck = QtGui.QCheckBox("Tabbed Conversations", self) if self.config.tabs(): self.tabcheck.setChecked(True) @@ -533,6 +537,12 @@ class PesterOptions(QtGui.QDialog): if self.config.showSeconds(): self.secondscheck.setChecked(True) + # Will add ability to turn off groups later + #self.groupscheck = QtGui.QCheckBox("Use Groups", self) + #self.groupscheck.setChecked(self.config.useGroups()) + self.showemptycheck = QtGui.QCheckBox("Show Empty Groups", self) + self.showemptycheck.setChecked(self.config.showEmptyGroups()) + self.ok = QtGui.QPushButton("OK", self) self.ok.setDefault(True) self.connect(self.ok, QtCore.SIGNAL('clicked()'), @@ -548,6 +558,9 @@ class PesterOptions(QtGui.QDialog): layout_0.addWidget(self.tabcheck) layout_0.addWidget(self.soundcheck) layout_0.addWidget(self.hideOffline) + #layout_0.addWidget(self.groupscheck) + layout_0.addWidget(self.showemptycheck) + layout_0.addWidget(hr) layout_0.addWidget(self.timestampcheck) layout_0.addWidget(self.timestampBox) layout_0.addWidget(self.secondscheck) diff --git a/parsetools.py b/parsetools.py index c70beb7..67f79da 100644 --- a/parsetools.py +++ b/parsetools.py @@ -216,7 +216,7 @@ def timeDifference(td): elif atd < timedelta(0,3600): if minutes == 1: timetext = "%d MINUTE %s" % (minutes, when) - else: + else: timetext = "%d MINUTES %s" % (minutes, when) elif atd < timedelta(0,3600*100): if hours == 1 and leftoverminutes == 0: @@ -235,7 +235,7 @@ def img2smiley(string): return string smiledict = { - ":rancorous:": "pc_rancorous.gif", + ":rancorous:": "pc_rancorous.gif", ":apple:": "apple.gif", ":bathearst:": "bathearst.gif", ":cathearst:": "cathearst.png", @@ -245,7 +245,7 @@ smiledict = { ":blueghost:": "blueslimer.gif", ":slimer:": "slimer.gif", ":candycorn:": "candycorn.gif", - ":cheer:": "cheer.gif", + ":cheer:": "cheer.gif", ":duhjohn:": "confusedjohn.gif", ":datrump:": "datrump.gif", ":facepalm:": "facepalm.gif", diff --git a/pesterchum.py b/pesterchum.py index ae172a9..2e7b2e4 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -18,7 +18,7 @@ from menus import PesterChooseQuirks, PesterChooseTheme, \ PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \ LoadingScreen, AboutPesterchum from dataobjs import PesterProfile, Mood, pesterQuirk, pesterQuirks -from generic import PesterIcon, RightClickList, MultiTextDialog, PesterList +from generic import PesterIcon, RightClickList, RightClickTree, MultiTextDialog, PesterList from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo from parsetools import convertTags, addTimeInitial from memos import PesterMemo, MemoTabWindow, TimeTracker @@ -131,7 +131,14 @@ class PesterProfileDB(dict): json.dump(chumdict, fp) fp.close() - converted = dict([(handle, PesterProfile(handle, color=QtGui.QColor(c['color']), mood=Mood(c['mood']))) for (handle, c) in chumdict.iteritems()]) + u = [] + for (handle, c) in chumdict.iteritems(): + try: + g = c['group'] + u.append((handle, PesterProfile(handle, color=QtGui.QColor(c['color']), mood=Mood(c['mood']), group=g))) + except KeyError: + u.append((handle, PesterProfile(handle, color=QtGui.QColor(c['color']), mood=Mood(c['mood'])))) + converted = dict(u) self.update(converted) def save(self): @@ -152,6 +159,17 @@ class PesterProfileDB(dict): self[handle].color = color else: self[handle] = PesterProfile(handle, color) + def getGroup(self, handle, default="Chums"): + if not self.has_key(handle): + return default + else: + return self[handle].group + def setGroup(self, handle, theGroup): + if self.has_key(handle): + self[handle].group = theGroup + else: + self[handle] = PesterProfile(handle, group=theGroup) + self.save() def __setitem__(self, key, val): dict.__setitem__(self, key, val) self.save() @@ -264,6 +282,18 @@ class userConfig(object): if not self.config.has_key('showSeconds'): self.set("showSeconds", False) return self.config.get('showSeconds', False) + def useGroups(self): + if not self.config.has_key('useGroups'): + self.set("useGroups", False) + return self.config.get('useGroups', False) + def openDefaultGroup(self): + if not self.config.has_key('openDefaultGroup'): + self.set("openDefaultGroup", True) + return self.config.get('openDefaultGroup', True) + def showEmptyGroups(self): + if not self.config.has_key('emptyGroups'): + self.set("emptyGroups", False) + return self.config.get('emptyGroups', False) def addChum(self, chum): if chum.handle not in self.chums(): fp = open(self.filename) # what if we have two clients open?? @@ -291,6 +321,25 @@ class userConfig(object): l = self.getBlocklist() l.pop(l.index(handle)) self.set('block', l) + def getGroups(self): + if not self.config.has_key('groups'): + self.set('groups', []) + return self.config.get('groups', []) + def addGroup(self, group, open=False): + l = self.getGroups() + if group not in l: + l.append([group,open]) + l.sort() + self.set('groups', l) + def delGroup(self, group): + l = self.getGroups() + i = 0 + for g in l: + if g[0] == group: break + i = i+1 + l.pop(i) + l.sort() + self.set('groups', l) def server(self): return self.config.get('server', 'irc.mindfang.org') def port(self): @@ -404,9 +453,9 @@ class WMButton(QtGui.QPushButton): self.setStyleSheet("QPushButton { padding: 0px; }") self.setAutoDefault(False) -class chumListing(QtGui.QListWidgetItem): +class chumListing(QtGui.QTreeWidgetItem): def __init__(self, chum, window): - QtGui.QListWidgetItem.__init__(self, chum.handle) + QtGui.QTreeWidgetItem.__init__(self, [chum.handle]) self.mainwindow = window self.chum = chum self.handle = chum.handle @@ -420,32 +469,44 @@ class chumListing(QtGui.QListWidgetItem): mood = self.chum.mood self.mood = mood icon = self.mood.icon(self.mainwindow.theme) - self.setIcon(icon) + self.setIcon(0, icon) try: - self.setTextColor(QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"])) + self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"])) except KeyError: - self.setTextColor(QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"])) + self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"])) def changeTheme(self, theme): icon = self.mood.icon(theme) - self.setIcon(icon) + self.setIcon(0, icon) try: - self.setTextColor(QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"])) + self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"])) except KeyError: - self.setTextColor(QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"])) + self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"])) def __lt__(self, cl): h1 = self.handle.lower() h2 = cl.handle.lower() return (h1 < h2) -class chumArea(RightClickList): +class chumArea(RightClickTree): def __init__(self, chums, parent=None): - QtGui.QListWidget.__init__(self, parent) + QtGui.QTreeWidget.__init__(self, parent) self.mainwindow = parent theme = self.mainwindow.theme self.chums = chums + gTemp = self.mainwindow.config.getGroups() + self.groups = [g[0] for g in gTemp] + self.openGroups = [g[1] for g in gTemp] + # quick hack to sort saved groups + self.mainwindow.config.addGroup("f3rskv9dssag[%3ffvsla09iv34G#$v") + self.mainwindow.config.delGroup("f3rskv9dssag[%3ffvsla09iv34G#$v") + # end quick hack + self.showAllGroups() if not self.mainwindow.config.hideOfflineChums(): self.showAllChums() - self.optionsMenu = QtGui.QMenu(self) + if not self.mainwindow.config.showEmptyGroups(): + self.hideEmptyGroups() + self.chumoptions = QtGui.QMenu(self) + self.groupoptions = QtGui.QMenu(self) + self.optionsMenu = self.chumoptions self.pester = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self) self.connect(self.pester, QtCore.SIGNAL('triggered()'), self, QtCore.SLOT('activateChum()')) @@ -458,13 +519,83 @@ class chumArea(RightClickList): self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self) self.connect(self.logchum, QtCore.SIGNAL('triggered()'), self, QtCore.SLOT('openChumLogs()')) - self.optionsMenu.addAction(self.pester) - self.optionsMenu.addAction(self.logchum) - self.optionsMenu.addAction(self.blockchum) - self.optionsMenu.addAction(self.removechum) + + self.removegroup = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removegroup"], self) + self.connect(self.removegroup, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('removeGroup()')) + self.renamegroup = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/renamegroup"], self) + self.connect(self.renamegroup, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('renameGroup()')) + self.chumoptions.addAction(self.pester) + self.chumoptions.addAction(self.logchum) + self.chumoptions.addAction(self.blockchum) + self.chumoptions.addAction(self.removechum) + self.moveMenu = QtGui.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/movechum"], self) + self.chumoptions.addMenu(self.moveMenu) + self.moveGroupMenu() + + self.groupoptions.addAction(self.renamegroup) + self.groupoptions.addAction(self.removegroup) self.initTheme(theme) - self.sortItems() + #self.sortItems() + #self.sortItems(1, QtCore.Qt.AscendingOrder) + self.setSortingEnabled(False) + self.header().hide() + self.setDropIndicatorShown(False) + self.setIndentation(0) + self.setDragEnabled(True) + self.setDragDropMode(QtGui.QAbstractItemView.InternalMove) + + self.connect(self, QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'), + self, QtCore.SLOT('expandGroup()')) + + def dropEvent(self, event): + item = self.itemAt(event.pos()) + if item: + if item.text(0) == "Chums" or item.text(0) in self.groups: + group = item.text(0) + else: + group = item.parent().text(0) + chumLabel = event.source().currentItem() + chumLabel.chum.group = group + self.mainwindow.chumdb.setGroup(chumLabel.chum.handle, group) + self.takeItem(chumLabel) + self.addItem(chumLabel) + + def chumoptionsmenu(self): + self.optionsMenu = self.chumoptions + def groupoptionsmenu(self): + self.optionsMenu = self.groupoptions + def moveGroupMenu(self): + currentGroup = self.currentItem() + if currentGroup: + currentGroup = currentGroup.parent().text(0) + self.moveMenu.clear() + actGroup = QtGui.QActionGroup(self) + + groups = self.groups[:] + groups.insert(0, "Chums") + for gtext in groups: + if gtext == currentGroup: + continue + movegroup = self.moveMenu.addAction(gtext) + actGroup.addAction(movegroup) + self.connect(actGroup, QtCore.SIGNAL('triggered(QAction *)'), + self, QtCore.SLOT('moveToGroup(QAction *)')) + def contextMenuEvent(self, event): + #fuckin Qt + if event.reason() == QtGui.QContextMenuEvent.Mouse: + listing = self.itemAt(event.pos()) + self.setCurrentItem(listing) + if self.currentItem().text(0) == "Chums" or \ + self.currentItem().text(0) in self.groups: + self.groupoptionsmenu() + else: + self.chumoptionsmenu() + self.moveGroupMenu() + self.optionsMenu.popup(event.globalPos()) + def addChum(self, chum): if len([c for c in self.chums if c.handle == chum.handle]) != 0: return @@ -473,29 +604,95 @@ class chumArea(RightClickList): chum.mood.name() == "offline"): chumLabel = chumListing(chum, self.mainwindow) self.addItem(chumLabel) - self.sortItems() + #self.topLevelItem(0).addChild(chumLabel) + #self.topLevelItem(0).sortChildren(0, QtCore.Qt.AscendingOrder) def getChums(self, handle): - chums = self.findItems(handle, QtCore.Qt.MatchFlags(0)) + chums = self.findItems(handle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive) return chums def showAllChums(self): for c in self.chums: chandle = c.handle - if not self.findItems(chandle, QtCore.Qt.MatchFlags(0)): + if not len(self.findItems(chandle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive)): chumLabel = chumListing(c, self.mainwindow) self.addItem(chumLabel) - self.sortItems() + #self.sortItems() def hideOfflineChums(self): + for j in range(self.topLevelItemCount()): + i = 0 + listing = self.topLevelItem(j).child(i) + while listing is not None: + if listing.chum.mood.name() == "offline": + self.topLevelItem(j).takeChild(i) + else: + i += 1 + listing = self.topLevelItem(j).child(i) + self.topLevelItem(j).sortChildren(0, QtCore.Qt.AscendingOrder) + def showAllGroups(self): + curgroups = [] + for i in range(self.topLevelItemCount()): + curgroups.append(self.topLevelItem(i).text(0)) + if "Chums" not in curgroups: + child_1 = QtGui.QTreeWidgetItem(["Chums"]) + self.addTopLevelItem(child_1) + if self.mainwindow.config.openDefaultGroup(): + child_1.setExpanded(True) + for i,g in enumerate(self.groups): + if g not in curgroups: + child_1 = QtGui.QTreeWidgetItem(["%s" % (g)]) + self.addTopLevelItem(child_1) + if self.openGroups[i]: + child_1.setExpanded(True) + def hideEmptyGroups(self): i = 0 - listing = self.item(i) + listing = self.topLevelItem(i) while listing is not None: - if listing.chum.mood.name() == "offline": - self.takeItem(i) + if listing.childCount() == 0: + self.takeTopLevelItem(i) else: i += 1 - listing = self.item(i) - self.sortItems() + listing = self.topLevelItem(i) + @QtCore.pyqtSlot() + def expandGroup(self): + item = self.currentItem() + if item.text(0) in self.groups: + self.mainwindow.config.delGroup(str(item.text(0))) + expand = item.isExpanded() + self.mainwindow.config.addGroup(str(item.text(0)), not expand) + elif item.text(0) == "Chums": + self.mainwindow.config.set("openDefaultGroup", not item.isExpanded()) + def addItem(self, chumLabel): + if hasattr(self, 'groups'): + if chumLabel.chum.group not in self.groups: + self.topLevelItem(0).addChild(chumLabel) + self.topLevelItem(0).sortChildren(0, QtCore.Qt.AscendingOrder) + else: + if not self.findItems(chumLabel.handle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive): + if not self.findItems(chumLabel.chum.group, QtCore.Qt.MatchFlags(0)): + child_1 = QtGui.QTreeWidgetItem(["%s" % (chumLabel.chum.group)]) + self.addTopLevelItem(child_1) + if self.openGroups[self.groups.index("%s" % (chumLabel.chum.group))]: + child_1.setExpanded(True) + for i in range(self.topLevelItemCount()): + if self.topLevelItem(i).text(0) == chumLabel.chum.group: + break + self.topLevelItem(i).addChild(chumLabel) + self.topLevelItem(i).sortChildren(0, QtCore.Qt.AscendingOrder) + else: # usually means this is now the trollslum + if not self.findItems(chumLabel.handle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive): + self.topLevelItem(0).addChild(chumLabel) + self.topLevelItem(0).sortChildren(0, QtCore.Qt.AscendingOrder) + def takeItem(self, chumLabel): + r = None + for i in range(self.topLevelItemCount()): + for j in range(self.topLevelItem(i).childCount()): + if self.topLevelItem(i).child(j).text(0) == chumLabel.chum.handle: + r = self.topLevelItem(i).takeChild(j) + break + if not self.mainwindow.config.showEmptyGroups(): + self.hideEmptyGroups() + return r def updateMood(self, handle, mood): hideoff = self.mainwindow.config.hideOfflineChums() chums = self.getChums(handle) @@ -506,7 +703,7 @@ class chumArea(RightClickList): handle in [p.handle for p in self.chums]: newLabel = chumListing([p for p in self.chums if p.handle == handle][0], self.mainwindow) self.addItem(newLabel) - self.sortItems() + #self.sortItems() chums = [newLabel] elif mood.name() == "offline" and \ len(chums) > 0: @@ -532,14 +729,27 @@ class chumArea(RightClickList): self.removechum.setText(theme["main/menus/rclickchumlist/removechum"]) self.blockchum.setText(theme["main/menus/rclickchumlist/blockchum"]) self.logchum.setText(theme["main/menus/rclickchumlist/viewlog"]) + self.removegroup.setText(theme["main/menus/rclickchumlist/removegroup"]) + self.renamegroup.setText(theme["main/menus/rclickchumlist/renamegroup"]) + self.moveMenu.setTitle(theme["main/menus/rclickchumlist/movechum"]) def changeTheme(self, theme): self.initTheme(theme) - chumlistings = [self.item(i) for i in range(0, self.count())] + chumlistings = [] + for i in range(self.topLevelItemCount()): + for j in range(self.topLevelItem(i).childCount()): + chumlistings.append(self.topLevelItem(i).child(j)) + #chumlistings = [self.item(i) for i in range(0, self.count())] for c in chumlistings: c.changeTheme(theme) + + def count(self): + c = 0 + for i in range(self.topLevelItemCount()): + c = c + self.topLevelItem(i).childCount() + return c @QtCore.pyqtSlot() def activateChum(self): - self.itemActivated.emit(self.currentItem()) + self.itemActivated.emit(self.currentItem(), 0) @QtCore.pyqtSlot() def removeChum(self, handle = None): if handle: @@ -551,7 +761,7 @@ class chumArea(RightClickList): currentChum = self.currentItem().chum self.chums = [c for c in self.chums if c.handle != currentChum.handle] self.removeChumSignal.emit(self.currentItem().chum.handle) - oldlist = self.takeItem(self.currentRow()) + oldlist = self.takeItem(self.currentItem()) del oldlist @QtCore.pyqtSlot() def blockChum(self): @@ -561,7 +771,7 @@ class chumArea(RightClickList): self.blockChumSignal.emit(self.currentItem().chum.handle) @QtCore.pyqtSlot() def openChumLogs(self): - currentChum = self.currentItem().text() + currentChum = self.currentItem().text(0) if not currentChum: return self.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow) @@ -574,6 +784,61 @@ class chumArea(RightClickList): def closeActiveLog(self): self.pesterlogviewer.close() self.pesterlogviewer = None + @QtCore.pyqtSlot() + def renameGroup(self): + if not hasattr(self, 'renamegroupdialog'): + self.renamegroupdialog = None + if not self.renamegroupdialog: + (gname, ok) = QtGui.QInputDialog.getText(self, "Rename Group", "Enter a new name for the group:") + if ok: + gname = unicode(gname) + currentGroup = self.currentItem() + if not currentGroup: + return + index = self.indexOfTopLevelItem(currentGroup) + if index != -1: + expanded = currentGroup.isExpanded() + self.mainwindow.config.delGroup(str(currentGroup.text(0))) + self.mainwindow.config.addGroup(gname, expanded) + gTemp = self.mainwindow.config.getGroups() + self.groups = [g[0] for g in gTemp] + self.openGroups = [g[1] for g in gTemp] + for i in range(currentGroup.childCount()): + currentGroup.child(i).chum.group = gname + self.mainwindow.chumdb.setGroup(currentGroup.child(i).chum.handle, gname) + currentGroup.setText(0, gname) + self.renamegroupdialog = None + @QtCore.pyqtSlot() + def removeGroup(self): + currentGroup = self.currentItem() + if not currentGroup: + return + self.mainwindow.config.delGroup(currentGroup.text(0)) + gTemp = self.mainwindow.config.getGroups() + self.groups = [g[0] for g in gTemp] + self.openGroups = [g[1] for g in gTemp] + for i in range(self.topLevelItemCount()): + if self.topLevelItem(i).text(0) == currentGroup.text(0): + break + while self.topLevelItem(i).child(0): + chumLabel = self.topLevelItem(i).child(0) + chumLabel.chum.group = "Chums" + self.mainwindow.chumdb.setGroup(chumLabel.chum.handle, "Chums") + self.takeItem(chumLabel) + self.addItem(chumLabel) + self.takeTopLevelItem(i) + @QtCore.pyqtSlot(QtGui.QAction) + def moveToGroup(self, item): + if not item: + return + group = str(item.text()) + chumLabel = self.currentItem() + if not chumLabel: + return + chumLabel.chum.group = group + self.mainwindow.chumdb.setGroup(chumLabel.chum.handle, group) + self.takeItem(chumLabel) + self.addItem(chumLabel) removeChumSignal = QtCore.pyqtSignal(QtCore.QString) blockChumSignal = QtCore.pyqtSignal(QtCore.QString) @@ -585,19 +850,34 @@ class trollSlum(chumArea): theme = self.mainwindow.theme self.setStyleSheet(theme["main/trollslum/chumroll/style"]) self.chums = trolls + child_1 = QtGui.QTreeWidgetItem([""]) + self.addTopLevelItem(child_1) + child_1.setExpanded(True) for c in self.chums: chandle = c.handle if not self.findItems(chandle, QtCore.Qt.MatchFlags(0)): chumLabel = chumListing(c, self.mainwindow) self.addItem(chumLabel) + self.setSortingEnabled(False) + self.header().hide() + self.setDropIndicatorShown(False) + self.setIndentation(0) + self.optionsMenu = QtGui.QMenu(self) self.unblockchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self) self.connect(self.unblockchum, QtCore.SIGNAL('triggered()'), self, QtCore.SIGNAL('unblockChumSignal()')) self.optionsMenu.addAction(self.unblockchum) - self.sortItems() + #self.sortItems() + def contextMenuEvent(self, event): + #fuckin Qt + if event.reason() == QtGui.QContextMenuEvent.Mouse: + listing = self.itemAt(event.pos()) + self.setCurrentItem(listing) + if self.currentItem().text(0) != "": + self.optionsMenu.popup(event.globalPos()) def changeTheme(self, theme): self.setStyleSheet(theme["main/trollslum/chumroll/style"]) self.removechum.setText(theme["main/menus/rclickchumlist/removechum"]) @@ -815,6 +1095,10 @@ class PesterWindow(MovingWindow): self.logv = logv self.connect(logv, QtCore.SIGNAL('triggered()'), self, QtCore.SLOT('openLogv()')) + grps = QtGui.QAction(self.theme["main/menus/client/addgroup"], self) + self.grps = grps + self.connect(grps, QtCore.SIGNAL('triggered()'), + self, QtCore.SLOT('addGroupWindow()')) opts = QtGui.QAction(self.theme["main/menus/client/options"], self) self.opts = opts self.connect(opts, QtCore.SIGNAL('triggered()'), @@ -851,6 +1135,7 @@ class PesterWindow(MovingWindow): filemenu.addAction(logv) filemenu.addAction(userlistaction) filemenu.addAction(self.idleaction) + filemenu.addAction(grps) filemenu.addAction(self.importaction) filemenu.addAction(self.reconnectAction) filemenu.addAction(exitaction) @@ -911,7 +1196,7 @@ class PesterWindow(MovingWindow): chums = [PesterProfile(c, chumdb=self.chumdb) for c in set(self.config.chums())] self.chumList = chumArea(chums, self) self.connect(self.chumList, - QtCore.SIGNAL('itemActivated(QListWidgetItem *)'), + QtCore.SIGNAL('itemActivated(QTreeWidgetItem *, int)'), self, QtCore.SLOT('pesterSelectedChum()')) self.connect(self.chumList, @@ -1147,6 +1432,7 @@ class PesterWindow(MovingWindow): # menus self.menu.move(*theme["main/menu/loc"]) self.logv.setText(theme["main/menus/client/logviewer"]) + self.grps.setText(theme["main/menus/client/addgroup"]) self.opts.setText(theme["main/menus/client/options"]) self.exitaction.setText(theme["main/menus/client/exit"]) self.userlistaction.setText(theme["main/menus/client/userlist"]) @@ -1301,7 +1587,9 @@ class PesterWindow(MovingWindow): def pesterSelectedChum(self): curChum = self.chumList.currentItem() if curChum: - self.newConversationWindow(curChum) + if curChum.text(0) not in self.chumList.groups and \ + curChum.text(0) != "Chums": + self.newConversationWindow(curChum) @QtCore.pyqtSlot(QtGui.QListWidgetItem) def newConversationWindow(self, chumlisting): # check chumdb @@ -1642,6 +1930,25 @@ class PesterWindow(MovingWindow): def closeLogUsers(self): self.logusermenu.close() self.logusermenu = None + + @QtCore.pyqtSlot() + def addGroupWindow(self): + if not hasattr(self, 'addgroupdialog'): + self.addgroupdialog = None + if not self.addgroupdialog: + (gname, ok) = QtGui.QInputDialog.getText(self, "Add Group", "Enter a name for the new group:") + if ok: + gname = unicode(gname) + self.config.addGroup(gname) + gTemp = self.config.getGroups() + self.chumList.groups = [g[0] for g in gTemp] + self.chumList.openGroups = [g[1] for g in gTemp] + self.chumList.showAllGroups() + if not self.config.showEmptyGroups(): + self.chumList.hideEmptyGroups() + + self.addgroupdialog = None + @QtCore.pyqtSlot() def openOpts(self): if not hasattr(self, 'optionmenu'): @@ -1723,6 +2030,16 @@ class PesterWindow(MovingWindow): self.config.set("time12Format", False) secondssetting = self.optionmenu.secondscheck.isChecked() self.config.set("showSeconds", secondssetting) + # groups + groupssetting = self.optionmenu.groupscheck.isChecked() + self.config.set("useGroups", groupssetting) + emptygroupssetting = self.optionmenu.showemptycheck.isChecked() + curemptygroup = self.config.showEmptyGroups() + if curemptygroup and not emptygroupssetting: + self.chumList.hideEmptyGroups() + elif emptygroupssetting and not curemptygroup: + self.chumList.showAllGroups() + self.config.set("emptyGroups", emptygroupssetting) self.optionmenu = None @QtCore.pyqtSlot() diff --git a/themes/enamel/style.js b/themes/enamel/style.js index 07f8b06..6536989 100644 --- a/themes/enamel/style.js +++ b/themes/enamel/style.js @@ -20,9 +20,10 @@ "memos": "Memos", "logviewer": "Pesterlogs", "userlist": "Userlist", + "addgroup": "Add Group", "import": "Import", "reconnect": "Reconnect", - "idle": "Idle", + "idle": "Idle", "exit": "Exit"}, "profile": {"_name": "Profile", "switch": "Switch", @@ -38,6 +39,9 @@ "addchum": "Add Chum", "viewlog": "View Pesterlog", "unblockchum": "Unblock", + "removegroup": "Remove Group", + "renamegroup": "Rename Group", + "movechum": "Move To", "banuser": "Ban User", "opuser": "Make OP", "quirksoff": "Quirks Off" @@ -54,7 +58,7 @@ "loc": [440, 211], "size": [289, 275], "userlistcolor": "black", - "moods": { + "moods": { "chummy": { "icon": "$path/chummy.gif", "color": "black" }, @@ -62,7 +66,7 @@ "offline": { "icon": "$path/offline.gif", "color": "#9d9d9d"}, - + "pleasant": { "icon": "$path/pleasant.gif", "color": "black" }, "distraught": { "icon": "$path/distraught.gif", "color": "black" }, @@ -90,7 +94,7 @@ "devious": { "icon": "$path/devious.gif", "color": "red" }, "sleek": { "icon": "$path/sleek.gif", "color": "red" }, - + "detestful": { "icon": "$path/detestful.gif", "color": "red" }, "mirthful": { "icon": "$path/mirthful.gif", "color": "red" }, @@ -109,7 +113,7 @@ } }, - "trollslum": { + "trollslum": { "style": "background: #fdb302; border:2px solid yellow; font-family: 'Century Gothic'", "size": [195, 200], "label": { "text": "TROLLSLUM", @@ -127,7 +131,7 @@ "text": "" }, "currentMood": [1500, 1500] }, - "defaultwindow": { "style": "background: #fdb302; font-family:'Century Gothic';font:bold;selection-background-color:#919191; " + "defaultwindow": { "style": "background: #fdb302; font-family:'Century Gothic';font:bold;selection-background-color:#919191; " }, "addchum": { "style": "background: rgba(255, 255, 0, 0%); border:0px; color: rgba(0, 0, 0, 0%);", "loc": [443,144], @@ -147,82 +151,82 @@ }, "defaultmood": 0, "moodlabel": { "style": "", - "loc": [20, 430], - "text": "" - }, + "loc": [20, 430], + "text": "" + }, "moods": [ - { "style": "background-image:url($path/mood1.png); border:0px;", - "selected": "background-image:url($path/mood1c.png); border:0px;", - "loc": [0, 258], - "size": [100,110], - "text": "", - "icon": "", - "mood": 0 - }, - { "style": "background-image:url($path/mood2.png); border:0px;", - "selected": "background-image:url($path/mood2c.png); border:0px;", - "loc": [106, 258], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 19 - }, - { "style": "background-image:url($path/mood3.png); border:0px;", - "selected": "background-image:url($path/mood3c.png); border:0px;", - "loc": [212, 258], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 22 - }, - { "style": "background-image:url($path/mood4.png); border:0px;", - "selected": "background-image:url($path/mood4c.png); border:0px;", - "loc": [318, 258], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 4 - }, - { "style": "background-image:url($path/mood5.png); border:0px;", - "selected": "background-image:url($path/mood5c.png); border:0px;", - "loc": [0, 382], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 3 - }, - { "style": "background-image:url($path/mood6.png); border:0px;", - "selected": "background-image:url($path/mood6c.png); border:0px;", - "loc": [106, 382], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 20 - }, - { "style": "background-image:url($path/mood7.png); border:0px;", - "selected": "background-image:url($path/mood7c.png); border:0px;", - "loc": [212, 382], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 5 - }, - { "style": "background-image:url($path/mood8.png); border:0px;", - "selected": "background-image:url($path/mood8c.png); border:0px;", - "loc": [318, 382], - "size": [100, 110], - "text": "", - "icon": "", - "mood": 1 - }, - { "style": "border:0px;", - "selected": "border:0px;", - "loc": [0, 0], - "size": [100, 100], - "text": "", - "icon": "", - "mood": 2 - } + { "style": "background-image:url($path/mood1.png); border:0px;", + "selected": "background-image:url($path/mood1c.png); border:0px;", + "loc": [0, 258], + "size": [100,110], + "text": "", + "icon": "", + "mood": 0 + }, + { "style": "background-image:url($path/mood2.png); border:0px;", + "selected": "background-image:url($path/mood2c.png); border:0px;", + "loc": [106, 258], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 19 + }, + { "style": "background-image:url($path/mood3.png); border:0px;", + "selected": "background-image:url($path/mood3c.png); border:0px;", + "loc": [212, 258], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 22 + }, + { "style": "background-image:url($path/mood4.png); border:0px;", + "selected": "background-image:url($path/mood4c.png); border:0px;", + "loc": [318, 258], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 4 + }, + { "style": "background-image:url($path/mood5.png); border:0px;", + "selected": "background-image:url($path/mood5c.png); border:0px;", + "loc": [0, 382], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 3 + }, + { "style": "background-image:url($path/mood6.png); border:0px;", + "selected": "background-image:url($path/mood6c.png); border:0px;", + "loc": [106, 382], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 20 + }, + { "style": "background-image:url($path/mood7.png); border:0px;", + "selected": "background-image:url($path/mood7c.png); border:0px;", + "loc": [212, 382], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 5 + }, + { "style": "background-image:url($path/mood8.png); border:0px;", + "selected": "background-image:url($path/mood8c.png); border:0px;", + "loc": [318, 382], + "size": [100, 110], + "text": "", + "icon": "", + "mood": 1 + }, + { "style": "border:0px;", + "selected": "border:0px;", + "loc": [0, 0], + "size": [100, 100], + "text": "", + "icon": "", + "mood": 2 + } ] }, "convo": @@ -230,7 +234,7 @@ "tabstyle": "background-color: #fdb302; font-family: 'Century Gothic'", "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;", "handle": "border-width: 5px; border-image:url($path/scrollbg.png) 5px; min-height:60px;", - "downarrow": "height:17px;border:0px solid #c48a00;", + "downarrow": "height:17px;border:0px solid #c48a00;", "darrowstyle": "image:url($path/downarrow.png);", "uparrow": "height:17px;border:0px solid #c48a00;", "uarrowstyle": "image:url($path/uparrow.png);" @@ -258,12 +262,12 @@ "ceasepester": "ceased pestering", "blocked": "blocked", "unblocked": "unblocked", - "blockedmsg": "did not receive message from", + "blockedmsg": "did not receive message from", "openmemo": "opened memo on board", "joinmemo": "responded to memo", "closememo": "ceased responding to memo", "kickedmemo": "You have been banned from this memo!", - "idle": "is now an idle chum!" + "idle": "is now an idle chum!" }, "systemMsgColor": "#646464" }, @@ -278,7 +282,7 @@ }, "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;", "handle": "border-width: 5px; border-image:url($path/scrollbg.png) 5px; min-height:60px;", - "downarrow": "height:17px;border:0px;", + "downarrow": "height:17px;border:0px;", "darrowstyle": "image:url();", "uparrow": "height:17px;border:0px;", "uarrowstyle": "image:url();" @@ -295,20 +299,20 @@ "userlist": { "width": 150, "style": "border:2px solid #c48a00; background: white; font-family: 'Century Gothic';selection-background-color:#646464; font-size: 14px; margin-left:0px; margin-right:10px;" }, - "time": { "text": { "width": 75, - "style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Century Gothic';font:bold;" + "time": { "text": { "width": 75, + "style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Century Gothic';font:bold;" }, "slider": { "style": "border: 0px;", "groove": "", "handle": "" }, - "buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, - "arrows": { "left": "$path/leftarrow.png", + "buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, + "arrows": { "left": "$path/leftarrow.png", "right": "$path/rightarrow.png", - "style": " border:0px; margin-top: 5px; margin-right:10px;" + "style": " border:0px; margin-top: 5px; margin-right:10px;" } }, "systemMsgColor": "#646464", "op": { "icon": "$path/smooth.png" } } -} \ No newline at end of file +} diff --git a/themes/gold/style.js b/themes/gold/style.js index c7fb706..d5cefa4 100644 --- a/themes/gold/style.js +++ b/themes/gold/style.js @@ -16,15 +16,16 @@ "loc": [150,22] }, "sounds": { "alertsound": "$path/alarm.wav", - "ceasesound": "$path/cease.wav" }, + "ceasesound": "$path/cease.wav" }, "menus": {"client": {"_name": "Client", "options": "Options", "memos": "Memos", "logviewer": "Pesterlogs", "userlist": "Userlist", + "addgroup": "Add Group", "import": "Import", - "reconnect": "Reconnect", - "idle": "Idle", + "reconnect": "Reconnect", + "idle": "Idle", "exit": "Exit"}, "profile": {"_name": "Profile", "switch": "Switch", @@ -40,6 +41,9 @@ "addchum": "Add Chum", "viewlog": "View Pesterlog", "unblockchum": "Unblock", + "removegroup": "Remove Group", + "renamegroup": "Rename Group", + "movechum": "Move To", "banuser": "Ban User", "opuser": "Make OP", "quirksoff": "Quirks Off" @@ -49,7 +53,7 @@ "loc": [123, 88], "size": [190, 65], "userlistcolor": "white", - "moods": { + "moods": { "chummy": { "icon": "$path/chummy.png", "color": "white" }, @@ -57,7 +61,7 @@ "offline": { "icon": "$path/offline.png", "color": "#bebebe"}, - + "pleasant": { "icon": "$path/pleasant.png", "color": "white" }, "distraught": { "icon": "$path/distraught.png", "color": "white" }, @@ -85,7 +89,7 @@ "devious": { "icon": "$path/devious.png", "color": "red" }, "sleek": { "icon": "$path/sleek.png", "color": "red" }, - + "detestful": { "icon": "$path/detestful.png", "color": "red" }, "mirthful": { "icon": "$path/mirthful.png", "color": "red" }, @@ -104,7 +108,7 @@ } }, - "trollslum": { + "trollslum": { "style": "background: #fdb302; border:2px solid yellow; font-family: 'Arial'", "size": [195, 200], "label": { "text": "TROLLSLUM", @@ -122,7 +126,7 @@ "text": "" }, "currentMood": [129, 176] }, - "defaultwindow": { "style": "background: #fdb302; font-family:'Arial';font:bold;selection-background-color:#919191; " + "defaultwindow": { "style": "background: #fdb302; font-family:'Arial';font:bold;selection-background-color:#919191; " }, "addchum": { "style": "background: rgba(255, 255, 0, 0%); border:0px; color: rgba(0, 0, 0, 0%);", "loc": [25,0], @@ -142,90 +146,90 @@ }, "defaultmood": 0, "moodlabel": { "style": "", - "loc": [20, 430], - "text": "MOODS" - }, + "loc": [20, 430], + "text": "MOODS" + }, "moods": [ - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck1.png); border:0px;", - "loc": [13, 204], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 0 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck2.png); border:0px;", - "loc": [13, 231], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 19 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck3.png); border:0px;", - "loc": [13, 258], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 20 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck4.png); border:0px;", - "loc": [116, 204], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 21 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck5.png); border:0px;", - "loc": [116, 231], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 22 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck6.png); border:0px;", - "loc": [116, 258], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 5 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck7.png); border:0px;", - "loc": [219, 204], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 6 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck8.png); border:0px;", - "loc": [219, 231], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 3 - }, - { "style": "border:0px;", - "selected": "background-image:url($path/moodcheck9.png); border:0px;", - "loc": [219, 258], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 1 - }, - { "style": "border:0px;", - "selected": "border:0px;", - "loc": [13, 175], - "size": [101, 27], - "text": "", - "icon": "", - "mood": 2 - } + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck1.png); border:0px;", + "loc": [13, 204], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 0 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck2.png); border:0px;", + "loc": [13, 231], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 19 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck3.png); border:0px;", + "loc": [13, 258], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 20 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck4.png); border:0px;", + "loc": [116, 204], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 21 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck5.png); border:0px;", + "loc": [116, 231], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 22 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck6.png); border:0px;", + "loc": [116, 258], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 5 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck7.png); border:0px;", + "loc": [219, 204], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 6 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck8.png); border:0px;", + "loc": [219, 231], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 3 + }, + { "style": "border:0px;", + "selected": "background-image:url($path/moodcheck9.png); border:0px;", + "loc": [219, 258], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 1 + }, + { "style": "border:0px;", + "selected": "border:0px;", + "loc": [13, 175], + "size": [101, 27], + "text": "", + "icon": "", + "mood": 2 + } ] }, "convo": @@ -233,7 +237,7 @@ "tabstyle": "background-color: #fdb302; font-family: 'Arial'", "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;", "handle": "background-color:#c48a00;min-height:20px;", - "downarrow": "height:17px;border:0px solid #c48a00;", + "downarrow": "height:17px;border:0px solid #c48a00;", "darrowstyle": "image:url($path/downarrow.png);", "uparrow": "height:17px;border:0px solid #c48a00;", "uarrowstyle": "image:url($path/uparrow.png);" @@ -263,12 +267,12 @@ "ceasepester": "ceased pestering", "blocked": "blocked", "unblocked": "unblocked", - "blockedmsg": "did not receive message from", + "blockedmsg": "did not receive message from", "openmemo": "opened memo on board", "joinmemo": "responded to memo", "closememo": "ceased responding to memo", "kickedmemo": "You have been banned from this memo!", - "idle": "is now an idle chum!" + "idle": "is now an idle chum!" }, "systemMsgColor": "#646464" }, @@ -284,7 +288,7 @@ }, "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;", "handle": "background-color:#c48a00;min-height:20px;", - "downarrow": "height:17px;border:0px solid #c48a00;", + "downarrow": "height:17px;border:0px solid #c48a00;", "darrowstyle": "image:url($path/downarrow.png);", "uparrow": "height:17px;border:0px solid #c48a00;", "uarrowstyle": "image:url($path/uparrow.png);" @@ -301,20 +305,20 @@ "userlist": { "width": 150, "style": "border:2px solid #c48a00; background: white; font-family: 'Arial';selection-background-color:#646464; font-size: 14px; margin-left:0px; margin-right:10px;" }, - "time": { "text": { "width": 75, - "style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Arial';font:bold;" + "time": { "text": { "width": 75, + "style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Arial';font:bold;" }, "slider": { "style": "border: 0px;", "groove": "", "handle": "" }, - "buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, - "arrows": { "left": "$path/leftarrow.png", + "buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, + "arrows": { "left": "$path/leftarrow.png", "right": "$path/rightarrow.png", - "style": " border:0px; margin-top: 5px; margin-right:10px;" + "style": " border:0px; margin-top: 5px; margin-right:10px;" } }, "systemMsgColor": "#646464", "op": { "icon": "$path/smooth.png" } } -} \ No newline at end of file +} diff --git a/themes/pesterchum/style.js b/themes/pesterchum/style.js index eb6e9db..e000af4 100644 --- a/themes/pesterchum/style.js +++ b/themes/pesterchum/style.js @@ -16,15 +16,16 @@ "loc": [10,0] }, "sounds": { "alertsound": "$path/alarm.wav", - "ceasesound": "$path/cease.wav" }, + "ceasesound": "$path/cease.wav" }, "menus": {"client": {"_name": "CLIENT", "options": "OPTIONS", "memos": "MEMOS", "logviewer": "PESTERLOGS", "userlist": "USERLIST", + "addgroup": "ADD GROUP", "import": "IMPORT", "reconnect": "RECONNECT", - "idle": "IDLE", + "idle": "IDLE", "exit": "EXIT"}, "profile": {"_name": "PROFILE", "switch": "SWITCH", @@ -40,6 +41,9 @@ "addchum": "ADD CHUM", "viewlog": "VIEW PESTERLOG", "unblockchum": "UNBLOCK", + "removegroup": "REMOVE GROUP", + "renamegroup": "RENAME GROUP", + "movechum": "MOVE TO", "banuser": "BAN USER", "opuser": "MAKE OP", "quirksoff": "QUIRKS OFF" @@ -49,7 +53,7 @@ "loc": [12, 117], "size": [209, 82], "userlistcolor": "white", - "moods": { + "moods": { "chummy": { "icon": "$path/chummy.png", "color": "white" }, @@ -57,7 +61,7 @@ "offline": { "icon": "$path/offline.png", "color": "#646464"}, - + "pleasant": { "icon": "$path/pleasant.png", "color": "white" }, "distraught": { "icon": "$path/distraught.png", "color": "white" }, @@ -85,7 +89,7 @@ "devious": { "icon": "$path/devious.png", "color": "red" }, "sleek": { "icon": "$path/sleek.png", "color": "red" }, - + "detestful": { "icon": "$path/detestful.png", "color": "red" }, "mirthful": { "icon": "$path/mirthful.png", "color": "red" }, @@ -104,7 +108,7 @@ } }, - "trollslum": { + "trollslum": { "style": "background: #fdb302; border:2px solid yellow; font-family: 'Courier'", "size": [195, 200], "label": { "text": "TROLLSLUM", @@ -122,7 +126,7 @@ "text": "" }, "currentMood": [18, 249] }, - "defaultwindow": { "style": "background: #fdb302; font-family:'Courier';font:bold;selection-background-color:#919191; " + "defaultwindow": { "style": "background: #fdb302; font-family:'Courier';font:bold;selection-background-color:#919191; " }, "addchum": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(0, 0, 0, 0%); font-family:'Courier';", "pressed" : "background: rgb(255, 255, 255, 30%);", @@ -136,7 +140,7 @@ "size": [71, 22], "text": "" }, - "block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';", + "block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';", "pressed" : "background: rgb(255, 255, 255, 30%);", "loc": [81,202], "size": [71, 22], @@ -144,73 +148,73 @@ }, "defaultmood": 0, "moodlabel": { "style": "", - "loc": [20, 430], - "text": "MOODS" - }, + "loc": [20, 430], + "text": "MOODS" + }, "moods": [ - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck1.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [12, 288], - "size": [104, 22], - "text": "CHUMMY", - "icon": "$path/chummy.png", - "mood": 0 - }, - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [12, 308], - "size": [104, 22], - "text": "PALSY", - "icon": "$path/chummy.png", - "mood": 3 - }, - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck3.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [12, 328], - "size": [104, 22], - "text": "CHIPPER", - "icon": "$path/chummy.png", - "mood": 4 - }, - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [117, 288], - "size": [104, 22], - "text": "BULLY", - "icon": "$path/chummy.png", - "mood": 5 - }, - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [117, 308], - "size": [104, 22], - "text": "PEPPY", - "icon": "$path/chummy.png", - "mood": 6 - }, - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck4.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [117, 328], - "size": [104, 22], - "text": "RANCOROUS", - "icon": "$path/rancorous.png", - "mood": 1 - }, - { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck5.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [12, 348], - "size": [209, 22], - "text": "ABSCOND", - "icon": "", - "mood": 2 - } + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck1.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [12, 288], + "size": [104, 22], + "text": "CHUMMY", + "icon": "$path/chummy.png", + "mood": 0 + }, + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [12, 308], + "size": [104, 22], + "text": "PALSY", + "icon": "$path/chummy.png", + "mood": 3 + }, + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck3.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [12, 328], + "size": [104, 22], + "text": "CHIPPER", + "icon": "$path/chummy.png", + "mood": 4 + }, + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [117, 288], + "size": [104, 22], + "text": "BULLY", + "icon": "$path/chummy.png", + "mood": 5 + }, + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [117, 308], + "size": [104, 22], + "text": "PEPPY", + "icon": "$path/chummy.png", + "mood": 6 + }, + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck4.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [117, 328], + "size": [104, 22], + "text": "RANCOROUS", + "icon": "$path/rancorous.png", + "mood": 1 + }, + { "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck5.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [12, 348], + "size": [209, 22], + "text": "ABSCOND", + "icon": "", + "mood": 2 + } ] }, "convo": {"style": "background-color: #fdb302;background-image:url($path/convobg.png);background-repeat: no-repeat; border:2px solid yellow; font-family: 'Courier'", "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: white; border:2px solid #c48a00;", "handle": "background-color:#c48a00;min-height:20px;", - "downarrow": "height:17px;border:0px solid #c48a00;", + "downarrow": "height:17px;border:0px solid #c48a00;", "darrowstyle": "image:url($path/downarrow.png);", "uparrow": "height:17px;border:0px solid #c48a00;", "uarrowstyle": "image:url($path/uparrow.png);" @@ -230,7 +234,7 @@ "style": "background: white; border:2px solid #c48a00;margin-top:5px; margin-right:10px; margin-left:10px; font-size: 12px;font-family: 'Courier'" }, "tabwindow" : { - "style": "background-color:#fdb302;border:0px" + "style": "background-color:#fdb302;border:0px" }, "tabs": { "style": "background-color: #7f7f7f; font-family: 'Courier';font:bold;font-size:12px;min-height:25px;", @@ -243,12 +247,12 @@ "ceasepester": "ceased pestering", "blocked": "blocked", "unblocked": "unblocked", - "blockedmsg": "did not receive message from", + "blockedmsg": "did not receive message from", "openmemo": "opened memo on board", "joinmemo": "responded to memo", "closememo": "ceased responding to memo", "kickedmemo": "You have been banned from this memo!", - "idle": "is now an idle chum!" + "idle": "is now an idle chum!" }, "systemMsgColor": "#646464" }, @@ -264,7 +268,7 @@ }, "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;", "handle": "background-color:#c48a00;min-height:20px;", - "downarrow": "height:17px;border:0px solid #c48a00;", + "downarrow": "height:17px;border:0px solid #c48a00;", "darrowstyle": "image:url($path/downarrow.png);", "uparrow": "height:17px;border:0px solid #c48a00;", "uarrowstyle": "image:url($path/uparrow.png);" @@ -281,20 +285,20 @@ "userlist": { "width": 150, "style": "border:2px solid #c48a00; background: white;font: bold;font-family: 'Courier';selection-background-color:#646464; font-size: 12px; margin-left:0px; margin-right:10px;" }, - "time": { "text": { "width": 75, - "style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;" + "time": { "text": { "width": 75, + "style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;" }, "slider": { "style": "border: 0px;", "groove": "", "handle": "" }, - "buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font: bold; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, - "arrows": { "left": "$path/leftarrow.png", + "buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font: bold; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, + "arrows": { "left": "$path/leftarrow.png", "right": "$path/rightarrow.png", - "style": " border:0px; margin-top: 5px; margin-right:10px;" + "style": " border:0px; margin-top: 5px; margin-right:10px;" } }, "systemMsgColor": "#646464", "op": { "icon": "$path/op.png" } } -} \ No newline at end of file +} diff --git a/themes/trollian/style.js b/themes/trollian/style.js index 0ec8137..86f4902 100644 --- a/themes/trollian/style.js +++ b/themes/trollian/style.js @@ -21,8 +21,10 @@ "memos": "Memos", "logviewer": "Pesterlogs", "userlist": "Fresh Targets", + "addgroup": "Add Group", "import": "import U2;", - "idle": "Idle", + "reconnect": "Reconnect", + "idle": "Idle", "exit": "Abscond"}, "profile": {"_name": "View", "switch": "Trolltag", @@ -38,6 +40,9 @@ "addchum": "Add Chump", "viewlog": "View Pesterlog", "unblockchum": "Mercy", + "removegroup": "Remove Group", + "renamegroup": "Rename Group", + "movechum": "Move To", "banuser": "Ban", "opuser": "Promote", "quirksoff": "Quirks Off" } @@ -54,50 +59,50 @@ "size": [171, 357], "userlistcolor": "black", "moods": { - + "chummy": { "icon": "$path/chummy.png", "color": "#63ea00" }, - + "rancorous": { "icon": "$path/rancorous.png", "color": "#7f7f7f" }, - + "offline": { "icon": "$path/offline.png", "color": "black"}, - - + + "pleasant": { "icon": "$path/pleasant.png", "color": "#d69df8" }, - + "distraught": { "icon": "$path/distraught.png", "color": "#706eba" }, - + "pranky": { "icon": "$path/pranky.png", "color": "blue" }, - - + + "smooth": { "icon": "$path/smooth.png", "color": "red" }, - - + + "ecstatic": { "icon": "$path/ecstatic.png", "color": "#99004d" }, - + "relaxed": { "icon": "$path/relaxed.png", "color": "#078446" }, - + "discontent": { "icon": "$path/discontent.png", "color": "#a75403" }, - + "devious": { "icon": "$path/devious.png", "color": "#008282" }, - + "sleek": { "icon": "$path/sleek.png", "color": "#a1a100" }, - + "detestful": { "icon": "$path/detestful.png", "color": "#6a006a" }, - + "mirthful": { "icon": "$path/mirthful.png", "color": "#450077" }, - + "manipulative": { "icon": "$path/manipulative.png", "color": "#004182" }, - + "vigorous": { "icon": "$path/vigorous.png", "color": "#0021cb" }, - + "perky": { "icon": "$path/perky.png", "color": "#406600" }, - + "acceptant": { "icon": "$path/acceptant.png", "color": "#a10000" }, - + "protective": { "icon": "$path/protective.png", "color": "white" }, - + "blocked": { "icon": "$path/blocked.png", "color": "black" } - + } }, "trollslum": { @@ -236,7 +241,7 @@ "icon": "", "mood": 7 }, - + { "style": "border:0px;color: rgba(0, 0, 0, 0%);", "selected": "border:0px; color: rgba(0, 0, 0, 0%);", "loc": [12, 117], @@ -266,7 +271,7 @@ "style": "background: white;margin-top:5px; border:1px solid #c2c2c2; margin-right: 54px; font-size: 12px; height: 19px;" }, "tabwindow" : { - "style": "background: rgb(190, 19, 4); font-family: 'Arial'" + "style": "background: rgb(190, 19, 4); font-family: 'Arial'" }, "tabs": { "style": "", @@ -312,15 +317,15 @@ "userlist": { "width": 125, "style": "font-size: 12px; background: white; margin-left: 5px; margin-bottom: 5px; border:2px solid #c2c2c2; padding: 5px; font-family: 'Arial';selection-background-color:rgb(200,200,200);" }, - "time": { "text": { "width": 75, - "style": "color: black; font:bold; border:1px solid #c2c2c2; background: white; height: 19px;" + "time": { "text": { "width": 75, + "style": "color: black; font:bold; border:1px solid #c2c2c2; background: white; height: 19px;" }, "slider": { "style": " border:1px solid #c2c2c2;", "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", + "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", "right": "$path/rightarrow.png", "style": "width: 19px; height: 19px; border:0px; margin-left: 2px;" } @@ -328,4 +333,4 @@ "systemMsgColor": "#646464", "op": { "icon": "$path/op.png" } } -} \ No newline at end of file +} diff --git a/themes/typewriter/style.js b/themes/typewriter/style.js index d141d74..996c106 100644 --- a/themes/typewriter/style.js +++ b/themes/typewriter/style.js @@ -16,15 +16,16 @@ "loc": [43,220] }, "sounds": { "alertsound": "$path/alarm.wav", - "ceasesound": "$path/cease.wav" }, + "ceasesound": "$path/cease.wav" }, "menus": {"client": {"_name": "Typewriter", "options": "Preferences", "memos": "Bulletin Boards", "logviewer": "Pesterlogs", "userlist": "Userlist", + "addgroup": "Add Group", "import": "Import", - "idle": "Idle", - "reconnect": "Reconnect", + "idle": "Idle", + "reconnect": "Reconnect", "exit": "Cease"}, "profile": {"_name": "Ink", "switch": "Alias", @@ -40,6 +41,9 @@ "addchum": "Add User", "viewlog": "View Pesterlog", "unblockchum": "Forgive", + "removegroup": "Remove Group", + "renamegroup": "Rename Group", + "movechum": "Move To", "banuser": "Expel User", "opuser": "Promote", "quirksoff": "Quirks Off" @@ -49,7 +53,7 @@ "loc": [70, 20], "size": [175,100], "userlistcolor": "black", - "moods": { + "moods": { "chummy": { "icon": "$path/chummy.png", "color": "black" }, @@ -57,7 +61,7 @@ "offline": { "icon": "$path/offline.png", "color": "#646464"}, - + "pleasant": { "icon": "$path/pleasant.png", "color": "black" }, "distraught": { "icon": "$path/distraught.png", "color": "black" }, @@ -85,7 +89,7 @@ "devious": { "icon": "$path/devious.png", "color": "red" }, "sleek": { "icon": "$path/sleek.png", "color": "red" }, - + "detestful": { "icon": "$path/detestful.png", "color": "red" }, "mirthful": { "icon": "$path/mirthful.png", "color": "red" }, @@ -104,7 +108,7 @@ } }, - "trollslum": { + "trollslum": { "style": "background: #bebebe; border:2px solid black; font-family: 'Courier'", "size": [195, 200], "label": { "text": "Ruffians", @@ -122,7 +126,7 @@ "text": "" }, "currentMood": [0, 0] }, - "defaultwindow": { "style": "background: #bebebe; font-family:'Courier';font:bold;selection-background-color: black; " + "defaultwindow": { "style": "background: #bebebe; font-family:'Courier';font:bold;selection-background-color: black; " }, "addchum": { "style": "background: rgba(255, 255, 0, 0%); border:0px solid #c48a00; font: bold; color: rgba(0, 0, 0, 0%); font-family:'Courier';", "pressed" : "background: rgb(255, 255, 255, 30%);", @@ -136,7 +140,7 @@ "size": [70, 15], "text": "" }, - "block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';", + "block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';", "pressed" : "background: rgb(255, 255, 255, 30%);", "loc": [0,0], "size": [0, 0], @@ -144,26 +148,26 @@ }, "defaultmood": 18, "moodlabel": { "style": "", - "loc": [20, 430], - "text": "MOODS" - }, + "loc": [20, 430], + "text": "MOODS" + }, "moods": [ - { "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck1.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [95, 323], - "size": [62, 9], - "text": "", - "icon": "", - "mood": 18 - }, - { "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", - "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", - "loc": [165, 323], - "size": [70, 9], - "text": "", - "icon": "", - "mood": 2 - } + { "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck1.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [95, 323], + "size": [62, 9], + "text": "", + "icon": "", + "mood": 18 + }, + { "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'", + "selected": "text-align:left; background-image:url($path/moodcheck2.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';", + "loc": [165, 323], + "size": [70, 9], + "text": "", + "icon": "", + "mood": 2 + } ] }, "convo": @@ -194,12 +198,12 @@ "ceasepester": "ceased pestering", "blocked": "blocked", "unblocked": "unblocked", - "blockedmsg": "did not receive message from", + "blockedmsg": "did not receive message from", "openmemo": "opened memo on board", "joinmemo": "responded to memo", "closememo": "ceased responding to memo", "kickedmemo": "You have been banned from this memo!", - "idle": "is now an idle chum!" + "idle": "is now an idle chum!" }, "systemMsgColor": "#646464" }, @@ -215,7 +219,7 @@ }, "scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;", "handle": "background-color:black;min-height:20px;", - "downarrow": "height:17px;border:0px;", + "downarrow": "height:17px;border:0px;", "darrowstyle": "image:url($path/downarrow.png);", "uparrow": "height:17px;border:0px;", "uarrowstyle": "image:url($path/uparrow.png);" @@ -232,20 +236,20 @@ "userlist": { "width": 150, "style": "border:2px solid black; background: white;font: bold;font-family: 'Courier';selection-background-color:black; font-size: 12px; margin-left:0px; margin-right:10px;" }, - "time": { "text": { "width": 75, - "style": " border: 2px solid black; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;" + "time": { "text": { "width": 75, + "style": " border: 2px solid black; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;" }, "slider": { "style": "border: 0px;", "groove": "", "handle": "" }, - "buttons": { "style": "color: black; font: bold; border: 2px solid black; font: bold; font-size: 12px; background: white; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, - "arrows": { "left": "$path/leftarrow.png", + "buttons": { "style": "color: black; font: bold; border: 2px solid black; font: bold; font-size: 12px; background: white; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }, + "arrows": { "left": "$path/leftarrow.png", "right": "$path/rightarrow.png", - "style": " border:0px; margin-top: 5px; margin-right:10px;" + "style": " border:0px; margin-top: 5px; margin-right:10px;" } }, "systemMsgColor": "#646464", "op": { "icon": "$path/protective.png" } } -} \ No newline at end of file +} From 403b3ca697ace1d35dd556862f4f11792b9f0860 Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Tue, 29 Mar 2011 00:36:02 -0700 Subject: [PATCH 10/13] lower() regexp function to go along with upper() --- dataobjs.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dataobjs.py b/dataobjs.py index d6e215d..b6459fc 100644 --- a/dataobjs.py +++ b/dataobjs.py @@ -8,6 +8,7 @@ from parsetools import timeDifference, convertTags, lexMessage from mispeller import mispeller _upperre = re.compile(r"upper\(([\w\\]+)\)") +_lowerre = re.compile(r"lower\(([\w\\]+)\)") _scramblere = re.compile(r"scramble\(([\w\\]+)\)") class Mood(object): @@ -63,9 +64,12 @@ class pesterQuirk(object): to = self.quirk["to"] def upperrep(m): return mo.expand(m.group(1)).upper() + def lowerrep(m): + return mo.expand(m.group(1)).lower() def scramblerep(m): return "".join(random.sample(mo.expand(m.group(1)), len(mo.expand(m.group(1))))) to = _upperre.sub(upperrep, to) + to = _lowerre.sub(lowerrep, to) to = _scramblere.sub(scramblerep, to) return mo.expand(to) return re.sub(fr, regexprep, string) @@ -81,9 +85,12 @@ class pesterQuirk(object): choice = random.choice(self.quirk["randomlist"]) def upperrep(m): return mo.expand(m.group(1)).upper() + def lowerrep(m): + return mo.expand(m.group(1)).lower() def scramblerep(m): return "".join(random.sample(mo.expand(m.group(1)), len(mo.expand(m.group(1))))) choice = _upperre.sub(upperrep, choice) + choice = _lowerre.sub(lowerrep, choice) choice = _upperre.sub(upperrep, choice) return mo.expand(choice) return re.sub(self.quirk["from"], randomrep, string) From 852e4f103412dcd429241285fa1121982a52c05b Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Tue, 29 Mar 2011 00:39:05 -0700 Subject: [PATCH 11/13] Added a Changelog to allow for attribution and to show new features. Added some descriptions of new features to readme. --- CHANGELOG.mkdn | 16 +++++++++++ readme.txt | 73 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 CHANGELOG.mkdn diff --git a/CHANGELOG.mkdn b/CHANGELOG.mkdn new file mode 100644 index 0000000..8953c48 --- /dev/null +++ b/CHANGELOG.mkdn @@ -0,0 +1,16 @@ +Pesterchum 3.14 +=============== + +Visit http://nova.xzibition.com/~illuminatedwax/help.html for tutorial. + +Visit https://github.com/illuminatedwax/pesterchum for git access and source code. + +CHANGELOG +--------- +### 3.14b (idk on version number scheme) +* Quirks lower() function - Kiooeht [evacipatedBox] +* Quirks scrabble() function - Kiooeht [evacipatedBox] +* Timestamps - Kiooeht [evacipatedBox] +* Logviewer - Kiooeht [evacipatedBox] +* Chum list groups - Kiooeht [evacipatedBox] +* Chum list bug fixes - Kiooeht [evacipatedBox] diff --git a/readme.txt b/readme.txt index 2be3e16..c6f5da7 100644 --- a/readme.txt +++ b/readme.txt @@ -6,7 +6,7 @@ Here's some tips to help you get started: CLIENT->IMPORT and opening your pesterchum.cfg file. This is usually in the 2.5 base directory or in Tinychum's data folder. - Some themes can be confusing if you haven't used the program -already! Some hints: +already! Some hints: Trollian: Moods are set by clicking the timelines, and you can add chums by clicking "Chumproll." Moods correspond to the troll @@ -36,11 +36,15 @@ style.js file will be documented soon, but feel free to poke at it. allow you to appear at multiple times in one chat. - Quirks: Prefix, suffix, simple replace, regexp replace (like in 2.5), random replacement, and an auto-mispeller :P +- Chum groups. Organize your chums into collapsible groups for easy +management. - Block/user list - Add/block chums directly from a conversation, the userlist, or memo userlist. +- Timestamps saved in logs and shown in conversations if wanted. - Logging. Logs are output in bbcode (for easy forum posting), html, and plain text. +- Logviewer for easy log reading inside Pesterchum - Idling. You can set yourself idle manually, and the computer will set it for you after 10 minutes. - Improved /me. Any letters immediately following /me will be @@ -125,19 +129,19 @@ While pestering your chum, here are some useful features: some appleberry blast to your conversation, just use color tags. These work like in TC 1.5: colored text. But in PC 3.14, you can use type your color in a lot of different ways: - - You can use the familiar r,g,b method: - "The Green Sun" + - You can use the familiar r,g,b method: + "The Green Sun" - You can use HTML tags: - "DURR I'M KARKAT AND I'M A HUGE IDIOT" + "DURR I'M KARKAT AND I'M A HUGE IDIOT" - You can even use plain color names: - "D4V3 TH1S 1S SO D3C4D3NT" - (list: http://www.w3schools.com/css/css_colornames.asp) + "D4V3 TH1S 1S SO D3C4D3NT" + (list: http://www.w3schools.com/css/css_colornames.asp) - You don't even have to add the if you are lazy. Just use a - new color tag whenever you want to change colors and PC 3.14 will - add the extra tags for you. + new color tag whenever you want to change colors and PC 3.14 will + add the extra tags for you. * URLS (anything with http:// in front of it) will automatically be - detected and made into a link you can CLIPK. + detected and made into a link you can CLIPK. * You can also link people to memos by typing "#" and the name of the menu like so: #R41NBOW_RUMPUS_P4RTYTOWN @@ -193,7 +197,7 @@ them in the order in which you open them (like in the comic). You can have one of your time frames cease responding to the memo by hitting "CLOSE." If you open that time frame again, the program will remember the number it originally gave it. If you want to be mysteeeeeeeerious, -you can type in "?" and you will appear as ???. +you can type in "?" and you will appear as ???. The memo viewer list: To the right is a list of people currently browsing the memo. A shade icon next to their name means they are the @@ -204,9 +208,9 @@ to the memo. You kick and op people by right clicking their name in the window. You can also add them to your chumroll! Inviting people to your memo: You can link to a memo by simply typing -"#nameofmemo" in any conversation or memo window. So you can say: +"#nameofmemo" in any conversation or memo window. So you can say: -CG: NOW YOU, ME, AND EGBERT NEED TO HAVE A CHAT. +CG: NOW YOU, ME, AND EGBERT NEED TO HAVE A CHAT. CG: CLICK IT. CG: #FRUITYRUMPUSASSHOLEFACTORY @@ -223,9 +227,18 @@ them for you. Sounds On: Uncheck to shut it the fuck up. -Hide Offline Chums: Turning this option on will hide all offline chums +Hide Offline Chums: Turning this option on will hide all offline chums off your chumroll. +Show Empty Groups: Turning this option of will show empty groups. + +Time Stamps: Turning this on will show timestamps in your chats. + +12/24 hour: Formatting for timestamps. Whether you want them in 12 or +24 hour time. + +Show Seconds: Turning this on will show the seconds in your timestamps. + MEMOS: Opens the Memo list as above. USERLIST: Shows a list of all the users that are currently logged onto @@ -278,7 +291,7 @@ Equius' quirks: PREFIX: ":33 < " You type: "*ac twitches her friendly whiskers at ct*" Result: -AC: :33 < *ac twitches her friendly whiskers at ct* +AC: :33 < *ac twitches her friendly whiskers at ct* PREFIX: "D --> " You type: "Hi" @@ -301,7 +314,7 @@ characters. Let's add a quirk to our Nepeta: Replace: "ee" With: "33" You type: "*ac saunters from her dark cave a little bit sleepy from the recent kill*" -Result: +Result: AC: :33 < *ac saunters from her dark cave a little bit sl33py from the recent kill* @@ -310,10 +323,10 @@ Replace: "loo" With: "100" Replace: "x" With "%" You type: "look" Result: -CT: D --> 100k +CT: D --> 100k You type: "What are you expecting to accomplish with this" Result: -CT: D --> What are you e%pecting to accomplish with this +CT: D --> What are you e%pecting to accomplish with this Aradia: Replace: "o" With: "0" @@ -356,7 +369,7 @@ Regexp: "(.)" Replace with: "upper(\1)" Three concepts here. Let's look at the regexp. "(.)" has two things going on. The first is that ".". In regexp speak, "." is the wildcard: -it will match *any* character -- and just one. +it will match *any* character -- and just one. The parentheses tell the regexp to *save* what's inside them so you can put it back when you replace. That's what the "\1" is for -- it @@ -385,6 +398,28 @@ either "a" or "A" will be matched and replaced with "4," and likewise, "i" and "I" will be replaced with "1", and "e" and "E" will be replaced with "3." +Just like there is an "upper()" function, there is also a "lower()" +function. It acts just like "upper()" but instead makes everything +inside the parentheses lowercase. This allows you to do things like: + +Regexp: "(.)" Replace with: "lower(\1)" +You type: "I AM YELLING" +Result: +GD: i am yelling + +Along with the upper and lower functions is a "scramble()" function. +The purpose of this function is to randomly scramble anything inside +the parentheses. + +Regexp: "(\w)(\w*)(\w)" Replace with: "\1scramble(\2)\3" +You type: "hello there" +Result: +GD: hlelo trhee + +This particular regular expression scrambles all of the letters in +the middle of a word. Notice that the "h" and "o" at the beginning +and end of hello remain in place while the other letters are scrambled. + You should also know that "^" is a special character in brackets. If placed immediately after the opening bracket (like "[^"), then the brackets instead match every character *except* the ones in the @@ -518,7 +553,7 @@ SMILIES ------- Here's a list of smilies: :rancorous: -:apple: +:apple: :bathearst: :cathearst: :woeful: From 7d46901a6621ba9d5866a1041cd486f43e346bc9 Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Tue, 29 Mar 2011 00:46:24 -0700 Subject: [PATCH 12/13] Attribute original Pesterchum 3.14 and art to proper people. --- CHANGELOG.mkdn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.mkdn b/CHANGELOG.mkdn index 8953c48..193c47f 100644 --- a/CHANGELOG.mkdn +++ b/CHANGELOG.mkdn @@ -8,6 +8,8 @@ Visit https://github.com/illuminatedwax/pesterchum for git access and source cod CHANGELOG --------- ### 3.14b (idk on version number scheme) +* Pesterchum 3.14 - illuminatedwax [ghostDunk] +* Art - Grimlive [aquaMarinist] * Quirks lower() function - Kiooeht [evacipatedBox] * Quirks scrabble() function - Kiooeht [evacipatedBox] * Timestamps - Kiooeht [evacipatedBox] From c466ecf5ac8cefc85f9e1844d5f7bb491748c8c3 Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Tue, 29 Mar 2011 00:53:21 -0700 Subject: [PATCH 13/13] Fix some small bugs I didn't catch before pushing. --- pesterchum.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pesterchum.py b/pesterchum.py index 2e7b2e4..cef7e34 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -820,7 +820,7 @@ class chumArea(RightClickTree): for i in range(self.topLevelItemCount()): if self.topLevelItem(i).text(0) == currentGroup.text(0): break - while self.topLevelItem(i).child(0): + while self.topLevelItem(i) and self.topLevelItem(i).child(0): chumLabel = self.topLevelItem(i).child(0) chumLabel.chum.group = "Chums" self.mainwindow.chumdb.setGroup(chumLabel.chum.handle, "Chums") @@ -2031,8 +2031,8 @@ class PesterWindow(MovingWindow): secondssetting = self.optionmenu.secondscheck.isChecked() self.config.set("showSeconds", secondssetting) # groups - groupssetting = self.optionmenu.groupscheck.isChecked() - self.config.set("useGroups", groupssetting) + #groupssetting = self.optionmenu.groupscheck.isChecked() + #self.config.set("useGroups", groupssetting) emptygroupssetting = self.optionmenu.showemptycheck.isChecked() curemptygroup = self.config.showEmptyGroups() if curemptygroup and not emptygroupssetting: