From fbbcd8d923733efb2370f2626c8ed431c7517c2f Mon Sep 17 00:00:00 2001 From: Kiooeht Date: Sun, 13 Mar 2011 23:29:45 -0700 Subject: [PATCH] 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