pesterchum/pesterchum.py

3948 lines
168 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
import sys
import os
import shutil
import getopt
2021-12-01 12:29:17 -05:00
import configparser
# Python 3
QString = str
2021-03-23 17:36:43 -04:00
2011-11-20 17:42:49 -05:00
if os.path.dirname(sys.argv[0]):
os.chdir(os.path.dirname(sys.argv[0]))
print("Usage: pesterchum.py [OPTIONS]")
2021-12-01 12:38:51 -05:00
print("Use -h/--help to see the available options.\nLogging is configured in logging.ini")
# Help
if ('--help' in sys.argv[1:]) or ('-h' in sys.argv[1:]):
print("Possible arguments:")
help_arguments = (" -l, --logging\n Specify level of logging, possible values are:\n"
+ " CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET.\n"
+ " The default value is WARNING.\n"
+ " (See https://docs.python.org/3/library/logging.html)\n\n"
+ " -s, --server\n Specify server override. (legacy)\n\n"
+ " -p, --port\n Specify port override. (legacy)\n\n"
+ " --advanced\n Enable advanced.\n\n"
+ " --no-honk\n Disable honking.\n")
print(help_arguments)
sys.exit()
2021-12-01 12:29:17 -05:00
import logging
import logging.config
from datetime import timedelta
2011-01-27 21:21:02 -05:00
import random
import re
from time import time
try:
import json
except:
pass
from pnc.dep.attrdict import AttrDict
reqmissing = []
optmissing = []
try:
2021-05-03 11:22:23 -04:00
from PyQt5 import QtCore, QtGui, QtWidgets
except ImportError as e:
module = str(e)
if module.startswith("No module named ") or \
module.startswith("cannot import name "):
reqmissing.append(module[module.rfind(" ")+1:])
2021-12-01 12:29:17 -05:00
else: logging.critical(e)
del module
# Because pygame intro msg :3c
# See https://stackoverflow.com/questions/54246668/how-do-i-delete-the-hello-from-the-pygame-community-console-alert-while-using
try:
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
except:
logging.exception("Failed to set PYGAME_HIDE_SUPPORT_PROMPT, this is a non-issue.")
try:
import pygame
except ImportError as e:
pygame = None
module = str(e)
if module[:16] == "No module named ": optmissing.append(module[16:])
2021-12-01 12:29:17 -05:00
else: logging.critical(e)
del module
if reqmissing:
2021-12-01 12:29:17 -05:00
logging.critical("ERROR: The following modules are required for Pesterchum to run and are missing on your system:")
for m in reqmissing: logging.critical("* "+m)
2021-03-23 17:36:43 -04:00
# False flag for some reason.
#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 > 5) or (major == 5 and minor >= 0)):
2021-12-01 12:29:17 -05:00
logging.critical("ERROR: Pesterchum requires at least Qt version >= 5.0")
logging.critical("You currently have version " + vnum + ". Please upgrade 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()
2022-03-25 19:37:01 -04:00
if not os.path.isdir(_datadir):
os.makedirs(_datadir)
# 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.
2011-11-29 00:15:19 -05:00
# 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.
2021-12-01 12:29:17 -05:00
config = configparser.ConfigParser()
# Create logging.ini
#if os.path.exists(_datadir + "logging.ini") == False:
try:
config.read(_datadir + 'logging.ini')
2021-12-01 12:29:17 -05:00
# Test load
logging.config.fileConfig(_datadir + "logging.ini")
PchumLog = logging.getLogger('pchumLogger')
except:
#config.read('logging.ini.example')
config = configparser.ConfigParser()
# Default setup
config['loggers'] = {'keys': 'root,pchumLogger'}
config['handlers'] = {'keys': 'consoleHandler,FileHandler'}
config['formatters'] = {'keys': 'simpleFormatter'}
config['logger_root'] = {'level': 'WARNING',
'handlers': 'consoleHandler'}
config['handler_consoleHandler'] = {'class': 'StreamHandler',
'level': 'WARNING',
'formatter': 'simpleFormatter',
'args': '(sys.stdout,)'}
config['handler_FileHandler'] = {'class': 'FileHandler',
'level': 'WARNING',
'formatter': 'simpleFormatter'}
config['logger_pchumLogger'] = {'level': 'WARNING',
'handlers': 'consoleHandler,FileHandler',
'qualname': 'pchumLogger',
'propagate': '0'}
config['formatter_simpleFormatter'] = {'format': '%(levelname)s - %(module)s - %(message)s',
'datefmt': ''}
2021-12-01 12:29:17 -05:00
# Enable file logging
config['handlers']['keys'] = 'consoleHandler,FileHandler'
config['logger_pchumLogger']['handlers'] = 'consoleHandler,FileHandler'
#(r'C:\Users\X\AppData\Local\pesterchum\pesterchum.log', 'a')
config['handler_FileHandler'] = {'class': 'FileHandler',
'level': 'WARNING',
'formatter': 'simpleFormatter',
'args': (_datadir + 'pesterchum.log', 'a')}
print(config.sections())
2021-12-01 12:29:17 -05:00
loglevel = "30"# Warning (Default)
if ('--logging' in sys.argv[1:]) or ('-l' in sys.argv[1:]) & (False == ('--logging' in sys.argv[1:]) and ('-l' in sys.argv[1:])):
try:
# If both are specified, this does not run.
if ('-l' in sys.argv[1:]):
loglevel = sys.argv[sys.argv.index('-l') + 1]
if ('--logging' in sys.argv[1:]):
loglevel = sys.argv[sys.argv.index('--logging') + 1]
loglevel = loglevel.upper().strip()
config.read(_datadir + 'logging.ini')
print("loglevel = " + loglevel)
if loglevel == "50" or loglevel == "CRITICAL":
loglevel = "CRITICAL"
print("Logging Level is CRITICAL")
elif loglevel == "40" or loglevel == "ERROR":
loglevel = "ERROR"
print("Logging Level is ERROR")
elif loglevel == "30" or loglevel == "WARNING":
loglevel = "WARNING"
print("Logging Level is WARNING")
elif loglevel == "20" or loglevel == "INFO":
loglevel = "INFO"
print("Logging Level is INFO")
elif loglevel == "10" or loglevel == "DEBUG":
loglevel = "DEBUG"
print("Logging Level is DEBUG")
elif loglevel == "0" or loglevel == "NOTSET":
loglevel = "NOTSET"
print("Logging Level is NOTSET")
else:
loglevel = "WARNING"
print("Logging Level is WARNING")
config['logger_root']['level'] = loglevel
config['logger_pchumLogger']['level'] = loglevel
config['handler_consoleHandler']['level'] = loglevel
2021-12-01 12:38:51 -05:00
config['handler_FileHandler']['level'] = loglevel
2021-12-01 12:29:17 -05:00
# Remove from argv because the rest of the code can't handle it :/
if ('-l' in sys.argv[1:]):
sys.argv.pop(sys.argv.index('-l') + 1)
sys.argv.pop(sys.argv.index('-l'))
if ('--logging' in sys.argv[1:]):
sys.argv.pop(sys.argv.index('--logging') + 1)
sys.argv.pop(sys.argv.index('--logging'))
except:
logging.exception("Invalid syntax?")
2022-04-13 09:29:42 -04:00
# Update logging.ini
2021-12-01 12:29:17 -05:00
with open(_datadir + "logging.ini", 'w') as configfile:
config.write(configfile)
2022-04-13 09:29:42 -04:00
# Load logging.ini
2021-12-01 12:29:17 -05:00
logging.config.fileConfig(_datadir + "logging.ini")
PchumLog = logging.getLogger('pchumLogger')
try:
import console
_CONSOLE = True
2021-12-01 12:29:17 -05:00
except ImportError:
_CONSOLE = False
logging.warning("Console file not shipped; skipping.")
2021-07-29 15:42:46 -04:00
2011-11-29 00:15:19 -05:00
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")
2011-03-02 18:36:10 -05:00
2022-04-13 09:29:42 -04:00
from profile import userConfig, userProfile, pesterTheme, PesterLog, \
PesterProfileDB
from menus import PesterChooseQuirks, PesterChooseTheme, \
PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \
2011-10-24 20:24:40 -04:00
LoadingScreen, AboutPesterchum, UpdatePesterchum, AddChumDialog
from mood import Mood, PesterMoodAction, PesterMoodHandler, PesterMoodButton
from dataobjs import PesterProfile, pesterQuirk, pesterQuirks
from generic import PesterIcon, RightClickTree, \
PesterList, CaseInsensitiveDict, MovingWindow, \
NoneSound, WMButton
from convo import PesterTabWindow, PesterConvo
from parsetools import convertTags, addTimeInitial, themeChecker, ThemeException
from memos import PesterMemo, MemoTabWindow, TimeTracker
from irc import PesterIRC
from logviewer import PesterLogUserSelect, PesterLogViewer
2014-01-12 02:33:33 -05:00
from randomer import RandomHandler, RANDNICK
2014-01-12 03:14:16 -05:00
import nickservmsgs
# Rawr, fuck you OSX leopard
#if not ostools.isOSXLeopard():
# from updatecheck import MSPAChecker
from toast import PesterToastMachine, PesterToast
2021-03-24 17:34:55 -04:00
import pytwmn
#canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosToreador", \
# "caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle", \
# "grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist", \
# "twinArmageddons", "terminallyCapricious", "turntechGodhead", "tentacleTherapist"]
canon_handles = ["",]# Unused, kept to prevent unexpected calls causing a crash.
CUSTOMBOTS = ["CALSPRITE", RANDNICK.upper()]
BOTNAMES = ["NICKSERV", "CHANSERV", "MEMOSERV", "OPERSERV", "HELPSERV", "HOSTSERV", "BOTSERV"]
BOTNAMES.extend(CUSTOMBOTS)
# Save the main app. From here, we should be able to get everything else in
# order, for console use.
_CONSOLE_ENV = AttrDict()
_CONSOLE_ENV.PAPP = None
class waitingMessageHolder(object):
def __init__(self, mainwindow, **msgfuncs):
self.mainwindow = mainwindow
self.funcs = msgfuncs
2021-03-23 17:36:43 -04:00
self.queue = list(msgfuncs.keys())
if len(self.queue) > 0:
self.mainwindow.updateSystemTray()
2011-02-10 13:00:06 -05:00
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):
2021-03-23 17:36:43 -04:00
if handle not in self.funcs:
self.queue.append(handle)
self.funcs[handle] = func
if len(self.queue) > 0:
self.mainwindow.updateSystemTray()
def __len__(self):
return len(self.queue)
2021-03-23 17:36:43 -04:00
class chumListing(QtWidgets.QTreeWidgetItem):
def __init__(self, chum, window):
super(chumListing, self).__init__([chum.handle])
self.mainwindow = window
2011-01-24 02:34:07 -05:00
self.chum = chum
self.handle = chum.handle
2011-01-22 04:36:24 -05:00
self.setMood(Mood("offline"))
self.status = None
2011-08-22 04:13:43 -04:00
self.setToolTip(0, "%s: %s" % (chum.handle, window.chumdb.getNotes(chum.handle)))
2011-01-22 04:36:24 -05:00
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
2011-01-24 04:10:44 -05:00
self.chum.mood = mood
self.updateMood(login=login, logout=logout)
2011-01-28 04:07:20 -05:00
def setColor(self, color):
self.chum.color = color
def updateMood(self, unblock=False, login=False, logout=False):
2011-01-24 04:10:44 -05:00
mood = self.chum.mood
2011-01-22 04:36:24 -05:00
self.mood = mood
2011-02-03 03:51:22 -05:00
icon = self.mood.icon(self.mainwindow.theme)
if login:
self.login()
elif logout:
self.logout()
else:
self.setIcon(0, icon)
2011-02-03 01:20:37 -05:00
try:
2021-03-23 17:41:52 -04:00
self.setForeground(0, QtGui.QBrush(QtGui.QColor(self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"])))
2011-02-03 01:20:37 -05:00
except KeyError:
2021-03-23 17:41:52 -04:00
self.setForeground(0, QtGui.QBrush(QtGui.QColor(self.mainwindow.theme["main/chums/moods/chummy/color"])))
2011-01-28 06:17:42 -05:00
def changeTheme(self, theme):
2011-02-03 03:51:22 -05:00
icon = self.mood.icon(theme)
self.setIcon(0, icon)
2011-02-03 01:20:37 -05:00
try:
2021-03-24 11:03:54 -04:00
self.setForeground(0, QtGui.QBrush(QtGui.QColor((self.mainwindow.theme["main/chums/moods"][self.mood.name()]["color"]))))
2011-02-03 01:20:37 -05:00
except KeyError:
2021-03-24 11:03:54 -04:00
self.setForeground(0, QtGui.QBrush(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)
2011-01-22 04:36:24 -05:00
def __lt__(self, cl):
h1 = self.handle.lower()
h2 = cl.handle.lower()
return (h1 < h2)
2011-01-21 05:18:22 -05:00
class chumArea(RightClickTree):
# This is the class that controls the actual main chumlist, I think.
# Looking into how the groups work might be wise.
def __init__(self, chums, parent=None):
super(chumArea, self).__init__(parent)
self.notify = False
2021-03-23 17:39:58 -04:00
QtCore.QTimer.singleShot(30000, self.beginNotify)
self.mainwindow = parent
theme = self.mainwindow.theme
2011-01-21 05:18:22 -05:00
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)
2011-02-24 18:46:09 -05:00
if not self.mainwindow.config.hideOfflineChums():
self.showAllChums()
if not self.mainwindow.config.showEmptyGroups():
self.hideEmptyGroups()
2021-03-23 17:36:43 -04:00
self.groupMenu = QtWidgets.QMenu(self)
self.canonMenu = QtWidgets.QMenu(self)
self.optionsMenu = QtWidgets.QMenu(self)
self.pester = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self)
self.pester.triggered.connect(self.activateChum)
self.removechum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removechum"], self)
self.removechum.triggered.connect(self.removeChum)
self.blockchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"], self)
self.blockchum.triggered.connect(self.blockChum)
self.logchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self)
self.logchum.triggered.connect(self.openChumLogs)
self.reportchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self)
self.reportchum.triggered.connect(self.reportChum)
self.findalts = QtWidgets.QAction("Find Alts", self)
self.findalts.triggered.connect(self.findAlts)
self.removegroup = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/removegroup"], self)
self.removegroup.triggered.connect(self.removeGroup)
self.renamegroup = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/renamegroup"], self)
self.renamegroup.triggered.connect(self.renameGroup)
self.notes = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/notes"], self)
self.notes.triggered.connect(self.editNotes)
self.optionsMenu.addAction(self.pester)
self.optionsMenu.addAction(self.logchum)
2011-08-22 04:13:43 -04:00
self.optionsMenu.addAction(self.notes)
self.optionsMenu.addAction(self.blockchum)
self.optionsMenu.addAction(self.removechum)
2021-03-23 17:36:43 -04:00
self.moveMenu = QtWidgets.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)
2011-04-13 02:12:19 -04:00
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)
2011-04-13 02:12:19 -04:00
self.canonMenu.addAction(self.reportchum)
self.canonMenu.addAction(self.findalts)
2011-02-11 04:07:07 -05:00
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)
2021-03-23 17:36:43 -04:00
self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
self.setAnimated(True)
self.setRootIsDecorated(False)
2021-03-23 17:39:58 -04:00
self.itemDoubleClicked[QtWidgets.QTreeWidgetItem, int].connect(self.expandGroup)
@QtCore.pyqtSlot()
def beginNotify(self):
PchumLog.info("BEGIN NOTIFY")
self.notify = True
2011-04-13 02:12:19 -04:00
def getOptionsMenu(self):
2011-10-24 20:24:40 -04:00
if not self.currentItem():
return None
2021-03-23 17:36:43 -04:00
text = str(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
2011-04-13 02:12:19 -04:00
else:
#currenthandle = self.currentItem().chum.handle
#if currenthandle in canon_handles:
# return self.canonMenu
#else:
return self.optionsMenu
def startDrag(self, dropAction):
2021-04-10 18:16:53 -04:00
## Traceback (most recent call last):
## File "pesterchum.py", line 355, in startDrag
## mime.setData('application/x-item', '???')
## TypeErroreError: setData(self, str, Union[QByteArray, bytes, bytearray]): argument 2 has unexpected type 'str'
try:
# create mime data object
mime = QtCore.QMimeData()
2021-08-09 18:38:42 -04:00
mime.setData('application/x-item', QtCore.QByteArray()) # Voodoo programming :"3
2021-04-10 18:16:53 -04:00
# start drag
drag = QtGui.QDrag(self)
drag.setMimeData(mime)
2021-08-09 18:38:42 -04:00
drag.exec_(QtCore.Qt.MoveAction)
2021-04-10 18:16:53 -04:00
except:
logging.exception('')
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))
2011-11-25 21:45:20 -05:00
if thisitem.rfind(" (") != -1:
thisitem = thisitem[0:thisitem.rfind(" (")]
# Drop item is a group
2021-03-23 17:36:43 -04:00
thisitem = str(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
2021-03-23 17:36:43 -04:00
droppos = str(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()):
2021-03-23 17:36:43 -04:00
text = str(self.topLevelItem(i).text(0))
if text.rfind(" (") != -1:
text = text[0:text.rfind(" (")]
2021-03-23 17:36:43 -04:00
gTemp.append([str(text), self.topLevelItem(i).isExpanded()])
self.mainwindow.config.saveGroups(gTemp)
2011-11-25 21:45:20 -05:00
# Drop item is a chum
else:
item = self.itemAt(event.pos())
if item:
2021-03-23 17:36:43 -04:00
text = str(item.text(0))
2011-11-25 21:45:20 -05:00
# 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
2011-11-25 21:45:20 -05:00
gitem = item
else:
2021-03-23 17:36:43 -04:00
ptext = str(item.parent().text(0))
if ptext.rfind(" ") != -1:
ptext = ptext[0:ptext.rfind(" ")]
group = ptext
2011-11-25 21:45:20 -05:00
gitem = item.parent()
chumLabel = event.source().currentItem()
chumLabel.chum.group = group
self.mainwindow.chumdb.setGroup(chumLabel.chum.handle, group)
self.takeItem(chumLabel)
2011-11-25 21:45:20 -05:00
# 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)
2021-03-23 17:36:43 -04:00
chums.insert(inPos, str(thisitem))
2011-11-25 21:45:20 -05:00
self.mainwindow.config.setChums(chums)
else:
self.addItem(chumLabel)
if self.mainwindow.config.showOnlineNumbers():
self.showOnlineNumbers()
def moveGroupMenu(self):
currentGroup = self.currentItem()
if currentGroup:
2011-05-06 02:25:51 -04:00
if currentGroup.parent():
2021-03-23 17:36:43 -04:00
text = str(currentGroup.parent().text(0))
2011-05-06 02:25:51 -04:00
else:
2021-03-23 17:36:43 -04:00
text = str(currentGroup.text(0))
if text.rfind(" (") != -1:
text = text[0:text.rfind(" (")]
currentGroup = text
self.moveMenu.clear()
2021-03-23 17:36:43 -04:00
actGroup = QtWidgets.QActionGroup(self)
groups = self.groups[:]
for gtext in groups:
if gtext == currentGroup:
continue
movegroup = self.moveMenu.addAction(gtext)
actGroup.addAction(movegroup)
2021-03-23 17:39:58 -04:00
actGroup.triggered[QtWidgets.QAction].connect(self.moveToGroup)
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
2011-02-25 01:28:35 -05:00
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)
2011-02-02 07:26:17 -05:00
def getChums(self, handle):
chums = self.findItems(handle, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
2011-02-02 07:26:17 -05:00
return chums
2011-02-24 18:46:09 -05:00
def showAllChums(self):
for c in self.chums:
chandle = c.handle
if not len(self.findItems(chandle, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)):
#if True:# For if it doesn't work at all :/
2011-02-24 18:46:09 -05:00
chumLabel = chumListing(c, self.mainwindow)
self.addItem(chumLabel)
self.sort()
2011-02-24 18:46:09 -05:00
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):
2021-03-23 17:36:43 -04:00
child_1 = QtWidgets.QTreeWidgetItem(["%s" % (g)])
self.addTopLevelItem(child_1)
if self.openGroups[i]:
child_1.setExpanded(True)
return
curgroups = []
for i in range(self.topLevelItemCount()):
2021-03-23 17:36:43 -04:00
text = str(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:
2021-03-23 17:36:43 -04:00
child_1 = QtWidgets.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:
2021-03-23 17:36:43 -04:00
totals[str(g)] = 0
online[str(g)] = 0
for c in self.chums:
yes = c.mood.name() != "offline"
if c.group == "Chums":
2021-03-23 17:36:43 -04:00
totals[str(c.group)] = totals[str(c.group)]+1
if yes:
2021-03-23 17:36:43 -04:00
online[str(c.group)] = online[str(c.group)]+1
elif c.group in totals:
2021-03-23 17:36:43 -04:00
totals[str(c.group)] = totals[str(c.group)]+1
if yes:
2021-03-23 17:36:43 -04:00
online[str(c.group)] = online[str(c.group)]+1
else:
totals["Chums"] = totals["Chums"]+1
if yes:
online["Chums"] = online["Chums"]+1
for i in range(self.topLevelItemCount()):
2021-03-23 17:36:43 -04:00
text = str(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()):
2021-03-23 17:36:43 -04:00
text = str(self.topLevelItem(i).text(0))
if text.rfind(" (") != -1:
text = text[0:text.rfind(" (")]
self.topLevelItem(i).setText(0, "%s" % (text))
def hideEmptyGroups(self):
2011-02-24 18:46:09 -05:00
i = 0
listing = self.topLevelItem(i)
2011-02-24 18:46:09 -05:00
while listing is not None:
if listing.childCount() == 0:
self.takeTopLevelItem(i)
2011-02-24 18:46:09 -05:00
else:
i += 1
listing = self.topLevelItem(i)
@QtCore.pyqtSlot()
def expandGroup(self):
item = self.currentItem()
2021-03-23 17:36:43 -04:00
text = str(item.text(0))
2011-05-06 02:25:51 -04:00
if text.rfind(" (") != -1:
text = text[0:text.rfind(" (")]
if text in self.groups:
expand = item.isExpanded()
2011-05-06 02:25:51 -04:00
self.mainwindow.config.expandGroup(text, not expand)
def addItem(self, chumLabel):
if hasattr(self, 'groups'):
if chumLabel.chum.group not in self.groups:
2011-05-06 02:25:51 -04:00
chumLabel.chum.group = "Chums"
if "Chums" not in self.groups:
self.mainwindow.config.addGroup("Chums")
curgroups = []
for i in range(self.topLevelItemCount()):
2021-03-23 17:36:43 -04:00
text = str(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.MatchExactly | QtCore.Qt.MatchRecursive):
#if True:# For if it doesn't work at all :/
if chumLabel.chum.group not in curgroups:
2021-03-23 17:36:43 -04:00
child_1 = QtWidgets.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
2011-05-06 02:25:51 -04:00
if self.openGroups[self.groups.index("%s" % (chumLabel.chum.group))]:
child_1.setExpanded(True)
2011-05-06 02:25:51 -04:00
for i in range(self.topLevelItemCount()):
2021-03-23 17:36:43 -04:00
text = str(self.topLevelItem(i).text(0))
2011-05-06 02:25:51 -04:00
if text.rfind(" (") != -1:
text = text[0:text.rfind(" (")]
2011-05-06 02:25:51 -04:00
if text == chumLabel.chum.group:
break
2011-11-25 21:45:20 -05:00
# 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
2011-11-25 21:45:20 -05:00
c = 1
# TODO: Rearrange chums list on drag-n-drop
bestj = 0
bestname = ""
if fi > 0:
while not bestj:
2021-03-23 17:36:43 -04:00
for j in range(self.topLevelItem(i).childCount()):
2011-11-25 21:45:20 -05:00
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()
2011-05-06 02:25:51 -04:00
if self.mainwindow.config.showOnlineNumbers():
self.showOnlineNumbers()
else: # usually means this is now the trollslum
if not self.findItems(chumLabel.handle, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive):
#if True:# For if it doesn't work at all :/
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
2011-02-02 07:26:17 -05:00
def updateMood(self, handle, mood):
2011-02-24 18:46:09 -05:00
hideoff = self.mainwindow.config.hideOfflineChums()
2011-02-02 07:26:17 -05:00
chums = self.getChums(handle)
2011-02-08 17:47:07 -05:00
oldmood = None
2011-02-24 18:46:09 -05:00
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()
2011-02-24 18:46:09 -05:00
chums = [newLabel]
elif mood.name() == "offline" and \
len(chums) > 0:
for c in chums:
if (hasattr(c, 'mood')):
c.setMood(mood)
#self.takeItem(c)
2011-02-24 18:46:09 -05:00
chums = []
2011-01-22 04:36:24 -05:00
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()
2011-02-08 17:47:07 -05:00
return oldmood
2011-01-28 04:07:20 -05:00
def updateColor(self, handle, color):
chums = self.findItems(handle, QtCore.Qt.MatchFlags(0))
for c in chums:
c.setColor(color)
2011-02-11 04:07:07 -05:00
def initTheme(self, theme):
2011-03-05 20:21:45 -05:00
self.resize(*theme["main/chums/size"])
self.move(*theme["main/chums/loc"])
2021-03-23 17:36:43 -04:00
if "main/chums/scrollbar" in theme:
2021-03-25 12:52:43 -04:00
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"] ))
2011-02-11 04:07:07 -05:00
else:
self.setStyleSheet(theme["main/chums/style"])
2011-02-01 06:14:56 -05:00
self.pester.setText(theme["main/menus/rclickchumlist/pester"])
self.removechum.setText(theme["main/menus/rclickchumlist/removechum"])
2011-02-02 07:26:17 -05:00
self.blockchum.setText(theme["main/menus/rclickchumlist/blockchum"])
self.logchum.setText(theme["main/menus/rclickchumlist/viewlog"])
self.reportchum.setText(theme["main/menus/rclickchumlist/report"])
2011-08-22 04:13:43 -04:00
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"])
2011-02-11 04:07:07 -05:00
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:
2011-01-28 06:17:42 -05:00
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):
2011-11-25 21:45:20 -05:00
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()
2011-02-02 19:06:03 -05:00
def removeChum(self, handle = None):
if handle:
clistings = self.getChums(handle)
if len(clistings) <= 0: return
2011-02-02 19:06:03 -05:00
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
2011-02-02 07:26:17 -05:00
@QtCore.pyqtSlot()
def blockChum(self):
currentChum = self.currentItem()
2011-02-02 19:06:03 -05:00
if not currentChum:
return
2011-02-02 07:26:17 -05:00
self.blockChumSignal.emit(self.currentItem().chum.handle)
@QtCore.pyqtSlot()
2011-04-13 02:12:19 -04:00
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):
2011-08-22 04:13:43 -04:00
currentChum = self.currentItem()
if not currentChum:
return
2011-08-22 04:13:43 -04:00
currentChum = currentChum.text(0)
self.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow)
2021-03-23 17:36:43 -04:00
self.pesterlogviewer.rejected.connect(self.closeActiveLog)
self.pesterlogviewer.show()
self.pesterlogviewer.raise_()
self.pesterlogviewer.activateWindow()
@QtCore.pyqtSlot()
def closeActiveLog(self):
self.pesterlogviewer.close()
self.pesterlogviewer = None
2011-03-29 03:02:05 -04:00
@QtCore.pyqtSlot()
2011-08-22 04:13:43 -04:00
def editNotes(self):
currentChum = self.currentItem()
if not currentChum:
return
2021-03-23 17:36:43 -04:00
(notes, ok) = QtWidgets.QInputDialog.getText(self, "Notes", "Enter your notes...")
2011-08-22 04:13:43 -04:00
if ok:
2021-03-23 17:36:43 -04:00
notes = str(notes)
2011-08-22 04:13:43 -04:00
self.mainwindow.chumdb.setNotes(currentChum.handle, notes)
currentChum.setToolTip(0, "%s: %s" % (currentChum.handle, notes))
@QtCore.pyqtSlot()
2011-03-29 03:02:05 -04:00
def renameGroup(self):
if not hasattr(self, 'renamegroupdialog'):
self.renamegroupdialog = None
if not self.renamegroupdialog:
2021-03-23 17:36:43 -04:00
(gname, ok) = QtWidgets.QInputDialog.getText(self, "Rename Group", "Enter a new name for the group:")
if ok:
2021-03-23 17:36:43 -04:00
gname = str(gname)
2012-03-31 20:54:49 -04:00
if re.search("[^A-Za-z0-9_\s]", gname) is not None:
2021-03-23 17:36:43 -04:00
msgbox = QtWidgets.QMessageBox()
msgbox.setStyleSheet("QMessageBox{" + self.mainwindow.theme["main/defaultwindow/style"] + "}")
2012-03-31 20:54:49 -04:00
msgbox.setInformativeText("THIS IS NOT A VALID GROUP NAME")
2021-03-23 17:36:43 -04:00
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok)
msgbox.exec_()
2012-03-31 20:54:49 -04:00
self.addgroupdialog = None
return
currentGroup = self.currentItem()
if not currentGroup:
return
index = self.indexOfTopLevelItem(currentGroup)
if index != -1:
expanded = currentGroup.isExpanded()
2021-03-23 17:36:43 -04:00
text = str(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
2011-03-29 03:02:05 -04:00
@QtCore.pyqtSlot()
def removeGroup(self):
currentGroup = self.currentItem()
if not currentGroup:
return
2021-03-23 17:36:43 -04:00
text = str(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)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QtWidgets.QAction)
2011-03-29 03:02:05 -04:00
def moveToGroup(self, item):
if not item:
return
2021-03-23 17:36:43 -04:00
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)
2021-03-23 17:36:43 -04:00
removeChumSignal = QtCore.pyqtSignal('QString')
blockChumSignal = QtCore.pyqtSignal('QString')
2011-02-02 19:06:03 -05:00
class trollSlum(chumArea):
2021-03-23 17:36:43 -04:00
unblockChumSignal = QtCore.pyqtSignal()
2011-02-02 19:06:03 -05:00
def __init__(self, trolls, mainwindow, parent=None):
#~super(trollSlum, self).__init__(parent)
# TODO: Rework inheritance here.
2021-03-23 17:36:43 -04:00
QtWidgets.QTreeWidgetItem.__init__(self, parent)
2011-02-02 19:06:03 -05:00
self.mainwindow = mainwindow
theme = self.mainwindow.theme
self.setStyleSheet(theme["main/trollslum/chumroll/style"])
self.chums = trolls
2021-03-23 17:36:43 -04:00
child_1 = QtWidgets.QTreeWidgetItem([""])
self.addTopLevelItem(child_1)
child_1.setExpanded(True)
2011-02-02 19:06:03 -05:00
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)
2021-03-23 17:36:43 -04:00
self.optionsMenu = QtWidgets.QMenu(self)
self.unblockchum = QtWidgets.QAction(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"], self)
self.unblockchum.triggered.connect(self.unblockChumSignal)
2011-02-02 19:32:35 -05:00
self.optionsMenu.addAction(self.unblockchum)
2011-02-02 19:06:03 -05:00
#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())
2011-02-02 19:06:03 -05:00
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)
2021-03-25 14:09:01 -04:00
# This causes:
# TypeError: connect() failed between triggered(bool) and unblockChumSignal()
# I'm not sure why this was here in the first place-
# Does removing it break anything else...?
#unblockChumSignal = QtCore.pyqtSignal('QString')
2011-02-02 19:06:03 -05:00
2021-03-23 17:36:43 -04:00
class TrollSlumWindow(QtWidgets.QFrame):
2011-02-02 19:06:03 -05:00
def __init__(self, trolls, mainwindow, parent=None):
super(TrollSlumWindow, self).__init__(parent)
2011-02-02 19:06:03 -05:00
self.mainwindow = mainwindow
theme = self.mainwindow.theme
2021-03-23 17:36:43 -04:00
self.slumlabel = QtWidgets.QLabel(self)
2011-02-02 19:06:03 -05:00
self.initTheme(theme)
self.trollslum = trollSlum(trolls, self.mainwindow, self)
2021-03-23 17:36:43 -04:00
self.trollslum.unblockChumSignal.connect(self.removeCurrentTroll)
layout_1 = QtWidgets.QHBoxLayout()
self.addButton = QtWidgets.QPushButton("ADD", self)
self.addButton.clicked.connect(self.addTrollWindow)
self.removeButton = QtWidgets.QPushButton("REMOVE", self)
self.removeButton.clicked.connect(self.removeCurrentTroll)
2011-02-02 19:06:03 -05:00
layout_1.addWidget(self.addButton)
layout_1.addWidget(self.removeButton)
2021-03-23 17:36:43 -04:00
layout_0 = QtWidgets.QVBoxLayout()
2011-02-02 19:06:03 -05:00
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'):
2011-02-02 19:06:03 -05:00
return
self.unblockChumSignal.emit(currentListing.chum.handle)
@QtCore.pyqtSlot()
def addTrollWindow(self):
if not hasattr(self, 'addtrolldialog'):
self.addtrolldialog = None
if self.addtrolldialog:
return
2021-03-23 17:36:43 -04:00
self.addtrolldialog = QtWidgets.QInputDialog(self)
2011-02-02 19:06:03 -05:00
(handle, ok) = self.addtrolldialog.getText(self, "Add Troll", "Enter Troll Handle:")
if ok:
2021-03-23 17:36:43 -04:00
handle = str(handle)
2011-02-02 19:06:03 -05:00
if not (PesterProfile.checkLength(handle) and
2011-08-23 06:23:59 -04:00
PesterProfile.checkValid(handle)[0]):
2021-03-23 17:36:43 -04:00
errormsg = QtWidgets.QErrorMessage(self)
2011-02-02 19:06:03 -05:00
errormsg.showMessage("THIS IS NOT A VALID CHUMTAG!")
self.addchumdialog = None
return
2011-10-24 20:24:40 -04:00
2011-02-02 19:06:03 -05:00
self.blockChumSignal.emit(handle)
self.addtrolldialog = None
2021-03-23 17:36:43 -04:00
blockChumSignal = QtCore.pyqtSignal('QString')
unblockChumSignal = QtCore.pyqtSignal('QString')
2011-01-21 05:18:22 -05:00
2011-01-22 04:36:24 -05:00
class PesterWindow(MovingWindow):
2021-03-23 17:36:43 -04:00
reconnectIRC = QtCore.pyqtSignal()
sendMessage = QtCore.pyqtSignal('QString', 'QString')
def __init__(self, options, parent=None, app=None):
super(PesterWindow, self).__init__(None,
2011-04-11 02:17:47 -04:00
(QtCore.Qt.CustomizeWindowHint |
2011-03-31 17:57:30 -04:00
QtCore.Qt.FramelessWindowHint))
# For debugging
_CONSOLE_ENV.PAPP = self
# TODO: karxi: SO! At the end of this function it seems like that
# object is just made into None or.../something/. Somehow, it just
# DIES, and I haven't the slightest idea why. I've tried multiple ways
# to set it that shouldn't cause issues with globals; I honestly don't
# know what to do.
# Putting logging statements in here *gives me an object*, but I can't
# carry it out of the function. I'll hvae to think of a way around
# this....
# If I use a definition made in here without having another elsewhere,
# it comes back as undefined. Just...what?
2014-01-12 20:50:01 -05:00
self.autoJoinDone = False
self.app = app
self.parent = parent
2011-04-14 05:50:55 -04:00
self.convos = CaseInsensitiveDict()
self.memos = CaseInsensitiveDict()
2011-01-31 06:04:03 -05:00
self.tabconvo = None
2011-02-04 19:50:56 -05:00
self.tabmemo = None
self.shortcuts = AttrDict()
2011-01-31 06:04:03 -05:00
self.setAutoFillBackground(False)
2011-01-22 04:36:24 -05:00
self.setObjectName("main")
2011-05-12 10:14:38 -04:00
self.config = userConfig(self)
# Trying to fix:
# IOError: [Errno 2]
# No such file or directory:
# u'XXX\\AppData\\Local\\pesterchum/profiles/XXX.js'
# Part 1 :(
try:
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()
2022-03-17 21:05:14 -04:00
except Exception as e:
msgBox = QtWidgets.QMessageBox()
msgBox.setIcon(QtWidgets.QMessageBox.Information)
msgBox.setWindowTitle(":(")
msgBox.setTextFormat(QtCore.Qt.RichText) # Clickable html links
self.filename = _datadir+"pesterchum.js"
msgBox.setText("<html><h3>A profile error occured, trying to switch to default pesterClient profile." + \
"<br><br>" + str(e) + "<\h3><\html>")
#"\" if pesterchum acts oddly you might want to try backing up and then deleting \"" + \
#_datadir+"pesterchum.js" + \
#"\"")
PchumLog.critical(e)
msgBox.exec_()
self.userprofile = userProfile(PesterProfile("pesterClient%d" % (random.randint(100,999)), QtGui.QColor("black"), Mood(0)))
self.theme = self.userprofile.getTheme()
# karxi: For the record, these are set via commandline arguments. By
# default, they aren't usable any other way - you can't set them via
# the config files.
# ...which means the flag for disabling honking is also hidden and
# impossible to set via pesterchum.js.
#
# This was almost certainly intentional.
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.modes = ""
self.sound_type = None
self.randhandler = RandomHandler(self)
2011-05-10 02:33:59 -04:00
try:
themeChecker(self.theme)
except ThemeException as inst:
PchumLog.error("Caught: " + inst.parameter)
2021-03-23 17:36:43 -04:00
themeWarning = QtWidgets.QMessageBox(self)
themeWarning.setText("Theme Error: %s" % inst)
2011-05-10 02:33:59 -04:00
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)
2011-02-02 03:20:48 -05:00
2011-01-31 06:04:03 -05:00
self.move(100, 100)
2011-01-22 04:36:24 -05:00
2021-03-23 17:36:43 -04:00
talk = QtWidgets.QAction(self.theme["main/menus/client/talk"], self)
self.talk = talk
2021-03-23 17:36:43 -04:00
talk.triggered.connect(self.openChat)
logv = QtWidgets.QAction(self.theme["main/menus/client/logviewer"], self)
self.logv = logv
2021-03-23 17:36:43 -04:00
logv.triggered.connect(self.openLogv)
grps = QtWidgets.QAction(self.theme["main/menus/client/addgroup"], self)
self.grps = grps
2021-03-23 17:36:43 -04:00
grps.triggered.connect(self.addGroupWindow)
self.rand = QtWidgets.QAction(self.theme["main/menus/client/randen"], self)
self.rand.triggered.connect(self.randhandler.getEncounter)
opts = QtWidgets.QAction(self.theme["main/menus/client/options"], self)
2011-02-01 06:14:56 -05:00
self.opts = opts
2021-03-23 17:36:43 -04:00
opts.triggered.connect(self.openOpts)
exitaction = QtWidgets.QAction(self.theme["main/menus/client/exit"], self)
2011-02-01 06:14:56 -05:00
self.exitaction = exitaction
2021-03-25 16:39:37 -04:00
exitaction.triggered.connect(self.quit)
2021-03-23 17:36:43 -04:00
userlistaction = QtWidgets.QAction(self.theme["main/menus/client/userlist"], self)
2011-02-03 01:20:37 -05:00
self.userlistaction = userlistaction
2021-03-23 17:36:43 -04:00
userlistaction.triggered.connect(self.showAllUsers)
memoaction = QtWidgets.QAction(self.theme["main/menus/client/memos"], self)
2011-02-04 16:17:27 -05:00
self.memoaction = memoaction
2021-03-23 17:36:43 -04:00
memoaction.triggered.connect(self.showMemos)
self.importaction = QtWidgets.QAction(self.theme["main/menus/client/import"], self)
self.importaction.triggered.connect(self.importExternalConfig)
self.idleaction = QtWidgets.QAction(self.theme["main/menus/client/idle"], self)
2011-02-13 04:27:12 -05:00
self.idleaction.setCheckable(True)
2021-03-23 17:36:43 -04:00
self.idleaction.toggled[bool].connect(self.toggleIdle)
self.reconnectAction = QtWidgets.QAction(self.theme["main/menus/client/reconnect"], self)
self.reconnectAction.triggered.connect(self.reconnectIRC)
2011-02-10 20:55:45 -05:00
2021-03-23 17:36:43 -04:00
self.menu = QtWidgets.QMenuBar(self)
self.menu.setNativeMenuBar(False)
self.menu.setObjectName("mainmenu")
2021-04-08 19:14:54 -04:00
if self.theme.has_key("main/menus/client/console"):
self.console = AttrDict(dict(
window = None,
action = QtWidgets.QAction(self.theme["main/menus/client/console"], self),
is_open = False
))
else:
self.console = AttrDict(dict(
window = None,
action = QtWidgets.QAction("Console", self),
is_open = False
))
self.console.shortcuts = AttrDict(dict(
2021-03-23 17:36:43 -04:00
conkey = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+`"), self,
context=QtCore.Qt.ApplicationShortcut),
2021-03-23 17:36:43 -04:00
curwgt = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+Alt+w"), self,
context=QtCore.Qt.ApplicationShortcut)
))
2021-03-23 17:36:43 -04:00
self.console.action.triggered.connect(self.toggleConsole)
# Make sure the shortcut works anywhere.
# karxi: There's something wrong with the inheritance scheme here.
#~self.console.shortcuts.conkey.setContext(QtCore.Qt.ApplicationShortcut)
2021-03-23 17:36:43 -04:00
self.console.shortcuts.conkey.activated.connect(self.toggleConsole)
#~# Use new-style connections
2017-01-09 17:20:03 -05:00
#~self.console.shortcut.activated.connect(self.toggleConsole)
# Apparently those can crash sometimes...c'est la vie. Can't use 'em.
#~self.connect(self.console.shortcuts.curwgt,
#~ QtCore.SIGNAL('activate()'), self.console.
self.console.is_open = False
2011-02-01 06:14:56 -05:00
filemenu = self.menu.addMenu(self.theme["main/menus/client/_name"])
self.filemenu = filemenu
2011-01-27 04:46:47 -05:00
filemenu.addAction(opts)
2011-02-04 16:17:27 -05:00
filemenu.addAction(memoaction)
filemenu.addAction(logv)
filemenu.addAction(self.rand)
if not self.randhandler.running:
self.rand.setEnabled(False)
2011-02-03 01:20:37 -05:00
filemenu.addAction(userlistaction)
filemenu.addAction(talk)
2011-02-13 04:27:12 -05:00
filemenu.addAction(self.idleaction)
filemenu.addAction(grps)
if _CONSOLE:
filemenu.addAction(self.console.action)
2011-02-06 19:50:21 -05:00
filemenu.addAction(self.importaction)
2011-02-14 16:15:32 -05:00
filemenu.addAction(self.reconnectAction)
2011-01-27 04:46:47 -05:00
filemenu.addAction(exitaction)
2011-01-28 01:41:01 -05:00
2021-03-23 17:36:43 -04:00
changequirks = QtWidgets.QAction(self.theme["main/menus/profile/quirks"], self)
2011-02-01 06:14:56 -05:00
self.changequirks = changequirks
2021-03-23 17:36:43 -04:00
changequirks.triggered.connect(self.openQuirks)
loadslum = QtWidgets.QAction(self.theme["main/menus/profile/block"], self)
2011-02-02 19:06:03 -05:00
self.loadslum = loadslum
2021-03-23 17:36:43 -04:00
loadslum.triggered.connect(self.showTrollSlum)
2011-01-29 16:55:35 -05:00
2021-03-23 17:36:43 -04:00
changecoloraction = QtWidgets.QAction(self.theme["main/menus/profile/color"], self)
2011-02-02 07:26:17 -05:00
self.changecoloraction = changecoloraction
2021-03-23 17:36:43 -04:00
changecoloraction.triggered.connect(self.changeMyColor)
2011-02-02 07:26:17 -05:00
2021-03-23 17:36:43 -04:00
switch = QtWidgets.QAction(self.theme["main/menus/profile/switch"], self)
2011-02-01 06:14:56 -05:00
self.switch = switch
2021-03-23 17:36:43 -04:00
switch.triggered.connect(self.switchProfile)
2011-02-01 06:14:56 -05:00
profilemenu = self.menu.addMenu(self.theme["main/menus/profile/_name"])
self.profilemenu = profilemenu
2011-01-29 16:55:35 -05:00
profilemenu.addAction(changequirks)
2011-02-02 19:06:03 -05:00
profilemenu.addAction(loadslum)
2011-02-02 07:26:17 -05:00
profilemenu.addAction(changecoloraction)
2011-01-29 16:55:35 -05:00
profilemenu.addAction(switch)
2011-01-28 01:41:01 -05:00
2021-03-23 17:36:43 -04:00
self.helpAction = QtWidgets.QAction(self.theme["main/menus/help/help"], self)
self.helpAction.triggered.connect(self.launchHelp)
self.botAction = QtWidgets.QAction(self.theme["main/menus/help/calsprite"], self)
self.botAction.triggered.connect(self.loadCalsprite)
self.nickServAction = QtWidgets.QAction(self.theme["main/menus/help/nickserv"], self)
self.nickServAction.triggered.connect(self.loadNickServ)
self.chanServAction = QtWidgets.QAction(self.theme["main/menus/help/chanserv"], self)
self.chanServAction.triggered.connect(self.loadChanServ)
self.aboutAction = QtWidgets.QAction(self.theme["main/menus/help/about"], self)
self.aboutAction.triggered.connect(self.aboutPesterchum)
2021-04-10 18:16:53 -04:00
# Because I can't expect all themes to have this included.
#if self.theme.has_key("main/menus/help/reportbug"):
try:
2021-04-10 18:16:53 -04:00
self.reportBugAction = QtWidgets.QAction(self.theme["main/menus/help/reportbug"], self)
except:
2021-04-10 18:16:53 -04:00
self.reportBugAction = QtWidgets.QAction("REPORT BUG", self)
2021-08-09 00:06:00 -04:00
try:
self.xyzRulesAction = QtWidgets.QAction(self.theme["main/menus/help/rules"], self)
except:
self.xyzRulesAction = QtWidgets.QAction("RULES", self)
2021-04-10 18:16:53 -04:00
2021-03-23 17:36:43 -04:00
self.reportBugAction.triggered.connect(self.reportBug)
2021-08-09 00:06:00 -04:00
self.xyzRulesAction.triggered.connect(self.xyzRules)
2011-02-09 01:26:23 -05:00
helpmenu = self.menu.addMenu(self.theme["main/menus/help/_name"])
self.helpmenu = helpmenu
2011-03-05 21:25:52 -05:00
self.helpmenu.addAction(self.helpAction)
2021-08-09 00:06:00 -04:00
self.helpmenu.addAction(self.xyzRulesAction)
2011-04-13 02:12:19 -04:00
self.helpmenu.addAction(self.botAction)
self.helpmenu.addAction(self.chanServAction)
self.helpmenu.addAction(self.nickServAction)
2011-02-09 01:26:23 -05:00
self.helpmenu.addAction(self.aboutAction)
2011-06-01 04:31:43 -04:00
self.helpmenu.addAction(self.reportBugAction)
2011-02-02 03:20:48 -05:00
self.closeButton = WMButton(PesterIcon(self.theme["main/close/image"]), self)
2011-05-05 02:48:44 -04:00
self.setButtonAction(self.closeButton, self.config.closeAction(), -1)
2011-02-02 03:20:48 -05:00
self.miniButton = WMButton(PesterIcon(self.theme["main/minimize/image"]), self)
2011-05-05 02:48:44 -04:00
self.setButtonAction(self.miniButton, self.config.minimizeAction(), -1)
2011-01-27 04:46:47 -05:00
2011-04-14 05:50:55 -04:00
self.namesdb = CaseInsensitiveDict()
2011-01-31 18:43:49 -05:00
self.chumdb = PesterProfileDB()
2011-02-24 18:46:09 -05:00
chums = [PesterProfile(c, chumdb=self.chumdb) for c in set(self.config.chums())]
self.chumList = chumArea(chums, self)
2021-03-23 17:39:58 -04:00
self.chumList.itemActivated[QtWidgets.QTreeWidgetItem, int].connect(self.pesterSelectedChum)
2021-03-23 17:36:43 -04:00
self.chumList.removeChumSignal['QString'].connect(self.removeChum)
self.chumList.blockChumSignal['QString'].connect(self.blockChum)
self.addChumButton = QtWidgets.QPushButton(self.theme["main/addchum/text"], self)
self.addChumButton.setObjectName("addchumbtn")
2021-03-23 17:36:43 -04:00
self.addChumButton.clicked.connect(self.addChumWindow)
self.pesterButton = QtWidgets.QPushButton(self.theme["main/pester/text"], self)
self.pesterButton.setObjectName("newpesterbtn")
2021-03-23 17:36:43 -04:00
self.pesterButton.clicked.connect(self.pesterSelectedChum)
self.blockButton = QtWidgets.QPushButton(self.theme["main/block/text"], self)
self.blockButton.setObjectName("blockbtn")
2021-03-23 17:36:43 -04:00
self.blockButton.clicked.connect(self.blockSelectedChum)
2021-03-23 17:36:43 -04:00
self.moodsLabel = QtWidgets.QLabel(self.theme["main/moodlabel/text"], self)
self.moodsLabel.setObjectName("moodlabel")
self.mychumhandleLabel = QtWidgets.QLabel(self.theme["main/mychumhandle/label/text"], self)
self.mychumhandleLabel.setObjectName("myhandlelabel")
2021-03-23 17:36:43 -04:00
self.mychumhandle = QtWidgets.QPushButton(self.profile().handle, self)
2011-01-29 07:33:35 -05:00
self.mychumhandle.setFlat(True)
2021-03-23 17:36:43 -04:00
self.mychumhandle.clicked.connect(self.switchProfile)
2011-01-29 07:33:35 -05:00
2021-03-23 17:36:43 -04:00
self.mychumcolor = QtWidgets.QPushButton(self)
self.mychumcolor.clicked.connect(self.changeMyColor)
# self.show() before self.initTheme() fixes a
# layering issue on windows... for some reason...
self.show()
2011-01-31 06:04:03 -05:00
self.initTheme(self.theme)
2021-04-08 19:14:54 -04:00
#self.mychumhandleLabel.setStyleSheet("QLabel {);};")
self.hide()
self.waitingMessages = waitingMessageHolder(self)
2011-01-31 06:04:03 -05:00
self.idler = AttrDict(dict(
# autoidle
auto = False,
# setidle
manual = False,
# idlethreshold
threshold = 60*self.config.idleTime(),
# idleaction
action = self.idleaction,
# idletimer
timer = QtCore.QTimer(self),
# idleposition
pos = QtGui.QCursor.pos(),
# idletime
time = 0
))
2021-03-23 17:36:43 -04:00
self.idler.timer.timeout.connect(self.checkIdle)
self.idler.timer.start(1000)
2011-02-10 20:55:45 -05:00
2011-01-31 06:04:03 -05:00
if not self.config.defaultprofile():
self.changeProfile()
# Fuck you some more OSX leopard! >:(
#if not ostools.isOSXLeopard():
# QtCore.QTimer.singleShot(1000, self.mspacheck)
2011-06-23 16:40:22 -04:00
2021-03-23 17:36:43 -04:00
self.pcUpdate['QString', 'QString'].connect(self.updateMsg)
self.pingtimer = QtCore.QTimer()
2021-03-23 17:36:43 -04:00
self.pingtimer.timeout.connect(self.checkPing)
self.lastping = int(time())
self.pingtimer.start(1000*90)
self.mychumhandleLabel.adjustSize() # Required so "CHUMHANDLE:" regardless of style-sheet.
self.moodsLabel.adjustSize() # Required so "MOOD:" regardless of style-sheet.
self.chooseServerAskedToReset = False
self.chooseServer()
# Update RE bot
try:
if self.userprofile.getRandom():
code = "+"
else:
code = "-"
self.sendNotice.emit(code, RANDNICK)
except:
PchumLog.warning("No randomEncounter set in userconfig?")
2021-03-25 16:39:37 -04:00
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString)
def updateMsg(self, ver, url):
if not hasattr(self, 'updatemenu'):
self.updatemenu = None
if not self.updatemenu:
self.updatemenu = UpdatePesterchum(ver, url, self)
2021-03-23 17:36:43 -04:00
self.updatemenu.accepted.connect(self.updatePC)
self.updatemenu.rejected.connect(self.noUpdatePC)
self.updatemenu.show()
self.updatemenu.raise_()
self.updatemenu.activateWindow()
"""
Depreciated
@QtCore.pyqtSlot()
def updatePC(self):
2021-03-23 17:36:43 -04:00
version.updateDownload(str(self.updatemenu.url))
self.updatemenu = None
@QtCore.pyqtSlot()
def noUpdatePC(self):
self.updatemenu = None
"""
@QtCore.pyqtSlot()
def checkPing(self):
curtime = int(time())
if curtime - self.lastping > 600:
self.pingServer.emit()
2011-01-28 21:36:12 -05:00
def profile(self):
return self.userprofile.chat
def closeConversations(self, switch=False):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'tabconvo'):
self.tabconvo = None
2011-01-26 05:32:35 -05:00
if self.tabconvo:
self.tabconvo.close()
2011-01-27 17:16:14 -05:00
else:
2021-03-23 17:36:43 -04:00
for c in list(self.convos.values()):
2011-01-27 17:16:14 -05:00
c.close()
2011-02-04 19:50:56 -05:00
if self.tabmemo:
if not switch:
self.tabmemo.close()
else:
for m in self.tabmemo.convos:
self.tabmemo.convos[m].sendtime()
2011-02-04 19:50:56 -05:00
else:
2021-03-23 17:36:43 -04:00
for m in list(self.memos.values()):
if not switch:
m.close()
else:
m.sendtime()
2011-02-06 19:50:21 -05:00
def paintEvent(self, event):
2021-03-26 17:54:03 -04:00
try:
self.backgroundImage
except:
pass
else:
palette = QtGui.QPalette()
brush = QtGui.QBrush(self.backgroundImage)
palette.setBrush(QtGui.QPalette.Window, brush)
2021-03-26 17:54:03 -04:00
self.setPalette(palette)
2011-02-04 19:50:56 -05:00
2011-02-08 02:56:30 -05:00
@QtCore.pyqtSlot()
def closeToTray(self):
# I'm just gonna include a toast here to make sure people don't get confused. :'3
t = self.tm.Toast("Notice:", "Pesterchum has been minimized to your tray. \
\n(This behavior is configurable in settings.)")
t.show()
2011-02-08 02:56:30 -05:00
self.hide()
self.closeToTraySignal.emit()
2011-01-28 01:41:01 -05:00
def closeEvent(self, event):
# This gets called directly if Pesterchum is closed from the taskbar, annoyingly enough.
2011-02-02 19:06:03 -05:00
if hasattr(self, 'trollslum') and self.trollslum:
self.trollslum.close()
try:
setting = self.config.closeAction()
except:
logging.exception('')
setting = 0
if setting == 0: # minimize to taskbar
self.showMinimized()
elif setting == 1: # minimize to tray
self.closeToTray()
elif setting == 2: # quit
self.closeConversations()
self.quit() # Shut down IRC & Pesterchum fully.
self.closeSignal.emit() # <-- A close signal here on it's own shuts down QT but not the Python and the IRC connection :(
2011-01-24 02:34:07 -05:00
event.accept()
def newMessage(self, handle, msg):
2011-02-02 19:06:03 -05:00
if handle in self.config.getBlocklist():
2011-02-02 07:26:17 -05:00
#yeah suck on this
2011-02-10 20:55:45 -05:00
self.sendMessage.emit("PESTERCHUM:BLOCKED", handle)
2011-02-02 07:26:17 -05:00
return
# notify
if self.config.notifyOptions() & self.config.NEWMSG:
2021-03-23 17:36:43 -04:00
if handle not in self.convos:
t = self.tm.Toast("New Conversation", "From: %s" % handle)
t.show()
elif not self.config.notifyOptions() & self.config.NEWCONVO:
if msg[:11] != "PESTERCHUM:":
2014-01-12 02:33:33 -05:00
if handle.upper() not in BOTNAMES:
t = self.tm.Toast("From: %s" % handle, re.sub("</?c(=.*?)?>", "", msg))
t.show()
else:
if msg == "PESTERCHUM:CEASE":
t = self.tm.Toast("Closed Conversation", handle)
t.show()
elif msg == "PESTERCHUM:BLOCK":
t = self.tm.Toast("Blocked", handle)
t.show()
elif msg == "PESTERCHUM:UNBLOCK":
t = self.tm.Toast("Unblocked", handle)
t.show()
2021-03-23 17:36:43 -04:00
if handle not in self.convos:
if msg == "PESTERCHUM:CEASE": # ignore cease after we hang up
return
2011-01-28 03:10:00 -05:00
matchingChums = [c for c in self.chumList.chums if c.handle == handle]
if len(matchingChums) > 0:
mood = matchingChums[0].mood
else:
mood = Mood(0)
2011-02-01 06:14:56 -05:00
chum = PesterProfile(handle, mood=mood, chumdb=self.chumdb)
2011-01-24 04:10:44 -05:00
self.newConversation(chum, False)
2011-01-28 03:10:00 -05:00
if len(matchingChums) == 0:
self.moodRequest.emit(chum)
2011-01-24 04:10:44 -05:00
convo = self.convos[handle]
convo.addMessage(msg, False)
# play sound here
2011-02-08 02:56:30 -05:00
if self.config.soundOn():
2017-05-08 23:45:11 -04:00
if self.config.chatSound() or convo.always_beep:
if msg in ["PESTERCHUM:CEASE", "PESTERCHUM:BLOCK"]:
self.ceasesound.play()
else:
self.alarm.play()
2011-02-04 19:50:56 -05:00
def newMemoMsg(self, chan, handle, msg):
2021-03-23 17:36:43 -04:00
if chan not in self.memos:
2011-02-04 19:50:56 -05:00
# silently ignore in case we forgot to /part
# TODO: This is really bad practice. Fix it later.
2011-02-04 19:50:56 -05:00
return
2011-04-14 05:50:55 -04:00
memo = self.memos[chan]
2021-03-23 17:36:43 -04:00
msg = str(msg)
if handle not in memo.times:
2011-02-13 04:27:12 -05:00
# new chum! time current
newtime = timedelta(0)
time = TimeTracker(newtime)
memo.times[handle] = time
if not (msg.startswith("/me") or msg.startswith("PESTERCHUM:ME")):
2011-02-13 04:27:12 -05:00
msg = addTimeInitial(msg, memo.times[handle].getGrammar())
if handle == "ChanServ":
systemColor = QtGui.QColor(self.theme["memos/systemMsgColor"])
msg = "<c=%s>%s</c>" % (systemColor.name(), msg)
2011-02-04 19:50:56 -05:00
memo.addMessage(msg, handle)
mentioned = False
m = convertTags(msg, "text")
if m.find(":") <= 3:
m = m[m.find(":"):]
for search in self.userprofile.getMentions():
if re.search(search, m):
mentioned = True
break
if mentioned:
if self.config.notifyOptions() & self.config.INITIALS:
t = self.tm.Toast(chan, re.sub("</?c(=.*?)?>", "", msg))
t.show()
2011-03-07 23:13:46 -05:00
if self.config.soundOn():
if self.config.memoSound():
2011-07-08 04:41:49 -04:00
if self.config.nameSound():
if mentioned:
self.namesound.play()
return
if not memo.notifications_muted:
if self.honk and re.search(r"\bhonk\b", convertTags(msg, "text"), re.I):
# TODO: I've got my eye on you, Gamzee.
self.honksound.play()
elif self.config.memoPing() or memo.always_beep:
self.memosound.play()
2011-01-24 04:10:44 -05:00
def changeColor(self, handle, color):
2011-01-28 04:07:20 -05:00
# pesterconvo and chumlist
self.chumList.updateColor(handle, color)
2021-03-23 17:36:43 -04:00
if handle in self.convos:
2011-01-28 04:07:20 -05:00
self.convos[handle].updateColor(color)
2011-01-31 18:43:49 -05:00
self.chumdb.setColor(handle, color)
2011-01-24 02:34:07 -05:00
def updateMood(self, handle, mood):
2011-02-24 18:46:09 -05:00
# updates OTHER chums' moods
2011-02-08 17:47:07 -05:00
oldmood = self.chumList.updateMood(handle, mood)
2021-03-23 17:36:43 -04:00
if handle in self.convos:
2011-02-08 17:47:07 -05:00
self.convos[handle].updateMood(mood, old=oldmood)
2011-02-02 19:06:03 -05:00
if hasattr(self, 'trollslum') and self.trollslum:
self.trollslum.updateMood(handle, mood)
2011-01-24 02:34:07 -05:00
def newConversation(self, chum, initiated=True):
2021-03-23 17:36:43 -04:00
if type(chum) in [str, str]:
2011-04-13 02:12:19 -04:00
matchingChums = [c for c in self.chumList.chums if c.handle == chum]
if len(matchingChums) > 0:
mood = matchingChums[0].mood
else:
mood = Mood(2)
chum = PesterProfile(chum, mood=mood, chumdb=self.chumdb)
if len(matchingChums) == 0:
self.moodRequest.emit(chum)
2021-03-23 17:36:43 -04:00
if chum.handle in self.convos:
2011-01-24 13:02:00 -05:00
self.convos[chum.handle].showChat()
return
2011-01-26 05:50:00 -05:00
if self.config.tabs():
2011-01-26 05:32:35 -05:00
if not self.tabconvo:
2011-01-27 17:16:14 -05:00
self.createTabWindow()
2011-01-26 05:32:35 -05:00
convoWindow = PesterConvo(chum, initiated, self, self.tabconvo)
self.tabconvo.show()
else:
convoWindow = PesterConvo(chum, initiated, self)
2021-03-23 17:36:43 -04:00
convoWindow.messageSent['QString', 'QString'].connect(self.sendMessage['QString', 'QString'])
convoWindow.windowClosed['QString'].connect(self.closeConvo)
2011-01-24 02:34:07 -05:00
self.convos[chum.handle] = convoWindow
2021-03-23 17:36:43 -04:00
if str(chum.handle).upper() in BOTNAMES:
convoWindow.toggleQuirks(True)
convoWindow.quirksOff.setChecked(True)
2021-03-23 17:36:43 -04:00
if str(chum.handle).upper() in CUSTOMBOTS:
self.newConvoStarted.emit(QString(chum.handle), initiated)
else:
2021-03-23 17:36:43 -04:00
self.newConvoStarted.emit(QString(chum.handle), initiated)
2011-01-24 02:34:07 -05:00
convoWindow.show()
2011-02-04 19:50:56 -05:00
2011-01-27 17:16:14 -05:00
def createTabWindow(self):
self.tabconvo = PesterTabWindow(self)
2021-03-23 17:36:43 -04:00
self.tabconvo.windowClosed.connect(self.tabsClosed)
2011-02-04 19:50:56 -05:00
def createMemoTabWindow(self):
self.tabmemo = MemoTabWindow(self)
2021-03-23 17:36:43 -04:00
self.tabmemo.windowClosed.connect(self.memoTabsClosed)
2011-02-04 16:17:27 -05:00
@QtCore.pyqtSlot()
2017-01-09 17:20:03 -05:00
def toggleConsole(self):
if not _CONSOLE:
# We don't have the module file for this at the moment.
return
win = self.console.window
if win is None:
# We have no console window; make one.
PchumLog.info("Making a console....")
self.console.window = win = console.ConsoleWindow(parent=self)
PchumLog.info("Console made.")
# 'ConsoleWindow' object has no attribute 'windowClosed'
win.finished.connect(self.consoleWindowClosed)
2021-03-23 17:36:43 -04:00
self.console.shortcuts.curwgt.activated.connect(win.designateCurrentWidget)
if self.console.is_open:
2021-03-23 17:36:43 -04:00
for wgt in win.findChildren(QtWidgets.QWidget):
try:
focused = wgt.hasFocus()
except AttributeError:
# The widget doesn't have a hasFocus method.
# Just to reduce ambiguity
focused = False
# Try the next one.
continue
# No error, let's see if we're actually focused.
if focused:
PchumLog.debug(
"{0!r} is in focus (parent: {1!r}); hiding".format(
wgt, wgt.parent())
)
# This widget, a child of our console, has focus.
# So...the console has focus.
# Set focus to the text input just for good measure.
win.text.input.setFocus()
# ...then hide it all.
win.hide()
self.console.is_open = False
break
else:
2017-01-09 17:20:03 -05:00
# The console is open, but not in focus. Bring it to the fore.
# NOTE: This is a bit of a kludgy method - it may not work
# properly on Windows. Need to look into workarounds.
#
# karxi: I *think* that Windows doesn't mind if the
# process/window that 'owns' this one changes our focus, since
# the application ultimately already *has* our focus - but I'm
# not sure.
PchumLog.debug("Console isn't in focus; fixing")
2017-01-09 17:20:03 -05:00
win.raise_()
win.show()
win.activateWindow()
win.text.input.setFocus()
# No need to explicitly set it as open; it already is.
else:
PchumLog.debug("Console not visible; showing")
# Console isn't visible - show it.
win.show()
self.console.is_open = True
@QtCore.pyqtSlot()
def consoleWindowClosed(self):
self.console.is_open = False
self.console.window = None
PchumLog.info("Console closed.")
def newMemo(self, channel, timestr, secret=False, invite=False):
2011-02-04 19:50:56 -05:00
if channel == "#pesterchum":
return
2021-03-23 17:36:43 -04:00
if channel in self.memos:
2011-04-14 05:50:55 -04:00
self.memos[channel].showChat()
2011-02-04 16:17:27 -05:00
return
# do slider dialog then set
if self.config.tabMemos():
2011-02-04 19:50:56 -05:00
if not self.tabmemo:
self.createMemoTabWindow()
memoWindow = PesterMemo(channel, timestr, self, self.tabmemo)
2011-02-04 19:50:56 -05:00
self.tabmemo.show()
2011-02-04 16:17:27 -05:00
else:
memoWindow = PesterMemo(channel, timestr, self, None)
2011-02-04 16:17:27 -05:00
# connect signals
2021-03-23 17:36:43 -04:00
self.inviteOnlyChan['QString'].connect(memoWindow.closeInviteOnly)
memoWindow.messageSent['QString', 'QString'].connect(self.sendMessage['QString', 'QString'])
memoWindow.windowClosed['QString'].connect(self.closeMemo)
self.namesUpdated['QString'].connect(memoWindow.namesUpdated)
self.modesUpdated['QString', 'QString'].connect(memoWindow.modesUpdated)
self.userPresentSignal['QString', 'QString', 'QString'].connect(memoWindow.userPresentChange)
2011-02-04 16:17:27 -05:00
# chat client send memo open
2011-04-14 05:50:55 -04:00
self.memos[channel] = memoWindow
self.joinChannel.emit(channel) # race condition?
2011-02-06 19:50:21 -05:00
self.secret = secret
if self.secret:
self.secret = True
self.setChannelMode.emit(channel, "+s", "")
if invite:
self.setChannelMode.emit(channel, "+i", "")
memoWindow.sendTimeInfo()
2011-02-04 19:50:56 -05:00
memoWindow.show()
2011-02-04 16:17:27 -05:00
def addChum(self, chum):
self.chumList.addChum(chum)
self.config.addChum(chum)
self.moodRequest.emit(chum)
2011-10-24 20:24:40 -04:00
def addGroup(self, 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.moveGroupMenu()
self.chumList.showAllGroups()
if not self.config.showEmptyGroups():
self.chumList.hideEmptyGroups()
if self.config.showOnlineNumbers():
self.chumList.showOnlineNumbers()
def changeProfile(self, collision=None):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'chooseprofile'):
self.chooseprofile = None
if not self.chooseprofile:
self.chooseprofile = PesterChooseProfile(self.userprofile, self.config, self.theme, self, collision=collision)
self.chooseprofile.exec_()
2011-01-28 06:17:42 -05:00
def themePicker(self):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'choosetheme'):
self.choosetheme = None
if not self.choosetheme:
self.choosetheme = PesterChooseTheme(self.config, self.theme, self)
self.choosetheme.exec_()
2011-01-31 06:04:03 -05:00
def initTheme(self, theme):
self.resize(*theme["main/size"])
2011-02-02 03:20:48 -05:00
self.setWindowIcon(PesterIcon(theme["main/icon"]))
2011-01-31 06:04:03 -05:00
self.setWindowTitle(theme["main/windowtitle"])
self.setStyleSheet("QtWidgets.QFrame#main { %s }" % (theme["main/style"]))
# QPixmap::mask and setMask are legacy and should probably be replaced;
# https://doc.qt.io/qt-5/qpixmap.html#pixmap-information
# It's slow and this way we don't use antialiasing, leaving us with very ugly borders.
# + It breaks transparency on Wayland: https://bugreports-test.qt.io/browse/QTBUG-69906
self.backgroundImage = QtGui.QImage(theme["main/background-image"])
self.backgroundPixmap = QtGui.QPixmap.fromImage(self.backgroundImage)
self.backgroundMask = self.backgroundPixmap.mask()
2011-02-06 19:50:21 -05:00
self.setMask(self.backgroundMask)
self.menu.setStyleSheet("QMenuBar { background: transparent; %s } QMenuBar::item { background: transparent; %s } "
% (theme["main/menubar/style"],
theme["main/menu/menuitem"])
+ "QMenu { background: transparent; %s } QMenu::item::selected { %s } QMenu::item::disabled { %s }"
% (theme["main/menu/style"],
theme["main/menu/selected"],
theme["main/menu/disabled"]))
2011-02-02 03:20:48 -05:00
newcloseicon = PesterIcon(theme["main/close/image"])
self.closeButton.setIcon(newcloseicon)
self.closeButton.setIconSize(newcloseicon.realsize())
self.closeButton.resize(newcloseicon.realsize())
2011-01-31 06:04:03 -05:00
self.closeButton.move(*theme["main/close/loc"])
2011-02-02 03:20:48 -05:00
newminiicon = PesterIcon(theme["main/minimize/image"])
self.miniButton.setIcon(newminiicon)
self.miniButton.setIconSize(newminiicon.realsize())
self.miniButton.resize(newminiicon.realsize())
2011-01-31 06:04:03 -05:00
self.miniButton.move(*theme["main/minimize/loc"])
2011-02-01 06:14:56 -05:00
# menus
self.menu.move(*theme["main/menu/loc"])
self.talk.setText(theme["main/menus/client/talk"])
self.logv.setText(theme["main/menus/client/logviewer"])
self.grps.setText(theme["main/menus/client/addgroup"])
self.rand.setText(self.theme["main/menus/client/randen"])
2011-02-01 06:14:56 -05:00
self.opts.setText(theme["main/menus/client/options"])
self.exitaction.setText(theme["main/menus/client/exit"])
2011-02-03 01:20:37 -05:00
self.userlistaction.setText(theme["main/menus/client/userlist"])
self.memoaction.setText(theme["main/menus/client/memos"])
2011-02-06 19:50:21 -05:00
self.importaction.setText(theme["main/menus/client/import"])
2011-02-13 04:27:12 -05:00
self.idleaction.setText(theme["main/menus/client/idle"])
2011-02-14 16:15:32 -05:00
self.reconnectAction.setText(theme["main/menus/client/reconnect"])
2011-02-01 06:14:56 -05:00
self.filemenu.setTitle(theme["main/menus/client/_name"])
self.changequirks.setText(theme["main/menus/profile/quirks"])
2011-02-03 01:20:37 -05:00
self.loadslum.setText(theme["main/menus/profile/block"])
2011-02-02 07:26:17 -05:00
self.changecoloraction.setText(theme["main/menus/profile/color"])
2011-02-01 06:14:56 -05:00
self.switch.setText(theme["main/menus/profile/switch"])
self.profilemenu.setTitle(theme["main/menus/profile/_name"])
2011-02-09 01:26:23 -05:00
self.aboutAction.setText(self.theme["main/menus/help/about"])
2011-07-12 03:15:47 -04:00
self.helpAction.setText(self.theme["main/menus/help/help"])
self.botAction.setText(self.theme["main/menus/help/calsprite"])
self.chanServAction.setText(self.theme["main/menus/help/chanserv"])
2011-07-12 03:15:47 -04:00
self.nickServAction.setText(self.theme["main/menus/help/nickserv"])
2011-02-09 01:26:23 -05:00
self.helpmenu.setTitle(self.theme["main/menus/help/_name"])
2011-02-01 06:14:56 -05:00
2021-04-08 19:14:54 -04:00
# Console
## if self.theme.has_key("main/menus/client/console"):
## self.console.action.setText(self.theme["main/menus/client/console"])
## else:
## self.console.action.setText("Console")
# has_key doesn't work out here for some reason, possibly because of inherits?
try:
self.console.action.setText(self.theme["main/menus/client/console"])
except:
self.console.action.setText("Console")
2021-04-10 18:16:53 -04:00
try:
self.reportBugAction.setText(self.theme["main/menus/help/reportbug"])
except:
self.reportBugAction.setText("REPORT BUG")
2021-08-09 00:06:00 -04:00
try:
self.xyzRulesAction.setText(self.theme["main/menus/help/rules"])
except:
self.xyzRulesAction.setText("RULES")
2011-01-28 21:36:12 -05:00
# moods
2011-01-31 18:43:49 -05:00
self.moodsLabel.setText(theme["main/moodlabel/text"])
self.moodsLabel.move(*theme["main/moodlabel/loc"])
self.moodsLabel.setStyleSheet(theme["main/moodlabel/style"])
2011-01-31 06:04:03 -05:00
if hasattr(self, 'moods'):
self.moods.removeButtons()
2011-02-23 16:31:20 -05:00
mood_list = theme["main/moods"]
2021-03-23 17:36:43 -04:00
mood_list = [dict([(str(k),v) for (k,v) in d.items()])
2011-02-23 16:31:20 -05:00
for d in mood_list]
self.moods = PesterMoodHandler(self, *[PesterMoodButton(self, **d) for d in mood_list])
2011-01-28 21:36:12 -05:00
self.moods.showButtons()
# chum
2011-02-06 19:50:21 -05:00
addChumStyle = "QPushButton { %s }" % (theme["main/addchum/style"])
2021-03-23 17:36:43 -04:00
if "main/addchum/pressed" in theme:
2011-02-06 19:50:21 -05:00
addChumStyle += "QPushButton:pressed { %s }" % (theme["main/addchum/pressed"])
pesterButtonStyle = "QPushButton { %s }" % (theme["main/pester/style"])
2021-03-23 17:36:43 -04:00
if "main/pester/pressed" in theme:
2011-02-06 19:50:21 -05:00
pesterButtonStyle += "QPushButton:pressed { %s }" % (theme["main/pester/pressed"])
blockButtonStyle = "QPushButton { %s }" % (theme["main/block/style"])
2021-03-23 17:36:43 -04:00
if "main/block/pressed" in theme:
2011-02-06 19:50:21 -05:00
pesterButtonStyle += "QPushButton:pressed { %s }" % (theme["main/block/pressed"])
2011-01-31 06:04:03 -05:00
self.addChumButton.setText(theme["main/addchum/text"])
self.addChumButton.resize(*theme["main/addchum/size"])
self.addChumButton.move(*theme["main/addchum/loc"])
2011-02-06 19:50:21 -05:00
self.addChumButton.setStyleSheet(addChumStyle)
2011-01-31 06:04:03 -05:00
self.pesterButton.setText(theme["main/pester/text"])
self.pesterButton.resize(*theme["main/pester/size"])
self.pesterButton.move(*theme["main/pester/loc"])
2011-02-06 19:50:21 -05:00
self.pesterButton.setStyleSheet(pesterButtonStyle)
2011-02-02 07:26:17 -05:00
self.blockButton.setText(theme["main/block/text"])
self.blockButton.resize(*theme["main/block/size"])
self.blockButton.move(*theme["main/block/loc"])
2011-02-06 19:50:21 -05:00
self.blockButton.setStyleSheet(blockButtonStyle)
2011-01-29 07:33:35 -05:00
# buttons
2011-01-31 06:04:03 -05:00
self.mychumhandleLabel.setText(theme["main/mychumhandle/label/text"])
self.mychumhandleLabel.move(*theme["main/mychumhandle/label/loc"])
self.mychumhandleLabel.setStyleSheet(theme["main/mychumhandle/label/style"])
2011-01-29 07:33:35 -05:00
self.mychumhandle.setText(self.profile().handle)
2011-01-31 06:04:03 -05:00
self.mychumhandle.move(*theme["main/mychumhandle/handle/loc"])
self.mychumhandle.resize(*theme["main/mychumhandle/handle/size"])
self.mychumhandle.setStyleSheet(theme["main/mychumhandle/handle/style"])
self.mychumcolor.resize(*theme["main/mychumhandle/colorswatch/size"])
self.mychumcolor.move(*theme["main/mychumhandle/colorswatch/loc"])
2011-01-29 07:33:35 -05:00
self.mychumcolor.setStyleSheet("background: %s" % (self.profile().colorhtml()))
2021-04-08 19:14:54 -04:00
# I don't know why "if "main/mychumhandle/currentMood" in self.theme:" doesn't work,
# But this seems to work just as well :3c
# GWAHH why does inheriting not work with this </3
# For some reason, this only works on trollian with 'try' :/
#if self.theme.has_key("main/mychumhandle/currentMood"):
try:
2011-02-06 19:50:21 -05:00
moodicon = self.profile().mood.icon(theme)
2011-02-08 05:18:37 -05:00
if hasattr(self, 'currentMoodIcon') and self.currentMoodIcon:
self.currentMoodIcon.hide()
self.currentMoodIcon = None
2021-03-23 17:36:43 -04:00
self.currentMoodIcon = QtWidgets.QLabel(self)
2011-02-06 19:50:21 -05:00
self.currentMoodIcon.setPixmap(moodicon.pixmap(moodicon.realsize()))
self.currentMoodIcon.move(*theme["main/mychumhandle/currentMood"])
self.currentMoodIcon.show()
except:
2011-02-06 19:50:21 -05:00
if hasattr(self, 'currentMoodIcon') and self.currentMoodIcon:
self.currentMoodIcon.hide()
self.currentMoodIcon = None
2021-03-25 12:52:43 -04:00
# This is a better spot to put this :)
# Setting QMessageBox's style usually doesn't do anything.
self.setStyleSheet("QInputDialog { %s } QMessageBox { %s }" % (self.theme["main/defaultwindow/style"], self.theme["main/defaultwindow/style"]))
2011-01-31 06:04:03 -05:00
if theme["main/mychumhandle/colorswatch/text"]:
self.mychumcolor.setText(theme["main/mychumhandle/colorswatch/text"])
2011-02-16 06:11:09 -05:00
else:
self.mychumcolor.setText("")
2011-01-29 07:33:35 -05:00
self.mychumhandleLabel.adjustSize() # Required so "CHUMHANDLE:" regardless of style-sheet.
self.moodsLabel.adjustSize() # Required so "MOOD:" regardless of style-sheet.
2021-03-25 12:52:43 -04:00
if _CONSOLE:
if self.console.window:
# A bit of an ugly hack....
self.console.window.changeTheme(theme)
# sounds
self._setup_sounds()
self.setVolume(self.config.volume())
def _setup_sounds(self, soundclass=None):
"""Set up the event sounds for later use."""
# Set up the sounds we're using.
if soundclass is None:
if (pygame and pygame.mixer):
# We have pygame, so we may as well use it.
soundclass = pygame.mixer.Sound
else:
PchumLog.warning("Failed to define pygame mixer, is pygame imported?")
2021-05-03 11:22:23 -04:00
soundclass = NoneSound
self.sound_type = soundclass
# Use the class we chose to build the sound set.
try:
# karxi: These all seem to be created using local paths.
# Note that if QSound.isAvailable is False, we could still try
# to play QSound objects - it'll just fail silently.
self.alarm = soundclass(self.theme["main/sounds/alertsound"])
self.memosound = soundclass(self.theme["main/sounds/memosound"])
self.namesound = soundclass("themes/namealarm.wav")
self.ceasesound = soundclass(self.theme["main/sounds/ceasesound"])
self.honksound = soundclass("themes/honk.wav")
except Exception as err:
PchumLog.error("Warning: Error loading sounds! ({0!r})".format(err))
self.alarm = NoneSound()
self.memosound = NoneSound()
2011-07-08 04:52:53 -04:00
self.namesound = NoneSound()
2011-02-10 20:55:45 -05:00
self.ceasesound = NoneSound()
2011-07-08 04:52:53 -04:00
self.honksound = NoneSound()
2011-06-24 12:27:18 -04:00
def setVolume(self, vol):
# TODO: Find a way to make this usable.
2011-06-24 12:27:18 -04:00
vol = vol/100.0
# TODO: Make these into an actual (stored) /dict/ later, for easier
# iteration.
sounds = [self.alarm, self.memosound, self.namesound, self.ceasesound,
self.honksound]
for sound in sounds:
try:
if pygame and pygame.mixer and \
isinstance(sound, pygame.mixer.Sound):#pygame.mixer.Sound is case sensitive!!
sound.set_volume(vol)
2021-05-03 11:22:23 -04:00
else:
sound.setVolume(vol)
except Exception as err:
# Why was this set as "info"? ?w?
PchumLog.warning("Couldn't set volume: {}".format(err))
2011-06-24 12:27:18 -04:00
def canSetVolume(self):
"""Returns the state of volume setting capabilities."""
# If the volume can be changed by Pesterchum.
if self.sound_type is None:
# We haven't initialized yet.
return False
if pygame and pygame.mixer:
# pygame lets us set the volume, thankfully
return True
# Aside from that, we don't have any alternatives at the moment.
return False
2011-01-31 06:04:03 -05:00
def changeTheme(self, theme):
2011-05-10 02:33:59 -04:00
# check theme
try:
themeChecker(theme)
except ThemeException as inst:
2021-03-23 17:36:43 -04:00
themeWarning = QtWidgets.QMessageBox(self)
themeWarning.setText("Theme Error: %s" % inst)
2011-05-10 02:33:59 -04:00
themeWarning.exec_()
theme = pesterTheme("pesterchum")
return
2011-01-31 06:04:03 -05:00
self.theme = theme
# do self
self.initTheme(theme)
2011-02-06 19:50:21 -05:00
# set mood
self.moods.updateMood(theme['main/defaultmood'])
2011-01-31 06:04:03 -05:00
# chum area
self.chumList.changeTheme(theme)
# do open windows
if self.tabconvo:
self.tabconvo.changeTheme(theme)
2011-02-05 22:24:27 -05:00
if self.tabmemo:
self.tabmemo.changeTheme(theme)
2021-03-23 17:36:43 -04:00
for c in list(self.convos.values()):
2011-01-31 06:04:03 -05:00
c.changeTheme(theme)
2021-03-23 17:36:43 -04:00
for m in list(self.memos.values()):
2011-02-05 22:27:13 -05:00
m.changeTheme(theme)
2011-02-02 19:06:03 -05:00
if hasattr(self, 'trollslum') and self.trollslum:
self.trollslum.changeTheme(theme)
2011-02-03 01:20:37 -05:00
if hasattr(self, 'allusers') and self.allusers:
self.allusers.changeTheme(theme)
2012-06-08 05:02:12 -04:00
if self.config.ghostchum():
self.theme["main"]["icon"] = "themes/pesterchum/pesterdunk.png"
self.theme["main"]["newmsgicon"] = "themes/pesterchum/ghostchum.png"
self.setWindowIcon(PesterIcon(self.theme["main/icon"]))
# system tray icon
self.updateSystemTray()
2011-01-31 06:04:03 -05:00
def updateSystemTray(self):
if len(self.waitingMessages) == 0:
self.trayIconSignal.emit(0)
else:
self.trayIconSignal.emit(1)
def systemTrayFunction(self):
if len(self.waitingMessages) == 0:
if self.isMinimized():
self.showNormal()
2011-02-08 02:56:30 -05:00
elif self.isHidden():
self.show()
else:
if self.isActiveWindow():
2011-03-05 20:21:45 -05:00
self.closeToTray()
else:
self.raise_()
self.activateWindow()
else:
self.waitingMessages.answerMessage()
2011-01-28 06:17:42 -05:00
2014-01-12 03:14:16 -05:00
def doAutoIdentify(self):
if self.userprofile.getAutoIdentify():
self.sendMessage.emit("identify " + self.userprofile.getNickServPass(), "NickServ")
2014-01-12 20:50:01 -05:00
def doAutoJoins(self):
if not self.autoJoinDone:
self.autoJoinDone = True
for memo in self.userprofile.getAutoJoins():
self.newMemo(memo, "i")
2011-02-04 19:50:56 -05:00
@QtCore.pyqtSlot()
def connected(self):
if self.loadingscreen:
2021-03-23 17:36:43 -04:00
self.loadingscreen.done(QtWidgets.QDialog.Accepted)
2011-02-04 19:50:56 -05:00
self.loadingscreen = None
2014-01-12 03:14:16 -05:00
self.doAutoIdentify()
2014-01-12 20:50:01 -05:00
self.doAutoJoins()
2014-01-12 03:14:16 -05:00
2011-01-29 07:33:35 -05:00
@QtCore.pyqtSlot()
2011-02-02 07:26:17 -05:00
def blockSelectedChum(self):
curChumListing = self.chumList.currentItem()
if curChumListing:
curChum = curChumListing.chum
2011-02-02 19:06:03 -05:00
self.blockChum(curChum.handle)
2011-02-02 07:26:17 -05:00
@QtCore.pyqtSlot()
2011-01-29 07:33:35 -05:00
def pesterSelectedChum(self):
curChum = self.chumList.currentItem()
if curChum:
2021-03-23 17:36:43 -04:00
text = str(curChum.text(0))
2011-05-06 02:25:51 -04:00
if text.rfind(" (") != -1:
text = text[0:text.rfind(" (")]
if text not in self.chumList.groups and \
text != "Chums":
self.newConversationWindow(curChum)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QtWidgets.QListWidgetItem)
2011-01-24 04:10:44 -05:00
def newConversationWindow(self, chumlisting):
2011-02-01 06:14:56 -05:00
# check chumdb
2011-01-24 04:10:44 -05:00
chum = chumlisting.chum
2011-02-01 06:14:56 -05:00
color = self.chumdb.getColor(chum)
if color:
chum.color = color
2011-01-24 04:10:44 -05:00
self.newConversation(chum)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
2011-01-26 05:32:35 -05:00
def closeConvo(self, handle):
2021-03-23 17:36:43 -04:00
h = str(handle)
try:
chum = self.convos[h].chum
except KeyError:
chum = self.convos[h.lower()].chum
try:
chumopen = self.convos[h].chumopen
except KeyError:
chumopen = self.convos[h.lower()].chumopen
2011-01-31 18:43:49 -05:00
if chumopen:
2011-02-13 04:27:12 -05:00
self.chatlog.log(chum.handle, self.profile().pestermsg(chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/ceasepester"]))
2011-01-31 18:43:49 -05:00
self.convoClosed.emit(handle)
self.chatlog.finish(h)
2011-02-02 03:20:48 -05:00
del self.convos[h]
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
def closeMemo(self, channel):
2021-03-23 17:36:43 -04:00
c = str(channel)
self.chatlog.finish(c)
self.leftChannel.emit(channel)
try:
del self.memos[c]
except KeyError:
del self.memos[c.lower()]
2011-01-27 06:05:36 -05:00
@QtCore.pyqtSlot()
2011-01-27 05:41:53 -05:00
def tabsClosed(self):
del self.tabconvo
self.tabconvo = None
2011-02-04 19:50:56 -05:00
@QtCore.pyqtSlot()
def memoTabsClosed(self):
del self.tabmemo
self.tabmemo = None
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, Mood)
2011-01-24 07:17:12 -05:00
def updateMoodSlot(self, handle, mood):
2021-03-23 17:36:43 -04:00
h = str(handle)
2011-01-24 07:17:12 -05:00
self.updateMood(h, mood)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QtGui.QColor)
2011-01-24 07:17:12 -05:00
def updateColorSlot(self, handle, color):
PchumLog.debug("updateColorSlot, "+ str(handle) +", " + str(color))
2021-03-23 17:36:43 -04:00
h = str(handle)
2011-01-24 07:17:12 -05:00
self.changeColor(h, color)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString)
2011-01-24 07:17:12 -05:00
def deliverMessage(self, handle, msg):
2021-03-23 17:36:43 -04:00
h = str(handle)
m = str(msg)
2011-01-24 07:17:12 -05:00
self.newMessage(h, m)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString, QString)
2011-02-04 19:50:56 -05:00
def deliverMemo(self, chan, handle, msg):
2021-03-23 17:36:43 -04:00
(c, h, m) = (str(chan), str(handle), str(msg))
2011-02-04 19:50:56 -05:00
self.newMemoMsg(c,h,m)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString)
def deliverNotice(self, handle, msg):
2021-03-23 17:36:43 -04:00
h = str(handle)
m = str(msg)
if h.upper() == "NICKSERV" and m.startswith("Your nickname is now being changed to"):
changedto = m[39:-1]
2021-03-23 17:36:43 -04:00
msgbox = QtWidgets.QMessageBox()
2021-03-25 12:52:43 -04:00
msgbox.setStyleSheet("QMessageBox{" + self.theme["main/defaultwindow/style"] + "}")
msgbox.setText("This chumhandle has been registered; you may not use it.")
msgbox.setInformativeText("Your handle is now being changed to %s." % (changedto))
2021-03-23 17:36:43 -04:00
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok)
msgbox.exec_()
elif h == self.randhandler.randNick:
self.randhandler.incoming(msg)
2021-03-23 17:36:43 -04:00
elif h in self.convos:
self.newMessage(h, m)
2014-01-12 03:14:16 -05:00
elif h.upper() == "NICKSERV" and "PESTERCHUM:" not in m:
m = nickservmsgs.translate(m)
if m:
t = self.tm.Toast("NickServ:", m)
t.show()
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString)
def deliverInvite(self, handle, channel):
2021-03-23 17:36:43 -04:00
msgbox = QtWidgets.QMessageBox()
msgbox.setText("You're invited!")
2021-03-25 12:52:43 -04:00
msgbox.setStyleSheet("QMessageBox{" + self.theme["main/defaultwindow/style"] + "}")
msgbox.setInformativeText("%s has invited you to the memo: %s\nWould you like to join them?" % (handle, channel))
2021-03-23 17:36:43 -04:00
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
# Find the Cancel button and make it default
for b in msgbox.buttons():
2021-03-23 17:36:43 -04:00
if msgbox.buttonRole(b) == QtWidgets.QMessageBox.RejectRole:
# We found the 'OK' button, set it as the default
b.setDefault(True)
b.setAutoDefault(True)
# Actually set it as the selected option, since we're
# already stealing focus
b.setFocus()
break
ret = msgbox.exec_()
2021-03-23 17:36:43 -04:00
if ret == QtWidgets.QMessageBox.Ok:
self.newMemo(str(channel), "+0:00")
@QtCore.pyqtSlot(QString)
def chanInviteOnly(self, channel):
self.inviteOnlyChan.emit(channel)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString)
def cannotSendToChan(self, channel, msg):
self.deliverMemo(channel, "ChanServ", msg)
# Unused and redefined.
#@QtCore.pyqtSlot(QString, QString)
#def modesUpdated(self, channel, modes):
# self.modesUpdated.emit(channel, modes)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString, QString)
def timeCommand(self, chan, handle, command):
2021-03-23 17:36:43 -04:00
(c, h, cmd) = (str(chan), str(handle), str(command))
2011-04-14 05:50:55 -04:00
if self.memos[c]:
self.memos[c].timeUpdate(h, cmd)
2011-01-24 07:17:12 -05:00
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString, QString)
2011-06-29 13:19:22 -04:00
def quirkDisable(self, channel, msg, op):
2021-03-23 17:36:43 -04:00
(c, msg, op) = (str(channel), str(msg), str(op))
if c not in self.memos:
2011-06-29 13:19:22 -04:00
return
memo = self.memos[c]
memo.quirkDisable(op, msg)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, PesterList)
2011-02-03 01:20:37 -05:00
def updateNames(self, channel, names):
2021-03-23 17:36:43 -04:00
c = str(channel)
2011-02-03 01:20:37 -05:00
# update name DB
self.namesdb[c] = names
# warn interested party of names
self.namesUpdated.emit(c)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString, QString)
2011-02-03 01:20:37 -05:00
def userPresentUpdate(self, handle, channel, update):
2021-03-23 17:36:43 -04:00
c = str(channel)
n = str(handle)
#PchumLog.debug("c=%s\nn=%s\nupdate=%s\n" % (c, n, update))
2011-02-06 01:02:39 -05:00
if update == "nick":
l = n.split(":")
oldnick = l[0]
newnick = l[1]
2011-07-17 04:58:19 -04:00
if update in ("quit", "netsplit"):
2021-03-23 17:36:43 -04:00
for c in list(self.namesdb.keys()):
2011-02-03 01:20:37 -05:00
try:
i = self.namesdb[c].index(n)
self.namesdb[c].pop(i)
except ValueError:
pass
except KeyError:
self.namesdb[c] = []
elif update == "left":
try:
i = self.namesdb[c].index(n)
self.namesdb[c].pop(i)
except ValueError:
pass
except KeyError:
self.namesdb[c] = []
2011-02-06 01:02:39 -05:00
elif update == "nick":
2021-03-23 17:36:43 -04:00
for c in list(self.namesdb.keys()):
2011-02-05 22:24:10 -05:00
try:
2011-02-06 01:02:39 -05:00
i = self.namesdb[c].index(oldnick)
self.namesdb[c].pop(i)
self.namesdb[c].append(newnick)
2011-02-05 22:24:10 -05:00
except ValueError:
2011-02-06 01:02:39 -05:00
pass
2011-02-05 22:24:10 -05:00
except KeyError:
2011-02-06 01:02:39 -05:00
pass
2011-02-03 01:20:37 -05:00
elif update == "join":
try:
i = self.namesdb[c].index(n)
except ValueError:
self.namesdb[c].append(n)
except KeyError:
self.namesdb[c] = [n]
#PchumLog.debug("handle=%s\nchannel=%s\nupdate=%s\n" % (handle, channel, update))
2011-02-03 01:20:37 -05:00
self.userPresentSignal.emit(handle, channel, update)
2011-01-27 04:46:47 -05:00
@QtCore.pyqtSlot()
def addChumWindow(self):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'addchumdialog'):
self.addchumdialog = None
if not self.addchumdialog:
2011-10-24 20:24:40 -04:00
available_groups = [g[0] for g in self.config.getGroups()]
self.addchumdialog = AddChumDialog(available_groups, self)
ok = self.addchumdialog.exec_()
2021-03-23 17:36:43 -04:00
handle = str(self.addchumdialog.chumBox.text()).strip()
newgroup = str(self.addchumdialog.newgroup.text()).strip()
2011-10-24 20:24:40 -04:00
selectedGroup = self.addchumdialog.groupBox.currentText()
group = newgroup if newgroup else selectedGroup
if ok:
2021-03-23 17:36:43 -04:00
handle = str(handle)
2011-10-24 20:24:40 -04:00
if handle in [h.handle for h in self.chumList.chums]:
self.addchumdialog = None
2011-10-24 20:24:40 -04:00
return
if not (PesterProfile.checkLength(handle) and
2011-08-23 06:23:59 -04:00
PesterProfile.checkValid(handle)[0]):
2021-03-23 17:36:43 -04:00
errormsg = QtWidgets.QErrorMessage(self)
errormsg.showMessage("THIS IS NOT A VALID CHUMTAG!")
self.addchumdialog = None
return
2011-10-24 20:24:40 -04:00
if re.search("[^A-Za-z0-9_\s]", group) is not None:
2021-03-23 17:36:43 -04:00
errormsg = QtWidgets.QErrorMessage(self)
2012-03-31 20:54:49 -04:00
errormsg.showMessage("THIS IS NOT A VALID GROUP NAME")
2011-10-24 20:24:40 -04:00
self.addchumdialog = None
return
if newgroup:
# make new group
self.addGroup(group)
chum = PesterProfile(handle, chumdb=self.chumdb, group=group)
self.chumdb.setGroup(handle, group)
2011-02-03 01:20:37 -05:00
self.addChum(chum)
self.addchumdialog = None
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
def removeChum(self, chumlisting):
self.config.removeChum(chumlisting)
def reportChum(self, handle):
2021-03-23 17:36:43 -04:00
(reason, ok) = QtWidgets.QInputDialog.getText(self, "Report User", "Enter the reason you are reporting this user (optional):")
2011-04-13 02:12:19 -04:00
if ok:
self.sendMessage.emit("REPORT %s %s" % (handle, reason) , "calSprite")
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
2011-02-02 07:26:17 -05:00
def blockChum(self, handle):
2021-03-23 17:36:43 -04:00
h = str(handle)
2011-02-02 19:06:03 -05:00
self.config.addBlocklist(h)
self.config.removeChum(h)
2021-03-23 17:36:43 -04:00
if h in self.convos:
2011-02-02 07:26:17 -05:00
convo = self.convos[h]
msg = self.profile().pestermsg(convo.chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/blocked"])
2011-02-03 03:51:22 -05:00
convo.textArea.append(convertTags(msg))
2011-02-13 04:27:12 -05:00
self.chatlog.log(convo.chum.handle, msg)
2011-02-02 07:26:17 -05:00
convo.updateBlocked()
2011-02-02 19:06:03 -05:00
self.chumList.removeChum(h)
if hasattr(self, 'trollslum') and self.trollslum:
newtroll = PesterProfile(h)
self.trollslum.addTroll(newtroll)
self.moodRequest.emit(newtroll)
2011-02-02 07:26:17 -05:00
self.blockedChum.emit(handle)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
2011-02-02 07:26:17 -05:00
def unblockChum(self, handle):
2021-03-23 17:36:43 -04:00
h = str(handle)
2011-02-02 19:06:03 -05:00
self.config.delBlocklist(h)
2021-03-23 17:36:43 -04:00
if h in self.convos:
2011-02-02 07:26:17 -05:00
convo = self.convos[h]
msg = self.profile().pestermsg(convo.chum, QtGui.QColor(self.theme["convo/systemMsgColor"]), self.theme["convo/text/unblocked"])
2011-02-03 03:51:22 -05:00
convo.textArea.append(convertTags(msg))
2011-02-13 04:27:12 -05:00
self.chatlog.log(convo.chum.handle, msg)
2011-02-02 07:26:17 -05:00
convo.updateMood(convo.chum.mood, unblocked=True)
2011-02-02 19:06:03 -05:00
chum = PesterProfile(h, chumdb=self.chumdb)
if hasattr(self, 'trollslum') and self.trollslum:
self.trollslum.removeTroll(handle)
self.config.addChum(chum)
self.chumList.addChum(chum)
self.moodRequest.emit(chum)
2011-02-02 07:26:17 -05:00
self.unblockedChum.emit(handle)
2011-02-02 19:06:03 -05:00
2011-02-10 20:55:45 -05:00
@QtCore.pyqtSlot(bool)
def toggleIdle(self, idle):
2011-02-13 04:27:12 -05:00
if idle:
# We checked the box to go idle.
self.idler.manual = True
2011-06-28 19:26:13 -04:00
self.setAway.emit(True)
self.randhandler.setIdle(True)
self._sendIdleMsgs()
2011-02-13 04:27:12 -05:00
else:
self.idler.manual = False
2011-06-28 19:26:13 -04:00
self.setAway.emit(False)
self.randhandler.setIdle(False)
self.idler.time = 0
# karxi: TODO: Need to consider sticking an idle-setter here.
2011-02-10 20:55:45 -05:00
@QtCore.pyqtSlot()
def checkIdle(self):
newpos = QtGui.QCursor.pos()
oldpos = self.idler.pos
# Save the new position.
self.idler.pos = newpos
if self.idler.manual:
# We're already idle, because the user said to be.
self.idler.time = 0
return
elif self.idler.auto:
self.idler.time = 0
if newpos != oldpos:
# Cursor moved; unset idle.
self.idler.auto = False
self.setAway.emit(False)
self.randhandler.setIdle(False)
return
if newpos != oldpos:
# Our cursor has moved, which means we can't be idle.
self.idler.time = 0
return
# If we got here, WE ARE NOT IDLE, but may become so
self.idler.time += 1
if self.idler.time >= self.idler.threshold:
# We've been idle for long enough to fall automatically idle.
self.idler.auto = True
# We don't need this anymore.
self.idler.time = 0
# Make it clear that we're idle.
self.setAway.emit(True)
self.randhandler.setIdle(True)
self._sendIdleMsgs()
def _sendIdleMsgs(self):
# Tell everyone we're in a chat with that we just went idle.
sysColor = QtGui.QColor(self.theme["convo/systemMsgColor"])
verb = self.theme["convo/text/idle"]
2021-03-23 17:36:43 -04:00
for (h, convo) in self.convos.items():
# karxi: There's an irritating issue here involving a lack of
# consideration for case-sensitivity.
# This fix is a little sloppy, and I need to look into what it
# might affect, but I've been using it for months and haven't
# noticed any issues....
handle = convo.chum.handle
2016-12-10 19:49:58 -05:00
if self.isBot(handle):
# Don't send these idle messages.
continue
# karxi: Now we just use 'handle' instead of 'h'.
if convo.chumopen:
msg = self.profile().idlemsg(sysColor, verb)
convo.textArea.append(convertTags(msg))
self.chatlog.log(handle, msg)
self.sendMessage.emit("PESTERCHUM:IDLE", handle)
2016-12-10 19:49:58 -05:00
# Presented here so it can be called by other scripts.
@staticmethod
def isBot(handle):
return handle.upper() in BOTNAMES
@QtCore.pyqtSlot()
2011-02-06 19:50:21 -05:00
def importExternalConfig(self):
2021-03-23 17:36:43 -04:00
f = QtWidgets.QFileDialog.getOpenFileName(self)[0]
2011-02-21 14:07:59 -05:00
if f == "":
return
2011-02-06 19:50:21 -05:00
fp = open(f, 'r')
2011-02-24 21:15:21 -05:00
regexp_state = None
2021-03-23 17:36:43 -04:00
for l in fp:
2011-02-06 19:50:21 -05:00
# import chumlist
2011-02-24 21:15:21 -05:00
l = l.rstrip()
2011-02-06 19:50:21 -05:00
chum_mo = re.match("handle: ([A-Za-z0-9]+)", l)
if chum_mo is not None:
chum = PesterProfile(chum_mo.group(1))
self.addChum(chum)
2011-02-24 21:15:21 -05:00
continue
if regexp_state is not None:
replace_mo = re.match("replace: (.+)", l)
if replace_mo is not None:
replace = replace_mo.group(1)
try:
re.compile(regexp_state)
except re.error:
2011-02-24 21:15:21 -05:00
continue
newquirk = pesterQuirk({"type": "regexp",
"from": regexp_state,
"to": replace})
qs = self.userprofile.quirks
qs.addQuirk(newquirk)
self.userprofile.setQuirks(qs)
regexp_state = None
continue
search_mo = re.match("search: (.+)", l)
if search_mo is not None:
regexp_state = search_mo.group(1)
continue
other_mo = re.match("(prefix|suffix): (.+)", l)
if other_mo is not None:
newquirk = pesterQuirk({"type": other_mo.group(1),
"value": other_mo.group(2)})
qs = self.userprofile.quirks
qs.addQuirk(newquirk)
self.userprofile.setQuirks(qs)
2011-02-06 19:50:21 -05:00
@QtCore.pyqtSlot()
def showMemos(self, channel=""):
2011-02-04 16:17:27 -05:00
if not hasattr(self, 'memochooser'):
self.memochooser = None
if self.memochooser:
return
2011-02-06 19:50:21 -05:00
self.memochooser = PesterMemoList(self, channel)
2021-03-23 17:36:43 -04:00
self.memochooser.accepted.connect(self.joinSelectedMemo)
self.memochooser.rejected.connect(self.memoChooserClose)
2011-02-04 16:17:27 -05:00
self.requestChannelList.emit()
self.memochooser.show()
@QtCore.pyqtSlot()
def joinSelectedMemo(self):
2021-03-23 17:36:43 -04:00
time = str(self.memochooser.timeinput.text())
2011-02-06 19:50:21 -05:00
secret = self.memochooser.secretChannel.isChecked()
invite = self.memochooser.inviteChannel.isChecked()
# Join the ones on the list first
for SelectedMemo in self.memochooser.SelectedMemos():
2021-03-23 17:36:43 -04:00
channel = "#"+str(SelectedMemo.target)
self.newMemo(channel, time)
if self.memochooser.newmemoname():
newmemo = self.memochooser.newmemoname()
2021-03-23 17:36:43 -04:00
channel = str(newmemo).replace(" ", "_")
channel = re.sub(r"[^A-Za-z0-9#_\,]", "", channel)
# Allow us to join more than one with this.
chans = channel.split(',')
# Filter out empty entries.
2021-03-23 17:36:43 -04:00
chans = [_f for _f in chans if _f]
for c in chans:
c = '#' + c
# We should really change this code to only make the memo once
# the server has confirmed that we've joined....
self.newMemo(c, time, secret=secret, invite=invite)
2011-02-04 16:17:27 -05:00
self.memochooser = None
@QtCore.pyqtSlot()
def memoChooserClose(self):
self.memochooser = None
@QtCore.pyqtSlot(PesterList)
def updateChannelList(self, channels):
if hasattr(self, 'memochooser') and self.memochooser:
self.memochooser.updateChannels(channels)
@QtCore.pyqtSlot()
2011-02-03 01:20:37 -05:00
def showAllUsers(self):
if not hasattr(self, 'allusers'):
self.allusers = None
if not self.allusers:
self.allusers = PesterUserlist(self.config, self.theme, self)
2021-03-23 17:36:43 -04:00
self.allusers.accepted.connect(self.userListClose)
self.allusers.rejected.connect(self.userListClose)
self.allusers.addChum['QString'].connect(self.userListAdd)
self.allusers.pesterChum['QString'].connect(self.userListPester)
2011-02-03 01:20:37 -05:00
self.requestNames.emit("#pesterchum")
self.allusers.show()
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
2011-02-03 01:20:37 -05:00
def userListAdd(self, handle):
2021-03-23 17:36:43 -04:00
h = str(handle)
2011-02-03 01:20:37 -05:00
chum = PesterProfile(h, chumdb=self.chumdb)
self.addChum(chum)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
2011-04-13 02:12:19 -04:00
def userListPester(self, handle):
2021-03-23 17:36:43 -04:00
h = str(handle)
2011-04-13 02:12:19 -04:00
self.newConversation(h)
2011-02-03 01:20:37 -05:00
@QtCore.pyqtSlot()
def userListClose(self):
self.allusers = None
2011-02-04 16:17:27 -05:00
2011-02-03 01:20:37 -05:00
@QtCore.pyqtSlot()
2011-01-29 16:55:35 -05:00
def openQuirks(self):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'quirkmenu'):
self.quirkmenu = None
2011-01-29 16:55:35 -05:00
if not self.quirkmenu:
self.quirkmenu = PesterChooseQuirks(self.config, self.theme, self)
2021-03-23 17:36:43 -04:00
self.quirkmenu.accepted.connect(self.updateQuirks)
self.quirkmenu.rejected.connect(self.closeQuirks)
2011-01-29 16:55:35 -05:00
self.quirkmenu.show()
self.quirkmenu.raise_()
self.quirkmenu.activateWindow()
@QtCore.pyqtSlot()
def updateQuirks(self):
2011-05-25 04:38:36 -04:00
for i in range(self.quirkmenu.quirkList.topLevelItemCount()):
2021-03-23 17:36:43 -04:00
curgroup = str(self.quirkmenu.quirkList.topLevelItem(i).text(0))
2011-05-25 04:38:36 -04:00
for j in range(self.quirkmenu.quirkList.topLevelItem(i).childCount()):
item = self.quirkmenu.quirkList.topLevelItem(i).child(j)
item.quirk.quirk["on"] = item.quirk.on = (item.checkState(0) == QtCore.Qt.Checked)
item.quirk.quirk["group"] = item.quirk.group = curgroup
2011-01-29 16:55:35 -05:00
quirks = pesterQuirks(self.quirkmenu.quirks())
self.userprofile.setQuirks(quirks)
if hasattr(self.quirkmenu, 'quirktester') and self.quirkmenu.quirktester:
self.quirkmenu.quirktester.close()
2011-01-29 16:55:35 -05:00
self.quirkmenu = None
@QtCore.pyqtSlot()
def closeQuirks(self):
if hasattr(self.quirkmenu, 'quirktester') and self.quirkmenu.quirktester:
self.quirkmenu.quirktester.close()
2011-01-29 16:55:35 -05:00
self.quirkmenu = None
@QtCore.pyqtSlot()
def openChat(self):
if not hasattr(self, "openchatdialog"):
self.openchatdialog = None
if not self.openchatdialog:
2021-03-23 17:36:43 -04:00
(chum, ok) = QtWidgets.QInputDialog.getText(self, "Pester Chum", "Enter a handle to pester:")
try:
if ok:
2021-03-23 17:36:43 -04:00
self.newConversation(str(chum))
except:
pass
finally:
self.openchatdialog = 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)
2021-03-23 17:36:43 -04:00
self.logusermenu.accepted.connect(self.closeLogUsers)
self.logusermenu.rejected.connect(self.closeLogUsers)
self.logusermenu.show()
self.logusermenu.raise_()
self.logusermenu.activateWindow()
@QtCore.pyqtSlot()
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:
2021-03-23 17:36:43 -04:00
(gname, ok) = QtWidgets.QInputDialog.getText(self, "Add Group", "Enter a name for the new group:")
if ok:
2021-03-23 17:36:43 -04:00
gname = str(gname)
2011-05-06 02:25:51 -04:00
if re.search("[^A-Za-z0-9_\s]", gname) is not None:
2021-03-23 17:36:43 -04:00
msgbox = QtWidgets.QMessageBox()
msgbox.setInformativeText("THIS IS NOT A VALID GROUP NAME")
2021-03-23 17:36:43 -04:00
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok)
2021-03-25 12:52:43 -04:00
msgbox.setStyleSheet("QMessageBox{" + self.theme["main/defaultwindow/style"] + "}")#Style :) (memos/style or convo/style works :3 )
msgbox.exec_()
self.addgroupdialog = None
return
2011-10-24 20:24:40 -04:00
self.addGroup(gname)
self.addgroupdialog = None
@QtCore.pyqtSlot()
2011-01-27 04:46:47 -05:00
def openOpts(self):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'optionmenu'):
self.optionmenu = None
2011-01-27 04:46:47 -05:00
if not self.optionmenu:
self.optionmenu = PesterOptions(self.config, self.theme, self)
2021-03-23 17:36:43 -04:00
self.optionmenu.accepted.connect(self.updateOptions)
self.optionmenu.rejected.connect(self.closeOptions)
2011-01-27 04:46:47 -05:00
self.optionmenu.show()
self.optionmenu.raise_()
self.optionmenu.activateWindow()
@QtCore.pyqtSlot()
2011-01-27 21:21:02 -05:00
def closeOptions(self):
self.optionmenu.close()
self.optionmenu = None
@QtCore.pyqtSlot()
2011-01-27 04:46:47 -05:00
def updateOptions(self):
try:
# tabs
curtab = self.config.tabs()
tabsetting = self.optionmenu.tabcheck.isChecked()
if curtab and not tabsetting:
# split tabs into windows
windows = []
if self.tabconvo:
windows = list(self.tabconvo.convos.values())
for w in windows:
w.setParent(None)
w.show()
w.raiseChat()
if self.tabconvo:
self.tabconvo.closeSoft()
# save options
self.config.set("tabs", tabsetting)
elif tabsetting and not curtab:
# combine
self.createTabWindow()
newconvos = {}
2021-03-23 17:36:43 -04:00
for (h,c) in self.convos.items():
c.setParent(self.tabconvo)
self.tabconvo.addChat(c)
self.tabconvo.show()
newconvos[h] = c
self.convos = newconvos
# save options
self.config.set("tabs", tabsetting)
# tabs memos
curtabmemo = self.config.tabMemos()
tabmemosetting = self.optionmenu.tabmemocheck.isChecked()
if curtabmemo and not tabmemosetting:
# split tabs into windows
windows = []
if self.tabmemo:
windows = list(self.tabmemo.convos.values())
for w in windows:
w.setParent(None)
w.show()
w.raiseChat()
if self.tabmemo:
self.tabmemo.closeSoft()
# save options
self.config.set("tabmemos", tabmemosetting)
elif tabmemosetting and not curtabmemo:
# combine
newmemos = {}
self.createMemoTabWindow()
2021-03-23 17:36:43 -04:00
for (h,m) in self.memos.items():
m.setParent(self.tabmemo)
self.tabmemo.addChat(m)
self.tabmemo.show()
newmemos[h] = m
self.memos = newmemos
# save options
self.config.set("tabmemos", tabmemosetting)
# hidden chums
chumsetting = self.optionmenu.hideOffline.isChecked()
curchum = self.config.hideOfflineChums()
if curchum and not chumsetting:
self.chumList.showAllChums()
elif chumsetting and not curchum:
self.chumList.hideOfflineChums()
self.config.set("hideOfflineChums", chumsetting)
# sorting method
sortsetting = self.optionmenu.sortBox.currentIndex()
cursort = self.config.sortMethod()
self.config.set("sortMethod", sortsetting)
if sortsetting != cursort:
self.chumList.sort()
# sound
soundsetting = self.optionmenu.soundcheck.isChecked()
self.config.set("soundon", soundsetting)
chatsoundsetting = self.optionmenu.chatsoundcheck.isChecked()
curchatsound = self.config.chatSound()
if chatsoundsetting != curchatsound:
self.config.set('chatSound', chatsoundsetting)
memosoundsetting = self.optionmenu.memosoundcheck.isChecked()
curmemosound = self.config.memoSound()
if memosoundsetting != curmemosound:
self.config.set('memoSound', memosoundsetting)
memopingsetting = self.optionmenu.memopingcheck.isChecked()
curmemoping = self.config.memoPing()
if memopingsetting != curmemoping:
self.config.set('pingSound', memopingsetting)
namesoundsetting = self.optionmenu.namesoundcheck.isChecked()
curnamesound = self.config.nameSound()
if namesoundsetting != curnamesound:
self.config.set('nameSound', namesoundsetting)
volumesetting = self.optionmenu.volume.value()
curvolume = self.config.volume()
if volumesetting != curvolume:
self.config.set('volume', volumesetting)
self.setVolume(volumesetting)
# timestamps
timestampsetting = self.optionmenu.timestampcheck.isChecked()
self.config.set("showTimeStamps", timestampsetting)
2021-03-23 17:36:43 -04:00
timeformatsetting = str(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)
# 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)
# online numbers
onlinenumsetting = self.optionmenu.showonlinenumbers.isChecked()
curonlinenum = self.config.showOnlineNumbers()
if onlinenumsetting and not curonlinenum:
self.chumList.showOnlineNumbers()
elif curonlinenum and not onlinenumsetting:
self.chumList.hideOnlineNumbers()
self.config.set("onlineNumbers", onlinenumsetting)
# logging
logpesterssetting = 0
if self.optionmenu.logpesterscheck.isChecked():
logpesterssetting = logpesterssetting | self.config.LOG
if self.optionmenu.stamppestercheck.isChecked():
logpesterssetting = logpesterssetting | self.config.STAMP
curlogpesters = self.config.logPesters()
if logpesterssetting != curlogpesters:
self.config.set('logPesters', logpesterssetting)
logmemossetting = 0
if self.optionmenu.logmemoscheck.isChecked():
logmemossetting = logmemossetting | self.config.LOG
if self.optionmenu.stampmemocheck.isChecked():
logmemossetting = logmemossetting | self.config.STAMP
curlogmemos = self.config.logMemos()
if logmemossetting != curlogmemos:
self.config.set('logMemos', logmemossetting)
# memo and user links
linkssetting = self.optionmenu.userlinkscheck.isChecked()
curlinks = self.config.disableUserLinks()
if linkssetting != curlinks:
self.config.set('userLinks', not linkssetting)
# idle time
idlesetting = self.optionmenu.idleBox.value()
curidle = self.config.idleTime()
if idlesetting != curidle:
self.config.set('idleTime', idlesetting)
self.idler.threshold = 60*idlesetting
# theme
2012-06-08 05:02:12 -04:00
ghostchumsetting = self.optionmenu.ghostchum.isChecked()
curghostchum = self.config.ghostchum()
self.config.set('ghostchum', ghostchumsetting)
self.themeSelected(ghostchumsetting != curghostchum)
# randoms
if self.randhandler.running:
self.randhandler.setRandomer(self.optionmenu.randomscheck.isChecked())
# button actions
minisetting = self.optionmenu.miniBox.currentIndex()
curmini = self.config.minimizeAction()
if minisetting != curmini:
self.config.set('miniAction', minisetting)
self.setButtonAction(self.miniButton, minisetting, curmini)
closesetting = self.optionmenu.closeBox.currentIndex()
curclose = self.config.closeAction()
if closesetting != curclose:
self.config.set('closeAction', closesetting)
self.setButtonAction(self.closeButton, closesetting, curclose)
# op and voice messages
opvmesssetting = self.optionmenu.memomessagecheck.isChecked()
curopvmess = self.config.opvoiceMessages()
if opvmesssetting != curopvmess:
self.config.set('opvMessages', opvmesssetting)
# animated smiles
animatesetting = self.optionmenu.animationscheck.isChecked()
curanimate = self.config.animations()
if animatesetting != curanimate:
self.config.set('animations', animatesetting)
self.animationSetting.emit(animatesetting)
# update checked
#updatechecksetting = self.optionmenu.updateBox.currentIndex()
#curupdatecheck = self.config.checkForUpdates()
#if updatechecksetting != curupdatecheck:
# self.config.set('checkUpdates', updatechecksetting)
# mspa update check
#if ostools.isOSXLeopard():
# mspachecksetting = false
#else:
# mspachecksetting = self.optionmenu.mspaCheck.isChecked()
#curmspacheck = self.config.checkMSPA()
#if mspachecksetting != curmspacheck:
# self.config.set('mspa', mspachecksetting)
# Taskbar blink
blinksetting = 0
if self.optionmenu.pesterBlink.isChecked():
blinksetting |= self.config.PBLINK
if self.optionmenu.memoBlink.isChecked():
blinksetting |= self.config.MBLINK
curblink = self.config.blink()
if blinksetting != curblink:
self.config.set('blink', blinksetting)
# toast notifications
self.tm.setEnabled(self.optionmenu.notifycheck.isChecked())
2021-03-23 17:36:43 -04:00
self.tm.setCurrentType(str(self.optionmenu.notifyOptions.currentText()))
notifysetting = 0
if self.optionmenu.notifySigninCheck.isChecked():
notifysetting |= self.config.SIGNIN
if self.optionmenu.notifySignoutCheck.isChecked():
notifysetting |= self.config.SIGNOUT
if self.optionmenu.notifyNewMsgCheck.isChecked():
notifysetting |= self.config.NEWMSG
if self.optionmenu.notifyNewConvoCheck.isChecked():
notifysetting |= self.config.NEWCONVO
if self.optionmenu.notifyMentionsCheck.isChecked():
notifysetting |= self.config.INITIALS
curnotify = self.config.notifyOptions()
if notifysetting != curnotify:
self.config.set('notifyOptions', notifysetting)
2011-09-13 00:03:05 -04:00
# low bandwidth
bandwidthsetting = self.optionmenu.bandwidthcheck.isChecked()
curbandwidth = self.config.lowBandwidth()
if bandwidthsetting != curbandwidth:
self.config.set('lowBandwidth', bandwidthsetting)
if bandwidthsetting:
self.leftChannel.emit("#pesterchum")
else:
self.joinChannel.emit("#pesterchum")
2014-01-12 03:14:16 -05:00
# nickserv
autoidentify = self.optionmenu.autonickserv.isChecked()
nickservpass = self.optionmenu.nickservpass.text()
self.userprofile.setAutoIdentify(autoidentify)
self.userprofile.setNickServPass(str(nickservpass))
2014-01-12 20:50:01 -05:00
# auto join memos
autojoins = []
for i in range(self.optionmenu.autojoinlist.count()):
autojoins.append(str(self.optionmenu.autojoinlist.item(i).text()))
self.userprofile.setAutoJoins(autojoins)
# advanced
## user mode
if self.advanced:
newmodes = self.optionmenu.modechange.text()
if newmodes:
self.setChannelMode.emit(self.profile().handle, newmodes, "")
except Exception as e:
PchumLog.error(e)
finally:
self.optionmenu = None
2011-01-27 21:21:02 -05:00
2011-05-05 02:48:44 -04:00
def setButtonAction(self, button, setting, old):
if old == 0: # minimize to taskbar
2021-03-23 17:36:43 -04:00
button.clicked.disconnect(self.showMinimized)
2011-05-05 02:48:44 -04:00
elif old == 1: # minimize to tray
2021-03-23 17:36:43 -04:00
button.clicked.disconnect(self.closeToTray)
2011-05-05 02:48:44 -04:00
elif old == 2: # quit
2021-03-23 17:36:43 -04:00
button.clicked.disconnect(self.app.quit)
2011-05-05 02:48:44 -04:00
if setting == 0: # minimize to taskbar
2021-03-23 17:36:43 -04:00
button.clicked.connect(self.showMinimized)
2011-05-05 02:48:44 -04:00
elif setting == 1: # minimize to tray
2021-03-23 17:36:43 -04:00
button.clicked.connect(self.closeToTray)
2011-05-05 02:48:44 -04:00
elif setting == 2: # quit
2021-03-23 17:36:43 -04:00
button.clicked.connect(self.app.quit)
2011-05-05 02:48:44 -04:00
2011-01-27 21:21:02 -05:00
@QtCore.pyqtSlot()
2011-11-07 21:07:06 -05:00
def themeSelectOverride(self):
self.themeSelected(self.theme.name)
@QtCore.pyqtSlot()
def themeSelected(self, override=False):
if not override:
2021-03-23 17:36:43 -04:00
themename = str(self.optionmenu.themeBox.currentText())
2011-11-07 21:07:06 -05:00
else:
themename = override
if override or themename != self.theme.name:
2011-01-31 18:43:49 -05:00
try:
self.changeTheme(pesterTheme(themename))
except ValueError as e:
2021-03-23 17:36:43 -04:00
themeWarning = QtWidgets.QMessageBox(self)
2011-02-01 06:14:56 -05:00
themeWarning.setText("Theme Error: %s" % (e))
themeWarning.exec_()
self.choosetheme = None
2011-01-31 18:43:49 -05:00
return
2011-01-28 06:26:13 -05:00
# update profile
self.userprofile.setTheme(self.theme)
2011-01-28 06:17:42 -05:00
self.choosetheme = None
@QtCore.pyqtSlot()
def closeTheme(self):
self.choosetheme = None
@QtCore.pyqtSlot()
2011-01-27 21:21:02 -05:00
def profileSelected(self):
if self.chooseprofile.profileBox and \
2011-01-28 01:41:01 -05:00
self.chooseprofile.profileBox.currentIndex() > 0:
2021-03-23 17:36:43 -04:00
handle = str(self.chooseprofile.profileBox.currentText())
2011-01-28 21:36:12 -05:00
if handle == self.profile().handle:
2011-02-01 06:14:56 -05:00
self.chooseprofile = None
2011-01-28 21:36:12 -05:00
return
try:
self.userprofile = userProfile(handle)
self.changeTheme(self.userprofile.getTheme())
except (json.JSONDecodeError, FileNotFoundError) as e:
msgBox = QtWidgets.QMessageBox()
msgBox.setIcon(QtWidgets.QMessageBox.Warning)
msgBox.setWindowTitle(":(")
msgBox.setTextFormat(QtCore.Qt.RichText) # Clickable html links
self.filename = _datadir+"pesterchum.js"
try:
msgBox.setText("<html><h3>Failed to load: " + ("<a href='%s'>%s/%s.js</a>" % (self.profiledir, self.profiledir, user)) + \
"<br><br> Try to check for syntax errors if the file exists." + \
"<br><br>If you got this message at launch you may want to change your default profile." + \
"<br><br>" + str(e) + "<\h3><\html>")
#"\" if pesterchum acts oddly you might want to try backing up and then deleting \"" + \
#_datadir+"pesterchum.js" + \
#"\"")
except:
# More generic error for if not all variables are available.
msgBox.setText("Unspecified profile error." + \
"<br><br> Try to check for syntax errors if the file exists." + \
"<br><br>If you got this message at launch you may want to change your default profile." + \
"<br><br>" + str(e) + "<\h3><\html>")
PchumLog.critical(e)
msgBox.exec_()
return
2011-01-27 21:21:02 -05:00
else:
2021-03-23 17:36:43 -04:00
handle = str(self.chooseprofile.chumHandle.text())
2011-01-28 21:36:12 -05:00
if handle == self.profile().handle:
2011-02-01 06:14:56 -05:00
self.chooseprofile = None
2011-01-28 21:36:12 -05:00
return
profile = PesterProfile(handle,
self.chooseprofile.chumcolor)
2011-01-27 21:21:02 -05:00
self.userprofile = userProfile.newUserProfile(profile)
2011-01-31 06:04:03 -05:00
self.changeTheme(self.userprofile.getTheme())
2011-01-27 21:21:02 -05:00
2011-02-02 03:20:48 -05:00
self.chatlog.close()
self.chatlog = PesterLog(handle, self)
2011-02-02 03:20:48 -05:00
2011-01-28 21:36:12 -05:00
# is default?
if self.chooseprofile.defaultcheck.isChecked():
self.config.set("defaultprofile", self.userprofile.chat.handle)
2011-02-02 19:06:03 -05:00
if hasattr(self, 'trollslum') and self.trollslum:
self.trollslum.close()
2011-02-01 06:14:56 -05:00
self.chooseprofile = None
2011-01-28 01:41:01 -05:00
self.profileChanged.emit()
2011-02-02 19:06:03 -05:00
@QtCore.pyqtSlot()
def showTrollSlum(self):
if not hasattr(self, 'trollslum'):
self.trollslum = None
if self.trollslum:
return
trolls = [PesterProfile(h) for h in self.config.getBlocklist()]
self.trollslum = TrollSlumWindow(trolls, self)
2021-03-23 17:36:43 -04:00
self.trollslum.blockChumSignal['QString'].connect(self.blockChum)
self.trollslum.unblockChumSignal['QString'].connect(self.unblockChum)
2011-02-03 01:20:37 -05:00
self.moodsRequest.emit(PesterList(trolls))
2011-02-02 19:06:03 -05:00
self.trollslum.show()
@QtCore.pyqtSlot()
def closeTrollSlum(self):
self.trollslum = None
2011-01-27 21:21:02 -05:00
@QtCore.pyqtSlot()
2011-01-29 07:33:35 -05:00
def changeMyColor(self):
2011-01-31 06:04:03 -05:00
if not hasattr(self, 'colorDialog'):
self.colorDialog = None
2011-01-29 07:33:35 -05:00
if self.colorDialog:
return
2021-03-23 17:36:43 -04:00
self.colorDialog = QtWidgets.QColorDialog(self)
2011-01-29 07:33:35 -05:00
color = self.colorDialog.getColor(initial=self.profile().color)
2011-02-04 16:17:27 -05:00
if not color.isValid():
color = self.profile().color
2011-01-29 07:33:35 -05:00
self.mychumcolor.setStyleSheet("background: %s" % color.name())
self.userprofile.setColor(color)
2011-01-31 18:43:49 -05:00
self.mycolorUpdated.emit()
2011-01-29 07:33:35 -05:00
self.colorDialog = None
@QtCore.pyqtSlot()
2011-01-27 21:21:02 -05:00
def closeProfile(self):
self.chooseprofile = None
2011-01-28 01:41:01 -05:00
@QtCore.pyqtSlot()
def switchProfile(self):
if self.convos:
2021-03-23 17:36:43 -04:00
closeWarning = QtWidgets.QMessageBox()
2011-01-29 07:33:35 -05:00
closeWarning.setText("WARNING: CHANGING PROFILES WILL CLOSE ALL CONVERSATION WINDOWS!")
closeWarning.setInformativeText("i warned you about windows bro!!!! i told you dog!")
2021-03-23 17:36:43 -04:00
closeWarning.setStandardButtons(QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Ok)
closeWarning.setDefaultButton(QtWidgets.QMessageBox.Ok)
ret = closeWarning.exec_()
2021-03-23 17:36:43 -04:00
if ret == QtWidgets.QMessageBox.Cancel:
return
self.changeProfile()
# Update RE bot
try:
if self.userprofile.getRandom():
code = "+"
else:
code = "-"
self.sendNotice.emit(code, RANDNICK)
except:
PchumLog.warning("No randomEncounter set in userconfig?")
2011-02-09 01:26:23 -05:00
def aboutPesterchum(self):
if hasattr(self, 'aboutwindow') and self.aboutwindow:
return
self.aboutwindow = AboutPesterchum(self)
self.aboutwindow.exec_()
self.aboutwindow = None
2011-03-05 21:25:52 -05:00
@QtCore.pyqtSlot()
2011-04-13 02:12:19 -04:00
def loadCalsprite(self):
self.newConversation("calSprite")
@QtCore.pyqtSlot()
def loadChanServ(self):
self.newConversation("chanServ")
@QtCore.pyqtSlot()
def loadNickServ(self):
self.newConversation("nickServ")
@QtCore.pyqtSlot()
2011-03-05 21:25:52 -05:00
def launchHelp(self):
2021-03-24 16:45:54 -04:00
QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://github.com/Dpeta/pesterchum-alt-servers/issues", QtCore.QUrl.TolerantMode))
2021-02-21 10:40:03 -05:00
QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://forum.homestuck.xyz/viewtopic.php?f=7&t=467", QtCore.QUrl.TolerantMode))
2011-06-01 04:31:43 -04:00
@QtCore.pyqtSlot()
def reportBug(self):
2021-02-21 10:40:03 -05:00
QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://github.com/Dpeta/pesterchum-alt-servers/issues", QtCore.QUrl.TolerantMode))
2021-08-09 00:06:00 -04:00
@QtCore.pyqtSlot()
def xyzRules(self):
QtGui.QDesktopServices.openUrl(QtCore.QUrl("https://www.pesterchum.xyz/pesterchum-rules", QtCore.QUrl.TolerantMode))
2011-01-27 21:21:02 -05:00
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString, QString)
2011-02-01 06:14:56 -05:00
def nickCollision(self, handle, tmphandle):
self.mychumhandle.setText(tmphandle)
2011-02-19 18:06:54 -05:00
self.userprofile = userProfile(PesterProfile("pesterClient%d" % (random.randint(100,999)), QtGui.QColor("black"), Mood(0)))
self.changeTheme(self.userprofile.getTheme())
2011-02-01 06:14:56 -05:00
if not hasattr(self, 'chooseprofile'):
self.chooseprofile = None
if not self.chooseprofile:
2021-03-23 17:36:43 -04:00
h = str(handle)
self.changeProfile(collision=h)
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QString)
2011-03-06 22:02:47 -05:00
def myHandleChanged(self, handle):
if self.profile().handle == handle:
2014-01-12 03:14:16 -05:00
self.doAutoIdentify()
2014-01-12 20:50:01 -05:00
self.doAutoJoins()
2011-03-06 22:02:47 -05:00
return
else:
self.nickCollision(self.profile().handle, handle)
2011-01-28 06:17:42 -05:00
@QtCore.pyqtSlot()
def pickTheme(self):
self.themePicker()
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QtWidgets.QSystemTrayIcon.ActivationReason)
def systemTrayActivated(self, reason):
2021-03-23 17:36:43 -04:00
if reason == QtWidgets.QSystemTrayIcon.Trigger:
self.systemTrayFunction()
2021-03-23 17:36:43 -04:00
elif reason == QtWidgets.QSystemTrayIcon.Context:
pass
2011-02-09 11:44:48 -05:00
# show context menu i guess
#self.showTrayContext.emit()
2011-06-20 19:18:47 -04:00
@QtCore.pyqtSlot()
def tooManyPeeps(self):
2021-03-23 17:36:43 -04:00
msg = QtWidgets.QMessageBox(self)
2011-06-20 19:18:47 -04:00
msg.setText("D: TOO MANY PEOPLE!!!")
msg.setInformativeText("The server has hit max capacity. Please try again later.")
msg.show()
2021-03-25 16:39:37 -04:00
@QtCore.pyqtSlot()
def quit(self):
try:
self.irc.quit_dc() # Actually send QUIT to server
except Exception as e:
# Not connected?
PchumLog.warning("QUIT failed: " + str(e))
try:
self.parent.trayicon.hide() #
self.app.quit()
except AttributeError as e:
# Called from outside main Window?
PchumLog.warning("Unelegant quit: " + str(e))
sys.exit()
2021-03-25 16:39:37 -04:00
def passIRC(self, irc):
self.irc = irc
def updateServerJson(self):
PchumLog.info(self.customServerPrompt_qline.text() + " chosen")
server_and_port = self.customServerPrompt_qline.text().split(':')
try:
server = {
"server": server_and_port[0],
2021-04-10 18:16:53 -04:00
"port": int(server_and_port[1]),# to make sure port is a valid integer, and raise an exception if it cannot be converted.
"TLS": self.TLS_checkbox.isChecked()
}
PchumLog.info("server: "+str(server))
except:
msgbox = QtWidgets.QMessageBox()
msgbox.setStyleSheet("QMessageBox{" + self.theme["main/defaultwindow/style"] + "}")
msgbox.setWindowIcon(PesterIcon(self.theme["main/icon"]))
msgbox.setInformativeText("Incorrect format :(")
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok)
msgbox.exec_()
self.chooseServer()
return 1
2021-04-08 19:50:50 -04:00
2021-04-08 20:38:34 -04:00
with open(_datadir + "serverlist.json", "r") as server_file:
read_file = server_file.read()
server_file.close()
server_list_obj = json.loads(read_file)
server_list_obj.append(server)
try:
2021-04-08 20:38:34 -04:00
with open(_datadir + "serverlist.json", "w") as server_file:
server_file.write(json.dumps(server_list_obj, indent = 4))
server_file.close()
except:
PchumLog.error("failed")
# Go back to original screen
self.chooseServer()
def resetServerlist(self):
default_server_list = [{
"server": "irc.pesterchum.xyz",
"port": "6697",
"TLS": True
}]
2021-04-08 20:38:34 -04:00
if os.path.isfile(_datadir + "serverlist.json"):
PchumLog.error("Failed to load server list from serverlist.json.")
2021-04-08 20:38:34 -04:00
msgbox = QtWidgets.QMessageBox()
msgbox.setStyleSheet("QMessageBox{" + self.theme["main/defaultwindow/style"] + "}")
msgbox.setWindowIcon(PesterIcon(self.theme["main/icon"]))
2022-03-17 18:30:04 -04:00
msgbox.setInformativeText("Failed to load server list, do you want to revert to defaults?\n" \
2021-04-08 20:38:34 -04:00
+ "If you choose no, Pesterchum will most likely crash unless you manually fix serverlist.json\n" \
+ "Please tell me if this error occurs :'3")
msgbox.addButton(QtWidgets.QPushButton("Yes"), QtWidgets.QMessageBox.YesRole)
msgbox.addButton(QtWidgets.QPushButton("No"), QtWidgets.QMessageBox.NoRole)
msgbox.exec_()
2021-04-08 20:38:34 -04:00
reply = msgbox.buttonRole(msgbox.clickedButton())
2021-04-08 20:38:34 -04:00
if (reply==QtWidgets.QMessageBox.YesRole):
with open(_datadir + "serverlist.json", "w") as server_file:
server_file.write(json.dumps(default_server_list, indent = 4) )
server_file.close()
else:
PchumLog.warning("Failed to load server list because serverlist.json doesn't exist, " \
2021-04-08 20:38:34 -04:00
+ "this isn't an issue if this is the first time Pesterchum has been started.")
with open(_datadir + "serverlist.json", "w") as server_file:
server_file.write(json.dumps(default_server_list, indent = 4) )
server_file.close()
self.chooseServer()
2021-04-08 19:50:50 -04:00
def removeServer(self):
server_list_items = []
try:
2021-04-08 20:38:34 -04:00
with open(_datadir + "serverlist.json", "r") as server_file:
2021-04-08 19:50:50 -04:00
read_file = server_file.read()
server_file.close()
server_list_obj = json.loads(read_file)
for i in range(len(server_list_obj)):
server_list_items.append(server_list_obj[i]["server"])
except:
if self.chooseServerAskedToReset == False:
self.chooseServerAskedToReset = True
2021-04-08 19:50:50 -04:00
self.resetServerlist()
return 1
2021-04-10 18:16:53 -04:00
selected_entry = None
2021-04-08 19:50:50 -04:00
for i in range(len(server_list_obj)):
if server_list_obj[i]["server"] == self.removeServerBox.currentText():
selected_entry = i
2021-04-10 18:16:53 -04:00
if selected_entry != None:
server_list_obj.pop(selected_entry)
try:
with open(_datadir + "serverlist.json", "w") as server_file:
server_file.write(json.dumps(server_list_obj, indent = 4))
server_file.close()
except:
PchumLog.error("failed")
2021-04-08 19:50:50 -04:00
self.chooseServer()
2021-04-08 19:50:50 -04:00
def setServer(self):
if self.serverBox.currentText() == "Add a server [Prompt]":
# Text input
self.customServerPrompt_qline = QtWidgets.QLineEdit(self)
self.customServerPrompt_qline.setMinimumWidth(200)
# Widget 1
self.customServerDialog = QtWidgets.QDialog()
# Buttons
cancel = QtWidgets.QPushButton("CANCEL")
ok = QtWidgets.QPushButton("OK")
ok.setDefault(True)
ok.clicked.connect(self.customServerDialog.accept)
cancel.clicked.connect(self.customServerDialog.reject)
#Layout
layout = QtWidgets.QHBoxLayout()
self.TLS_checkbox = QtWidgets.QCheckBox(self)
self.TLS_checkbox.setChecked(True)
TLS_checkbox_label = QtWidgets.QLabel(":33 < Check if you want to connect over TLS!!")
2021-04-08 19:50:50 -04:00
TLS_checkbox_label.setStyleSheet("QLabel { color: #416600; font-weight: bold;}")
TLS_layout = QtWidgets.QHBoxLayout()
TLS_layout.addWidget(TLS_checkbox_label)
TLS_layout.addWidget(self.TLS_checkbox)
layout.addWidget(cancel)
layout.addWidget(ok)
main_layout = QtWidgets.QVBoxLayout()
nep_prompt = QtWidgets.QLabel(":33 < Please put in the server's address in the format HOSTNAME:PORT\n:33 < Fur example, irc.pesterchum.xyz:6697")
2021-04-08 19:50:50 -04:00
nep_prompt.setStyleSheet("QLabel { color: #416600; font-weight: bold;}")
main_layout.addWidget(nep_prompt)
main_layout.addWidget(self.customServerPrompt_qline)
main_layout.addLayout(TLS_layout)
main_layout.addLayout(layout)
self.customServerDialog.setLayout(main_layout)
# Theme
self.customServerDialog.setStyleSheet(self.theme["main/defaultwindow/style"])
self.customServerDialog.setWindowIcon(PesterIcon(self.theme["main/icon"]))
# Connect
self.customServerDialog.accepted.connect(self.updateServerJson)
self.customServerDialog.rejected.connect(self.chooseServer)
# Show
self.customServerDialog.show()
self.customServerDialog.setFocus()
2021-04-08 20:38:34 -04:00
2021-04-08 19:50:50 -04:00
elif self.serverBox.currentText() == "Remove a server [Prompt]":
# Read servers.
server_list_items = []
try:
2021-04-08 20:38:34 -04:00
with open(_datadir + "serverlist.json", "r") as server_file:
2021-04-08 19:50:50 -04:00
read_file = server_file.read()
server_file.close()
server_obj = json.loads(read_file)
for i in range(len(server_obj)):
server_list_items.append(server_obj[i]["server"])
except:
if self.chooseServerAskedToReset == False:
self.chooseServerAskedToReset = True
2021-04-08 19:50:50 -04:00
self.resetServerlist()
return 1
PchumLog.info("server_list_items: " + str(server_list_items))
2021-04-08 19:50:50 -04:00
# Widget 1
self.chooseRemoveServerWidged = QtWidgets.QDialog()
# removeServerBox
self.removeServerBox = QtWidgets.QComboBox()
for i in range(len(server_list_items)):
self.removeServerBox.addItem(server_list_items[i])
# Buttons
cancel = QtWidgets.QPushButton("CANCEL")
ok = QtWidgets.QPushButton("OK")
ok.setDefault(True)
ok.clicked.connect(self.chooseRemoveServerWidged.accept)
cancel.clicked.connect(self.chooseRemoveServerWidged.reject)
#Layout
layout = QtWidgets.QHBoxLayout()
layout.addWidget(cancel)
layout.addWidget(ok)
main_layout = QtWidgets.QVBoxLayout()
main_layout.addWidget(QtWidgets.QLabel("Please choose a server to remove."))
main_layout.addWidget(self.removeServerBox)
main_layout.addLayout(layout)
self.chooseRemoveServerWidged.setLayout(main_layout)
# Theme
self.chooseRemoveServerWidged.setStyleSheet(self.theme["main/defaultwindow/style"])
self.chooseRemoveServerWidged.setWindowIcon(PesterIcon(self.theme["main/icon"]))
# Connect
self.chooseRemoveServerWidged.accepted.connect(self.removeServer)
self.chooseRemoveServerWidged.rejected.connect(self.chooseServer)
2021-04-08 19:50:50 -04:00
# Show
self.chooseRemoveServerWidged.show()
self.chooseRemoveServerWidged.setFocus()
else:
PchumLog.info(self.serverBox.currentText() + " chosen.")
2021-04-08 20:38:34 -04:00
with open(_datadir + "serverlist.json", "r") as server_file:
read_file = server_file.read()
server_file.close()
server_obj = json.loads(read_file)
selected_entry = None
for i in range(len(server_obj)):
if server_obj[i]["server"] == self.serverBox.currentText():
selected_entry = i
try:
2021-04-08 20:38:34 -04:00
with open(_datadir + "server.json", "w") as server_file:
json_server_file = {
"server": server_obj[selected_entry]["server"],
"port": server_obj[selected_entry]["port"],
"TLS": server_obj[selected_entry]["TLS"]
}
server_file.write(json.dumps(json_server_file, indent = 4) )
server_file.close()
except:
PchumLog.error("Failed to set server :(")
# Continue running Pesterchum as usual
# Sorry-
self.irc.start()
self.parent.reconnectok = False
self.parent.showLoading(self.parent.widget)
self.show() # Not required?
self.setFocus()
def chooseServer(self):
# Read servers.
server_list_items = []
try:
2021-04-08 20:38:34 -04:00
with open(_datadir + "serverlist.json", "r") as server_file:
read_file = server_file.read()
server_file.close()
server_obj = json.loads(read_file)
for i in range(len(server_obj)):
server_list_items.append(server_obj[i]["server"])
except:
if self.chooseServerAskedToReset == False:
self.chooseServerAskedToReset = True
self.resetServerlist()
return 1
PchumLog.info("server_list_items: " + str(server_list_items))
# Widget 1
self.chooseServerWidged = QtWidgets.QDialog()
# Serverbox
self.serverBox = QtWidgets.QComboBox()
for i in range(len(server_list_items)):
self.serverBox.addItem(server_list_items[i])
self.serverBox.addItem("Add a server [Prompt]")
2021-04-08 19:50:50 -04:00
self.serverBox.addItem("Remove a server [Prompt]")
# Buttons
cancel = QtWidgets.QPushButton("CANCEL")
ok = QtWidgets.QPushButton("OK")
ok.setDefault(True)
ok.clicked.connect(self.chooseServerWidged.accept)
cancel.clicked.connect(self.chooseServerWidged.reject)
#Layout
layout = QtWidgets.QHBoxLayout()
layout.addWidget(cancel)
layout.addWidget(ok)
main_layout = QtWidgets.QVBoxLayout()
main_layout.addWidget(QtWidgets.QLabel("Please choose a server."))
main_layout.addWidget(self.serverBox)
main_layout.addLayout(layout)
self.chooseServerWidged.setLayout(main_layout)
# Theme
self.chooseServerWidged.setStyleSheet(self.theme["main/defaultwindow/style"])
self.chooseServerWidged.setWindowIcon(PesterIcon(self.theme["main/icon"]))
# Connect
self.chooseServerWidged.accepted.connect(self.setServer)
self.chooseServerWidged.rejected.connect(self.quit)
# Show
self.chooseServerWidged.show()
self.chooseServerWidged.setFocus()
2021-03-23 17:36:43 -04:00
pcUpdate = QtCore.pyqtSignal('QString', 'QString')
2011-02-08 02:56:30 -05:00
closeToTraySignal = QtCore.pyqtSignal()
2021-03-23 17:36:43 -04:00
newConvoStarted = QtCore.pyqtSignal('QString', bool, name="newConvoStarted")
sendMessage = QtCore.pyqtSignal('QString', 'QString')
sendNotice = QtCore.pyqtSignal('QString', 'QString')
2022-06-02 17:15:45 -04:00
sendCTCP = QtCore.pyqtSignal('QString', 'QString')
2021-03-23 17:36:43 -04:00
convoClosed = QtCore.pyqtSignal('QString')
2011-01-28 01:41:01 -05:00
profileChanged = QtCore.pyqtSignal()
animationSetting = QtCore.pyqtSignal(bool)
2011-01-28 03:10:00 -05:00
moodRequest = QtCore.pyqtSignal(PesterProfile)
2011-02-03 01:20:37 -05:00
moodsRequest = QtCore.pyqtSignal(PesterList)
2011-01-28 21:36:12 -05:00
moodUpdated = QtCore.pyqtSignal()
2011-02-04 16:17:27 -05:00
requestChannelList = QtCore.pyqtSignal()
2021-03-23 17:36:43 -04:00
requestNames = QtCore.pyqtSignal('QString')
namesUpdated = QtCore.pyqtSignal('QString')
modesUpdated = QtCore.pyqtSignal('QString', 'QString')
userPresentSignal = QtCore.pyqtSignal('QString','QString','QString')
2011-01-31 18:43:49 -05:00
mycolorUpdated = QtCore.pyqtSignal()
trayIconSignal = QtCore.pyqtSignal(int)
2021-03-23 17:36:43 -04:00
blockedChum = QtCore.pyqtSignal('QString')
unblockedChum = QtCore.pyqtSignal('QString')
kickUser = QtCore.pyqtSignal('QString', 'QString')
joinChannel = QtCore.pyqtSignal('QString')
leftChannel = QtCore.pyqtSignal('QString')
setChannelMode = QtCore.pyqtSignal('QString', 'QString', 'QString')
channelNames = QtCore.pyqtSignal('QString')
inviteChum = QtCore.pyqtSignal('QString', 'QString')
inviteOnlyChan = QtCore.pyqtSignal('QString')
2011-02-13 20:32:02 -05:00
closeSignal = QtCore.pyqtSignal()
2011-02-14 16:15:32 -05:00
reconnectIRC = QtCore.pyqtSignal()
2021-03-23 17:36:43 -04:00
gainAttention = QtCore.pyqtSignal(QtWidgets.QWidget)
pingServer = QtCore.pyqtSignal()
2011-06-28 19:26:13 -04:00
setAway = QtCore.pyqtSignal(bool)
2021-03-23 17:36:43 -04:00
killSomeQuirks = QtCore.pyqtSignal('QString', 'QString')
2011-01-21 05:18:22 -05:00
2021-03-23 17:36:43 -04:00
class PesterTray(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, mainwindow, parent):
super(PesterTray, self).__init__(icon, parent)
self.mainwindow = mainwindow
@QtCore.pyqtSlot(int)
def changeTrayIcon(self, i):
if i == 0:
2011-02-02 03:20:48 -05:00
self.setIcon(PesterIcon(self.mainwindow.theme["main/icon"]))
else:
2011-02-02 03:20:48 -05:00
self.setIcon(PesterIcon(self.mainwindow.theme["main/newmsgicon"]))
2011-02-13 20:32:02 -05:00
@QtCore.pyqtSlot()
def mainWindowClosed(self):
self.hide()
2011-02-06 19:50:21 -05:00
class MainProgram(QtCore.QObject):
def __init__(self):
super(MainProgram, self).__init__()
if os.name.upper() == "NT":
# karxi: Before we do *anything* else, we have to make a special
# exception for Windows. Otherwise, the icon won't work properly.
# NOTE: This is presently being tested, since I don't have a
# Windows computer at the moment. Hopefully it'll work.
# See http://stackoverflow.com/a/1552105 for more details.
from ctypes import windll
# Note that this has to be unicode.
2021-03-23 17:36:43 -04:00
wid = "mspa.homestuck.pesterchum.314"
# Designate this as a separate process - i.e., tell Windows that
# Python is just hosting Pesterchum.
# TODO: Eventually we should get this changed so it checks and
# restores the old ID upon exit, but this usually doesn't matter -
# most users won't keep the process running once Pesterchum closes.
try:
windll.shell32.SetCurrentProcessExplicitAppUserModelID(wid)
except Exception as err:
# Log, but otherwise ignore any exceptions.
PchumLog.error("Failed to set AppUserModel ID: {0}".format(err))
PchumLog.error("Attempted to set as {0!r}.".format(wid))
# Back to our scheduled program.
2021-03-23 17:36:43 -04:00
self.app = QtWidgets.QApplication(sys.argv)
self.app.setApplicationName("Pesterchum")
self.app.setQuitOnLastWindowClosed(False)
2011-05-12 10:14:38 -04:00
options = self.oppts(sys.argv[1:])
2016-12-03 00:27:34 -05:00
def doSoundInit():
# TODO: Make this more uniform, adapt it into a general function.
if pygame and pygame.mixer:
# we could set the frequency higher but i love how cheesy it sounds
try:
pygame.mixer.init()
pygame.mixer.init()
except pygame.error as err:
2021-03-23 17:36:43 -04:00
print("Warning: No sound! (pygame error: %s)" % err)
2016-12-03 00:27:34 -05:00
else:
# Sound works, we're done.
return
# ... Other alternatives here. ...
# Last resort. (Always 'works' on Windows, no volume control.)
2021-03-23 17:38:53 -04:00
# QSound.isAvailable is no longer a thing :(
# Maybe fix.
#if QtMultimedia.QSound.isAvailable():
# # Sound works, we're done.
# return
#else:
# print("Warning: No sound! (No pygame/QSound)")
2016-12-03 00:27:34 -05:00
doSoundInit()
self.widget = PesterWindow(options, parent=self, app=self.app)
#self.widget.show() <== Already called in showLoading()
2011-02-06 19:50:21 -05:00
self.trayicon = PesterTray(PesterIcon(self.widget.theme["main/icon"]), self.widget, self.app)
2021-03-23 17:36:43 -04:00
self.traymenu = QtWidgets.QMenu()
2011-02-10 00:55:45 -05:00
moodMenu = self.traymenu.addMenu("SET MOOD")
2011-02-23 06:06:00 -05:00
moodCategories = {}
for k in Mood.moodcats:
moodCategories[k] = moodMenu.addMenu(k.upper())
2011-02-10 00:55:45 -05:00
self.moodactions = {}
for (i,m) in enumerate(Mood.moods):
2021-03-23 17:36:43 -04:00
maction = QtWidgets.QAction(m.upper(), self)
2011-02-10 00:55:45 -05:00
mobj = PesterMoodAction(i, self.widget.moods.updateMood)
2021-03-23 17:36:43 -04:00
maction.triggered.connect(mobj.updateMood)
2011-02-10 00:55:45 -05:00
self.moodactions[i] = mobj
2011-02-23 06:06:00 -05:00
moodCategories[Mood.revmoodcats[m]].addAction(maction)
2021-03-23 17:36:43 -04:00
miniAction = QtWidgets.QAction("MINIMIZE", self)
miniAction.triggered.connect(self.widget.showMinimized)
exitAction = QtWidgets.QAction("EXIT", self)
2021-03-25 16:39:37 -04:00
exitAction.triggered.connect(PesterWindow.quit)
2011-03-06 02:08:08 -05:00
self.traymenu.addAction(miniAction)
2011-02-10 13:00:06 -05:00
self.traymenu.addAction(exitAction)
2011-02-10 00:55:45 -05:00
2011-02-09 11:44:48 -05:00
self.trayicon.setContextMenu(self.traymenu)
2011-02-06 19:50:21 -05:00
self.trayicon.show()
2021-03-23 17:40:24 -04:00
self.trayicon.activated[QtWidgets.QSystemTrayIcon.ActivationReason].connect(self.widget.systemTrayActivated)
2021-03-23 17:36:43 -04:00
self.widget.trayIconSignal[int].connect(self.trayicon.changeTrayIcon)
self.widget.closeToTraySignal.connect(self.trayiconShow)
self.widget.closeSignal.connect(self.trayicon.mainWindowClosed)
self.trayicon.messageClicked.connect(self.trayMessageClick)
2011-02-06 19:50:21 -05:00
2011-02-19 21:38:06 -05:00
self.attempts = 0
# but it's at least better than the way it was before.
self.irc = PesterIRC(self.widget.config, self.widget)
2011-02-19 18:06:54 -05:00
self.connectWidgets(self.irc, self.widget)
2011-02-06 19:50:21 -05:00
self.widget.passIRC(self.irc) # Maybe this is absolutely terrible in practice, but screw it.
2021-03-23 17:40:24 -04:00
self.widget.gainAttention[QtWidgets.QWidget].connect(self.alertWindow)
2021-03-25 16:39:37 -04:00
2021-03-23 17:36:43 -04:00
@QtCore.pyqtSlot(QtWidgets.QWidget)
2011-06-20 06:34:06 -04:00
def alertWindow(self, widget):
self.app.alert(widget)
@QtCore.pyqtSlot()
def trayiconShow(self):
self.trayicon.show()
if self.widget.config.trayMessage():
self.trayicon.showMessage("Pesterchum", "Pesterchum is still running in the system tray.\n\
Right click to close it.\n\
Click this message to never see this again.")
@QtCore.pyqtSlot()
def trayMessageClick(self):
self.widget.config.set('traymsg', False)
widget2irc = [('sendMessage(QString, QString)',
'sendMessage(QString, QString)'),
('sendNotice(QString, QString)',
'sendNotice(QString, QString)'),
2022-06-02 17:15:45 -04:00
('sendCTCP(QString, QString)',
'sendCTCP(QString, QString)'),
('newConvoStarted(QString, bool)',
'startConvo(QString, bool)'),
('convoClosed(QString)',
'endConvo(QString)'),
('profileChanged()',
'updateProfile()'),
('moodRequest(PyQt_PyObject)',
'getMood(PyQt_PyObject)'),
('moodsRequest(PyQt_PyObject)',
'getMoods(PyQt_PyObject)'),
('moodUpdated()', 'updateMood()'),
('mycolorUpdated()','updateColor()'),
('blockedChum(QString)', 'blockedChum(QString)'),
('unblockedChum(QString)', 'unblockedChum(QString)'),
('requestNames(QString)','requestNames(QString)'),
('requestChannelList()', 'requestChannelList()'),
('joinChannel(QString)', 'joinChannel(QString)'),
('leftChannel(QString)', 'leftChannel(QString)'),
('kickUser(QString, QString)',
'kickUser(QString, QString)'),
('setChannelMode(QString, QString, QString)',
'setChannelMode(QString, QString, QString)'),
('channelNames(QString)',
'channelNames(QString)'),
('inviteChum(QString, QString)',
'inviteChum(QString, QString)'),
('pingServer()', 'pingServer()'),
('setAway(bool)', 'setAway(bool)'),
('killSomeQuirks(QString, QString)',
'killSomeQuirks(QString, QString)'),
('reconnectIRC()', 'reconnectIRC()')
]
# IRC --> Main window
irc2widget = [('connected()', 'connected()'),
('moodUpdated(QString, PyQt_PyObject)',
'updateMoodSlot(QString, PyQt_PyObject)'),
('colorUpdated(QString, QtGui.QColor)',
'updateColorSlot(QString, QtGui.QColor)'),
('messageReceived(QString, QString)',
'deliverMessage(QString, QString)'),
('memoReceived(QString, QString, QString)',
'deliverMemo(QString, QString, QString)'),
('noticeReceived(QString, QString)',
'deliverNotice(QString, QString)'),
('inviteReceived(QString, QString)',
'deliverInvite(QString, QString)'),
('nickCollision(QString, QString)',
'nickCollision(QString, QString)'),
('myHandleChanged(QString)',
'myHandleChanged(QString)'),
('namesReceived(QString, PyQt_PyObject)',
'updateNames(QString, PyQt_PyObject)'),
('userPresentUpdate(QString, QString, QString)',
'userPresentUpdate(QString, QString, QString)'),
('channelListReceived(PyQt_PyObject)',
'updateChannelList(PyQt_PyObject)'),
('timeCommand(QString, QString, QString)',
'timeCommand(QString, QString, QString)'),
('chanInviteOnly(QString)',
'chanInviteOnly(QString)'),
('modesUpdated(QString, QString)',
'modesUpdated(QString, QString)'),
('cannotSendToChan(QString, QString)',
'cannotSendToChan(QString, QString)'),
('tooManyPeeps()',
'tooManyPeeps()'),
('quirkDisable(QString, QString, QString)',
'quirkDisable(QString, QString, QString)')
]
2021-03-23 17:40:24 -04:00
def ircQtConnections(self, irc, widget):
# IRC --> Main window
return ((widget.sendMessage, irc.sendMessage),
(widget.sendNotice, irc.sendNotice),
2022-06-02 17:15:45 -04:00
(widget.sendCTCP, irc.sendCTCP),
2021-03-23 17:40:24 -04:00
(widget.newConvoStarted, irc.startConvo),
(widget.convoClosed, irc.endConvo),
(widget.profileChanged, irc.updateProfile),
(widget.moodRequest, irc.getMood),
(widget.moodsRequest, irc.getMoods),
(widget.moodUpdated, irc.updateMood),
(widget.mycolorUpdated, irc.updateColor),
(widget.blockedChum, irc.blockedChum),
(widget.unblockedChum, irc.unblockedChum),
(widget.requestNames, irc.requestNames),
(widget.requestChannelList, irc.requestChannelList),
(widget.joinChannel, irc.joinChannel),
(widget.leftChannel, irc.leftChannel),
(widget.kickUser, irc.kickUser),
(widget.setChannelMode, irc.setChannelMode),
(widget.channelNames, irc.channelNames),
(widget.inviteChum, irc.inviteChum),
(widget.pingServer, irc.pingServer),
(widget.setAway, irc.setAway),
(widget.killSomeQuirks, irc.killSomeQuirks),
(widget.reconnectIRC, irc.reconnectIRC),
# Main window --> IRC
(irc.connected, widget.connected),
(irc.moodUpdated, widget.updateMoodSlot),
(irc.colorUpdated, widget.updateColorSlot),
2021-03-23 17:40:24 -04:00
(irc.messageReceived, widget.deliverMessage),
(irc.memoReceived, widget.deliverMemo),
(irc.noticeReceived, widget.deliverNotice),
(irc.inviteReceived, widget.deliverInvite),
(irc.nickCollision, widget.nickCollision),
(irc.myHandleChanged, widget.myHandleChanged),
(irc.namesReceived, widget.updateNames),
(irc.userPresentUpdate, widget.userPresentUpdate),
(irc.channelListReceived, widget.updateChannelList),
(irc.timeCommand, widget.timeCommand),
(irc.chanInviteOnly, widget.chanInviteOnly),
(irc.modesUpdated, widget.modesUpdated),
(irc.cannotSendToChan, widget.cannotSendToChan),
(irc.tooManyPeeps, widget.tooManyPeeps),
(irc.quirkDisable, widget.quirkDisable))
2011-02-06 19:50:21 -05:00
def connectWidgets(self, irc, widget):
2021-03-23 17:36:43 -04:00
irc.finished.connect(self.restartIRC)
irc.connected.connect(self.connected)
2021-03-23 17:40:24 -04:00
for sig, slot in self.ircQtConnections(irc, widget):
sig.connect(slot)
2011-02-19 18:06:54 -05:00
def disconnectWidgets(self, irc, widget):
2021-03-23 17:40:24 -04:00
for sig, slot in self.ircQtConnections(irc, widget):
sig.disconnect(slot)
2021-03-23 17:36:43 -04:00
irc.connected.disconnect(self.connected)
self.irc.finished.disconnect(self.restartIRC)
2011-02-19 18:06:54 -05:00
def showUpdate(self, q):
new_url = q.get()
if new_url[0]:
self.widget.pcUpdate.emit(new_url[0], new_url[1])
q.task_done()
2011-02-19 18:06:54 -05:00
def showLoading(self, widget, msg="CONN3CT1NG"):
2011-02-06 19:50:21 -05:00
self.widget.show()
if len(msg) > 60:
newmsg = []
while len(msg) > 60:
s = msg.rfind(" ", 0, 60)
if s == -1:
break
newmsg.append(msg[:s])
newmsg.append("\n")
msg = msg[s+1:]
newmsg.append(msg)
msg = "".join(newmsg)
2011-02-21 14:07:59 -05:00
if hasattr(self.widget, 'loadingscreen') and widget.loadingscreen:
widget.loadingscreen.loadinglabel.setText(msg)
if self.reconnectok:
widget.loadingscreen.showReconnect()
else:
widget.loadingscreen.hideReconnect()
else:
widget.loadingscreen = LoadingScreen(widget)
widget.loadingscreen.loadinglabel.setText(msg)
2021-03-23 17:36:43 -04:00
widget.loadingscreen.rejected.connect(widget.app.quit)
self.widget.loadingscreen.tryAgain.connect(self.tryAgain)
2011-02-21 14:07:59 -05:00
if hasattr(self, 'irc') and self.irc.registeredIRC:
return
if self.reconnectok:
widget.loadingscreen.showReconnect()
else:
widget.loadingscreen.hideReconnect()
status = widget.loadingscreen.exec_()
2021-03-23 17:36:43 -04:00
if status == QtWidgets.QDialog.Rejected:
2011-02-21 14:07:59 -05:00
sys.exit(0)
else:
if self.widget.tabmemo:
for c in self.widget.tabmemo.convos:
self.irc.joinChannel(c)
else:
2021-03-23 17:36:43 -04:00
for c in list(self.widget.memos.values()):
self.irc.joinChannel(c.channel)
2011-02-21 14:07:59 -05:00
return True
2011-02-19 18:06:54 -05:00
@QtCore.pyqtSlot()
2011-02-19 21:38:06 -05:00
def connected(self):
self.attempts = 0
@QtCore.pyqtSlot()
2011-02-19 18:06:54 -05:00
def tryAgain(self):
2011-02-21 14:07:59 -05:00
if not self.reconnectok:
return
2011-02-19 21:38:06 -05:00
if self.widget.loadingscreen:
2021-03-23 17:36:43 -04:00
self.widget.loadingscreen.done(QtWidgets.QDialog.Accepted)
2011-02-21 14:07:59 -05:00
self.widget.loadingscreen = None
2011-02-19 21:38:06 -05:00
self.attempts += 1
if hasattr(self, 'irc') and self.irc:
self.irc.reconnectIRC()
self.irc.quit()
else:
self.restartIRC()
2011-02-19 18:06:54 -05:00
@QtCore.pyqtSlot()
def restartIRC(self):
2011-02-19 21:38:06 -05:00
if hasattr(self, 'irc') and self.irc:
2011-02-19 18:06:54 -05:00
self.disconnectWidgets(self.irc, self.widget)
stop = self.irc.stopIRC
del self.irc
else:
stop = None
2011-02-21 14:07:59 -05:00
if stop is None:
self.irc = PesterIRC(self.widget.config, self.widget)
2011-02-19 18:06:54 -05:00
self.connectWidgets(self.irc, self.widget)
self.irc.start()
2011-02-19 21:38:06 -05:00
if self.attempts == 1:
msg = "R3CONN3CT1NG"
elif self.attempts > 1:
msg = "R3CONN3CT1NG %d" % (self.attempts)
else:
msg = "CONN3CT1NG"
2011-02-21 14:07:59 -05:00
self.reconnectok = False
2011-02-19 21:38:06 -05:00
self.showLoading(self.widget, msg)
2011-02-18 03:17:13 -05:00
else:
2011-02-21 14:07:59 -05:00
self.reconnectok = True
2011-02-19 18:06:54 -05:00
self.showLoading(self.widget, "F41L3D: %s" % stop)
2011-02-06 19:50:21 -05:00
def oppts(self, argv):
2011-05-12 10:14:38 -04:00
options = {}
try:
2011-07-08 04:41:49 -04:00
opts, args = getopt.getopt(argv, "s:p:", ["server=", "port=", "advanced", "no-honk"])
except getopt.GetoptError:
2011-05-12 10:14:38 -04:00
return options
for opt, arg in opts:
2011-05-12 10:14:38 -04:00
if opt in ("-s", "--server"):
options["server"] = arg
elif opt in ("-p", "--port"):
options["port"] = arg
elif opt in ("--advanced"):
options["advanced"] = True
2011-07-08 04:41:49 -04:00
elif opt in ("--no-honk"):
options["honk"] = False
2011-05-12 10:14:38 -04:00
return options
2011-02-06 19:50:21 -05:00
def run(self):
#PchumLog.critical("mreowww") <--- debug thingy :3
2011-02-13 20:32:02 -05:00
sys.exit(self.app.exec_())
2011-02-06 19:50:21 -05:00
def _retrieveGlobals():
# NOTE: Yes, this is a terrible kludge so that the console can work
# properly. I'm open to alternatives.
return globals()
#def main():
# pesterchum = MainProgram()
# pesterchum.run()
if __name__ == "__main__":
# We're being run as a script - not being imported.
pesterchum = MainProgram()
pesterchum.run()