Fix tray visibility and message reception issues
- Disable sound initialization to prevent hanging
- Add missing import re in utils.py
- Fix settings loading for QSettings
- Update file paths to use PROJECT_ROOT
- Revert to working API paths and listener from commit efdc63e
This commit is contained in:
541
venv/lib/python3.12/site-packages/PyQt6/uic/properties.py
Normal file
541
venv/lib/python3.12/site-packages/PyQt6/uic/properties.py
Normal file
@@ -0,0 +1,541 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2024 Riverbank Computing Limited.
|
||||
## Copyright (C) 2006 Thorsten Marek.
|
||||
## All right reserved.
|
||||
##
|
||||
## This file is part of PyQt.
|
||||
##
|
||||
## You may use this file under the terms of the GPL v2 or the revised BSD
|
||||
## license as follows:
|
||||
##
|
||||
## "Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted provided that the following conditions are
|
||||
## met:
|
||||
## * Redistributions of source code must retain the above copyright
|
||||
## notice, this list of conditions and the following disclaimer.
|
||||
## * Redistributions in binary form must reproduce the above copyright
|
||||
## notice, this list of conditions and the following disclaimer in
|
||||
## the documentation and/or other materials provided with the
|
||||
## distribution.
|
||||
## * Neither the name of the Riverbank Computing Limited nor the names
|
||||
## of its contributors may be used to endorse or promote products
|
||||
## derived from this software without specific prior written
|
||||
## permission.
|
||||
##
|
||||
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
from .enum_map import EnumMap
|
||||
from .exceptions import NoSuchClassError, UnsupportedPropertyError
|
||||
from .icon_cache import IconCache
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
DEBUG = logger.debug
|
||||
|
||||
|
||||
QtCore = None
|
||||
QtGui = None
|
||||
QtWidgets = None
|
||||
|
||||
|
||||
def int_list(prop):
|
||||
return [int(child.text) for child in prop]
|
||||
|
||||
def float_list(prop):
|
||||
return [float(child.text) for child in prop]
|
||||
|
||||
bool_ = lambda v: v == "true"
|
||||
|
||||
def qfont_style_strategy(v):
|
||||
return getattr(QtGui.QFont.StyleStrategy, v)
|
||||
|
||||
def needsWidget(func):
|
||||
func.needsWidget = True
|
||||
return func
|
||||
|
||||
|
||||
# A translation table for converting ASCII lower case to upper case.
|
||||
_ascii_trans_table = bytes.maketrans(b'abcdefghijklmnopqrstuvwxyz',
|
||||
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
|
||||
def ascii_upper(s):
|
||||
""" Convert a string to ASCII upper case irrespective of the current
|
||||
locale.
|
||||
"""
|
||||
|
||||
return s.translate(_ascii_trans_table)
|
||||
|
||||
|
||||
class Properties(object):
|
||||
def __init__(self, factory, qtcore_module, qtgui_module, qtwidgets_module):
|
||||
self.factory = factory
|
||||
|
||||
global QtCore, QtGui, QtWidgets
|
||||
QtCore = qtcore_module
|
||||
QtGui = qtgui_module
|
||||
QtWidgets = qtwidgets_module
|
||||
|
||||
self._base_dir = ''
|
||||
|
||||
self.reset()
|
||||
|
||||
def set_base_dir(self, base_dir):
|
||||
""" Set the base directory to be used for all relative filenames. """
|
||||
|
||||
self._base_dir = base_dir
|
||||
self.icon_cache.set_base_dir(base_dir)
|
||||
|
||||
def reset(self):
|
||||
self.buddies = []
|
||||
self.delayed_props = []
|
||||
self.icon_cache = IconCache(self.factory, QtGui)
|
||||
|
||||
def _pyEnumMember(self, cpp_name):
|
||||
if '::' not in cpp_name:
|
||||
cpp_name = 'Qt::' + cpp_name
|
||||
|
||||
cpp_name = EnumMap.get(cpp_name, cpp_name)
|
||||
|
||||
parts = cpp_name.split('::')
|
||||
|
||||
if parts[0] == 'Qt':
|
||||
scope = QtCore.Qt
|
||||
else:
|
||||
scope = self.factory.findQObjectType(parts[0])
|
||||
if scope is None:
|
||||
raise NoSuchClassError(parts[0])
|
||||
|
||||
for tail in parts[1:]:
|
||||
scope = getattr(scope, tail)
|
||||
|
||||
return scope
|
||||
|
||||
def _set(self, prop):
|
||||
expr = [self._pyEnumMember(v) for v in prop.text.split('|')]
|
||||
|
||||
value = expr[0]
|
||||
for v in expr[1:]:
|
||||
value |= v
|
||||
|
||||
return value
|
||||
|
||||
def _enum(self, prop):
|
||||
return self._pyEnumMember(prop.text)
|
||||
|
||||
def _number(self, prop):
|
||||
return int(prop.text)
|
||||
|
||||
_UInt = _uInt = _longLong = _uLongLong = _number
|
||||
|
||||
def _double(self, prop):
|
||||
return float(prop.text)
|
||||
|
||||
def _bool(self, prop):
|
||||
return prop.text == 'true'
|
||||
|
||||
def _stringlist(self, prop):
|
||||
return [self._string(p, notr='true') for p in prop]
|
||||
|
||||
def _string(self, prop, notr=None):
|
||||
text = prop.text
|
||||
|
||||
if text is None:
|
||||
return ""
|
||||
|
||||
if prop.get('notr', notr) == 'true':
|
||||
return text
|
||||
|
||||
disambig = prop.get('comment')
|
||||
|
||||
return QtWidgets.QApplication.translate(self.uiname, text, disambig)
|
||||
|
||||
_char = _string
|
||||
|
||||
def _cstring(self, prop):
|
||||
return str(prop.text)
|
||||
|
||||
def _color(self, prop):
|
||||
args = int_list(prop)
|
||||
|
||||
# Handle the optional alpha component.
|
||||
alpha = int(prop.get("alpha", "255"))
|
||||
|
||||
if alpha != 255:
|
||||
args.append(alpha)
|
||||
|
||||
return QtGui.QColor(*args)
|
||||
|
||||
def _point(self, prop):
|
||||
return QtCore.QPoint(*int_list(prop))
|
||||
|
||||
def _pointf(self, prop):
|
||||
return QtCore.QPointF(*float_list(prop))
|
||||
|
||||
def _rect(self, prop):
|
||||
return QtCore.QRect(*int_list(prop))
|
||||
|
||||
def _rectf(self, prop):
|
||||
return QtCore.QRectF(*float_list(prop))
|
||||
|
||||
def _size(self, prop):
|
||||
return QtCore.QSize(*int_list(prop))
|
||||
|
||||
def _sizef(self, prop):
|
||||
return QtCore.QSizeF(*float_list(prop))
|
||||
|
||||
def _pixmap(self, prop):
|
||||
if prop.text:
|
||||
fname = prop.text.replace("\\", "\\\\")
|
||||
if self._base_dir != '' and fname[0] != ':' and not os.path.isabs(fname):
|
||||
fname = os.path.join(self._base_dir, fname)
|
||||
|
||||
return QtGui.QPixmap(fname)
|
||||
|
||||
# Don't bother to set the property if the pixmap is empty.
|
||||
return None
|
||||
|
||||
def _iconset(self, prop):
|
||||
return self.icon_cache.get_icon(prop)
|
||||
|
||||
def _url(self, prop):
|
||||
return QtCore.QUrl(prop[0].text)
|
||||
|
||||
def _locale(self, prop):
|
||||
lang = getattr(QtCore.QLocale.Language, prop.attrib['language'])
|
||||
country = getattr(QtCore.QLocale.Country, prop.attrib['country'])
|
||||
return QtCore.QLocale(lang, country)
|
||||
|
||||
def _date(self, prop):
|
||||
return QtCore.QDate(*int_list(prop))
|
||||
|
||||
def _datetime(self, prop):
|
||||
args = int_list(prop)
|
||||
return QtCore.QDateTime(QtCore.QDate(*args[-3:]), QtCore.QTime(*args[:-3]))
|
||||
|
||||
def _time(self, prop):
|
||||
return QtCore.QTime(*int_list(prop))
|
||||
|
||||
def _gradient(self, prop):
|
||||
name = 'gradient'
|
||||
|
||||
# Create the specific gradient.
|
||||
gtype = prop.get('type', '')
|
||||
|
||||
if gtype == 'LinearGradient':
|
||||
startx = float(prop.get('startx'))
|
||||
starty = float(prop.get('starty'))
|
||||
endx = float(prop.get('endx'))
|
||||
endy = float(prop.get('endy'))
|
||||
gradient = self.factory.createQtObject('QLinearGradient', name,
|
||||
ctor_args=(startx, starty, endx, endy), is_attribute=False)
|
||||
|
||||
elif gtype == 'ConicalGradient':
|
||||
centralx = float(prop.get('centralx'))
|
||||
centraly = float(prop.get('centraly'))
|
||||
angle = float(prop.get('angle'))
|
||||
gradient = self.factory.createQtObject('QConicalGradient', name,
|
||||
ctor_args=(centralx, centraly, angle), is_attribute=False)
|
||||
|
||||
elif gtype == 'RadialGradient':
|
||||
centralx = float(prop.get('centralx'))
|
||||
centraly = float(prop.get('centraly'))
|
||||
radius = float(prop.get('radius'))
|
||||
focalx = float(prop.get('focalx'))
|
||||
focaly = float(prop.get('focaly'))
|
||||
gradient = self.factory.createQtObject('QRadialGradient', name,
|
||||
ctor_args=(centralx, centraly, radius, focalx, focaly),
|
||||
is_attribute=False)
|
||||
|
||||
else:
|
||||
raise UnsupportedPropertyError(prop.tag)
|
||||
|
||||
# Set the common values.
|
||||
spread = prop.get('spread')
|
||||
if spread:
|
||||
gradient.setSpread(getattr(QtGui.QGradient.Spread, spread))
|
||||
|
||||
cmode = prop.get('coordinatemode')
|
||||
if cmode:
|
||||
gradient.setCoordinateMode(
|
||||
getattr(QtGui.QGradient.CoordinateMode, cmode))
|
||||
|
||||
# Get the gradient stops.
|
||||
for gstop in prop:
|
||||
if gstop.tag != 'gradientstop':
|
||||
raise UnsupportedPropertyError(gstop.tag)
|
||||
|
||||
position = float(gstop.get('position'))
|
||||
color = self._color(gstop[0])
|
||||
|
||||
gradient.setColorAt(position, color)
|
||||
|
||||
return gradient
|
||||
|
||||
def _palette(self, prop):
|
||||
palette = self.factory.createQtObject('QPalette', 'palette',
|
||||
is_attribute=False)
|
||||
|
||||
for palette_elem in prop:
|
||||
sub_palette = getattr(QtGui.QPalette.ColorGroup,
|
||||
palette_elem.tag.title())
|
||||
|
||||
for role, color in enumerate(palette_elem):
|
||||
if color.tag == 'color':
|
||||
# Handle simple colour descriptions where the role is
|
||||
# implied by the colour's position.
|
||||
palette.setColor(sub_palette,
|
||||
QtGui.QPalette.ColorRole(role), self._color(color))
|
||||
elif color.tag == 'colorrole':
|
||||
role = getattr(QtGui.QPalette.ColorRole, color.get('role'))
|
||||
brush = self._brush(color[0])
|
||||
palette.setBrush(sub_palette, role, brush)
|
||||
else:
|
||||
raise UnsupportedPropertyError(color.tag)
|
||||
|
||||
return palette
|
||||
|
||||
def _brush(self, prop):
|
||||
brushstyle = prop.get('brushstyle')
|
||||
|
||||
if brushstyle in ('LinearGradientPattern', 'ConicalGradientPattern', 'RadialGradientPattern'):
|
||||
gradient = self._gradient(prop[0])
|
||||
brush = self.factory.createQtObject('QBrush', 'brush',
|
||||
ctor_args=(gradient, ), is_attribute=False)
|
||||
else:
|
||||
color = self._color(prop[0])
|
||||
brush = self.factory.createQtObject('QBrush', 'brush',
|
||||
ctor_args=(color, ), is_attribute=False)
|
||||
|
||||
brushstyle = getattr(QtCore.Qt.BrushStyle, brushstyle)
|
||||
brush.setStyle(brushstyle)
|
||||
|
||||
return brush
|
||||
|
||||
#@needsWidget
|
||||
def _sizepolicy(self, prop, widget):
|
||||
values = [int(child.text) for child in prop]
|
||||
|
||||
if len(values) == 2:
|
||||
# Qt v4.3.0 and later.
|
||||
horstretch, verstretch = values
|
||||
hsizetype = getattr(QtWidgets.QSizePolicy.Policy, prop.get('hsizetype'))
|
||||
vsizetype = getattr(QtWidgets.QSizePolicy.Policy, prop.get('vsizetype'))
|
||||
else:
|
||||
hsizetype, vsizetype, horstretch, verstretch = values
|
||||
hsizetype = QtWidgets.QSizePolicy.Policy(hsizetype)
|
||||
vsizetype = QtWidgets.QSizePolicy.Policy(vsizetype)
|
||||
|
||||
sizePolicy = self.factory.createQtObject('QSizePolicy', 'sizePolicy',
|
||||
ctor_args=(hsizetype, vsizetype), is_attribute=False)
|
||||
sizePolicy.setHorizontalStretch(horstretch)
|
||||
sizePolicy.setVerticalStretch(verstretch)
|
||||
sizePolicy.setHeightForWidth(widget.sizePolicy().hasHeightForWidth())
|
||||
return sizePolicy
|
||||
_sizepolicy = needsWidget(_sizepolicy)
|
||||
|
||||
# font needs special handling/conversion of all child elements.
|
||||
_font_attributes = (("Family", lambda s: s),
|
||||
("PointSize", int),
|
||||
("Bold", bool_),
|
||||
("Italic", bool_),
|
||||
("Underline", bool_),
|
||||
("Weight", int),
|
||||
("StrikeOut", bool_),
|
||||
("Kerning", bool_),
|
||||
("StyleStrategy", qfont_style_strategy))
|
||||
|
||||
def _font(self, prop):
|
||||
newfont = self.factory.createQtObject('QFont', 'font',
|
||||
is_attribute=False)
|
||||
for attr, converter in self._font_attributes:
|
||||
v = prop.findtext("./%s" % (attr.lower(),))
|
||||
if v is None:
|
||||
continue
|
||||
|
||||
getattr(newfont, "set%s" % (attr,))(converter(v))
|
||||
return newfont
|
||||
|
||||
def _cursor(self, prop):
|
||||
return QtGui.QCursor(QtCore.Qt.CursorShape(int(prop.text)))
|
||||
|
||||
def _cursorShape(self, prop):
|
||||
return QtGui.QCursor(getattr(QtCore.Qt.CursorShape, prop.text))
|
||||
|
||||
def convert(self, prop, widget=None):
|
||||
try:
|
||||
func = getattr(self, "_" + prop[0].tag)
|
||||
except AttributeError:
|
||||
raise UnsupportedPropertyError(prop[0].tag)
|
||||
else:
|
||||
args = {}
|
||||
if getattr(func, "needsWidget", False):
|
||||
assert widget is not None
|
||||
args["widget"] = widget
|
||||
|
||||
return func(prop[0], **args)
|
||||
|
||||
|
||||
def _getChild(self, elem_tag, elem, name, default=None):
|
||||
for prop in elem.findall(elem_tag):
|
||||
if prop.attrib["name"] == name:
|
||||
return self.convert(prop)
|
||||
else:
|
||||
return default
|
||||
|
||||
def getProperty(self, elem, name, default=None):
|
||||
return self._getChild("property", elem, name, default)
|
||||
|
||||
def getAttribute(self, elem, name, default=None):
|
||||
return self._getChild("attribute", elem, name, default)
|
||||
|
||||
def setProperties(self, widget, elem):
|
||||
# Lines are sunken unless the frame shadow is explicitly set.
|
||||
set_sunken = (elem.attrib.get('class') == 'Line')
|
||||
|
||||
for prop in elem.findall('property'):
|
||||
prop_name = prop.attrib['name']
|
||||
DEBUG("setting property %s" % (prop_name,))
|
||||
|
||||
if prop_name == 'frameShadow':
|
||||
set_sunken = False
|
||||
|
||||
try:
|
||||
stdset = bool(int(prop.attrib['stdset']))
|
||||
except KeyError:
|
||||
stdset = True
|
||||
|
||||
if not stdset:
|
||||
self._setViaSetProperty(widget, prop)
|
||||
elif hasattr(self, prop_name):
|
||||
getattr(self, prop_name)(widget, prop)
|
||||
else:
|
||||
prop_value = self.convert(prop, widget)
|
||||
if prop_value is not None:
|
||||
getattr(widget, 'set%s%s' % (ascii_upper(prop_name[0]), prop_name[1:]))(prop_value)
|
||||
|
||||
if set_sunken:
|
||||
widget.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
|
||||
|
||||
# SPECIAL PROPERTIES
|
||||
# If a property has a well-known value type but needs special,
|
||||
# context-dependent handling, the default behaviour can be overridden here.
|
||||
|
||||
# Delayed properties will be set after the whole widget tree has been
|
||||
# populated.
|
||||
def _delayed_property(self, widget, prop):
|
||||
prop_value = self.convert(prop)
|
||||
if prop_value is not None:
|
||||
prop_name = prop.attrib["name"]
|
||||
self.delayed_props.append((widget, False,
|
||||
'set%s%s' % (ascii_upper(prop_name[0]), prop_name[1:]),
|
||||
prop_value))
|
||||
|
||||
# These properties will be set with a widget.setProperty call rather than
|
||||
# calling the set<property> function.
|
||||
def _setViaSetProperty(self, widget, prop):
|
||||
prop_value = self.convert(prop, widget)
|
||||
if prop_value is not None:
|
||||
prop_name = prop.attrib['name']
|
||||
|
||||
# This appears to be a Designer/uic hack where stdset=0 means that
|
||||
# the viewport should be used.
|
||||
if prop[0].tag == 'cursorShape':
|
||||
widget.viewport().setProperty(prop_name, prop_value)
|
||||
else:
|
||||
widget.setProperty(prop_name, prop_value)
|
||||
|
||||
# Ignore the property.
|
||||
def _ignore(self, widget, prop):
|
||||
pass
|
||||
|
||||
# Define properties that use the canned handlers.
|
||||
currentIndex = _delayed_property
|
||||
currentRow = _delayed_property
|
||||
|
||||
showDropIndicator = _setViaSetProperty
|
||||
intValue = _setViaSetProperty
|
||||
value = _setViaSetProperty
|
||||
|
||||
objectName = _ignore
|
||||
margin = _ignore
|
||||
leftMargin = _ignore
|
||||
topMargin = _ignore
|
||||
rightMargin = _ignore
|
||||
bottomMargin = _ignore
|
||||
spacing = _ignore
|
||||
horizontalSpacing = _ignore
|
||||
verticalSpacing = _ignore
|
||||
|
||||
# tabSpacing is actually the spacing property of the widget's layout.
|
||||
def tabSpacing(self, widget, prop):
|
||||
prop_value = self.convert(prop)
|
||||
if prop_value is not None:
|
||||
self.delayed_props.append((widget, True, 'setSpacing', prop_value))
|
||||
|
||||
# buddy setting has to be done after the whole widget tree has been
|
||||
# populated. We can't use delay here because we cannot get the actual
|
||||
# buddy yet.
|
||||
def buddy(self, widget, prop):
|
||||
buddy_name = prop[0].text
|
||||
if buddy_name:
|
||||
self.buddies.append((widget, buddy_name))
|
||||
|
||||
# geometry is handled specially if set on the toplevel widget.
|
||||
def geometry(self, widget, prop):
|
||||
if widget.objectName() == self.uiname:
|
||||
geom = int_list(prop[0])
|
||||
widget.resize(geom[2], geom[3])
|
||||
else:
|
||||
widget.setGeometry(self._rect(prop[0]))
|
||||
|
||||
def orientation(self, widget, prop):
|
||||
# If the class is a QFrame, it's a line.
|
||||
if widget.metaObject().className() == 'QFrame':
|
||||
# Designer v6.7.0 and later use fully qualified enum names.
|
||||
widget.setFrameShape(
|
||||
{'Qt::Orientation::Horizontal': QtWidgets.QFrame.Shape.HLine,
|
||||
'Qt::Horizontal': QtWidgets.QFrame.Shape.HLine,
|
||||
'Qt::Orientation::Vertical' : QtWidgets.QFrame.Shape.VLine,
|
||||
'Qt::Vertical' : QtWidgets.QFrame.Shape.VLine}[prop[0].text])
|
||||
else:
|
||||
widget.setOrientation(self._enum(prop[0]))
|
||||
|
||||
# The isWrapping attribute of QListView is named inconsistently, it should
|
||||
# be wrapping.
|
||||
def isWrapping(self, widget, prop):
|
||||
widget.setWrapping(self.convert(prop))
|
||||
|
||||
# This is a pseudo-property injected to deal with margins.
|
||||
def pyuicMargins(self, widget, prop):
|
||||
widget.setContentsMargins(*int_list(prop))
|
||||
|
||||
# This is a pseudo-property injected to deal with spacing.
|
||||
def pyuicSpacing(self, widget, prop):
|
||||
horiz, vert = int_list(prop)
|
||||
|
||||
if horiz == vert:
|
||||
widget.setSpacing(horiz)
|
||||
else:
|
||||
if horiz >= 0:
|
||||
widget.setHorizontalSpacing(horiz)
|
||||
|
||||
if vert >= 0:
|
||||
widget.setVerticalSpacing(vert)
|
||||
Reference in New Issue
Block a user