diff --git a/CHANGELOG.mkdn b/CHANGELOG.mkdn index a519d4c..1d29811 100644 --- a/CHANGELOG.mkdn +++ b/CHANGELOG.mkdn @@ -25,6 +25,7 @@ CHANGELOG * Minimizable memo userlist - Kiooeht [evacipatedBox] (Idea: [alGore], [lostGash]) * Chumroll notifications on chum sign-in/out - Kiooeht [evacipatedBox] * Chum notes - Kiooeht [evacipatedBox] +* Customizable name alerts - Kiooeht [evacipatedBox] * Bug fixes * Don't delete random chum when blocking someone not on chumroll - Kiooeht [evacipatedBox] * Openning global userlist doesn't reset OP status of memo users - Kiooeht [evacipatedBox] diff --git a/TODO.mkdn b/TODO.mkdn index f904509..1b1c3fb 100644 --- a/TODO.mkdn +++ b/TODO.mkdn @@ -14,7 +14,6 @@ Features * Colour saving boxes things? * Whowas for last seen online? * Tab completion of two letter names -* Customizable name alerts * When 'banned' make impossible to connect using timestamp banned under * Explain why a chumhandle is invalid * Fully working Toasts @@ -29,6 +28,7 @@ Bugs * When left for a really long time, animations slow down pesterchum * Closing a timeclone doesn't actually cease for everyone else * Kill Zalgo +* Random invisible, tiny links to last link at end of every message Windows Bugs ------------ diff --git a/menus.py b/menus.py index 6acef98..8d67809 100644 --- a/menus.py +++ b/menus.py @@ -896,6 +896,85 @@ class PesterChooseProfile(QtGui.QDialog): problem.setStandardButtons(QtGui.QMessageBox.Ok) problem.exec_() +class PesterMentions(QtGui.QDialog): + def __init__(self, window, theme, parent): + QtGui.QDialog.__init__(self, parent) + self.setWindowTitle("Mentions") + self.setModal(True) + self.mainwindow = window + self.theme = theme + self.setStyleSheet(self.theme["main/defaultwindow/style"]) + + self.mentionlist = QtGui.QListWidget(self) + self.mentionlist.addItems(self.mainwindow.userprofile.getMentions()) + + self.addBtn = QtGui.QPushButton("ADD MENTION", self) + self.connect(self.addBtn, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('addMention()')) + + self.editBtn = QtGui.QPushButton("EDIT", self) + self.connect(self.editBtn, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('editSelected()')) + self.rmBtn = QtGui.QPushButton("REMOVE", self) + self.connect(self.rmBtn, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('removeCurrent()')) + layout_1 = QtGui.QHBoxLayout() + layout_1.addWidget(self.editBtn) + layout_1.addWidget(self.rmBtn) + + self.ok = QtGui.QPushButton("OK", self) + 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.addWidget(self.mentionlist) + layout_0.addWidget(self.addBtn) + layout_0.addLayout(layout_1) + layout_0.addLayout(layout_2) + + self.setLayout(layout_0) + + @QtCore.pyqtSlot() + def editSelected(self): + m = self.mentionlist.currentItem() + if not m: + return + self.addMention(m) + + @QtCore.pyqtSlot() + def addMention(self, mitem=None): + d = {"label": "Mention:", "inputname": "value" } + if mitem is not None: + d["value"] = str(mitem.text()) + pdict = MultiTextDialog("ENTER MENTION", self, d).getText() + if pdict is None: + return + try: + re.compile(pdict["value"]) + except re.error, e: + quirkWarning = QtGui.QMessageBox(self) + quirkWarning.setText("Not a valid regular expression!") + quirkWarning.setInformativeText("H3R3S WHY DUMP4SS: %s" % (e)) + quirkWarning.exec_() + else: + if mitem is None: + self.mentionlist.addItem(pdict["value"]) + else: + mitem.setText(pdict["value"]) + + @QtCore.pyqtSlot() + def removeCurrent(self): + i = self.mentionlist.currentRow() + if i >= 0: + self.mentionlist.takeItem(i) + class PesterOptions(QtGui.QDialog): def __init__(self, config, theme, parent): QtGui.QDialog.__init__(self, parent) @@ -955,6 +1034,11 @@ class PesterOptions(QtGui.QDialog): self.chatsoundcheck.setEnabled(False) self.memosoundcheck.setEnabled(False) self.memoSoundChange(0) + + self.editMentions = QtGui.QPushButton("Edit Mentions", self) + self.connect(self.editMentions, QtCore.SIGNAL('clicked()'), + self, QtCore.SLOT('openMentions()')) + self.volume = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.volume.setMinimum(0) self.volume.setMaximum(100) @@ -1155,6 +1239,7 @@ class PesterOptions(QtGui.QDialog): layout_doubleindent = QtGui.QVBoxLayout() layout_doubleindent.addWidget(self.memopingcheck) layout_doubleindent.addWidget(self.namesoundcheck) + layout_doubleindent.addWidget(self.editMentions) layout_doubleindent.setContentsMargins(22,0,0,0) layout_indent.addLayout(layout_doubleindent) layout_indent.setContentsMargins(22,0,0,0) @@ -1241,6 +1326,31 @@ class PesterOptions(QtGui.QDialog): def printValue(self, v): self.currentVol.setText(str(v)+"%") + @QtCore.pyqtSlot() + def openMentions(self): + if not hasattr(self, 'mentionmenu'): + self.mentionmenu = None + if not self.mentionmenu: + self.mentionmenu = PesterMentions(self.parent(), self.theme, self) + self.connect(self.mentionmenu, QtCore.SIGNAL('accepted()'), + self, QtCore.SLOT('updateMentions()')) + self.connect(self.mentionmenu, QtCore.SIGNAL('rejected()'), + self, QtCore.SLOT('closeMentions()')) + self.mentionmenu.show() + self.mentionmenu.raise_() + self.mentionmenu.activateWindow() + @QtCore.pyqtSlot() + def closeMentions(self): + self.mentionmenu.close() + self.mentionmenu = None + @QtCore.pyqtSlot() + def updateMentions(self): + m = [] + for i in range(self.mentionmenu.mentionlist.count()): + m.append(str(self.mentionmenu.mentionlist.item(i).text())) + self.parent().userprofile.setMentions(m) + self.mentionmenu = None + class PesterUserlist(QtGui.QDialog): def __init__(self, config, theme, parent): QtGui.QDialog.__init__(self, parent) diff --git a/pesterchum.py b/pesterchum.py index 87a8cf7..11abb27 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -570,6 +570,12 @@ class userProfile(object): self.lastmood = self.chat.mood.value() self.quirks = pesterQuirks([]) self.randoms = False + initials = self.chat.initials() + if len(initials) >= 2: + initials = (initials, "%s%s" % (initials[0].lower(), initials[1]), "%s%s" % (initials[0], initials[1].lower())) + self.mentions = [r"\b(%s)\b" % ("|".join(initials))] + else: + self.mentions = [] else: fp = open("%s/%s.js" % (self.profiledir, user)) self.userprofile = json.load(fp) @@ -586,6 +592,14 @@ class userProfile(object): if "randoms" not in self.userprofile: self.userprofile["randoms"] = False self.randoms = self.userprofile["randoms"] + if "mentions" not in self.userprofile: + initials = self.chat.initials() + if len(initials) >= 2: + initials = (initials, "%s%s" % (initials[0].lower(), initials[1]), "%s%s" % (initials[0], initials[1].lower())) + self.userprofile["mentions"] = [r"\b(%s)\b" % ("|".join(initials))] + else: + self.userprofile["mentions"] = [] + self.mentions = self.userprofile["mentions"] def setMood(self, mood): self.chat.mood = mood @@ -607,6 +621,18 @@ class userProfile(object): self.randoms = random self.userprofile["randoms"] = random self.save() + def getMentions(self): + return self.mentions + def setMentions(self, mentions): + try: + for (i,m) in enumerate(mentions): + re.compile(m) + except re.error, e: + logging.error("#%s Not a valid regular expression: %s" % (i, e)) + else: + self.mentions = mentions + self.userprofile["mentions"] = mentions + self.save() def getLastMood(self): return self.lastmood def setLastMood(self, mood): @@ -1865,15 +1891,13 @@ class PesterWindow(MovingWindow): if self.config.soundOn(): if self.config.memoSound(): if self.config.nameSound(): - initials = self.userprofile.chat.initials() - initials = (initials, "%s%s" % (initials[0].lower(), initials[1]), "%s%s" % (initials[0], initials[1].lower())) - search = r"\b(%s)\b" % ("|".join(initials)) m = convertTags(msg, "text") if m.find(":") <= 3: m = m[m.find(":"):] - if re.search(search, m): - self.namesound.play() - return + for search in self.userprofile.getMentions(): + if re.search(search, m): + self.namesound.play() + return if self.honk and re.search(r"\bhonk\b", convertTags(msg, "text"), re.I): self.honksound.play() elif self.config.memoPing():