From da59c896100ccb0d4edcda0d25b369bdcc402780 Mon Sep 17 00:00:00 2001 From: Damian Wrobel Date: Sun, 5 May 2019 23:24:26 +0200 Subject: [PATCH] Port to QT5 (squashed) commit d3a3514d048a08e10a39e1d9d5e9bf08b92aa41d Author: purboo Date: Thu Nov 15 12:27:13 2018 +0800 fix QPrinter issue commit 57189d9adb3b0f29339f9710b3a6d0b78f2faf5d Author: Purboo Date: Sun Jul 30 12:50:39 2017 +0800 fix audio file saving commit fc799a4a1fe27010c1e35f6763e2f63a9303c5d6 Merge: 67ef415 b2bd214 Author: Shudong Xie Date: Sun Jul 30 12:48:30 2017 +0800 Merge pull request #2 from gitfortat/save_file_pyqt5 fix audio file saving commit b2bd21469ed7b7746e8b049617f0d1344d3e9497 Merge: 9ce4c7b c8c4efc Author: JayT Date: Thu Jul 13 11:16:26 2017 +0200 Merge branch 'save_file_pyqt5' of https://github.com/gitfortat/ldoce5viewer into save_file_pyqt5 commit 9ce4c7b40dfc5bc8d141c7b2319e32bd31e8d269 Author: JayT Date: Thu Jul 13 11:11:44 2017 +0200 move selection of first filename string element up commit 8477c0b21d057bbd121d13b75409bacd788cd1f8 Merge: 02bd2f4 67ef415 Author: JayT Date: Wed Jul 12 17:26:36 2017 +0200 Merge remote-tracking branch 'upstream-pyqt5/master' into save_file_pyqt5 commit c8c4efc25b530e177283dc0c16dc309c592b7757 Merge: 02bd2f4 67ef415 Author: JayT Date: Wed Jul 12 17:26:36 2017 +0200 Merge remote-tracking branch 'upstream-pyqt5/master' into save_file_pyqt5 commit 02bd2f443bd0befcc4324a20cab48dd2a7a87451 Author: JayT Date: Wed Jul 12 17:24:54 2017 +0200 fix audio file saving File saving gives an error, because the filename consists of two strings. To fix it just use the first element filename[0] and also change type from "w" to "wb" (write binary) commit 67ef415cd2bfa9868b519fb432075154843c62d5 Merge: 0a9ac3a f05ceba Author: Shudong Xie Date: Wed Apr 19 19:41:04 2017 +0800 Merge pull request #1 from jiedo/master fix: click "Definitions" error; Ctrl-Scroll error. port UrlQuery to qt5; commit f05ceba88d1f653c42424e43c68929dc45399ee3 Author: jiedo Date: Tue Apr 18 18:26:12 2017 +0800 fix: click "Definitions" error; Ctrl-Scroll error. port UrlQuery to qt5; commit 0a9ac3a60e9f0cb344102e40db07899feef705e8 Author: Purboo Date: Wed Mar 1 23:15:30 2017 +0800 Fix unexpected crashes when clicking related links commit 62ad241eede710fb71633caf75ab7421849fc515 Author: Purboo Date: Tue Feb 28 21:09:24 2017 +0800 Ported to PyQt5 commit 248ba20f757d77c0bb94e610925c2aa7b7e00d4a Author: Purboo Date: Tue Feb 28 20:56:43 2017 +0800 Ported to PyQt5 commit ded2d5e5f72a890e78cedfec8936c10a08972d96 Author: Purboo Date: Tue Feb 28 20:14:40 2017 +0800 Ported to PyQt5 --- ldoce5viewer/qtgui/__init__.py | 6 ++-- ldoce5viewer/qtgui/access.py | 4 +-- ldoce5viewer/qtgui/advanced.py | 24 ++++++++------ ldoce5viewer/qtgui/{async.py => async_.py} | 2 +- ldoce5viewer/qtgui/config.py | 2 +- ldoce5viewer/qtgui/indexer.py | 5 +-- ldoce5viewer/qtgui/main.py | 34 ++++++++++++------- ldoce5viewer/qtgui/resources/Makefile | 2 +- ldoce5viewer/qtgui/ui/Makefile | 2 +- ldoce5viewer/qtgui/ui/custom.py | 10 +++--- ldoce5viewer/qtgui/ui/main.ui | 2 +- ldoce5viewer/qtgui/utils/error.py | 4 +-- ldoce5viewer/qtgui/utils/fontfallback.py | 2 +- ldoce5viewer/qtgui/utils/singleapp.py | 6 ++-- ldoce5viewer/qtgui/utils/soundplayer.py | 38 ++++++++++++++++++++-- 15 files changed, 96 insertions(+), 47 deletions(-) rename ldoce5viewer/qtgui/{async.py => async_.py} (99%) diff --git a/ldoce5viewer/qtgui/__init__.py b/ldoce5viewer/qtgui/__init__.py index 093ba01..56fa851 100644 --- a/ldoce5viewer/qtgui/__init__.py +++ b/ldoce5viewer/qtgui/__init__.py @@ -17,7 +17,7 @@ import codecs import os.path -from PyQt4.QtGui import QIcon +from PyQt5.QtGui import QIcon from .utils.singleapp import SingleApplication from .utils.error import StdErrWrapper, MyStreamHandler @@ -25,7 +25,7 @@ # set a dummy function if QLineEdit doesn't have setPlaceholderText -from PyQt4.QtGui import QLineEdit +from PyQt5.QtWidgets import QLineEdit if not hasattr(QLineEdit, 'setPlaceholderText'): def _dummySetPlaceholderText(self, *args, **kwargs): pass @@ -107,7 +107,7 @@ def messageHandler(msg): # On Windows-ja if app.font().family() == u'MS UI Gothic': cand = (('Segoe UI', None), ('Meiryo UI', None), ('Tahoma', 8)) - from PyQt4.QtGui import QFont + from PyQt5.QtGui import QFont for name, point in cand: ps = app.font().pointSize() if point is None: diff --git a/ldoce5viewer/qtgui/access.py b/ldoce5viewer/qtgui/access.py index b25aa86..c8752e0 100644 --- a/ldoce5viewer/qtgui/access.py +++ b/ldoce5viewer/qtgui/access.py @@ -8,9 +8,9 @@ import os.path import traceback -from PyQt4.QtCore import ( +from PyQt5.QtCore import ( Qt, Q_ARG, QMetaObject, QIODevice, QTimer,) -from PyQt4.QtNetwork import ( +from PyQt5.QtNetwork import ( QNetworkAccessManager, QNetworkReply, QNetworkRequest,) from .. import __version__ diff --git a/ldoce5viewer/qtgui/advanced.py b/ldoce5viewer/qtgui/advanced.py index fa35480..36743a4 100644 --- a/ldoce5viewer/qtgui/advanced.py +++ b/ldoce5viewer/qtgui/advanced.py @@ -5,9 +5,11 @@ from operator import itemgetter -from PyQt4.QtCore import Qt, QUrl -from PyQt4.QtGui import ( - QAction, QDialog, QKeySequence, QIcon, QTreeWidgetItem,) +from PyQt5.QtCore import Qt, QUrl, QUrlQuery +from PyQt5.QtGui import ( + QKeySequence, QIcon) +from PyQt5.QtWidgets import ( + QAction, QDialog, QTreeWidgetItem,) from ..ldoce5 import advtree from ..utils.compat import range @@ -194,11 +196,13 @@ def _render_header(title, mode, phrase, filters): for (name, spec) in modes: href = QUrl('search:///') + urlquery = QUrlQuery() if phrase: - href.addQueryItem('phrase', phrase) + urlquery.addQueryItem('phrase', phrase) if filters: - href.addQueryItem('filters', filters) - href.addQueryItem('mode', name) + urlquery.addQueryItem('filters', filters) + urlquery.addQueryItem('mode', name) + href.setQuery(urlquery) if name != mode: r.append( '
  • {title}
  • \n'.format( @@ -276,10 +280,10 @@ def _render_hwdphr(items, mode): def search_and_render(url, fulltext_hp, fulltext_de): - query = dict((k, v) for (k, v) in url.queryItems()) - mode = query.get('mode', None) - phrase = query.get('phrase', None) - filters = query.get('filters', None) + query = QUrlQuery(url) + mode = query.queryItemValue('mode') + phrase = query.queryItemValue('phrase') + filters = query.queryItemValue('filters') r = [] if mode in MODE_DICT: diff --git a/ldoce5viewer/qtgui/async.py b/ldoce5viewer/qtgui/async_.py similarity index 99% rename from ldoce5viewer/qtgui/async.py rename to ldoce5viewer/qtgui/async_.py index 4b06af4..f578c5b 100644 --- a/ldoce5viewer/qtgui/async.py +++ b/ldoce5viewer/qtgui/async_.py @@ -5,7 +5,7 @@ import logging -from PyQt4.QtCore import ( +from PyQt5.QtCore import ( QObject, QThread, QMutex, QWaitCondition, pyqtSignal) _logger = logging.getLogger(__name__) diff --git a/ldoce5viewer/qtgui/config.py b/ldoce5viewer/qtgui/config.py index 84ea8b1..89e08e9 100644 --- a/ldoce5viewer/qtgui/config.py +++ b/ldoce5viewer/qtgui/config.py @@ -12,7 +12,7 @@ except ImportError: import pickle -from PyQt4.QtCore import QReadWriteLock +from PyQt5.QtCore import QReadWriteLock __config = None diff --git a/ldoce5viewer/qtgui/indexer.py b/ldoce5viewer/qtgui/indexer.py index 0fedba6..76baa0b 100644 --- a/ldoce5viewer/qtgui/indexer.py +++ b/ldoce5viewer/qtgui/indexer.py @@ -14,8 +14,9 @@ from struct import Struct import traceback -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * import lxml.etree as et from .. import __version__ diff --git a/ldoce5viewer/qtgui/main.py b/ldoce5viewer/qtgui/main.py index 129133c..ef6f257 100644 --- a/ldoce5viewer/qtgui/main.py +++ b/ldoce5viewer/qtgui/main.py @@ -20,10 +20,13 @@ except ImportError: objc = None -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from PyQt4.QtNetwork import * -from PyQt4.QtWebKit import * +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtNetwork import * +from PyQt5.QtWebKit import * +from PyQt5.QtWebKitWidgets import * +from PyQt5.QtWidgets import * +from PyQt5.QtPrintSupport import * from .. import fulltext from .. import incremental @@ -36,7 +39,7 @@ from .advanced import AdvancedSearchDialog from .config import get_config from .access import MyNetworkAccessManager, _load_static_data -from .async import AsyncFTSearcher +from .async_ import AsyncFTSearcher from .utils.soundplayer import create_soundplayer from .indexer import IndexerDialog from .ui.custom import ToolButton, LineEdit @@ -556,9 +559,13 @@ def finished(): def downloadSelectedAudio(self): path = self._ui.webView.audioUrlToDownload.path() def showSaveDialog(data): - filename = QFileDialog.getSaveFileName(self, u'Save mp3', '', u'MP3 Files (*.mp3)') + filename = QFileDialog.getSaveFileName(self, u'Save mp3', \ + '', u'MP3 Files (*.mp3)') + if type(filename) is tuple: + filename = filename[0] + if filename != '': - file = open(filename, "w") + file = open(filename, "wb") file.write(data) file.close() self._getAudioData(path, showSaveDialog) @@ -568,7 +575,8 @@ def _onWebViewLinkClicked(self, url): if scheme == 'audio': self._playbackAudio(url.path()) elif scheme == 'lookup': - query = dict((k, v) for (k, v) in url.queryItems()) + urlQuery = QUrlQuery(url) + query = dict(urlQuery.queryItems()) if 'q' in query: q = query['q'].replace('+', ' ') self._ui.lineEditSearch.setText(q) @@ -682,13 +690,15 @@ def fullSearch(self, phrase, filters, mode=None, only_web=False): self._timerUpdateIndex.start(0) if self._fts_hwdphr and self._fts_defexa: - url = QUrl("search:///") + urlquery = QUrlQuery() if phrase: - url.addQueryItem("phrase", phrase) + urlquery.addQueryItem("phrase", phrase) if filters: - url.addQueryItem("filters", filters) + urlquery.addQueryItem("filters", filters) if mode: - url.addQueryItem("mode", mode) + urlquery.addQueryItem("mode", mode) + url = QUrl("search:///") + url.setQuery(urlquery) self._ui.webView.load(url) diff --git a/ldoce5viewer/qtgui/resources/Makefile b/ldoce5viewer/qtgui/resources/Makefile index f7c9958..f6a80a0 100644 --- a/ldoce5viewer/qtgui/resources/Makefile +++ b/ldoce5viewer/qtgui/resources/Makefile @@ -3,7 +3,7 @@ FILES := $(wildcard *.png) $(wildcard *.svg) $(wildcard */*.png) __init__.py: resource.qrc $(FILES) - pyrcc4 -py3 $< -o $@ + pyrcc5 $< -o $@ .PHONY: clean clean: diff --git a/ldoce5viewer/qtgui/ui/Makefile b/ldoce5viewer/qtgui/ui/Makefile index 7f80401..ed1f405 100644 --- a/ldoce5viewer/qtgui/ui/Makefile +++ b/ldoce5viewer/qtgui/ui/Makefile @@ -6,7 +6,7 @@ __init__.py: touch $@ %.py: %.ui - pyuic4 $< -o $@ + pyuic5 $< -o $@ .PYONY: clean clean: diff --git a/ldoce5viewer/qtgui/ui/custom.py b/ldoce5viewer/qtgui/ui/custom.py index f475f42..ad455c4 100644 --- a/ldoce5viewer/qtgui/ui/custom.py +++ b/ldoce5viewer/qtgui/ui/custom.py @@ -2,9 +2,11 @@ import sys -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from PyQt4.QtWebKit import * +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWebKit import * +from PyQt5.QtWidgets import * +from PyQt5.QtWebKitWidgets import * from ...utils.text import ellipsis @@ -285,7 +287,7 @@ def mouseReleaseEvent(self, event): def wheelEvent(self, event): if event.modifiers() & Qt.ControlModifier: - self.wheelWithCtrl.emit(event.delta()) + self.wheelWithCtrl.emit(event.pixelDelta()) return super(WebView, self).wheelEvent(event) diff --git a/ldoce5viewer/qtgui/ui/main.ui b/ldoce5viewer/qtgui/ui/main.ui index 427ecf6..bd5d91b 100644 --- a/ldoce5viewer/qtgui/ui/main.ui +++ b/ldoce5viewer/qtgui/ui/main.ui @@ -758,7 +758,7 @@ QWebInspector QWidget -
    PyQt4/QtWebKit
    +
    PyQt5/QtWebKitWidgets
    HtmlListWidget diff --git a/ldoce5viewer/qtgui/utils/error.py b/ldoce5viewer/qtgui/utils/error.py index 59721a2..3a10bda 100644 --- a/ldoce5viewer/qtgui/utils/error.py +++ b/ldoce5viewer/qtgui/utils/error.py @@ -2,8 +2,8 @@ from logging import StreamHandler -from PyQt4.QtCore import QMutex, QObject, pyqtSignal -from PyQt4.QtGui import QPlainTextEdit +from PyQt5.QtCore import QMutex, QObject, pyqtSignal +from PyQt5.QtWidgets import QPlainTextEdit class MyStreamHandler(StreamHandler): diff --git a/ldoce5viewer/qtgui/utils/fontfallback.py b/ldoce5viewer/qtgui/utils/fontfallback.py index 3cd769c..a43e19a 100644 --- a/ldoce5viewer/qtgui/utils/fontfallback.py +++ b/ldoce5viewer/qtgui/utils/fontfallback.py @@ -5,7 +5,7 @@ import re -from PyQt4.QtGui import QFont +from PyQt5.QtGui import QFont _DEFAULT_FONT_NAMES = frozenset((b'sans-serif', b'serif', b'monospace')) diff --git a/ldoce5viewer/qtgui/utils/singleapp.py b/ldoce5viewer/qtgui/utils/singleapp.py index f6e40ff..7511f7d 100644 --- a/ldoce5viewer/qtgui/utils/singleapp.py +++ b/ldoce5viewer/qtgui/utils/singleapp.py @@ -1,9 +1,9 @@ '''This module prevent you from running two instances of the app''' -from PyQt4.QtCore import pyqtSignal, QIODevice -from PyQt4.QtGui import QApplication -from PyQt4.QtNetwork import QLocalSocket, QLocalServer +from PyQt5.QtCore import pyqtSignal, QIODevice +from PyQt5.QtWidgets import QApplication +from PyQt5.QtNetwork import QLocalSocket, QLocalServer class SingleApplication(QApplication): diff --git a/ldoce5viewer/qtgui/utils/soundplayer.py b/ldoce5viewer/qtgui/utils/soundplayer.py index 0c8046d..8d93665 100644 --- a/ldoce5viewer/qtgui/utils/soundplayer.py +++ b/ldoce5viewer/qtgui/utils/soundplayer.py @@ -1,10 +1,10 @@ import sys import os import abc -from tempfile import NamedTemporaryFile +from tempfile import NamedTemporaryFile, mkdtemp import logging -from PyQt4.QtCore import * +from PyQt5.QtCore import * from ...utils.compat import range _logger = logging.getLogger(__name__) @@ -50,11 +50,18 @@ # Qt-Phonon try: - from PyQt4.phonon import Phonon + from PyQt5.phonon import Phonon except ImportError: Phonon = None +# Qt-Multimedia +try: + import PyQt5.QtMultimedia as QtMultimedia +except ImportError: + QtMultimedia = None + + class Backend(object): __metaclass__ = abc.ABCMeta def __init__(self, parent, temp_dir): @@ -254,6 +261,29 @@ def close(self): self._clean_tmp() +class QtMultimediaBackend(Backend): + def __init__(self, parent, temp_dir): + self._player = QtMultimedia.QMediaPlayer() + self._tmpdir = mkdtemp() + + def _play(self): + url = QUrl.fromLocalFile(self._path) + content = QtMultimedia.QMediaContent(url) + self._player.setMedia(content) + self._player.play() + + def play(self, data): + self._player.stop() + with NamedTemporaryFile(mode='w+b', prefix='', + suffix='.tmp.mp3', dir=self._tmpdir, delete=False) as f: + f.write(data) + self._path = f.name + QTimer.singleShot(0, self._play) + + def close(self): + self._player.stop() + + class AppKitBackend(Backend): def __init__(self, parent, temp_dir): self._sound = None @@ -281,6 +311,8 @@ def create_soundplayer(parent, temp_dir): backends.append(WinMCIBackend) if Phonon: backends.append(PhononBackend) + if QtMultimedia: + backends.append(QtMultimediaBackend) if Gst: backends.append(GstreamerBackend) if gst: