1

Improved update checking

Former-commit-id: 66d9959e9190f49c4d1bbc38261e847c846cae59
This commit is contained in:
Alex Yatskov 2015-02-15 15:03:46 +09:00
parent 30cb4926b9
commit 2662f20c09
10 changed files with 227 additions and 56 deletions

View File

@ -2,4 +2,5 @@
pyuic4 ui/about.ui -o yomi_base/gen/about_ui.py pyuic4 ui/about.ui -o yomi_base/gen/about_ui.py
pyuic4 ui/preferences.ui -o yomi_base/gen/preferences_ui.py pyuic4 ui/preferences.ui -o yomi_base/gen/preferences_ui.py
pyuic4 ui/reader.ui -o yomi_base/gen/reader_ui.py pyuic4 ui/reader.ui -o yomi_base/gen/reader_ui.py
pyuic4 ui/updates.ui -o yomi_base/gen/updates_ui.py
pyrcc4 ui/resources.qrc -o yomi_base/gen/resources_rc.py pyrcc4 ui/resources.qrc -o yomi_base/gen/resources_rc.py

84
ui/updates.ui Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogUpdates</class>
<widget class="QDialog" name="DialogUpdates">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Update Checker</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelUpdates">
<property name="text">
<string>&lt;p&gt;A new version of Yomichan is available for download!&lt;/p&gt;
&lt;p&gt;You can download this update (version {0} to version {1}) from the add-ons section on &lt;a href=&quot;https://ankiweb.net/shared/info/934748696&quot;&gt;Anki Online&lt;/a&gt; or directly from the &lt;a href=&quot;http://foosoft.net/projects/yomichan&quot;&gt;Yomichan homepage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Changes from your version are listed below:&lt;/p&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="textBrowser"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogUpdates</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogUpdates</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'ui/about.ui' # Form implementation generated from reading ui file 'ui/about.ui'
# #
# Created: Sun Feb 15 13:27:51 2015 # Created: Sun Feb 15 15:01:20 2015
# by: PyQt4 UI code generator 4.10.4 # by: PyQt4 UI code generator 4.10.4
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'ui/preferences.ui' # Form implementation generated from reading ui file 'ui/preferences.ui'
# #
# Created: Sun Feb 15 13:27:51 2015 # Created: Sun Feb 15 15:01:20 2015
# by: PyQt4 UI code generator 4.10.4 # by: PyQt4 UI code generator 4.10.4
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'ui/reader.ui' # Form implementation generated from reading ui file 'ui/reader.ui'
# #
# Created: Sun Feb 15 13:27:51 2015 # Created: Sun Feb 15 15:01:20 2015
# by: PyQt4 UI code generator 4.10.4 # by: PyQt4 UI code generator 4.10.4
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Resource object code # Resource object code
# #
# Created: Sun Feb 15 13:27:51 2015 # Created: Sun Feb 15 15:01:20 2015
# by: The Resource Compiler for PyQt (Qt v4.8.6) # by: The Resource Compiler for PyQt (Qt v4.8.6)
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/updates.ui'
#
# Created: Sun Feb 15 15:01:20 2015
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_DialogUpdates(object):
def setupUi(self, DialogUpdates):
DialogUpdates.setObjectName(_fromUtf8("DialogUpdates"))
DialogUpdates.resize(500, 400)
self.verticalLayout = QtGui.QVBoxLayout(DialogUpdates)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.labelUpdates = QtGui.QLabel(DialogUpdates)
self.labelUpdates.setWordWrap(True)
self.labelUpdates.setOpenExternalLinks(True)
self.labelUpdates.setObjectName(_fromUtf8("labelUpdates"))
self.verticalLayout.addWidget(self.labelUpdates)
self.textBrowser = QtGui.QTextBrowser(DialogUpdates)
self.textBrowser.setObjectName(_fromUtf8("textBrowser"))
self.verticalLayout.addWidget(self.textBrowser)
self.buttonBox = QtGui.QDialogButtonBox(DialogUpdates)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.verticalLayout.addWidget(self.buttonBox)
self.retranslateUi(DialogUpdates)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), DialogUpdates.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), DialogUpdates.reject)
QtCore.QMetaObject.connectSlotsByName(DialogUpdates)
def retranslateUi(self, DialogUpdates):
DialogUpdates.setWindowTitle(_translate("DialogUpdates", "Update Checker", None))
self.labelUpdates.setText(_translate("DialogUpdates", "<p>A new version of Yomichan is available for download!</p>\n"
"\n"
"<p>You can download this update (version {0} to version {1}) from the add-ons section on <a href=\"https://ankiweb.net/shared/info/934748696\">Anki Online</a> or directly from the <a href=\"http://foosoft.net/projects/yomichan\">Yomichan homepage</a>.</p>\n"
"\n"
"<p>Changes from your version are listed below:</p>", None))

View File

@ -24,7 +24,7 @@ import japanese.util
import os import os
import preferences import preferences
import reader_util import reader_util
import update import updates
class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader): class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
@ -52,7 +52,7 @@ class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
self.language = language self.language = language
self.preferences = preferences self.preferences = preferences
self.state = self.State() self.state = self.State()
self.updater = update.UpdateFinder() self.updates = updates.UpdateFinder()
self.zoom = 0 self.zoom = 0
self.applyPreferences() self.applyPreferences()
@ -90,10 +90,10 @@ class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
self.textKanjiSearch.returnPressed.connect(self.onKanjiDefSearchReturn) self.textKanjiSearch.returnPressed.connect(self.onKanjiDefSearchReturn)
self.textVocabDefs.anchorClicked.connect(self.onVocabDefsAnchorClicked) self.textVocabDefs.anchorClicked.connect(self.onVocabDefsAnchorClicked)
self.textVocabSearch.returnPressed.connect(self.onVocabDefSearchReturn) self.textVocabSearch.returnPressed.connect(self.onVocabDefSearchReturn)
self.updater.updateResult.connect(self.onUpdaterSearchResult) self.updates.updateResult.connect(self.onUpdaterSearchResult)
if self.preferences['checkForUpdates']: if self.preferences['checkForUpdates']:
self.updater.start() self.updates.start()
def applyPreferences(self): def applyPreferences(self):
@ -323,14 +323,10 @@ class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
self.actionToggleKanji.setChecked(self.dockKanji.isVisible()) self.actionToggleKanji.setChecked(self.dockKanji.isVisible())
def onUpdaterSearchResult(self, result): def onUpdaterSearchResult(self, versions):
if result and unicode(result) > constants.c['appVersion']: if versions['latest'] > constants.c['appVersion']:
QtGui.QMessageBox.information( dialog = updates.DialogUpdates(self, versions)
self, dialog.exec_()
'Yomichan',
'A new version of Yomichan is available for download!\n\nYou can download this update ({0} > {1}) ' \
'from "Shared Plugins" in Anki or directly from the Yomichan homepage.'.format(constants.c['appVersion'], result)
)
def onContentMouseMove(self, event): def onContentMouseMove(self, event):

View File

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2013 Alex Yatskov
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4 import QtCore
from xml.dom import minidom
import constants
import urllib2
class UpdateFinder(QtCore.QThread):
updateResult = QtCore.pyqtSignal(str)
def run(self):
latest = None
try:
fp = urllib2.urlopen('http://foosoft.net/pub/projects/yomichan/updates.xml')
data = fp.read()
doc = minidom.parseString(data)
root = doc.documentElement
if root.nodeName == 'updates':
latest = root.getAttribute('latest') or None
except:
pass
finally:
self.updateResult.emit(latest or constants.c['appVersion'])

72
yomi_base/updates.py Normal file
View File

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2013 Alex Yatskov
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4 import QtCore, QtGui
import constants
import gen.updates_ui
import json
import urllib2
class DialogUpdates(QtGui.QDialog, gen.updates_ui.Ui_DialogUpdates):
def __init__(self, parent, versions):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.updateHtml(versions)
self.labelUpdates.setText(
unicode(self.labelUpdates.text()).format(
constants.c['appVersion'],
versions['latest']
)
)
def updateHtml(self, versions):
html = '<html><body>'
for update in versions['updates']:
version = update.get('version')
if version > constants.c['appVersion']:
html += '<strong>Version {0}</strong>'.format(version)
html += '<ul>'
for feature in update['features']:
html += '<li>{0}</li>'.format(feature)
html += '</ul>'
self.textBrowser.setHtml(html)
class UpdateFinder(QtCore.QThread):
updateResult = QtCore.pyqtSignal(dict)
def run(self):
latest = constants.c['appVersion']
updates = list()
try:
fp = urllib2.urlopen('http://foosoft.net/projects/yomichan/index/updates.json')
updates = json.loads(fp.read())
fp.close()
for update in updates:
latest = max(latest, update.get('version'))
except:
pass
finally:
self.updateResult.emit({ 'latest': latest, 'updates': updates })