From 6629a92156eaaa29df58af6b28dd8dfb189bad45 Mon Sep 17 00:00:00 2001 From: sandorracz Date: Mon, 5 Jan 2015 10:25:15 -0500 Subject: [PATCH] Added PyQt5 support (PyQ4 and PySide are also supported) --- bootstrap.py | 6 +- spyderlib/plugins/__init__.py | 22 ++++-- spyderlib/plugins/console.py | 16 ++++- spyderlib/plugins/editor.py | 15 +++- spyderlib/plugins/explorer.py | 3 + spyderlib/plugins/externalconsole.py | 13 +++- spyderlib/plugins/findinfiles.py | 3 + spyderlib/plugins/history.py | 10 ++- spyderlib/plugins/inspector.py | 11 ++- spyderlib/plugins/ipythonconsole.py | 10 ++- spyderlib/plugins/onlinehelp.py | 4 ++ spyderlib/plugins/outlineexplorer.py | 2 + spyderlib/plugins/projectexplorer.py | 3 + spyderlib/plugins/shortcuts.py | 5 ++ spyderlib/plugins/variableexplorer.py | 3 + spyderlib/plugins/workingdirectory.py | 14 +++- spyderlib/qt/QtCore.py | 51 ++++++++++--- spyderlib/qt/QtGui.py | 72 ++++++++++++++++++- spyderlib/qt/QtSvg.py | 7 +- spyderlib/qt/QtWebKit.py | 8 ++- spyderlib/qt/__init__.py | 23 ++++-- spyderlib/qt/compat.py | 13 ++-- spyderlib/requirements.py | 25 +++---- spyderlib/spyder.py | 9 +-- spyderlib/widgets/arrayeditor.py | 5 ++ spyderlib/widgets/dataframeeditor.py | 5 ++ spyderlib/widgets/dependencies.py | 5 ++ spyderlib/widgets/dicteditor.py | 8 ++- spyderlib/widgets/externalshell/baseshell.py | 6 +- .../widgets/externalshell/pythonshell.py | 11 ++- .../widgets/externalshell/sitecustomize.py | 13 +++- .../widgets/externalshell/systemshell.py | 10 ++- spyderlib/widgets/importwizard.py | 3 + spyderlib/widgets/internalshell.py | 1 + spyderlib/widgets/ipython.py | 1 + spyderlib/widgets/mixins.py | 4 +- spyderlib/widgets/projectexplorer.py | 6 +- spyderlib/widgets/shell.py | 2 + spyderlib/widgets/sourcecode/base.py | 1 + spyderplugins/p_breakpoints.py | 5 ++ spyderplugins/p_profiler.py | 5 ++ spyderplugins/p_pylint.py | 5 ++ spyderplugins/widgets/breakpointsgui.py | 5 ++ spyderplugins/widgets/profilergui.py | 9 ++- 44 files changed, 384 insertions(+), 74 deletions(-) diff --git a/bootstrap.py b/bootstrap.py index 7ce7cc7c520..ce026c91987 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -32,7 +32,7 @@ Type `python bootstrap.py -- --help` to read about Spyder options.""") parser.add_option('--gui', default=None, - help="GUI toolkit: pyqt (for PyQt4) or pyside (for PySide)") + help="GUI toolkit: pyqt (for PyQt4/PyQt5) or pyside (for PySide)") parser.add_option('--hide-console', action='store_true', default=False, help="Hide parent console window (Windows only)") parser.add_option('--test', dest="test", action='store_true', default=False, @@ -104,7 +104,7 @@ print(" and %s" % EXTPATH) -# Selecting the GUI toolkit: PySide if installed, otherwise PyQt4 +# Selecting the GUI toolkit: PySide if installed, otherwise PyQt4 or PyQt5 # (Note: PyQt4 is still the officially supported GUI toolkit for Spyder) if options.gui is None: try: @@ -112,7 +112,7 @@ print("02. PySide is detected, selecting (experimental)") os.environ['QT_API'] = 'pyside' except: - print("02. No PySide detected, using PyQt4 if available") + print("02. No PySide detected, using PyQt4 or PyQt5 if available") else: print ("02. Skipping GUI toolkit detection") os.environ['QT_API'] = options.gui diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index b764c9aaba9..7bc91b19626 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -31,6 +31,7 @@ from spyderlib.plugins.configdialog import SpyderConfigPage from spyderlib.py3compat import configparser, is_text_string import sys +from spyderlib.qt import PYQT5 class PluginConfigPage(SpyderConfigPage): @@ -154,9 +155,12 @@ class SpyderPluginMixin(object): show_message = None update_plugin_title = None - def __init__(self, main): + def __init__(self, main = None, **kwds): """Bind widget to a QMainWindow instance""" - super(SpyderPluginMixin, self).__init__() + if PYQT5: + super().__init__(**kwds) + else: + super(SpyderPluginMixin, self).__init__() assert self.CONF_SECTION is not None self.main = main self.default_margins = None @@ -169,6 +173,7 @@ def __init__(self, main): # the one that comes with dockwidget because it's not possible # to raise and focus the plugin with it. self.toggle_view_action = None + def initialize_plugin(self): """Initialize plugin: connect signals, setup actions, ...""" @@ -341,6 +346,7 @@ def get_plugin_font(self, option=None): def set_plugin_font(self, font, option=None): """Set plugin font option""" set_font(font, self.CONF_SECTION, option) + def __show_message(self, message, timeout=0): """Show message in main window's status bar""" @@ -399,10 +405,14 @@ class SpyderPluginWidget(QWidget, SpyderPluginMixin): sig_option_changed = Signal(str, object) show_message = Signal(str, int) update_plugin_title = Signal() - - def __init__(self, parent): - QWidget.__init__(self, parent) - SpyderPluginMixin.__init__(self, parent) + if PYQT5: + def __init__(self, parent, **kwds): + super().__init__(**kwds) + else: + def __init__(self, parent): + QWidget.__init__(self, parent) + SpyderPluginMixin.__init__(self, parent) + def get_plugin_title(self): """ diff --git a/spyderlib/plugins/console.py b/spyderlib/plugins/console.py index a04e7af5f8f..b3d67d4bdc3 100644 --- a/spyderlib/plugins/console.py +++ b/spyderlib/plugins/console.py @@ -34,6 +34,7 @@ from spyderlib.plugins import SpyderPluginWidget from spyderlib.py3compat import to_text_string, getcwd +from spyderlib.qt import PYQT5 class Console(SpyderPluginWidget): """ @@ -43,10 +44,16 @@ class Console(SpyderPluginWidget): focus_changed = Signal() redirect_stdio = Signal(bool) edit_goto = Signal(str, int, str) - + show_message = Signal(str, int) + update_plugin_title = Signal() + + def __init__(self, parent=None, namespace=None, commands=[], message=None, exitfunc=None, profile=False, multithreaded=False): - SpyderPluginWidget.__init__(self, parent) + if PYQT5: + SpyderPluginWidget.__init__(self, parent, main = parent) + else: + SpyderPluginWidget.__init__(self, parent) debug_print(" ..internal console: initializing") self.dialog_manager = DialogManager() @@ -61,13 +68,15 @@ def __init__(self, parent=None, namespace=None, commands=[], message=None, self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0)) self.shell.go_to_error.connect(self.go_to_error) self.shell.focus_changed.connect(lambda: self.focus_changed.emit()) + + # Redirecting some signals: self.shell.redirect_stdio.connect(lambda state: self.redirect_stdio.emit(state)) # Initialize plugin self.initialize_plugin() - + # Find/replace widget self.find_widget = FindReplace(self) self.find_widget.set_editor(self.shell) @@ -85,6 +94,7 @@ def __init__(self, parent=None, namespace=None, commands=[], message=None, # Accepting drops self.setAcceptDrops(True) + #------ Private API -------------------------------------------------------- def set_historylog(self, historylog): diff --git a/spyderlib/plugins/editor.py b/spyderlib/plugins/editor.py index cd420437f64..a645a8a5872 100644 --- a/spyderlib/plugins/editor.py +++ b/spyderlib/plugins/editor.py @@ -45,6 +45,7 @@ get_run_configuration, ALWAYS_OPEN_FIRST_RUN_OPTION) from spyderlib.py3compat import to_text_string, getcwd, qbytearray_to_str +from spyderlib.qt import PYQT5 def _load_all_breakpoints(): @@ -339,9 +340,15 @@ class Editor(SpyderPluginWidget): open_dir = Signal(str) breakpoints_saved = Signal() run_in_current_extconsole = Signal(str, str, str, bool) + show_message = Signal(str, int) + update_plugin_title = Signal() + def __init__(self, parent, ignore_last_opened_files=False): - SpyderPluginWidget.__init__(self, parent) + if PYQT5: + SpyderPluginWidget.__init__(self, parent, main=parent) + else: + SpyderPluginWidget.__init__(self, parent) self.__set_eol_chars = True @@ -1548,7 +1555,8 @@ def change_max_recent_files(self): if valid: self.set_option('max_recent_files', mrf) - @Slot() + + @Slot(str, int, str, object) def load(self, filenames=None, goto=None, word='', editorwindow=None, processevents=True): """ @@ -1985,9 +1993,12 @@ def debug_command(self, command): self.main.extconsole.execute_python_code(command) else: self.main.ipyconsole.write_to_stdin(command) + focus_widget = self.main.ipyconsole.get_focus_widget() + if focus_widget: focus_widget.setFocus() + else: self.main.extconsole.execute_python_code(command) diff --git a/spyderlib/plugins/explorer.py b/spyderlib/plugins/explorer.py index 62784d293ff..cad51380d73 100644 --- a/spyderlib/plugins/explorer.py +++ b/spyderlib/plugins/explorer.py @@ -36,6 +36,9 @@ class Explorer(ExplorerWidget, SpyderPluginMixin): create_module = Signal(str) run = Signal(str) open_dir = Signal(str) + show_message = Signal(str, int) + update_plugin_title = Signal() + def __init__(self, parent=None): ExplorerWidget.__init__(self, parent=parent, diff --git a/spyderlib/plugins/externalconsole.py b/spyderlib/plugins/externalconsole.py index 9f71524bb4b..75c29ae0930 100644 --- a/spyderlib/plugins/externalconsole.py +++ b/spyderlib/plugins/externalconsole.py @@ -41,6 +41,7 @@ from spyderlib.plugins.runconfig import get_run_configuration from spyderlib.py3compat import to_text_string, is_text_string, getcwd from spyderlib import dependencies +from spyderlib.qt import PYQT5 MPL_REQVER = '>=1.0' dependencies.add("matplotlib", _("Interactive data plotting in the consoles"), @@ -48,6 +49,7 @@ class ExternalConsoleConfigPage(PluginConfigPage): + def __init__(self, plugin, parent): PluginConfigPage.__init__(self, plugin, parent) self.get_name = lambda: _("Console") @@ -448,9 +450,16 @@ class ExternalConsole(SpyderPluginWidget): edit_goto = Signal(str, int, str, bool) focus_changed = Signal() redirect_stdio = Signal(bool) + show_message = Signal(str, int) + update_plugin_title = Signal() + go_to_error = Signal(str) + def __init__(self, parent, light_mode): - SpyderPluginWidget.__init__(self, parent) + if PYQT5: + SpyderPluginWidget.__init__(self, parent, main = parent) + else: + SpyderPluginWidget.__init__(self, parent) self.light_mode = light_mode self.tabwidget = None self.menu_actions = None @@ -693,7 +702,7 @@ def pdb_has_stopped(self, fname, lineno, shellwidget): # This is a unique form of the edit_goto signal that is intended to # prevent keyboard input from accidentally entering the editor # during repeated, rapid entry of debugging commands. - self.edit_got.emit(fname, lineno, '', False) + self.edit_goto.emit(fname, lineno, '', False) if shellwidget.is_ipykernel: # Focus client widget, not kernel ipw = self.main.ipyconsole.get_focus_widget() diff --git a/spyderlib/plugins/findinfiles.py b/spyderlib/plugins/findinfiles.py index 639d051a2dc..f28d3c4d53d 100644 --- a/spyderlib/plugins/findinfiles.py +++ b/spyderlib/plugins/findinfiles.py @@ -29,6 +29,9 @@ class FindInFiles(FindInFilesWidget, SpyderPluginMixin): toggle_visibility = Signal(bool) edit_goto = Signal(str, int, str) redirect_stdio = Signal(bool) + show_message = Signal(str, int) + update_plugin_title = Signal() + def __init__(self, parent=None): supported_encodings = self.get_option('supported_encodings') diff --git a/spyderlib/plugins/history.py b/spyderlib/plugins/history.py index 5941be44635..9576c8fb991 100644 --- a/spyderlib/plugins/history.py +++ b/spyderlib/plugins/history.py @@ -24,6 +24,7 @@ from spyderlib.widgets.findreplace import FindReplace from spyderlib.plugins import SpyderPluginWidget, PluginConfigPage from spyderlib.py3compat import to_text_string, is_text_string +from spyderlib.qt import PYQT5 class HistoryConfigPage(PluginConfigPage): @@ -75,6 +76,9 @@ class HistoryLog(SpyderPluginWidget): CONFIGWIDGET_CLASS = HistoryConfigPage # Signals focus_changed = Signal() + show_message = Signal(str, int) + update_plugin_title = Signal() + def __init__(self, parent): self.tabwidget = None @@ -85,8 +89,10 @@ def __init__(self, parent): self.editors = [] self.filenames = [] self.icons = [] - - SpyderPluginWidget.__init__(self, parent) + if PYQT5: + SpyderPluginWidget.__init__(self, parent, main = parent) + else: + SpyderPluginWidget.__init__(self, parent) # Initialize plugin self.initialize_plugin() diff --git a/spyderlib/plugins/inspector.py b/spyderlib/plugins/inspector.py index 60b3ddbcc5b..4836d973b4f 100644 --- a/spyderlib/plugins/inspector.py +++ b/spyderlib/plugins/inspector.py @@ -34,6 +34,7 @@ from spyderlib.widgets.externalshell.pythonshell import ExtPythonShellWidget from spyderlib.plugins import SpyderPluginWidget, PluginConfigPage from spyderlib.py3compat import to_text_string, get_meth_class_inst +from spyderlib.qt import PYQT5 #XXX: Hardcoded dependency on optional IPython plugin component # that requires the hack to make this work without IPython @@ -354,9 +355,16 @@ class ObjectInspector(SpyderPluginWidget): LOG_PATH = get_conf_path(CONF_SECTION) # Signals focus_changed = Signal() + show_message = Signal(str, int) + update_plugin_title = Signal() + focus_changed = Signal() + def __init__(self, parent): - SpyderPluginWidget.__init__(self, parent) + if PYQT5: + SpyderPluginWidget.__init__(self, parent, main = parent) + else: + SpyderPluginWidget.__init__(self, parent) self.internal_shell = None @@ -371,6 +379,7 @@ def __init__(self, parent): self.set_default_color_scheme() self.plain_text = PlainText(self) + self.rich_text = RichText(self) color_scheme = get_color_scheme(self.get_option('color_scheme_name')) diff --git a/spyderlib/plugins/ipythonconsole.py b/spyderlib/plugins/ipythonconsole.py index d8f3cd29783..a77f5810924 100644 --- a/spyderlib/plugins/ipythonconsole.py +++ b/spyderlib/plugins/ipythonconsole.py @@ -59,6 +59,7 @@ from spyderlib.widgets.findreplace import FindReplace from spyderlib.plugins import SpyderPluginWidget, PluginConfigPage from spyderlib.py3compat import to_text_string, u +from spyderlib.qt import PYQT5 SYMPY_REQVER = '>=0.7.0' @@ -148,6 +149,8 @@ def openssh_tunnel(self, lport, rport, server, remoteip='127.0.0.1', class IPythonConsoleConfigPage(PluginConfigPage): + + append_to_history = Signal(str, str) def __init__(self, plugin, parent): PluginConfigPage.__init__(self, plugin, parent) @@ -577,9 +580,14 @@ class IPythonConsole(SpyderPluginWidget): focus_changed = Signal() edit_goto = Signal(str, int, str) focus_changed = Signal() + show_message = Signal(str, int) + update_plugin_title = Signal() def __init__(self, parent): - SpyderPluginWidget.__init__(self, parent) + if PYQT5: + SpyderPluginWidget.__init__(self, parent, main = parent) + else: + SpyderPluginWidget.__init__(self, parent) self.tabwidget = None self.menu_actions = None diff --git a/spyderlib/plugins/onlinehelp.py b/spyderlib/plugins/onlinehelp.py index b07c28d792d..caaaa169ff8 100644 --- a/spyderlib/plugins/onlinehelp.py +++ b/spyderlib/plugins/onlinehelp.py @@ -22,8 +22,12 @@ class OnlineHelp(PydocBrowser, SpyderPluginMixin): Online Help Plugin """ sig_option_changed = Signal(str, object) + show_message = Signal(str, int) + update_plugin_title = Signal() + CONF_SECTION = 'onlinehelp' LOG_PATH = get_conf_path(CONF_SECTION) + def __init__(self, parent): self.main = parent PydocBrowser.__init__(self, parent) diff --git a/spyderlib/plugins/outlineexplorer.py b/spyderlib/plugins/outlineexplorer.py index 4734a40303b..fc38d9c76ea 100644 --- a/spyderlib/plugins/outlineexplorer.py +++ b/spyderlib/plugins/outlineexplorer.py @@ -24,6 +24,8 @@ class OutlineExplorer(OutlineExplorerWidget, SpyderPluginMixin): CONF_SECTION = 'outline_explorer' sig_option_changed = Signal(str, object) + show_message = Signal(str, int) + update_plugin_title = Signal() def __init__(self, parent=None, fullpath_sorting=True): show_fullpath = self.get_option('show_fullpath') diff --git a/spyderlib/plugins/projectexplorer.py b/spyderlib/plugins/projectexplorer.py index 37ae94e848d..16f83a3671a 100644 --- a/spyderlib/plugins/projectexplorer.py +++ b/spyderlib/plugins/projectexplorer.py @@ -31,6 +31,9 @@ class ProjectExplorer(ProjectExplorerWidget, SpyderPluginMixin): removed_tree = Signal(str) renamed = Signal(str, str) redirect_stdio = Signal(bool) + show_message = Signal(str, int) + update_plugin_title = Signal() + def __init__(self, parent=None): ProjectExplorerWidget.__init__(self, parent=parent, diff --git a/spyderlib/plugins/shortcuts.py b/spyderlib/plugins/shortcuts.py index 0077073cebd..24b9ca8f112 100644 --- a/spyderlib/plugins/shortcuts.py +++ b/spyderlib/plugins/shortcuts.py @@ -211,6 +211,11 @@ def setData(self, index, value, role=Qt.EditRole): return True return False + def reset(self): + self.beginResetModel() + self.endResetModel() + + class ShortcutsDelegate(QItemDelegate): def __init__(self, parent=None): diff --git a/spyderlib/plugins/variableexplorer.py b/spyderlib/plugins/variableexplorer.py index 03af4f0233c..0bf36d02268 100644 --- a/spyderlib/plugins/variableexplorer.py +++ b/spyderlib/plugins/variableexplorer.py @@ -86,6 +86,9 @@ class VariableExplorer(QStackedWidget, SpyderPluginMixin): CONF_SECTION = 'variable_explorer' CONFIGWIDGET_CLASS = VariableExplorerConfigPage sig_option_changed = Signal(str, object) + show_message = Signal(str, int) + update_plugin_title = Signal() + def __init__(self, parent): QStackedWidget.__init__(self, parent) SpyderPluginMixin.__init__(self, parent) diff --git a/spyderlib/plugins/workingdirectory.py b/spyderlib/plugins/workingdirectory.py index 8aca9898a1a..3ef763a3349 100644 --- a/spyderlib/plugins/workingdirectory.py +++ b/spyderlib/plugins/workingdirectory.py @@ -29,6 +29,7 @@ from spyderlib.plugins import SpyderPluginMixin, PluginConfigPage from spyderlib.py3compat import to_text_string, getcwd +from spyderlib.qt import PYQT5 class WorkingDirectoryConfigPage(PluginConfigPage): def setup_page(self): @@ -147,10 +148,17 @@ class WorkingDirectory(QToolBar, SpyderPluginMixin): set_explorer_cwd = Signal(str) refresh_findinfiles = Signal() set_current_console_wd = Signal(str) + show_message = Signal(str, int) + update_plugin_title = Signal() + - def __init__(self, parent, workdir=None): - QToolBar.__init__(self, parent) - SpyderPluginMixin.__init__(self, parent) + def __init__(self, parent, workdir=None, **kwds): + if PYQT5: + super().__init__(**kwds) + else: + QToolBar.__init__(self, parent) + SpyderPluginMixin.__init__(self, parent) + # Initialize plugin self.initialize_plugin() diff --git a/spyderlib/qt/QtCore.py b/spyderlib/qt/QtCore.py index ac23049c8c4..e41e767ef47 100644 --- a/spyderlib/qt/QtCore.py +++ b/spyderlib/qt/QtCore.py @@ -5,16 +5,49 @@ # (see spyderlib/__init__.py for details) import os +import sys + if os.environ['QT_API'] == 'pyqt': - from PyQt4.QtCore import * # analysis:ignore - from PyQt4.Qt import QCoreApplication # analysis:ignore - from PyQt4.Qt import Qt # analysis:ignore - from PyQt4.QtCore import pyqtSignal as Signal # analysis:ignore - from PyQt4.QtCore import pyqtSlot as Slot # analysis:ignore - from PyQt4.QtCore import pyqtProperty as Property # analysis:ignore - from PyQt4.QtCore import QT_VERSION_STR as __version__ + if "PyQt4" in sys.modules: + from PyQt4.Qt import QSize, QByteArray, QUrl, QThread + from PyQt4.Qt import QAbstractTableModel, QModelIndex + from PyQt4.Qt import QObject, Qt, QLocale, QTranslator + from PyQt4.Qt import QProcess, QTimer, QTextCodec + from PyQt4.Qt import QEventLoop, QEvent, QPoint, QRect + from PyQt4.Qt import QRegExp, QFileInfo, QMimeData, QDir + from PyQt4.Qt import QMutexLocker, QMutex, QCoreApplication, QDateTime + from PyQt4.Qt import QBasicTimer + from PyQt4.QtCore import QLibraryInfo + from PyQt4.QtCore import pyqtSignal as Signal + from PyQt4.QtCore import pyqtSlot as Slot + from PyQt4.QtCore import pyqtProperty as Property + from PyQt4.QtCore import QT_VERSION_STR as __version__ + from PyQt4.QtCore import QProcessEnvironment + try: + # PyQt =v4.6 + QString = None + elif "PyQt5" in sys.modules: + from PyQt5.QtCore import QSize, QByteArray, QUrl, QThread + from PyQt5.QtCore import QAbstractTableModel, QModelIndex + from PyQt5.QtCore import QObject, Qt, QLocale, QTranslator + from PyQt5.QtCore import QProcess, QTimer, QTextCodec + from PyQt5.QtCore import QEventLoop, QEvent, QPoint, QRect + from PyQt5.QtCore import QRegExp, QFileInfo, QMimeData, QDir + from PyQt5.QtCore import QMutexLocker, QMutex, QCoreApplication, QDateTime + from PyQt5.QtCore import QBasicTimer, QLibraryInfo + from PyQt5.QtCore import pyqtSignal as Signal + from PyQt5.QtCore import pyqtSlot as Slot + from PyQt5.QtCore import pyqtProperty as Property + from PyQt5.QtCore import QT_VERSION_STR as __version__ + from PyQt5.QtCore import QProcessEnvironment + + + else: import PySide.QtCore - __version__ = PySide.QtCore.__version__ # analysis:ignore - from PySide.QtCore import * # analysis:ignore + __version__ = PySide.QtCore.__version__ + from PySide.QtCore import * diff --git a/spyderlib/qt/QtGui.py b/spyderlib/qt/QtGui.py index 2eae128beff..df6c7c12ed1 100644 --- a/spyderlib/qt/QtGui.py +++ b/spyderlib/qt/QtGui.py @@ -5,9 +5,77 @@ # (see spyderlib/__init__.py for details) import os +import sys if os.environ['QT_API'] == 'pyqt': - from PyQt4.Qt import QKeySequence, QTextCursor # analysis:ignore - from PyQt4.QtGui import * # analysis:ignore + if "PyQt4" in sys.modules: + from PyQt4.QtGui import QApplication, QMainWindow, QWidget, QLabel + from PyQt4.QtGui import QDockWidget, QShortcut, QCursor, QDialog, QListWidget + from PyQt4.QtGui import QListWidgetItem, QVBoxLayout, QStackedWidget, QListView + from PyQt4.QtGui import QHBoxLayout, QDialogButtonBox, QCheckBox, QMessageBox + from PyQt4.QtGui import QLabel, QLineEdit, QSpinBox, QPushButton + from PyQt4.QtGui import QFontComboBox, QGroupBox, QComboBox, QColor, QGridLayout + from PyQt4.QtGui import QTabWidget, QRadioButton, QButtonGroup, QSplitter + from PyQt4.QtGui import QStyleFactory, QScrollArea, QAction, QPrinter + from PyQt4.QtGui import QPrintDialog, QToolBar, QActionGroup + from PyQt4.QtGui import QInputDialog, QMenu, QAbstractPrintDialog, QKeySequence + from PyQt4.QtGui import QPrintPreviewDialog, QFontDialog, QSizePolicy, QToolButton + from PyQt4.QtGui import QFormLayout, QStackedWidget, QFrame, QItemDelegate + from PyQt4.QtGui import QTableView, QStackedWidget, QDesktopServices, QStyle + from PyQt4.QtGui import QIcon, QKeyEvent, QPixmap, QFont + from PyQt4.QtGui import QCursor, QTextCursor, QTextEdit, QTextCharFormat + from PyQt4.QtGui import QToolTip, QPlainTextEdit, QPalette, QTextOption + from PyQt4.QtGui import QMouseEvent, QTextFormat, QClipboard, QPainter + from PyQt4.QtGui import QBrush, QTextDocument, QTextBlockUserData, QIntValidator + from PyQt4.QtGui import QSyntaxHighlighter, QDoubleValidator, QAbstractItemDelegate, QProgressBar + from PyQt4.QtGui import QColorDialog, QCompleter, QDateEdit, QDateTimeEdit + from PyQt4.QtGui import QTreeWidgetItem, QFileSystemModel, QDrag, QSortFilterProxyModel + from PyQt4.QtGui import QSpacerItem, QFileIconProvider, QHeaderView, QAbstractItemView + from PyQt4.QtGui import QTabBar, QFontDatabase, QSplashScreen + from PyQt4.QtGui import QFileDialog, QTreeWidget, QTreeView + from PyQt4.QtGui import QStylePainter, QStyleOptionFrame,QPaintEvent + elif "PyQt5" in sys.modules: + from PyQt5.QtGui import QCursor + from PyQt5.QtGui import QColor + from PyQt5.QtGui import QKeySequence + from PyQt5.QtGui import QDesktopServices + from PyQt5.QtGui import QIcon, QKeyEvent, QPixmap, QFont + from PyQt5.QtGui import QCursor, QTextCursor + from PyQt5.QtGui import QTextCharFormat + from PyQt5.QtGui import QPalette, QTextOption + from PyQt5.QtGui import QMouseEvent, QTextFormat, QClipboard, QPainter + from PyQt5.QtGui import QBrush, QTextDocument, QTextBlockUserData, QIntValidator + from PyQt5.QtGui import QSyntaxHighlighter, QDoubleValidator + from PyQt5.QtGui import QDrag + from PyQt5.QtGui import QFontDatabase, QPaintEvent + from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel + from PyQt5.QtWidgets import QDockWidget, QShortcut + from PyQt5.QtWidgets import QDialog, QListWidget + from PyQt5.QtWidgets import QListWidgetItem, QVBoxLayout, QStackedWidget, QListView + from PyQt5.QtWidgets import QHBoxLayout, QDialogButtonBox, QCheckBox, QMessageBox + from PyQt5.QtWidgets import QLabel, QLineEdit, QSpinBox, QPushButton + from PyQt5.QtWidgets import QFontComboBox, QGroupBox, QComboBox + from PyQt5.QtWidgets import QGridLayout + from PyQt5.QtWidgets import QTabWidget, QRadioButton, QButtonGroup, QSplitter + from PyQt5.QtWidgets import QStyleFactory, QScrollArea, QAction + from PyQt5.QtWidgets import QToolBar, QActionGroup + from PyQt5.QtWidgets import QInputDialog, QMenu + from PyQt5.QtWidgets import QFontDialog, QSizePolicy, QToolButton + from PyQt5.QtWidgets import QFormLayout, QStackedWidget, QFrame, QItemDelegate + from PyQt5.QtWidgets import QTableView, QStackedWidget + from PyQt5.QtWidgets import QStyle + from PyQt5.QtWidgets import QTextEdit + from PyQt5.QtWidgets import QToolTip, QPlainTextEdit + from PyQt5.QtWidgets import QProgressBar, QAbstractItemDelegate + from PyQt5.QtWidgets import QColorDialog, QCompleter, QDateEdit, QDateTimeEdit + from PyQt5.QtWidgets import QTreeWidgetItem, QFileSystemModel + from PyQt5.QtWidgets import QSpacerItem, QFileIconProvider, QHeaderView, QAbstractItemView + from PyQt5.QtWidgets import QTabBar, QSplashScreen + from PyQt5.QtWidgets import QFileDialog, QTreeWidget, QTreeView + from PyQt5.QtWidgets import QStylePainter, QStyleOptionFrame + from PyQt5.QtCore import QSortFilterProxyModel + from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog + from PyQt5.QtPrintSupport import QPrintPreviewDialog + else: from PySide.QtGui import * # analysis:ignore diff --git a/spyderlib/qt/QtSvg.py b/spyderlib/qt/QtSvg.py index 46d5a48dc33..5813f65d2e9 100644 --- a/spyderlib/qt/QtSvg.py +++ b/spyderlib/qt/QtSvg.py @@ -5,8 +5,13 @@ # (see spyderlib/__init__.py for details) import os +import sys if os.environ['QT_API'] == 'pyqt': - from PyQt4.QtSvg import * # analysis:ignore + if "PyQt4" in sys.modules: + from PyQt4.QtSvg import * # analysis:ignore + elif "PyQt5" in sys.modules: + from PyQt5.QtSvg import * # analysis:ignore + else: from PySide.QtSvg import * # analysis:ignore \ No newline at end of file diff --git a/spyderlib/qt/QtWebKit.py b/spyderlib/qt/QtWebKit.py index 3f133d89b99..fb924302447 100644 --- a/spyderlib/qt/QtWebKit.py +++ b/spyderlib/qt/QtWebKit.py @@ -5,8 +5,14 @@ # (see spyderlib/__init__.py for details) import os +import sys if os.environ['QT_API'] == 'pyqt': - from PyQt4.QtWebKit import * # analysis:ignore + if "PyQt4" in sys.modules: + from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings + elif "PyQt5" in sys.modules: + from PyQt5.QtWebKitWidgets import QWebPage, QWebView + from PyQt5.QtWebKit import QWebSettings + else: from PySide.QtWebKit import * # analysis:ignore \ No newline at end of file diff --git a/spyderlib/qt/__init__.py b/spyderlib/qt/__init__.py index 8c8a6bed8ce..eaaf5d641f5 100644 --- a/spyderlib/qt/__init__.py +++ b/spyderlib/qt/__init__.py @@ -12,7 +12,10 @@ assert os.environ['QT_API'] in ('pyqt', 'pyside') API = os.environ['QT_API'] -API_NAME = {'pyqt': 'PyQt4', 'pyside': 'PySide'}[API] +#API_NAME = {'pyqt': 'PyQt4', 'pyside': 'PySide'}[API] + +PYQT5 = False + if API == 'pyqt': # We do not force QString, QVariant, ... API to #1 or #2 anymore @@ -27,20 +30,28 @@ # pass try: from PyQt4.QtCore import PYQT_VERSION_STR as __version__ - except ImportError: - # Switching to PySide - API = os.environ['QT_API'] = 'pyside' - API_NAME = 'PySide' - else: __version_info__ = tuple(__version__.split('.')+['final', 1]) is_old_pyqt = __version__.startswith(('4.4', '4.5', '4.6', '4.7')) is_pyqt46 = __version__.startswith('4.6') + API_NAME = 'PyQt4' import sip try: + API_NAME += (" (API v%d)" % sip.getapi('QString')) except AttributeError: pass + except ImportError: + try: + from PyQt5.QtCore import PYQT_VERSION_STR as __version__ + is_pyqt46 = False + API_NAME = 'PyQt5' + PYQT5 = True + except: + # Switching to PySide + API = os.environ['QT_API'] = 'pyside' + API_NAME = 'PySide' + if API == 'pyside': try: from PySide import __version__ # analysis:ignore diff --git a/spyderlib/qt/compat.py b/spyderlib/qt/compat.py index 5c9c01c318b..821895aa9db 100644 --- a/spyderlib/qt/compat.py +++ b/spyderlib/qt/compat.py @@ -33,12 +33,13 @@ PYQT_API_1 = False if os.environ['QT_API'] == 'pyqt': - import sip - try: - PYQT_API_1 = sip.getapi('QVariant') == 1 # PyQt API #1 - except AttributeError: - # PyQt