From 06bcad0ca0734de6a7c76c03675a92541191dac6 Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Fri, 11 Mar 2011 23:44:59 -0800 Subject: [PATCH] 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)'),