/pesterchum.py
Python | 3030 lines | 2959 code | 37 blank | 34 comment | 184 complexity | 47506ef152ea949f18334b2aa8c08a2e MD5 | raw file
Possible License(s): GPL-3.0, Cube
Large files files are truncated, but you can click here to view the full file
- # pesterchum
- import os, shutil, sys, getopt
- if os.path.dirname(sys.argv[0]):
- os.chdir(os.path.dirname(sys.argv[0]))
- import version
- version.pcVerCalc()
- import logging
- from datetime import *
- import random
- import re
- from time import time
- import threading, Queue
- reqmissing = []
- optmissing = []
- try:
- from PyQt4 import QtGui, QtCore
- except ImportError, e:
- module = str(e)
- if module.startswith("No module named ") or \
- module.startswith("cannot import name "):
- reqmissing.append(module[module.rfind(" ")+1:])
- else: print e
- try:
- import pygame
- except ImportError, e:
- pygame = None
- module = str(e)
- if module[:16] == "No module named ": optmissing.append(module[16:])
- else: print e
- if reqmissing:
- print "ERROR: The following modules are required for Pesterchum to run and are missing on your system:"
- for m in reqmissing: print "* "+m
- exit()
- vnum = QtCore.qVersion()
- major = int(vnum[:vnum.find(".")])
- if vnum.find(".", vnum.find(".")+1) != -1:
- minor = int(vnum[vnum.find(".")+1:vnum.find(".", vnum.find(".")+1)])
- else:
- minor = int(vnum[vnum.find(".")+1:])
- if not ((major > 4) or (major == 4 and minor >= 6)):
- print "ERROR: Pesterchum requires Qt version >= 4.6"
- print "You currently have version " + vnum + ". Please ungrade Qt"
- exit()
- import ostools
- # Placed here before importing the rest of pesterchum, since bits of it need
- # OSX's data directory and it doesn't hurt to have everything set up before
- # plowing on. :o)
- # ~Lex
- _datadir = ostools.getDataDir()
- # See, what I've done here is that _datadir is '' if we're not on OSX, so the
- # concatination is the same as if it wasn't there.
- # UPDATE 2011-11-28 <Kiooeht>:
- # Now using data directory as defined by QDesktopServices on all platforms
- # (on Linux, same as using xdg). To stay safe with older versions, copy any
- # data (profiles, logs, etc) from old location to new data directory.
- if _datadir:
- if not os.path.exists(_datadir):
- os.makedirs(_datadir)
- if not os.path.exists(_datadir+"profiles/") and os.path.exists("profiles/"):
- shutil.move("profiles/", _datadir+"profiles/")
- if not os.path.exists(_datadir+"pesterchum.js") and os.path.exists("pesterchum.js"):
- shutil.move("pesterchum.js", _datadir+"pesterchum.js")
- if not os.path.exists(_datadir+"logs/") and os.path.exists("logs/"):
- shutil.move("logs/", _datadir+"logs/")
- if not os.path.exists(_datadir+"profiles"):
- os.mkdir(_datadir+"profiles")
- if not os.path.exists(_datadir+"pesterchum.js"):
- f = open(_datadir+"pesterchum.js", 'w')
- f.write("{}")
- f.close()
- if not os.path.exists(_datadir+"logs"):
- os.mkdir(_datadir+"logs")
- from menus import PesterChooseQuirks, PesterChooseTheme, \
- PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \
- LoadingScreen, AboutPesterchum, UpdatePesterchum, AddChumDialog
- from mood import Mood, PesterMoodAction, PesterMoodHandler, PesterMoodButton
- from dataobjs import PesterProfile, pesterQuirk, pesterQuirks
- from generic import PesterIcon, RightClickList, RightClickTree, \
- MultiTextDialog, PesterList, CaseInsensitiveDict, MovingWindow, \
- NoneSound, WMButton
- from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo
- from parsetools import convertTags, addTimeInitial, themeChecker, ThemeException
- from memos import PesterMemo, MemoTabWindow, TimeTracker
- from irc import PesterIRC
- from logviewer import PesterLogUserSelect, PesterLogViewer
- from bugreport import BugReporter
- from randomer import RandomHandler
- # Rawr, fuck you OSX leopard
- if not ostools.isOSXLeopard():
- from updatecheck import MSPAChecker
- from toast import PesterToastMachine, PesterToast
- from libs import pytwmn
- from profile import *
- canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosToreador", \
- "caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle", \
- "grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist", \
- "twinArmageddons", "terminallyCapricious", "turntechGodhead", "tentacleTherapist"]
- class waitingMessageHolder(object):
- def __init__(self, mainwindow, **msgfuncs):
- self.mainwindow = mainwindow
- self.funcs = msgfuncs
- self.queue = msgfuncs.keys()
- if len(self.queue) > 0:
- self.mainwindow.updateSystemTray()
- def waitingHandles(self):
- return self.queue
- def answerMessage(self):
- func = self.funcs[self.queue[0]]
- func()
- def messageAnswered(self, handle):
- if handle not in self.queue:
- return
- self.queue = [q for q in self.queue if q != handle]
- del self.funcs[handle]
- if len(self.queue) == 0:
- self.mainwindow.updateSystemTray()
- def addMessage(self, handle, func):
- if not self.funcs.has_key(handle):
- self.queue.append(handle)
- self.funcs[handle] = func
- if len(self.queue) > 0:
- self.mainwindow.updateSystemTray()
- def __len__(self):
- return len(self.queue)
- class chumListing(QtGui.QTreeWidgetItem):
- def __init__(self, chum, window):
- QtGui.QTreeWidgetItem.__init__(self, [chum.handle])
- self.mainwindow = window
- self.chum = chum
- self.handle = chum.handle
- self.setMood(Mood("offline"))
- self.status = None
- self.setToolTip(0, "%s: %s" % (chum.handle, window.chumdb.getNotes(chum.handle)))
- def setMood(self, mood):
- if hasattr(self.mainwindow, "chumList") and self.mainwindow.chumList.notify:
- #print "%s -> %s" % (self.chum.mood.name(), mood.name())
- if self.mainwindow.config.notifyOptions() & self.mainwindow.config.SIGNOUT and \
- mood.name() == "offline" and self.chum.mood.name() != "offline":
- #print "OFFLINE NOTIFY: " + self.handle
- uri = self.mainwindow.theme["toasts/icon/signout"]
- n = self.mainwindow.tm.Toast(self.mainwindow.tm.appName,
- "%s is Offline" % (self.handle), uri)
- n.show()
- elif self.mainwindow.config.notifyOptions() & self.mainwindow.config.SIGNIN and \
- mood.name() != "offline" and self.chum.mood.name() == "offline":
- #print "ONLINE NOTIFY: " + self.handle
- uri = self.mainwindow.theme["toasts/icon/signin"]
- n = self.mainwindow.tm.Toast(self.mainwindow.tm.appName,
- "%s is Online" % (self.handle), uri)
- n.show()
- login = False
- logout = False
- if mood.name() == "offline" and self.chum.mood.name() != "offline":
- logout = True
- elif mood.name() != "offline" and self.chum.mood.name() == "offline":
- login = True
- self.chum.mood = mood
- self.updateMood(login=login, logout=logout)
- def setColor(self, color):
- self.chum.color = color
- def updateMood(self, unblock=False, login=False, logout=False):
- mood = self.chum.mood
- self.mood = mood
- icon = self.mood.icon(self.mainwindow.theme)
- if login:
- self.login()
- elif logout:
- self.logout()
- else:
- self.setIcon(0, icon)
- try:
- self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"]))
- except KeyError:
- self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"]))
- def changeTheme(self, theme):
- icon = self.mood.icon(theme)
- self.setIcon(0, icon)
- try:
- self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"]))
- except KeyError:
- self.setTextColor(0, QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"]))
- def login(self):
- self.setIcon(0, PesterIcon("themes/arrow_right.png"))
- self.status = "in"
- QtCore.QTimer.singleShot(5000, self.doneLogin)
- def doneLogin(self):
- icon = self.mood.icon(self.mainwindow.theme)
- self.setIcon(0, icon)
- def logout(self):
- self.setIcon(0, PesterIcon("themes/arrow_left.png"))
- self.status = "out"
- QtCore.QTimer.singleShot(5000, self.doneLogout)
- def doneLogout(self):
- hideoff = self.mainwindow.config.hideOfflineChums()
- icon = self.mood.icon(self.mainwindow.theme)
- self.setIcon(0, icon)
- if hideoff and self.status and self.status == "out":
- self.mainwindow.chumList.takeItem(self)
- def __lt__(self, cl):
- h1 = self.handle.lower()
- h2 = cl.handle.lower()
- return (h1 < h2)
- class chumArea(RightClickTree):
- def __init__(self, chums, parent=None):
- QtGui.QTreeWidget.__init__(self, parent)
- self.notify = False
- QtCore.QTimer.singleShot(30000, self, QtCore.SLOT('beginNotify()'))
- 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]
- self.showAllGroups(True)
- if not self.mainwindow.config.hideOfflineChums():
- self.showAllChums()
- if not self.mainwindow.config.showEmptyGroups():
- self.hideEmptyGroups()
- self.groupMenu = QtGui.QMenu(self)
- self.canonMenu = QtGui.QMenu(self)
- self.optionsMenu = QtGui.QMenu(self)
- self.pester = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self)
- self.connect(self.pester, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('activateChum()'))
- self.removechum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removechum"], self)
- self.connect(self.removechum, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('removeChum()'))
- 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.reportchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self)
- self.connect(self.reportchum, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('reportChum()'))
- self.findalts = QtGui.QAction("Find Alts", self)
- self.connect(self.findalts, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('findAlts()'))
- 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.notes = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/notes"], self)
- self.connect(self.notes, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('editNotes()'))
- self.optionsMenu.addAction(self.pester)
- self.optionsMenu.addAction(self.logchum)
- self.optionsMenu.addAction(self.notes)
- self.optionsMenu.addAction(self.blockchum)
- self.optionsMenu.addAction(self.removechum)
- self.moveMenu = QtGui.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/movechum"], self)
- self.optionsMenu.addMenu(self.moveMenu)
- self.optionsMenu.addAction(self.reportchum)
- self.moveGroupMenu()
- self.groupMenu.addAction(self.renamegroup)
- self.groupMenu.addAction(self.removegroup)
- self.canonMenu.addAction(self.pester)
- self.canonMenu.addAction(self.logchum)
- self.canonMenu.addAction(self.blockchum)
- self.canonMenu.addAction(self.removechum)
- self.canonMenu.addMenu(self.moveMenu)
- self.canonMenu.addAction(self.reportchum)
- self.canonMenu.addAction(self.findalts)
- self.initTheme(theme)
- #self.sortItems()
- #self.sortItems(1, QtCore.Qt.AscendingOrder)
- self.setSortingEnabled(False)
- self.header().hide()
- self.setDropIndicatorShown(True)
- self.setIndentation(4)
- self.setDragEnabled(True)
- self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
- self.setAnimated(True)
- self.setRootIsDecorated(False)
- self.connect(self, QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'),
- self, QtCore.SLOT('expandGroup()'))
- @QtCore.pyqtSlot()
- def beginNotify(self):
- print "BEGIN NOTIFY"
- self.notify = True
- def getOptionsMenu(self):
- if not self.currentItem():
- return None
- text = unicode(self.currentItem().text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- if text == "Chums":
- return None
- elif text in self.groups:
- return self.groupMenu
- else:
- currenthandle = self.currentItem().chum.handle
- if currenthandle in canon_handles:
- return self.canonMenu
- else:
- return self.optionsMenu
- def startDrag(self, dropAction):
- # create mime data object
- mime = QtCore.QMimeData()
- mime.setData('application/x-item', '???')
- # start drag
- drag = QtGui.QDrag(self)
- drag.setMimeData(mime)
- drag.start(QtCore.Qt.MoveAction)
- def dragMoveEvent(self, event):
- if event.mimeData().hasFormat("application/x-item"):
- event.setDropAction(QtCore.Qt.MoveAction)
- event.accept()
- else:
- event.ignore()
- def dragEnterEvent(self, event):
- if (event.mimeData().hasFormat('application/x-item')):
- event.accept()
- else:
- event.ignore()
- def dropEvent(self, event):
- if (event.mimeData().hasFormat('application/x-item')):
- event.acceptProposedAction()
- else:
- event.ignore()
- return
- thisitem = str(event.source().currentItem().text(0))
- if thisitem.rfind(" (") != -1:
- thisitem = thisitem[0:thisitem.rfind(" (")]
- # Drop item is a group
- thisitem = unicode(event.source().currentItem().text(0))
- if thisitem.rfind(" (") != -1:
- thisitem = thisitem[0:thisitem.rfind(" (")]
- if thisitem == "Chums" or thisitem in self.groups:
- droppos = self.itemAt(event.pos())
- if not droppos: return
- droppos = unicode(droppos.text(0))
- if droppos.rfind(" ") != -1:
- droppos = droppos[0:droppos.rfind(" ")]
- if droppos == "Chums" or droppos in self.groups:
- saveOpen = event.source().currentItem().isExpanded()
- saveDrop = self.itemAt(event.pos())
- saveItem = self.takeTopLevelItem(self.indexOfTopLevelItem(event.source().currentItem()))
- self.insertTopLevelItems(self.indexOfTopLevelItem(saveDrop)+1, [saveItem])
- if saveOpen:
- saveItem.setExpanded(True)
- gTemp = []
- for i in range(self.topLevelItemCount()):
- text = unicode(self.topLevelItem(i).text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- gTemp.append([unicode(text), self.topLevelItem(i).isExpanded()])
- self.mainwindow.config.saveGroups(gTemp)
- # Drop item is a chum
- else:
- item = self.itemAt(event.pos())
- if item:
- text = unicode(item.text(0))
- # Figure out which group to drop into
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- if text == "Chums" or text in self.groups:
- group = text
- gitem = item
- else:
- ptext = unicode(item.parent().text(0))
- if ptext.rfind(" ") != -1:
- ptext = ptext[0:ptext.rfind(" ")]
- group = ptext
- gitem = item.parent()
- chumLabel = event.source().currentItem()
- chumLabel.chum.group = group
- self.mainwindow.chumdb.setGroup(chumLabel.chum.handle, group)
- self.takeItem(chumLabel)
- # Using manual chum reordering
- if self.mainwindow.config.sortMethod() == 2:
- insertIndex = gitem.indexOfChild(item)
- if insertIndex == -1:
- insertIndex = 0
- gitem.insertChild(insertIndex, chumLabel)
- chums = self.mainwindow.config.chums()
- if item == gitem:
- item = gitem.child(0)
- inPos = chums.index(str(item.text(0)))
- if chums.index(thisitem) < inPos:
- inPos -= 1
- chums.remove(thisitem)
- chums.insert(inPos, unicode(thisitem))
- self.mainwindow.config.setChums(chums)
- else:
- self.addItem(chumLabel)
- if self.mainwindow.config.showOnlineNumbers():
- self.showOnlineNumbers()
- def moveGroupMenu(self):
- currentGroup = self.currentItem()
- if currentGroup:
- if currentGroup.parent():
- text = unicode(currentGroup.parent().text(0))
- else:
- text = unicode(currentGroup.text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- currentGroup = text
- self.moveMenu.clear()
- actGroup = QtGui.QActionGroup(self)
- groups = self.groups[:]
- 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 addChum(self, chum):
- 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
- chum.mood.name() == "offline"):
- chumLabel = chumListing(chum, self.mainwindow)
- self.addItem(chumLabel)
- #self.topLevelItem(0).addChild(chumLabel)
- #self.topLevelItem(0).sortChildren(0, QtCore.Qt.AscendingOrder)
- def getChums(self, handle):
- chums = self.findItems(handle, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
- return chums
- def showAllChums(self):
- for c in self.chums:
- chandle = c.handle
- if not len(self.findItems(chandle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive)):
- chumLabel = chumListing(c, self.mainwindow)
- self.addItem(chumLabel)
- self.sort()
- 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.sort()
- def showAllGroups(self, first=False):
- if first:
- for i,g in enumerate(self.groups):
- child_1 = QtGui.QTreeWidgetItem(["%s" % (g)])
- self.addTopLevelItem(child_1)
- if self.openGroups[i]:
- child_1.setExpanded(True)
- return
- curgroups = []
- for i in range(self.topLevelItemCount()):
- text = unicode(self.topLevelItem(i).text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- curgroups.append(text)
- for i,g in enumerate(self.groups):
- if g not in curgroups:
- child_1 = QtGui.QTreeWidgetItem(["%s" % (g)])
- j = 0
- for h in self.groups:
- if h == g:
- self.insertTopLevelItem(j, child_1)
- break
- if h in curgroups:
- j += 1
- if self.openGroups[i]:
- child_1.setExpanded(True)
- if self.mainwindow.config.showOnlineNumbers():
- self.showOnlineNumbers()
- def showOnlineNumbers(self):
- if hasattr(self, 'groups'):
- self.hideOnlineNumbers()
- totals = {'Chums': 0}
- online = {'Chums': 0}
- for g in self.groups:
- totals[unicode(g)] = 0
- online[unicode(g)] = 0
- for c in self.chums:
- yes = c.mood.name() != "offline"
- if c.group == "Chums":
- totals[unicode(c.group)] = totals[unicode(c.group)]+1
- if yes:
- online[unicode(c.group)] = online[unicode(c.group)]+1
- elif c.group in totals:
- totals[unicode(c.group)] = totals[unicode(c.group)]+1
- if yes:
- online[unicode(c.group)] = online[unicode(c.group)]+1
- else:
- totals["Chums"] = totals["Chums"]+1
- if yes:
- online["Chums"] = online["Chums"]+1
- for i in range(self.topLevelItemCount()):
- text = unicode(self.topLevelItem(i).text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- if text in online:
- self.topLevelItem(i).setText(0, "%s (%i/%i)" % (text, online[text], totals[text]))
- def hideOnlineNumbers(self):
- for i in range(self.topLevelItemCount()):
- text = unicode(self.topLevelItem(i).text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- self.topLevelItem(i).setText(0, "%s" % (text))
- def hideEmptyGroups(self):
- i = 0
- listing = self.topLevelItem(i)
- while listing is not None:
- if listing.childCount() == 0:
- self.takeTopLevelItem(i)
- else:
- i += 1
- listing = self.topLevelItem(i)
- @QtCore.pyqtSlot()
- def expandGroup(self):
- item = self.currentItem()
- text = unicode(item.text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- if text in self.groups:
- expand = item.isExpanded()
- self.mainwindow.config.expandGroup(text, not expand)
- def addItem(self, chumLabel):
- if hasattr(self, 'groups'):
- if chumLabel.chum.group not in self.groups:
- chumLabel.chum.group = "Chums"
- if "Chums" not in self.groups:
- self.mainwindow.config.addGroup("Chums")
- curgroups = []
- for i in range(self.topLevelItemCount()):
- text = unicode(self.topLevelItem(i).text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- curgroups.append(text)
- if not self.findItems(chumLabel.handle, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive):
- if chumLabel.chum.group not in curgroups:
- child_1 = QtGui.QTreeWidgetItem(["%s" % (chumLabel.chum.group)])
- i = 0
- for g in self.groups:
- if g == chumLabel.chum.group:
- self.insertTopLevelItem(i, child_1)
- break
- if g in curgroups:
- i += 1
- if self.openGroups[self.groups.index("%s" % (chumLabel.chum.group))]:
- child_1.setExpanded(True)
- for i in range(self.topLevelItemCount()):
- text = unicode(self.topLevelItem(i).text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- if text == chumLabel.chum.group:
- break
- # Manual sorting
- if self.mainwindow.config.sortMethod() == 2:
- chums = self.mainwindow.config.chums()
- if chumLabel.chum.handle in chums:
- fi = chums.index(chumLabel.chum.handle)
- else:
- fi = 0
- c = 1
- # TODO: Rearrange chums list on drag-n-drop
- bestj = 0
- bestname = ""
- if fi > 0:
- while not bestj:
- for j in xrange(self.topLevelItem(i).childCount()):
- if chums[fi-c] == str(self.topLevelItem(i).child(j).text(0)):
- bestj = j
- bestname = chums[fi-c]
- break
- c += 1
- if fi-c < 0:
- break
- if bestname:
- self.topLevelItem(i).insertChild(bestj+1, chumLabel)
- else:
- self.topLevelItem(i).insertChild(bestj, chumLabel)
- #sys.exit(0)
- self.topLevelItem(i).addChild(chumLabel)
- else: # All other sorting
- self.topLevelItem(i).addChild(chumLabel)
- self.sort()
- if self.mainwindow.config.showOnlineNumbers():
- self.showOnlineNumbers()
- 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
- if not hasattr(chumLabel, 'chum'):
- return r
- 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()
- if self.mainwindow.config.showOnlineNumbers():
- self.showOnlineNumbers()
- return r
- def updateMood(self, handle, mood):
- hideoff = self.mainwindow.config.hideOfflineChums()
- chums = self.getChums(handle)
- oldmood = None
- if hideoff:
- if mood.name() != "offline" and \
- len(chums) == 0 and \
- 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()
- chums = [newLabel]
- elif mood.name() == "offline" and \
- len(chums) > 0:
- for c in chums:
- if (hasattr(c, 'mood')):
- c.setMood(mood)
- #self.takeItem(c)
- chums = []
- for c in chums:
- if (hasattr(c, 'mood')):
- oldmood = c.mood
- c.setMood(mood)
- if self.mainwindow.config.sortMethod() == 1:
- for i in range(self.topLevelItemCount()):
- saveCurrent = self.currentItem()
- self.moodSort(i)
- self.setCurrentItem(saveCurrent)
- if self.mainwindow.config.showOnlineNumbers():
- self.showOnlineNumbers()
- return oldmood
- def updateColor(self, handle, color):
- chums = self.findItems(handle, QtCore.Qt.MatchFlags(0))
- for c in chums:
- c.setColor(color)
- def initTheme(self, theme):
- self.resize(*theme["main/chums/size"])
- self.move(*theme["main/chums/loc"])
- if theme.has_key("main/chums/scrollbar"):
- self.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["main/chums/style"], theme["main/chums/scrollbar/style"], theme["main/chums/scrollbar/handle"], theme["main/chums/scrollbar/downarrow"], theme["main/chums/scrollbar/uparrow"], theme["main/chums/scrollbar/uarrowstyle"], theme["main/chums/scrollbar/darrowstyle"] ))
- else:
- self.setStyleSheet(theme["main/chums/style"])
- 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"])
- self.reportchum.setText(theme["main/menus/rclickchumlist/report"])
- self.notes.setText(theme["main/menus/rclickchumlist/notes"])
- 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 = []
- 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
- def sort(self):
- if self.mainwindow.config.sortMethod() == 2:
- pass # Do nothing!!!!! :OOOOOOO It's manual, bitches
- elif self.mainwindow.config.sortMethod() == 1:
- for i in range(self.topLevelItemCount()):
- self.moodSort(i)
- else:
- for i in range(self.topLevelItemCount()):
- self.topLevelItem(i).sortChildren(0, QtCore.Qt.AscendingOrder)
- def moodSort(self, group):
- scrollPos = self.verticalScrollBar().sliderPosition()
- chums = []
- listing = self.topLevelItem(group).child(0)
- while listing is not None:
- chums.append(self.topLevelItem(group).takeChild(0))
- listing = self.topLevelItem(group).child(0)
- chums.sort(key=lambda x: ((999 if x.chum.mood.value() == 2 else x.chum.mood.value()), x.chum.handle), reverse=False)
- for c in chums:
- self.topLevelItem(group).addChild(c)
- self.verticalScrollBar().setSliderPosition(scrollPos)
- @QtCore.pyqtSlot()
- def activateChum(self):
- self.itemActivated.emit(self.currentItem(), 0)
- @QtCore.pyqtSlot()
- def removeChum(self, handle = None):
- if handle:
- clistings = self.getChums(handle)
- if len(clistings) <= 0: return
- for c in clistings:
- self.setCurrentItem(c)
- if not self.currentItem():
- return
- 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.currentItem())
- del oldlist
- @QtCore.pyqtSlot()
- def blockChum(self):
- currentChum = self.currentItem()
- if not currentChum:
- return
- self.blockChumSignal.emit(self.currentItem().chum.handle)
- @QtCore.pyqtSlot()
- def reportChum(self):
- currentChum = self.currentItem()
- if not currentChum:
- return
- self.mainwindow.reportChum(self.currentItem().chum.handle)
- @QtCore.pyqtSlot()
- def findAlts(self):
- currentChum = self.currentItem()
- if not currentChum:
- return
- self.mainwindow.sendMessage.emit("ALT %s" % (currentChum.chum.handle) , "calSprite")
- @QtCore.pyqtSlot()
- def openChumLogs(self):
- currentChum = self.currentItem()
- if not currentChum:
- return
- currentChum = currentChum.text(0)
- 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
- @QtCore.pyqtSlot()
- def editNotes(self):
- currentChum = self.currentItem()
- if not currentChum:
- return
- (notes, ok) = QtGui.QInputDialog.getText(self, "Notes", "Enter your notes...")
- if ok:
- notes = unicode(notes)
- self.mainwindow.chumdb.setNotes(currentChum.handle, notes)
- currentChum.setToolTip(0, "%s: %s" % (currentChum.handle, notes))
- @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)
- if re.search("[^A-Za-z0-9_\s]", gname) is not None:
- msgbox = QtGui.QMessageBox()
- msgbox.setInformativeText("THIS IS NOT A VALID GROUP NAME")
- msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
- ret = msgbox.exec_()
- self.addgroupdialog = None
- return
- currentGroup = self.currentItem()
- if not currentGroup:
- return
- index = self.indexOfTopLevelItem(currentGroup)
- if index != -1:
- expanded = currentGroup.isExpanded()
- text = unicode(currentGroup.text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- self.mainwindow.config.delGroup(text)
- 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)
- if self.mainwindow.config.showOnlineNumbers():
- self.showOnlineNumbers()
- self.renamegroupdialog = None
- @QtCore.pyqtSlot()
- def removeGroup(self):
- currentGroup = self.currentItem()
- if not currentGroup:
- return
- text = unicode(currentGroup.text(0))
- if text.rfind(" (") != -1:
- text = text[0:text.rfind(" (")]
- self.mainwindow.config.delGroup(text)
- gTemp = self.mainwindow.config.getGroups()
- self.groups = [g[0] for g in gTemp]
- self.openGroups = [g[1] for g in gTemp]
- for c in self.chums:
- if c.group == text:
- c.group = "Chums"
- self.mainwindow.chumdb.setGroup(c.handle, "Chums")
- for i in range(self.topLevelItemCount()):
- if self.topLevelItem(i).text(0) == currentGroup.text(0):
- break
- while self.topLevelItem(i) and self.topLevelItem(i).child(0):
- chumLabel = self.topLevelItem(i).child(0)
- self.takeItem(chumLabel)
- self.addItem(chumLabel)
- self.takeTopLevelItem(i)
- @QtCore.pyqtSlot(QtGui.QAction)
- def moveToGroup(self, item):
- if not item:
- return
- group = unicode(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)
- class trollSlum(chumArea):
- def __init__(self, trolls, mainwindow, parent=None):
- QtGui.QListWidget.__init__(self, parent)
- self.mainwindow = mainwindow
- 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()
- 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"])
- self.unblockchum.setText(theme["main/menus/rclickchumlist/blockchum"])
- chumlistings = [self.item(i) for i in range(0, self.count())]
- for c in chumlistings:
- c.changeTheme(theme)
- unblockChumSignal = QtCore.pyqtSignal(QtCore.QString)
- class TrollSlumWindow(QtGui.QFrame):
- def __init__(self, trolls, mainwindow, parent=None):
- QtGui.QFrame.__init__(self, parent)
- self.mainwindow = mainwindow
- theme = self.mainwindow.theme
- self.slumlabel = QtGui.QLabel(self)
- self.initTheme(theme)
- self.trollslum = trollSlum(trolls, self.mainwindow, self)
- self.connect(self.trollslum, QtCore.SIGNAL('unblockChumSignal()'),
- self, QtCore.SLOT('removeCurrentTroll()'))
- layout_1 = QtGui.QHBoxLayout()
- self.addButton = QtGui.QPushButton("ADD", self)
- self.connect(self.addButton, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('addTrollWindow()'))
- self.removeButton = QtGui.QPushButton("REMOVE", self)
- self.connect(self.removeButton, QtCore.SIGNAL('clicked()'),
- self, QtCore.SLOT('removeCurrentTroll()'))
- layout_1.addWidget(self.addButton)
- layout_1.addWidget(self.removeButton)
- layout_0 = QtGui.QVBoxLayout()
- layout_0.addWidget(self.slumlabel)
- layout_0.addWidget(self.trollslum)
- layout_0.addLayout(layout_1)
- self.setLayout(layout_0)
- def initTheme(self, theme):
- self.resize(*theme["main/trollslum/size"])
- self.setStyleSheet(theme["main/trollslum/style"])
- self.slumlabel.setText(theme["main/trollslum/label/text"])
- self.slumlabel.setStyleSheet(theme["main/trollslum/label/style"])
- if not self.parent():
- self.setWindowTitle(theme["main/menus/profile/block"])
- self.setWindowIcon(self.mainwindow.windowIcon())
- def changeTheme(self, theme):
- self.initTheme(theme)
- self.trollslum.changeTheme(theme)
- # move unblocked trolls from slum to chumarea
- def closeEvent(self, event):
- self.mainwindow.closeTrollSlum()
- def updateMood(self, handle, mood):
- self.trollslum.updateMood(handle, mood)
- def addTroll(self, chum):
- self.trollslum.addChum(chum)
- def removeTroll(self, handle):
- self.trollslum.removeChum(handle)
- @QtCore.pyqtSlot()
- def removeCurrentTroll(self):
- currentListing = self.trollslum.currentItem()
- if not currentListing or not hasattr(currentListing, 'chum'):
- return
- self.unblockChumSignal.emit(currentListing.chum.handle)
- @QtCore.pyqtSlot()
- def addTrollWindow(self):
- if not hasattr(self, 'addtrolldialog'):
- self.addtrolldialog = None
- if self.addtrolldialog:
- return
- self.addtrolldialog = QtGui.QInputDialog(self)
- (handle, ok) = self.addtrolldialog.getText(self, "Add Troll", "Enter Troll Handle:")
- if ok:
- handle = unicode(handle)
- if not (PesterProfile.checkLength(handle) and
- PesterProfile.checkValid(handle)[0]):
- errormsg = QtGui.QErrorMessage(self)
- errormsg.showMessage("THIS IS NOT A VALID CHUMTAG!")
- self.addchumdialog = None
- return
- self.blockChumSignal.emit(handle)
- self.addtrolldialog = None
- blockChumSignal = QtCore.pyqtSignal(QtCore.QString)
- unblockChumSignal = QtCore.pyqtSignal(QtCore.QString)
- class PesterWindow(MovingWindow):
- def __init__(self, options, parent=None):
- MovingWindow.__init__(self, parent,
- (QtCore.Qt.CustomizeWindowHint |
- QtCore.Qt.FramelessWindowHint))
- self.convos = CaseInsensitiveDict()
- self.memos = CaseInsensitiveDict()
- self.tabconvo = None
- self.tabmemo = None
- if "advanced" in options:
- self.advanced = options["advanced"]
- else: self.advanced = False
- if "server" in options:
- self.serverOverride = options["server"]
- if "port" in options:
- self.portOverride = options["port"]
- if "honk" in options:
- self.honk = options["honk"]
- else: self.honk = True
- self.setAutoFillBackground(True)
- self.setObjectName("main")
- self.config = userConfig(self)
- if self.config.defaultprofile():
- self.userprofile = userProfile(self.config.defaultprofile())
- self.theme = self.userprofile.getTheme()
- else:
- self.userprofile = userProfile(PesterProfile("pesterClient%d" % (random.randint(100,999)), QtGui.QColor("black"), Mood(0)))
- self.theme = self.userprofile.getTheme()
- self.modes = ""
- self.randhandler = RandomHandler(self)
- try:
- themeChecker(self.theme)
- except ThemeException, (inst):
- print "Caught: "+inst.parameter
- themeWarning = QtGui.QMessageBox(self)
- themeWarning.setText("Theme Error: %s" % (inst))
- themeWarning.exec_()
- self.theme = pesterTheme("pesterchum")
- extraToasts = {'default': PesterToast}
- if pytwmn.confExists():
- extraToasts['twmn'] = pytwmn.Notification
- self.tm = PesterToastMachine(self, lambda: self.theme["main/windowtitle"], on=self.config.notify(),
- type=self.config.notifyType(), extras=extraToasts)
- self.tm.run()
- self.chatlog = PesterLog(self.profile().handle, self)
- self.move(100, 100)
- talk = QtGui.QAction(self.theme["main/menus/client/talk"], self)
- self.talk = talk
- self.connect(talk, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('openChat()'))
- logv = QtGui.QAction(self.theme["main/menus/client/logviewer"], self)
- 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()'))
- self.rand = QtGui.QAction(self.theme["main/menus/client/randen"], self)
- self.connect(self.rand, QtCore.SIGNAL('triggered()'),
- self.randhandler, QtCore.SLOT('getEncounter()'))
- opts = QtGui.QAction(self.theme["main/menus/client/options"], self)
- self.opts = opts
- self.connect(opts, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('openOpts()'))
- exitaction = QtGui.QAction(self.theme["main/menus/client/exit"], self)
- self.exitaction = exitaction
- self.connect(exitaction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('close()'))
- userlistaction = QtGui.QAction(self.theme["main/menus/client/userlist"], self)
- self.userlistaction = userlistaction
- self.connect(userlistaction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('showAllUsers()'))
- memoaction = QtGui.QAction(self.theme["main/menus/client/memos"], self)
- self.memoaction = memoaction
- self.connect(memoaction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('showMemos()'))
- self.importaction = QtGui.QAction(self.theme["main/menus/client/import"], self)
- self.connect(self.importaction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('importExternalConfig()'))
- self.idleaction = QtGui.QAction(self.theme["main/menus/client/idle"], self)
- self.idleaction.setCheckable(True)
- self.connect(self.idleaction, QtCore.SIGNAL('toggled(bool)'),
- self, QtCore.SLOT('toggleIdle(bool)'))
- self.reconnectAction = QtGui.QAction(self.theme["main/menus/client/reconnect"], self)
- self.connect(self.reconnectAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SIGNAL('reconnectIRC()'))
- self.menu = QtGui.QMenuBar(self)
- self.menu.setNativeMenuBar(False)
- filemenu = self.menu.addMenu(self.theme["main/menus/client/_name"])
- self.filemenu = filemenu
- filemenu.addAction(opts)
- filemenu.addAction(memoaction)
- filemenu.addAction(logv)
- filemenu.addAction(self.rand)
- if not self.randhandler.running:
- self.rand.setEnabled(False)
- filemenu.addAction(userlistaction)
- filemenu.addAction(talk)
- filemenu.addAction(self.idleaction)
- filemenu.addAction(grps)
- filemenu.addAction(self.importaction)
- filemenu.addAction(self.reconnectAction)
- filemenu.addAction(exitaction)
- changequirks = QtGui.QAction(self.theme["main/menus/profile/quirks"], self)
- self.changequirks = changequirks
- self.connect(changequirks, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('openQuirks()'))
- loadslum = QtGui.QAction(self.theme["main/menus/profile/block"], self)
- self.loadslum = loadslum
- self.connect(loadslum, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('showTrollSlum()'))
- changecoloraction = QtGui.QAction(self.theme["main/menus/profile/color"], self)
- self.changecoloraction = changecoloraction
- self.connect(changecoloraction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('changeMyColor()'))
- switch = QtGui.QAction(self.theme["main/menus/profile/switch"], self)
- self.switch = switch
- self.connect(switch, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('switchProfile()'))
- profilemenu = self.menu.addMenu(self.theme["main/menus/profile/_name"])
- self.profilemenu = profilemenu
- profilemenu.addAction(changequirks)
- profilemenu.addAction(loadslum)
- profilemenu.addAction(changecoloraction)
- profilemenu.addAction(switch)
- self.helpAction = QtGui.QAction(self.theme["main/menus/help/help"], self)
- self.connect(self.helpAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('launchHelp()'))
- self.botAction = QtGui.QAction(self.theme["main/menus/help/calsprite"], self)
- self.connect(self.botAction, QtCore.SIGNAL('triggered()'),
- self, QtCore.SLOT('loadCalsprite()'))
- self.nickServAction = QtGui.QAction(self.theme["main/menus/help/nickserv"], self)
- self.connect(self.nickServAction, QtCore.SIGNAL('triggered()'),
- …
Large files files are truncated, but you can click here to view the full file