diff --git a/CHANGELOG.mkdn b/CHANGELOG.mkdn index 7f6f619..cd0eb15 100644 --- a/CHANGELOG.mkdn +++ b/CHANGELOG.mkdn @@ -34,6 +34,7 @@ CHANGELOG * Advanced Mode: View memo (channel) modes - Kiooeht [evacipatedBox] * Quirk groups - Kiooeht [evacipatedBox] * CTCP Version reply - Kiooeht [evacipatedBox] +* Check for Pesterchum updates - Kiooeht [evacipatedBox] * Bug fixes * Logviewer updates - Kiooeht [evacipatedBox] * Memo scrollbar thing - Kiooeht [evacipatedBox] diff --git a/menus.py b/menus.py index 48abc2f..cd56882 100644 --- a/menus.py +++ b/menus.py @@ -751,7 +751,7 @@ class PesterOptions(QtGui.QDialog): self.tabs = QtGui.QButtonGroup(self) self.connect(self.tabs, QtCore.SIGNAL('buttonClicked(int)'), self, QtCore.SLOT('changePage(int)')) - tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Logging", "Idle", "Theme"] + tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Logging", "Idle/Updates", "Theme"] if parent.advanced: tabNames.append("Advanced") for t in tabNames: button = QtGui.QPushButton(t) @@ -854,6 +854,9 @@ class PesterOptions(QtGui.QDialog): layout_5.addWidget(QtGui.QLabel("Minutes before Idle:")) layout_5.addWidget(self.idleBox) + self.updatecheck = QtGui.QCheckBox("Check for Updates on Start", self) + self.updatecheck.setChecked(self.config.checkForUpdates()) + avail_themes = self.config.availableThemes() self.themeBox = QtGui.QComboBox(self) for (i, t) in enumerate(avail_themes): @@ -951,11 +954,12 @@ class PesterOptions(QtGui.QDialog): layout_logs.addWidget(self.stampmemocheck) self.pages.addWidget(widget) - # Idle + # Idle/Updates widget = QtGui.QWidget() layout_idle = QtGui.QVBoxLayout(widget) layout_idle.setAlignment(QtCore.Qt.AlignTop) layout_idle.addLayout(layout_5) + layout_idle.addWidget(self.updatecheck) self.pages.addWidget(widget) # Theme @@ -1259,3 +1263,32 @@ Special Thanks:\n\ layout_0.addWidget(self.ok) self.setLayout(layout_0) + +class UpdatePesterchum(QtGui.QDialog): + def __init__(self, ver, url, parent=None): + QtGui.QDialog.__init__(self, parent) + self.url = url + self.mainwindow = parent + self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"]) + self.setWindowTitle("Pesterchum v%s Update" % (ver)) + self.setModal(False) + + self.title = QtGui.QLabel("An update to Pesterchum is avaliable!") + + layout_0 = QtGui.QVBoxLayout() + layout_0.addWidget(self.title) + + self.ok = QtGui.QPushButton("D0WNL04D N0W", 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.addLayout(layout_2) + + self.setLayout(layout_0) diff --git a/pesterchum.py b/pesterchum.py index 820a548..7f90134 100644 --- a/pesterchum.py +++ b/pesterchum.py @@ -44,7 +44,7 @@ if not ((major > 4) or (major == 4 and minor >= 6)): from menus import PesterChooseQuirks, PesterChooseTheme, \ PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList, \ - LoadingScreen, AboutPesterchum + LoadingScreen, AboutPesterchum, UpdatePesterchum from dataobjs import PesterProfile, Mood, pesterQuirk, pesterQuirks from generic import PesterIcon, RightClickList, RightClickTree, MultiTextDialog, PesterList, CaseInsensitiveDict from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo @@ -402,6 +402,8 @@ class userConfig(object): return self.config.get('opvMessages', True) def animations(self): return self.config.get('animations', True) + def checkForUpdates(self): + return self.config.get('checkUpdates', True) def addChum(self, chum): if chum.handle not in self.chums(): fp = open(self.filename) # what if we have two clients open?? @@ -1569,6 +1571,31 @@ class PesterWindow(MovingWindow): if not self.config.defaultprofile(): self.changeProfile() + self.connect(self, QtCore.SIGNAL('pcUpdate(QString, QString)'), + self, QtCore.SLOT('updateMsg(QString, QString)')) + + @QtCore.pyqtSlot(QtCore.QString, QtCore.QString) + def updateMsg(self, ver, url): + if not hasattr(self, 'updatemenu'): + self.updatemenu = None + if not self.updatemenu: + self.updatemenu = UpdatePesterchum(ver, url, self) + self.connect(self.updatemenu, QtCore.SIGNAL('accepted()'), + self, QtCore.SLOT('updatePC()')) + self.connect(self.updatemenu, QtCore.SIGNAL('rejected()'), + self, QtCore.SLOT('noUpdatePC()')) + self.updatemenu.show() + self.updatemenu.raise_() + self.updatemenu.activateWindow() + + @QtCore.pyqtSlot() + def updatePC(self): + QtGui.QDesktopServices.openUrl(QtCore.QUrl(self.updatemenu.url, QtCore.QUrl.TolerantMode)) + self.updatemenu = None + @QtCore.pyqtSlot() + def noUpdatePC(self): + self.updatemenu = None + def profile(self): return self.userprofile.chat def closeConversations(self, switch=False): @@ -2534,6 +2561,11 @@ class PesterWindow(MovingWindow): curanimate = self.config.animations() if animatesetting != curanimate: self.config.set('animations', animatesetting) + # update checked + updatechecksetting = self.optionmenu.updatecheck.isChecked() + curupdatecheck = self.config.checkForUpdates() + if updatechecksetting != curupdatecheck: + self.config.set('checkUpdates', updatechecksetting) # advanced ## user mode if self.advanced: @@ -2705,6 +2737,7 @@ class PesterWindow(MovingWindow): # show context menu i guess #self.showTrayContext.emit() + pcUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) closeToTraySignal = QtCore.pyqtSignal() newConvoStarted = QtCore.pyqtSignal(QtCore.QString, bool, name="newConvoStarted") sendMessage = QtCore.pyqtSignal(QtCore.QString, QtCore.QString) @@ -2813,6 +2846,11 @@ class MainProgram(QtCore.QObject): self.irc = PesterIRC(self.widget.config, self.widget) self.connectWidgets(self.irc, self.widget) + if self.widget.config.checkForUpdates(): + (new,url) = version.updateCheck() + if new: + self.widget.pcUpdate.emit(new, url) + widget2irc = [('sendMessage(QString, QString)', 'sendMessage(QString, QString)'), ('newConvoStarted(QString, bool)', diff --git a/version.py b/version.py index c89fd06..1f984a3 100644 --- a/version.py +++ b/version.py @@ -1,4 +1,7 @@ import urllib +import re + +USER_TYPE = "dev" _pcMajor = "3.14" _pcMinor = "2" @@ -12,3 +15,31 @@ _pcVersion = "" def pcVerCalc(): global _pcVersion _pcVersion = "%s.%s.%s-%s" % (_pcMajor, _pcMinor, _pcStatus, _pcRevision) + +def verStrToNum(ver): + w = re.match("(\d+\.?\d+)\.(\d+)\.?(\d*)-?(\d*):(\S+)", ver) + if not w: + print "Update check Failure: 3"; return + full = ver[:ver.find(":")] + return full,w.group(1),w.group(2),w.group(3),w.group(4),w.group(5) + + +def updateCheck(): + data = urllib.urlencode({"type" : USER_TYPE}) + try: + f = urllib.urlopen("http://distantsphere.com/pesterchum.php?" + data) + except: + print "Update check Failure: 1"; return False,1 + newest = f.read() + f.close() + if newest[0] == "<": + print "Update check Failure: 2"; return False,2 + try: + (full, major, minor, status, revision, url) = verStrToNum(newest) + except TypeError: + return False,3 + print full + if full > _pcVersion: + print "A new version of Pesterchum is avaliable!" + return full,url + return False,0