From e3ae0bee89aaabc8e25322b94e6d49fb2d6a8c4d Mon Sep 17 00:00:00 2001 From: Stephen Dranger Date: Thu, 27 Jan 2011 20:21:02 -0600 Subject: [PATCH] step 1 of profiles --- TODO | 16 +++ oyoyo/helpers.py | 3 + oyoyo/helpers.pyc | Bin 3869 -> 4044 bytes pesterchum.py | 204 +++++++++++++++++++++++++++++++++++-- profiles/geniusBar.js | 1 + profiles/ghostDunk.js | 1 + themes/pesterchum/style.js | 3 +- 7 files changed, 219 insertions(+), 9 deletions(-) create mode 100644 TODO create mode 100644 profiles/geniusBar.js create mode 100644 profiles/ghostDunk.js diff --git a/TODO b/TODO new file mode 100644 index 0000000..1d7d6d8 --- /dev/null +++ b/TODO @@ -0,0 +1,16 @@ +Features: +* Profile management +* Theme Changing +* Handle user signoffs +* Logging +* Moods +* Add chum +* REMOVE chum +* New message reminder +* User profile options +* Quirks +* Block list +* User list/add from list +* Chat rooms + +* Spy mode \ No newline at end of file diff --git a/oyoyo/helpers.py b/oyoyo/helpers.py index 815ea35..21973a4 100644 --- a/oyoyo/helpers.py +++ b/oyoyo/helpers.py @@ -23,6 +23,9 @@ def msg(cli, user, msg): for line in msg.split('\n'): cli.send("PRIVMSG", user, ":%s" % line) +def nick(cli, nick): + cli.send("NICK", nick) + def msgrandom(cli, choices, dest, user=None): o = "%s: " % user if user else "" o += random.choice(choices) diff --git a/oyoyo/helpers.pyc b/oyoyo/helpers.pyc index da83df78981db06980c0910251021d19a1027720..c0234d25d072796f8b388b87b552b1546ccf3529 100644 GIT binary patch delta 904 zcmZuuO=}Zj5T19lyUA{MHy>3=8%?y05KPrrs%eqZmY^WgO5Y$t6oT#>OQ=aplOBo% z#q=!5dlSUpP(1hGLA-cT`X{^y+KVEhGqY+vxXU~{GtYeQi~PGn?)?|vJ@~e;7{c$z z!tXpv@58fP;gJbD0F4+Z1C#|j0vZ-5o1HeaY*2Af2~ZBK#9)AIoShCR7gh}RB-k?q z%KPI%*5?W?sDKq@lb}*u-vgBfm0{hV;l{&k1fWKtfpJ;RNkJTv*MBZ z$(l{d1iD61dK3k^X#5l>bTPJ7NTOMy1kRE^X;e3=>FLMudF%dWHyqc(%pdiLP7#gr zH|BM$s#ncpVoX0VzlsU{&{{5x5Kqk{{UJ%c4~LUE{W4e>COYh$M~uc2GOOq8Ju#_& z*l)!}{U*MDa)wwM2t-zJ8QyID?na-N(tC*mk<+_Qy?phsP&6L5FQZpZApA3OS>woo zL-Fm-`h!;3QCD=|ZP@21_^jS{Z;RTi%1~Kg={w%y6y-|_=ktlE6klzcnE&;drXH7F zq`RA))Pvlzb!Mm9*h@{lbRbBt-j_Jho_h9T7=JAVQ delta 770 zcmZuuJ#W-N5S{hezB~Kuy&#eMNEAmQh)XVCeC0p_6riAhfU+qNrZ|E3h!9c&+)+eA zqDcM#OhrLK2@(aOO=^Th0f>T%KR_3X&>%502N6iv+UGa(X5P-O-zU#ThCc2@!PniB ziy8cWJo+xs>b`qClst04y0EDrb-{YD36Ofw@xc0E^I!|Gl7kIWeMuI;7GcGaOkOep z*ziw=)RH(9!A3$zjlpX155bnf4hS!SrG57ipMx|4TZ5G9D$=8&qhSL;*{Z~4=#=}h z1Ivy2>z&gIKRG{D9Y5sOlZXz|$PpNUkeSOl#Vo)jeX7Xutp}^wD86z>_6ID)TtaKF z?z!K>iZ`edobi6B2|VO4B^A~k0>f8ks(YbqRl`gAEROoF&bm`1b-5Ch8N_e?wwlEk z`M2r_-Ya|_pJ$ba0993D)8pvwjr%g5Pj4(-A(`COY<1kX^a5zl;X|9>Vhv9X#@a9X{ROIMJi^sU_3ax)!Ujx(IW3;Jrn*W)`Sr|9BKJ@yN; C9(Sk! diff --git a/pesterchum.py b/pesterchum.py index f69261a..ade7f1e 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -3,7 +3,9 @@ from oyoyo.client import IRCClient from oyoyo.cmdhandler import DefaultCommandHandler from oyoyo import helpers import logging -import sys +import os, sys +import os.path +import random import json from PyQt4 import QtGui, QtCore @@ -72,11 +74,18 @@ class userConfig(object): fp = open("pesterchum.js") self.config = json.load(fp) fp.close() - self.theme = pesterTheme(self.config["theme"]) + self.defaulttheme = pesterTheme("pesterchum") + if self.config.has_key("defaultprofile"): + self.profile = userProfile(self.config["defaultprofile"]) + else: + self.profile = None def chums(self): return self.config['chums'] def getTheme(self): - return self.theme + if self.profile: + return self.profile.getTheme() + else: + return self.defaulttheme def tabs(self): return self.config["tabs"] def set(self, item, setting): @@ -84,6 +93,135 @@ class userConfig(object): fp = open("pesterchum.js", 'w') json.dump(self.config, fp) fp.close() + def availableProfiles(self): + profs = [] + for dirname, dirnames, filenames in os.walk('profiles'): + for filename in filenames: + l = len(filename) + if filename[l-3:l] == ".js": + profs.append(filename[0:l-3]) + profs.sort() + return [userProfile(p) for p in profs] +class userProfile(object): + def __init__(self, user): + if type(user) is PesterProfile: + self.chat = user + self.userprofile = {"handle":user.handle, + "color": unicode(user.color.name()), + "quirks": [], + "theme": "pesterchum"} + self.theme = pesterTheme("pesterchum") + self.quirks = pesterQuirks([]) + else: + fp = open("profiles/%s.js" % (user)) + self.userprofile = json.load(fp) + fp.close() + self.chat = PesterProfile(self.userprofile["handle"], + QtGui.QColor(self.userprofile["color"]), + Mood(0)) + self.theme = pesterTheme(self.userprofile["theme"]) + self.quirks = pesterQuirks(self.userprofile["quirks"]) + def getTheme(self): + return self.theme + def save(self): + handle = self.chat.handle + fp = open("profiles/%s.js" % (handle), 'w') + json.dump(self.userprofile, fp) + fp.close() + @staticmethod + def newUserProfile(chatprofile): + if os.path.exists("profiles/%s.js" % (chatprofile.handle)): + newprofile = userProfile(chatprofile.handle) + else: + newprofile = userProfile(chatprofile) + newprofile.save() + return newprofile + +class pesterQuirks(object): + def __init__(self, quirklist): + self.quirklist = quirklist + +class PesterChooseProfile(QtGui.QDialog): + def __init__(self, userprofile, config, theme, parent): + QtGui.QDialog.__init__(self, parent) + self.userprofile = userprofile + self.theme = theme + self.config = config + self.parent = parent + self.setStyleSheet(self.theme["main/defaultwindow/style"]) + + self.chumHandle = QtGui.QLineEdit(self) + self.chumHandle.setMinimumWidth(200) + self.chumHandleLabel = QtGui.QLabel(self.theme["main/labels/mychumhandle"], self) + self.chumColorButton = QtGui.QPushButton(self) + self.chumColorButton.resize(50, 20) + self.chumColorButton.setStyleSheet("background: %s" % (userprofile.chat.colorhtml())) + self.chumcolor = userprofile.chat.color + self.connect(self.chumColorButton, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('openColorDialog()')) + layout_1 = QtGui.QHBoxLayout() + layout_1.addWidget(self.chumHandleLabel) + layout_1.addWidget(self.chumHandle) + layout_1.addWidget(self.chumColorButton) + + # available profiles? + avail_profiles = self.config.availableProfiles() + if avail_profiles: + self.profileBox = QtGui.QComboBox(self) + self.profileBox.addItem("Choose a profile...") + for p in avail_profiles: + self.profileBox.addItem(p.chat.handle) + else: + self.profileBox = None + + self.ok = QtGui.QPushButton("OK", self) + self.ok.setDefault(True) + self.connect(self.ok, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('validateProfile()')) + self.cancel = QtGui.QPushButton("CANCEL", self) + self.connect(self.cancel, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('reject()')) + layout_ok = QtGui.QHBoxLayout() + layout_ok.addWidget(self.cancel) + layout_ok.addWidget(self.ok) + + layout_0 = QtGui.QVBoxLayout() + layout_0.addLayout(layout_1) + if avail_profiles: + profileLabel = QtGui.QLabel("Or choose an existing profile:", self) + layout_0.addWidget(profileLabel) + layout_0.addWidget(self.profileBox) + layout_0.addLayout(layout_ok) + self.errorMsg = QtGui.QLabel(self) + self.errorMsg.setStyleSheet("color:red;") + layout_0.addWidget(self.errorMsg) + self.setLayout(layout_0) + + self.connect(self, QtCore.SIGNAL('accepted()'), + parent, QtCore.SLOT('profileSelected()')) + self.connect(self, QtCore.SIGNAL('rejected()'), + parent, QtCore.SLOT('closeProfile()')) + + @QtCore.pyqtSlot() + def openColorDialog(self): + self.colorDialog = QtGui.QColorDialog(self) + color = self.colorDialog.getColor(initial=self.userprofile.chat.color) + self.chumColorButton.setStyleSheet("background: %s" % color.name()) + self.chumcolor = color + self.colorDialog = None + + @QtCore.pyqtSlot() + def validateProfile(self): + if not self.profileBox or self.profileBox.currentIndex() == 0: + handle = unicode(self.chumHandle.text()) + if len(handle) > 256: + self.errorMsg.setText("PROFILE HANDLE IS TOO LONG") + return + caps = [l for l in handle if l.isupper()] + if len(caps) != 1 or handle[0].isupper(): + self.errorMsg.setText("NOT A VALID CHUMTAG") + return + self.accept() class PesterOptions(QtGui.QDialog): def __init__(self, config, theme, parent): @@ -105,10 +243,16 @@ class PesterOptions(QtGui.QDialog): self.ok.setDefault(True) self.connect(self.ok, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('accept()')) + self.cancel = QtGui.QPushButton("CANCEL", self) + self.connect(self.cancel, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('reject()')) + layout_2 = QtGui.QHBoxLayout() + layout_2.addWidget(self.cancel) + layout_2.addWidget(self.ok) layout_0 = QtGui.QVBoxLayout() layout_0.addLayout(layout_1) - layout_0.addWidget(self.ok) + layout_0.addLayout(layout_2) self.setLayout(layout_0) @@ -403,8 +547,16 @@ class PesterWindow(MovingWindow): self.chumList = chumArea(chums, self.theme, self) self.connect(self.chumList, QtCore.SIGNAL('itemDoubleClicked(QListWidgetItem *)'), self, QtCore.SLOT('newConversationWindow(QListWidgetItem *)')) + if self.config.profile: + pass + #self.userprofile = self.config.profile + #self.profile = self.userprofile.chat + else: + self.userprofile = userProfile(PesterProfile("pesterClient%d" % (random.randint(100,999)), QtGui.QColor("black"), Mood(0))) + self.profile = self.userprofile.chat + self.chooseprofile = PesterChooseProfile(self.userprofile, self.config, self.theme, self) + self.chooseprofile.exec_() - self.profile = PesterProfile("superGhost", QtGui.QColor("red"), Mood(0)) self.convos = {} self.tabconvo = None self.optionmenu = None @@ -497,10 +649,16 @@ class PesterWindow(MovingWindow): self.optionmenu = PesterOptions(self.config, self.theme, self) self.connect(self.optionmenu, QtCore.SIGNAL('accepted()'), self, QtCore.SLOT('updateOptions()')) + self.connect(self.optionmenu, QtCore.SIGNAL('rejected()'), + self, QtCore.SLOT('closeOptions()')) self.optionmenu.show() self.optionmenu.raise_() self.optionmenu.activateWindow() @QtCore.pyqtSlot() + def closeOptions(self): + self.optionmenu.close() + self.optionmenu = None + @QtCore.pyqtSlot() def updateOptions(self): # tabs curtab = self.config.tabs() @@ -528,9 +686,31 @@ class PesterWindow(MovingWindow): self.convos = newconvos # save options self.config.set("tabs", tabsetting) - - pass self.optionmenu = None + + @QtCore.pyqtSlot() + def profileSelected(self): + if self.chooseprofile.profileBox and \ + self.chooseprofile.profileBox.currentIndex > 0: + handle = unicode(self.chooseprofile.profileBox.currentText()) + self.userprofile = userProfile(handle) + self.profile = self.userprofile.chat + # update themes here + else: + profile = PesterProfile(unicode(self.chooseprofile.chumHandle.text()), + self.chooseprofile.chumcolor, + Mood(0)) + self.userprofile = userProfile.newUserProfile(profile) + self.profile = self.userprofile.chat + + self.chooseprofile = None + @QtCore.pyqtSlot() + def closeProfile(self): + self.chooseprofile = None + + @QtCore.pyqtSlot() + def nickCollision(self): + pass newConvoStarted = QtCore.pyqtSignal(QtCore.QString, bool, name="newConvoStarted") sendMessage = QtCore.pyqtSignal(QtCore.QString, PesterProfile) @@ -574,7 +754,7 @@ class PesterIRC(QtCore.QObject): colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor) pesterchumBegin = QtCore.pyqtSignal(PesterProfile) messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) - + nickCollision = QtCore.pyqtSignal() class PesterHandler(DefaultCommandHandler): def privmsg(self, nick, chan, msg): @@ -623,6 +803,10 @@ class PesterHandler(DefaultCommandHandler): chums = self.chums self.getMood(*chums) + + def nicknameinuse(self, server, cmd, nick, msg): + helpers.nick(self.client, "pesterClient%d" % (random.randint(100,999))) + self.parent().emit.nickCollision.emit() def getMood(self, *chums): chumglub = "GETMOOD " for c in chums: @@ -680,6 +864,10 @@ def main(): QtCore.SIGNAL('messageReceived(QString, QString)'), widget, QtCore.SLOT('deliverMessage(QString, QString)')) + irc.connect(irc, + QtCore.SIGNAL('nickCollision()'), + widget, + QtCore.SLOT('nickCollision()')) ircapp = IRCThread(irc) ircapp.start() diff --git a/profiles/geniusBar.js b/profiles/geniusBar.js new file mode 100644 index 0000000..30820c0 --- /dev/null +++ b/profiles/geniusBar.js @@ -0,0 +1 @@ +{"color": "#ff007f", "theme": "pesterchum", "quirks": [], "handle": "geniusBar"} \ No newline at end of file diff --git a/profiles/ghostDunk.js b/profiles/ghostDunk.js new file mode 100644 index 0000000..338c689 --- /dev/null +++ b/profiles/ghostDunk.js @@ -0,0 +1 @@ +{"color": "#ff00ff", "theme": "pesterchum", "quirks": [], "handle": "ghostDunk"} \ No newline at end of file diff --git a/themes/pesterchum/style.js b/themes/pesterchum/style.js index 46818b1..53aded7 100644 --- a/themes/pesterchum/style.js +++ b/themes/pesterchum/style.js @@ -21,8 +21,9 @@ "color": "red" } } }, - "defaultwindow": { "style": "background: #fdb302;" + "defaultwindow": { "style": "background: #fdb302; font-family:'Courier New';font:bold;" }, + "labels": { "mychumhandle": "MYCHUMHANDLE" }, "elements": [ { "style": "" } ]