You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.5 KiB
231 lines
7.5 KiB
6 years ago
|
# -*- coding: utf-8 -*-
|
||
|
#
|
||
|
# Copyright © 2009-2011 Pierre Raybaut
|
||
|
# Licensed under the terms of the MIT License
|
||
|
# (copied from Spyder source code [spyderlib.qt])
|
||
|
#
|
||
|
# Qt5 migration would not have been possible without
|
||
|
# 2014-2015 Spyder Development Team work
|
||
|
# (MIT License too, same parent project)
|
||
|
|
||
|
"""Qt utilities"""
|
||
|
|
||
|
# winpython.qt becomes winpython._vendor.qtpy
|
||
|
from winpython._vendor.qtpy.QtWidgets import (QAction, QStyle, QWidget, QApplication,
|
||
|
QLabel, QVBoxLayout, QHBoxLayout, QLineEdit,
|
||
|
QMenu, QToolButton)
|
||
|
|
||
|
from winpython._vendor.qtpy.QtGui import (QIcon, QKeyEvent, QKeySequence, QPixmap)
|
||
|
|
||
|
from winpython._vendor.qtpy.QtCore import (Signal, QObject, Qt, QLocale, QTranslator,
|
||
|
QLibraryInfo, QEvent, Slot)
|
||
|
from winpython._vendor.qtpy.compat import to_qvariant, from_qvariant
|
||
|
|
||
|
import os
|
||
|
import re
|
||
|
import os.path as osp
|
||
|
import sys
|
||
|
|
||
|
# Local import
|
||
|
from winpython import config
|
||
|
from winpython.py3compat import is_text_string, to_text_string
|
||
|
|
||
|
|
||
|
def get_icon(name):
|
||
|
"""Return QIcon from icon name"""
|
||
|
return QIcon(osp.join(config.IMAGE_PATH, name))
|
||
|
|
||
|
|
||
|
class MacApplication(QApplication):
|
||
|
"""Subclass to be able to open external files with our Mac app"""
|
||
|
open_external_file = Signal(str)
|
||
|
|
||
|
def __init__(self, *args):
|
||
|
QApplication.__init__(self, *args)
|
||
|
|
||
|
def event(self, event):
|
||
|
if event.type() == QEvent.FileOpen:
|
||
|
fname = str(event.file())
|
||
|
# PyQt4 old SIGNAL: self.emit(SIGNAL('open_external_file(QString)'), fname)
|
||
|
self.open_external_file.emit(fname)
|
||
|
return QApplication.event(self, event)
|
||
|
|
||
|
|
||
|
def qapplication(translate=True):
|
||
|
"""Return QApplication instance
|
||
|
Creates it if it doesn't already exist"""
|
||
|
if sys.platform == "darwin" and 'Spyder.app' in __file__:
|
||
|
SpyderApplication = MacApplication
|
||
|
else:
|
||
|
SpyderApplication = QApplication
|
||
|
|
||
|
app = SpyderApplication.instance()
|
||
|
if not app:
|
||
|
# Set Application name for Gnome 3
|
||
|
# https://groups.google.com/forum/#!topic/pyside/24qxvwfrRDs
|
||
|
app = SpyderApplication(['Spyder'])
|
||
|
if translate:
|
||
|
install_translator(app)
|
||
|
return app
|
||
|
|
||
|
|
||
|
def file_uri(fname):
|
||
|
"""Select the right file uri scheme according to the operating system"""
|
||
|
if os.name == 'nt':
|
||
|
# Local file
|
||
|
if re.search(r'^[a-zA-Z]:', fname):
|
||
|
return 'file:///' + fname
|
||
|
# UNC based path
|
||
|
else:
|
||
|
return 'file://' + fname
|
||
|
else:
|
||
|
return 'file://' + fname
|
||
|
|
||
|
|
||
|
QT_TRANSLATOR = None
|
||
|
|
||
|
|
||
|
def install_translator(qapp):
|
||
|
"""Install Qt translator to the QApplication instance"""
|
||
|
global QT_TRANSLATOR
|
||
|
if QT_TRANSLATOR is None:
|
||
|
qt_translator = QTranslator()
|
||
|
if qt_translator.load("qt_"+QLocale.system().name(),
|
||
|
QLibraryInfo.location(QLibraryInfo.TranslationsPath)):
|
||
|
QT_TRANSLATOR = qt_translator # Keep reference alive
|
||
|
if QT_TRANSLATOR is not None:
|
||
|
qapp.installTranslator(QT_TRANSLATOR)
|
||
|
|
||
|
|
||
|
def keybinding(attr):
|
||
|
"""Return keybinding"""
|
||
|
ks = getattr(QKeySequence, attr)
|
||
|
return from_qvariant(QKeySequence.keyBindings(ks)[0], str)
|
||
|
|
||
|
|
||
|
def _process_mime_path(path, extlist):
|
||
|
if path.startswith(r"file://"):
|
||
|
if os.name == 'nt':
|
||
|
# On Windows platforms, a local path reads: file:///c:/...
|
||
|
# and a UNC based path reads like: file://server/share
|
||
|
if path.startswith(r"file:///"): # this is a local path
|
||
|
path = path[8:]
|
||
|
else: # this is a unc path
|
||
|
path = path[5:]
|
||
|
else:
|
||
|
path = path[7:]
|
||
|
if osp.exists(path):
|
||
|
if extlist is None or osp.splitext(path)[1] in extlist:
|
||
|
return path
|
||
|
|
||
|
|
||
|
def mimedata2url(source, extlist=None):
|
||
|
"""
|
||
|
Extract url list from MIME data
|
||
|
extlist: for example ('.py', '.pyw')
|
||
|
"""
|
||
|
pathlist = []
|
||
|
if source.hasUrls():
|
||
|
for url in source.urls():
|
||
|
path = _process_mime_path(to_text_string(url.toString()), extlist)
|
||
|
if path is not None:
|
||
|
pathlist.append(path)
|
||
|
elif source.hasText():
|
||
|
for rawpath in to_text_string(source.text()).splitlines():
|
||
|
path = _process_mime_path(rawpath, extlist)
|
||
|
if path is not None:
|
||
|
pathlist.append(path)
|
||
|
if pathlist:
|
||
|
return pathlist
|
||
|
|
||
|
|
||
|
def action2button(action, autoraise=True, text_beside_icon=False, parent=None):
|
||
|
"""Create a QToolButton directly from a QAction object"""
|
||
|
if parent is None:
|
||
|
parent = action.parent()
|
||
|
button = QToolButton(parent)
|
||
|
button.setDefaultAction(action)
|
||
|
button.setAutoRaise(autoraise)
|
||
|
if text_beside_icon:
|
||
|
button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||
|
return button
|
||
|
|
||
|
|
||
|
def toggle_actions(actions, enable):
|
||
|
"""Enable/disable actions"""
|
||
|
if actions is not None:
|
||
|
for action in actions:
|
||
|
if action is not None:
|
||
|
action.setEnabled(enable)
|
||
|
|
||
|
|
||
|
def create_action(parent, text, shortcut=None, icon=None, tip=None,
|
||
|
toggled=None, triggered=None, data=None, menurole=None,
|
||
|
context=Qt.WindowShortcut):
|
||
|
"""Create a QAction"""
|
||
|
action = QAction(text, parent)
|
||
|
if triggered is not None:
|
||
|
# PyQt4 old SIGNAL: parent.connect(action, SIGNAL("triggered()"), triggered)
|
||
|
action.triggered.connect(triggered)
|
||
|
if toggled is not None:
|
||
|
# PyQt4 old SIGNAL: parent.connect(action, SIGNAL("toggled(bool)"), toggled)
|
||
|
action.toggled.connect(toggled)
|
||
|
action.setCheckable(True)
|
||
|
if icon is not None:
|
||
|
if is_text_string(icon):
|
||
|
icon = get_icon(icon)
|
||
|
action.setIcon(icon)
|
||
|
if shortcut is not None:
|
||
|
action.setShortcut(shortcut)
|
||
|
if tip is not None:
|
||
|
action.setToolTip(tip)
|
||
|
action.setStatusTip(tip)
|
||
|
if data is not None:
|
||
|
action.setData(to_qvariant(data))
|
||
|
if menurole is not None:
|
||
|
action.setMenuRole(menurole)
|
||
|
# TODO: Hard-code all shortcuts and choose context=Qt.WidgetShortcut
|
||
|
# (this will avoid calling shortcuts from another dockwidget
|
||
|
# since the context thing doesn't work quite well with these widgets)
|
||
|
action.setShortcutContext(context)
|
||
|
return action
|
||
|
|
||
|
|
||
|
def add_actions(target, actions, insert_before=None):
|
||
|
"""Add actions to a menu"""
|
||
|
previous_action = None
|
||
|
target_actions = list(target.actions())
|
||
|
if target_actions:
|
||
|
previous_action = target_actions[-1]
|
||
|
if previous_action.isSeparator():
|
||
|
previous_action = None
|
||
|
for action in actions:
|
||
|
if (action is None) and (previous_action is not None):
|
||
|
if insert_before is None:
|
||
|
target.addSeparator()
|
||
|
else:
|
||
|
target.insertSeparator(insert_before)
|
||
|
elif isinstance(action, QMenu):
|
||
|
if insert_before is None:
|
||
|
target.addMenu(action)
|
||
|
else:
|
||
|
target.insertMenu(insert_before, action)
|
||
|
elif isinstance(action, QAction):
|
||
|
if insert_before is None:
|
||
|
target.addAction(action)
|
||
|
else:
|
||
|
target.insertAction(insert_before, action)
|
||
|
previous_action = action
|
||
|
|
||
|
|
||
|
def get_std_icon(name, size=None):
|
||
|
"""Get standard platform icon
|
||
|
Call 'show_std_icons()' for details"""
|
||
|
if not name.startswith('SP_'):
|
||
|
name = 'SP_'+name
|
||
|
icon = QWidget().style().standardIcon(getattr(QStyle, name))
|
||
|
if size is None:
|
||
|
return icon
|
||
|
else:
|
||
|
return QIcon(icon.pixmap(size, size))
|