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:
@@ -0,0 +1,20 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (c) 2025 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
##
|
||||
## This file is part of PyQt6.
|
||||
##
|
||||
## This file may be used under the terms of the GNU General Public License
|
||||
## version 3.0 as published by the Free Software Foundation and appearing in
|
||||
## the file LICENSE included in the packaging of this file. Please review the
|
||||
## following information to ensure the GNU General Public License version 3.0
|
||||
## requirements will be met: http://www.gnu.org/copyleft/gpl.html.
|
||||
##
|
||||
## If you do not wish to use this file under the terms of the GPL version 3.0
|
||||
## then you may purchase a commercial license. For more information contact
|
||||
## info@riverbankcomputing.com.
|
||||
##
|
||||
## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
##
|
||||
#############################################################################
|
||||
@@ -0,0 +1,40 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (c) 2025 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
##
|
||||
## This file is part of PyQt6.
|
||||
##
|
||||
## This file may be used under the terms of the GNU General Public License
|
||||
## version 3.0 as published by the Free Software Foundation and appearing in
|
||||
## the file LICENSE included in the packaging of this file. Please review the
|
||||
## following information to ensure the GNU General Public License version 3.0
|
||||
## requirements will be met: http://www.gnu.org/copyleft/gpl.html.
|
||||
##
|
||||
## If you do not wish to use this file under the terms of the GPL version 3.0
|
||||
## then you may purchase a commercial license. For more information contact
|
||||
## info@riverbankcomputing.com.
|
||||
##
|
||||
## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def as_string(obj):
|
||||
if isinstance(obj, str):
|
||||
return '"' + _escape(obj) + '"'
|
||||
|
||||
return str(obj)
|
||||
|
||||
|
||||
_esc_regex = re.compile(r"(\"|\'|\\)")
|
||||
|
||||
def _escape(text):
|
||||
# This escapes any escaped single or double quote or backslash.
|
||||
x = _esc_regex.sub(r"\\\1", text)
|
||||
|
||||
# This replaces any '\n' with an escaped version and a real line break.
|
||||
return re.sub(r'\n', r'\\n"\n"', x)
|
||||
107
venv/lib/python3.12/site-packages/PyQt6/uic/Compiler/compiler.py
Normal file
107
venv/lib/python3.12/site-packages/PyQt6/uic/Compiler/compiler.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# Copyright (c) 2023 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 v3 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 sys
|
||||
|
||||
from ..properties import Properties
|
||||
from ..uiparser import UIParser
|
||||
from . import qtproxies
|
||||
from .indenter import createCodeIndenter, getIndenter, write_code
|
||||
from .qobjectcreator import CompilerCreatorPolicy
|
||||
|
||||
|
||||
class UICompiler(UIParser):
|
||||
def __init__(self):
|
||||
UIParser.__init__(self, qtproxies.QtCore, qtproxies.QtGui,
|
||||
qtproxies.QtWidgets, CompilerCreatorPolicy())
|
||||
|
||||
def reset(self):
|
||||
qtproxies.i18n_strings = []
|
||||
UIParser.reset(self)
|
||||
|
||||
def setContext(self, context):
|
||||
qtproxies.i18n_context = context
|
||||
|
||||
def createToplevelWidget(self, classname, widgetname):
|
||||
indenter = getIndenter()
|
||||
indenter.level = 0
|
||||
|
||||
indenter.write("from PyQt6 import QtCore, QtGui, QtWidgets")
|
||||
indenter.write("")
|
||||
|
||||
indenter.write("")
|
||||
indenter.write("class Ui_%s(object):" % self.uiname)
|
||||
indenter.indent()
|
||||
indenter.write("def setupUi(self, %s):" % widgetname)
|
||||
indenter.indent()
|
||||
w = self.factory.createQtObject(classname, widgetname,
|
||||
is_attribute=False, no_instantiation=True)
|
||||
w.baseclass = classname
|
||||
w.uiclass = "Ui_%s" % self.uiname
|
||||
return w
|
||||
|
||||
def setDelayedProps(self):
|
||||
write_code("")
|
||||
write_code("self.retranslateUi(%s)" % self.toplevelWidget)
|
||||
UIParser.setDelayedProps(self)
|
||||
|
||||
def finalize(self):
|
||||
indenter = getIndenter()
|
||||
indenter.level = 1
|
||||
indenter.write("")
|
||||
indenter.write("def retranslateUi(self, %s):" % self.toplevelWidget)
|
||||
|
||||
indenter.indent()
|
||||
|
||||
if qtproxies.i18n_strings:
|
||||
indenter.write("_translate = QtCore.QCoreApplication.translate")
|
||||
for s in qtproxies.i18n_strings:
|
||||
indenter.write(s)
|
||||
else:
|
||||
indenter.write("pass")
|
||||
|
||||
indenter.dedent()
|
||||
indenter.dedent()
|
||||
|
||||
def compileUi(self, input_stream, output_stream):
|
||||
createCodeIndenter(output_stream)
|
||||
w = self.parse(input_stream)
|
||||
|
||||
self.factory._cpolicy._writeOutImports()
|
||||
|
||||
return {"widgetname": str(w),
|
||||
"uiclass" : w.uiclass,
|
||||
"baseclass" : w.baseclass}
|
||||
@@ -0,0 +1,77 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2014 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."
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
|
||||
indentwidth = 4
|
||||
|
||||
_indenter = None
|
||||
|
||||
class _IndentedCodeWriter(object):
|
||||
def __init__(self, output):
|
||||
self.level = 0
|
||||
self.output = output
|
||||
|
||||
def indent(self):
|
||||
self.level += 1
|
||||
|
||||
def dedent(self):
|
||||
self.level -= 1
|
||||
|
||||
def write(self, line):
|
||||
if line.strip():
|
||||
if indentwidth > 0:
|
||||
indent = " " * indentwidth
|
||||
line = line.replace("\t", indent)
|
||||
else:
|
||||
indent = "\t"
|
||||
|
||||
self.output.write("%s%s\n" % (indent * self.level, line))
|
||||
else:
|
||||
self.output.write("\n")
|
||||
|
||||
|
||||
def createCodeIndenter(output):
|
||||
global _indenter
|
||||
_indenter = _IndentedCodeWriter(output)
|
||||
|
||||
def getIndenter():
|
||||
return _indenter
|
||||
|
||||
def write_code(string):
|
||||
_indenter.write(string)
|
||||
59
venv/lib/python3.12/site-packages/PyQt6/uic/Compiler/misc.py
Normal file
59
venv/lib/python3.12/site-packages/PyQt6/uic/Compiler/misc.py
Normal file
@@ -0,0 +1,59 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2016 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."
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
|
||||
def moduleMember(module, name):
|
||||
if module:
|
||||
return "%s.%s" % (module, name)
|
||||
|
||||
return name
|
||||
|
||||
|
||||
class Literal(object):
|
||||
"""Literal(string) -> new literal
|
||||
|
||||
string will not be quoted when put into an argument list"""
|
||||
def __init__(self, string):
|
||||
self.string = string
|
||||
|
||||
def __str__(self):
|
||||
return self.string
|
||||
|
||||
def __or__(self, r_op):
|
||||
return Literal("%s|%s" % (self, r_op))
|
||||
@@ -0,0 +1,100 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2014 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."
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
|
||||
from .misc import Literal, moduleMember
|
||||
|
||||
|
||||
class ProxyMetaclass(type):
|
||||
""" ProxyMetaclass is the meta-class for proxies. """
|
||||
|
||||
def __init__(*args):
|
||||
""" Initialise the meta-class. """
|
||||
|
||||
# Initialise as normal.
|
||||
type.__init__(*args)
|
||||
|
||||
# The proxy type object we have created.
|
||||
proxy = args[0]
|
||||
|
||||
# Go through the proxy's attributes looking for other proxies.
|
||||
for sub_proxy in proxy.__dict__.values():
|
||||
if type(sub_proxy) is ProxyMetaclass:
|
||||
# Set the module name of the contained proxy to the name of the
|
||||
# container proxy.
|
||||
sub_proxy.module = proxy.__name__
|
||||
|
||||
# Attribute hierachies are created depth first so any proxies
|
||||
# contained in the sub-proxy whose module we have just set will
|
||||
# already exist and have an incomplete module name. We need to
|
||||
# revisit them and prepend the new name to their module names.
|
||||
# Note that this should be recursive but with current usage we
|
||||
# know there will be only one level to revisit.
|
||||
for sub_sub_proxy in sub_proxy.__dict__.values():
|
||||
if type(sub_sub_proxy) is ProxyMetaclass:
|
||||
sub_sub_proxy.module = '%s.%s' % (proxy.__name__, sub_sub_proxy.module)
|
||||
|
||||
# Makes sure there is a 'module' attribute.
|
||||
if not hasattr(proxy, 'module'):
|
||||
proxy.module = ''
|
||||
|
||||
def __getattribute__(cls, name):
|
||||
try:
|
||||
return type.__getattribute__(cls, name)
|
||||
except AttributeError:
|
||||
# Make sure __init__()'s use of hasattr() works.
|
||||
if name == 'module':
|
||||
raise
|
||||
|
||||
# Avoid a circular import.
|
||||
from .qtproxies import LiteralProxyClass
|
||||
|
||||
return type(name, (LiteralProxyClass, ),
|
||||
{"module": moduleMember(type.__getattribute__(cls, "module"),
|
||||
type.__getattribute__(cls, "__name__"))})
|
||||
|
||||
def __str__(cls):
|
||||
return moduleMember(type.__getattribute__(cls, "module"),
|
||||
type.__getattribute__(cls, "__name__"))
|
||||
|
||||
def __or__(self, r_op):
|
||||
return Literal("%s|%s" % (self, r_op))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(self) == str(other)
|
||||
@@ -0,0 +1,178 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2023 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 sys
|
||||
|
||||
from .as_string import as_string
|
||||
from .indenter import write_code
|
||||
from .qtproxies import QtGui, QtWidgets, Literal, strict_getattr
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
DEBUG = logger.debug
|
||||
|
||||
|
||||
class _QtWrapper(object):
|
||||
@classmethod
|
||||
def search(cls, name):
|
||||
try:
|
||||
return strict_getattr(cls.module, name)
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
|
||||
class _QtGuiWrapper(_QtWrapper):
|
||||
module = QtGui
|
||||
|
||||
|
||||
class _QtWidgetsWrapper(_QtWrapper):
|
||||
module = QtWidgets
|
||||
|
||||
|
||||
class _ModuleWrapper(object):
|
||||
def __init__(self, name, classes):
|
||||
if "." in name:
|
||||
idx = name.rfind(".")
|
||||
self._package = name[:idx]
|
||||
self._module = name[idx + 1:]
|
||||
else:
|
||||
self._package = None
|
||||
self._module = name
|
||||
|
||||
self._classes = classes
|
||||
self._used = False
|
||||
|
||||
def search(self, cls):
|
||||
if cls in self._classes:
|
||||
self._used = True
|
||||
|
||||
# Remove any C++ scope.
|
||||
cls = cls.split('.')[-1]
|
||||
|
||||
return type(cls, (QtWidgets.QWidget,), {"module": self._module})
|
||||
else:
|
||||
return None
|
||||
|
||||
def _writeImportCode(self):
|
||||
if self._used:
|
||||
if self._package is None:
|
||||
write_code("import %s" % self._module)
|
||||
else:
|
||||
write_code("from %s import %s" % (self._package, self._module))
|
||||
|
||||
|
||||
class _CustomWidgetLoader(object):
|
||||
def __init__(self):
|
||||
self._widgets = {}
|
||||
self._usedWidgets = set()
|
||||
|
||||
def addCustomWidget(self, widgetClass, baseClass, module):
|
||||
assert widgetClass not in self._widgets
|
||||
self._widgets[widgetClass] = (baseClass, module)
|
||||
|
||||
def _resolveBaseclass(self, baseClass):
|
||||
try:
|
||||
for x in range(0, 10):
|
||||
try: return strict_getattr(QtWidgets, baseClass)
|
||||
except AttributeError: pass
|
||||
|
||||
baseClass = self._widgets[baseClass][0]
|
||||
else:
|
||||
raise ValueError("baseclass resolve took too long, check custom widgets")
|
||||
|
||||
except KeyError:
|
||||
raise ValueError("unknown baseclass %s" % baseClass)
|
||||
|
||||
def search(self, cls):
|
||||
try:
|
||||
baseClass = self._resolveBaseclass(self._widgets[cls][0])
|
||||
DEBUG("resolved baseclass of %s: %s" % (cls, baseClass))
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
self._usedWidgets.add(cls)
|
||||
|
||||
return type(cls, (baseClass, ), {"module" : ""})
|
||||
|
||||
def _writeImportCode(self):
|
||||
imports = {}
|
||||
for widget in self._usedWidgets:
|
||||
_, module = self._widgets[widget]
|
||||
imports.setdefault(module, []).append(widget)
|
||||
|
||||
for module, classes in sorted(imports.items()):
|
||||
write_code("from %s import %s" % (module, ", ".join(sorted(classes))))
|
||||
|
||||
|
||||
class CompilerCreatorPolicy(object):
|
||||
def __init__(self):
|
||||
self._modules = []
|
||||
|
||||
def createQtGuiWidgetsWrappers(self):
|
||||
return [_QtGuiWrapper, _QtWidgetsWrapper]
|
||||
|
||||
def createModuleWrapper(self, name, classes):
|
||||
mw = _ModuleWrapper(name, classes)
|
||||
self._modules.append(mw)
|
||||
return mw
|
||||
|
||||
def createCustomWidgetLoader(self):
|
||||
cw = _CustomWidgetLoader()
|
||||
self._modules.append(cw)
|
||||
return cw
|
||||
|
||||
def instantiate(self, ctor, object_name, ctor_args, ctor_kwargs,
|
||||
is_attribute, no_instantiation):
|
||||
return ctor(object_name, ctor_args, ctor_kwargs, is_attribute,
|
||||
no_instantiation)
|
||||
|
||||
def invoke(self, rname, method, args):
|
||||
return method(rname, *args)
|
||||
|
||||
def getSlot(self, object, slotname):
|
||||
return Literal("%s.%s" % (object, slotname))
|
||||
|
||||
def asString(self, s):
|
||||
return as_string(s)
|
||||
|
||||
def _writeOutImports(self):
|
||||
for module in self._modules:
|
||||
module._writeImportCode()
|
||||
@@ -0,0 +1,471 @@
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2023 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 sys
|
||||
import re
|
||||
|
||||
from .as_string import as_string
|
||||
from .indenter import write_code
|
||||
from .misc import Literal, moduleMember
|
||||
from .proxy_metaclass import ProxyMetaclass
|
||||
|
||||
|
||||
i18n_strings = []
|
||||
i18n_context = ""
|
||||
|
||||
def i18n_print(string):
|
||||
i18n_strings.append(string)
|
||||
|
||||
def i18n_void_func(name):
|
||||
def _printer(self, *args):
|
||||
i18n_print("%s.%s(%s)" % (self, name, ", ".join(map(as_string, args))))
|
||||
return _printer
|
||||
|
||||
def i18n_func(name):
|
||||
def _printer(self, rname, *args):
|
||||
i18n_print("%s = %s.%s(%s)" % (rname, self, name, ", ".join(map(as_string, args))))
|
||||
return Literal(rname)
|
||||
|
||||
return _printer
|
||||
|
||||
def strict_getattr(module, clsname):
|
||||
cls = getattr(module, clsname)
|
||||
if issubclass(cls, LiteralProxyClass):
|
||||
raise AttributeError(cls)
|
||||
else:
|
||||
return cls
|
||||
|
||||
|
||||
class i18n_string(object):
|
||||
def __init__(self, string, disambig):
|
||||
self.string = string
|
||||
self.disambig = disambig
|
||||
|
||||
def __str__(self):
|
||||
if self.disambig is None:
|
||||
return '_translate("%s", %s)' % (i18n_context, as_string(self.string))
|
||||
|
||||
return '_translate("%s", %s, %s)' % (i18n_context, as_string(self.string), as_string(self.disambig))
|
||||
|
||||
|
||||
# Classes with this flag will be handled as literal values. If functions are
|
||||
# called on these classes, the literal value changes.
|
||||
# Example:
|
||||
# the code
|
||||
# >>> QSize(9,10).expandedTo(...)
|
||||
# will print just that code.
|
||||
AS_ARGUMENT = 0x02
|
||||
|
||||
# Classes with this flag may have members that are signals which themselves
|
||||
# will have a connect() member.
|
||||
AS_SIGNAL = 0x01
|
||||
|
||||
# ATTENTION: currently, classes can either be literal or normal. If a class
|
||||
# should need both kinds of behaviour, the code has to be changed.
|
||||
|
||||
class ProxyClassMember(object):
|
||||
def __init__(self, proxy, function_name, flags):
|
||||
self.proxy = proxy
|
||||
self.function_name = function_name
|
||||
self.flags = flags
|
||||
|
||||
def __str__(self):
|
||||
return "%s.%s" % (self.proxy, self.function_name)
|
||||
|
||||
def __call__(self, *args):
|
||||
if self.function_name == 'setProperty':
|
||||
str_args = (as_string(args[0]), as_string(args[1]))
|
||||
else:
|
||||
str_args = map(as_string, args)
|
||||
|
||||
func_call = "%s.%s(%s)" % (self.proxy,
|
||||
self.function_name,
|
||||
", ".join(str_args))
|
||||
if self.flags & AS_ARGUMENT:
|
||||
self.proxy._uic_name = func_call
|
||||
return self.proxy
|
||||
else:
|
||||
needs_translation = False
|
||||
for arg in args:
|
||||
if isinstance(arg, i18n_string):
|
||||
needs_translation = True
|
||||
if needs_translation:
|
||||
i18n_print(func_call)
|
||||
else:
|
||||
if self.function_name == 'connect':
|
||||
func_call += ' # type: ignore'
|
||||
|
||||
write_code(func_call)
|
||||
|
||||
def __getattribute__(self, attribute):
|
||||
""" Reimplemented to create a proxy connect() if requested and this
|
||||
might be a proxy for a signal.
|
||||
"""
|
||||
|
||||
try:
|
||||
return object.__getattribute__(self, attribute)
|
||||
except AttributeError:
|
||||
if attribute == 'connect' and self.flags & AS_SIGNAL:
|
||||
return ProxyClassMember(self, attribute, 0)
|
||||
|
||||
raise
|
||||
|
||||
def __getitem__(self, idx):
|
||||
""" Reimplemented to create a proxy member that should be a signal that
|
||||
passes arguments. We handle signals without arguments before we get
|
||||
here and never apply the index notation to them.
|
||||
"""
|
||||
|
||||
return ProxySignalWithArguments(self.proxy, self.function_name, idx)
|
||||
|
||||
|
||||
class ProxySignalWithArguments(object):
|
||||
""" This is a proxy for (what should be) a signal that passes arguments.
|
||||
"""
|
||||
|
||||
def __init__(self, sender, signal_name, signal_index):
|
||||
self._sender = sender
|
||||
self._signal_name = signal_name
|
||||
|
||||
# Convert the signal index, which will be a single argument or a tuple
|
||||
# of arguments, to quoted strings.
|
||||
if isinstance(signal_index, tuple):
|
||||
self._signal_index = ','.join(["'%s'" % a for a in signal_index])
|
||||
else:
|
||||
self._signal_index = "'%s'" % signal_index
|
||||
|
||||
def connect(self, slot):
|
||||
write_code("%s.%s[%s].connect(%s) # type: ignore" % (self._sender, self._signal_name, self._signal_index, slot))
|
||||
|
||||
|
||||
class ProxyBase(metaclass=ProxyMetaclass):
|
||||
""" A base class for proxies using Python v3 syntax for setting the
|
||||
meta-class.
|
||||
"""
|
||||
|
||||
|
||||
class ProxyClass(ProxyBase):
|
||||
flags = 0
|
||||
|
||||
def __init__(self, object_name, ctor_args=None, ctor_kwargs=None,
|
||||
is_attribute=False, no_instantiation=True):
|
||||
if object_name:
|
||||
if is_attribute:
|
||||
object_name = 'self.' + object_name
|
||||
|
||||
self._uic_name = object_name
|
||||
else:
|
||||
self._uic_name = "Unnamed"
|
||||
|
||||
if not no_instantiation:
|
||||
args = [] if ctor_args is None else list(map(str, ctor_args))
|
||||
|
||||
if ctor_kwargs is not None:
|
||||
for k, v in ctor_kwargs.items():
|
||||
args.append(k + '=' + str(v))
|
||||
|
||||
fun_call = '%s(%s)' % \
|
||||
(moduleMember(self.module, self.__class__.__name__),
|
||||
', '.join(args))
|
||||
|
||||
if object_name:
|
||||
fun_call = '%s = %s' % (object_name, fun_call)
|
||||
|
||||
write_code(fun_call)
|
||||
|
||||
def __str__(self):
|
||||
return self._uic_name
|
||||
|
||||
def __getattribute__(self, attribute):
|
||||
try:
|
||||
return object.__getattribute__(self, attribute)
|
||||
except AttributeError:
|
||||
return ProxyClassMember(self, attribute, self.flags)
|
||||
|
||||
|
||||
class LiteralProxyClass(ProxyClass):
|
||||
"""LiteralObject(*args) -> new literal class
|
||||
|
||||
a literal class can be used as argument in a function call
|
||||
|
||||
>>> class Foo(LiteralProxyClass): pass
|
||||
>>> str(Foo(1,2,3)) == "Foo(1,2,3)"
|
||||
"""
|
||||
flags = AS_ARGUMENT
|
||||
|
||||
def __init__(self, *args):
|
||||
self._uic_name = "%s(%s)" % \
|
||||
(moduleMember(self.module, self.__class__.__name__),
|
||||
", ".join(map(as_string, args)))
|
||||
|
||||
|
||||
class ProxyNamespace(ProxyBase):
|
||||
pass
|
||||
|
||||
|
||||
# These are all the Qt classes used by pyuic6 in their namespaces. If a class
|
||||
# is missing, the compiler will fail, normally with an AttributeError.
|
||||
#
|
||||
# For adding new classes:
|
||||
# - utility classes used as literal values do not need to be listed
|
||||
# because they are created on the fly as subclasses of LiteralProxyClass
|
||||
# - classes which are *not* QWidgets inherit from ProxyClass and they
|
||||
# have to be listed explicitly in the correct namespace. These classes
|
||||
# are created via a ProxyQObjectCreator
|
||||
# - new QWidget-derived classes have to inherit from qtproxies.QWidget
|
||||
# If the widget does not need any special methods, it can be listed
|
||||
# in _qwidgets
|
||||
|
||||
class QtCore(ProxyNamespace):
|
||||
class Qt(ProxyNamespace):
|
||||
pass
|
||||
|
||||
## connectSlotsByName and connect have to be handled as class methods,
|
||||
## otherwise they would be created as LiteralProxyClasses and never be
|
||||
## printed
|
||||
class QMetaObject(ProxyClass):
|
||||
@classmethod
|
||||
def connectSlotsByName(cls, *args):
|
||||
ProxyClassMember(cls, "connectSlotsByName", 0)(*args)
|
||||
|
||||
class QObject(ProxyClass):
|
||||
flags = AS_SIGNAL
|
||||
|
||||
def metaObject(self):
|
||||
class _FakeMetaObject(object):
|
||||
def className(*args):
|
||||
return self.__class__.__name__
|
||||
return _FakeMetaObject()
|
||||
|
||||
def objectName(self):
|
||||
return self._uic_name.split(".")[-1]
|
||||
|
||||
|
||||
class QtGui(ProxyNamespace):
|
||||
class QIcon(ProxyClass):
|
||||
class fromTheme(ProxyClass): pass
|
||||
|
||||
class QConicalGradient(ProxyClass): pass
|
||||
class QLinearGradient(ProxyClass): pass
|
||||
class QRadialGradient(ProxyClass): pass
|
||||
class QBrush(ProxyClass): pass
|
||||
class QPainter(ProxyClass): pass
|
||||
class QPalette(ProxyClass): pass
|
||||
class QFont(ProxyClass): pass
|
||||
class QFontDatabase(ProxyClass): pass
|
||||
# QActions inherit from QObject for the meta-object stuff and the hierarchy
|
||||
# has to be correct since we have a isinstance(x, QtWidgets.QLayout) call
|
||||
# in the UI parser.
|
||||
class QAction(QtCore.QObject): pass
|
||||
class QActionGroup(QtCore.QObject): pass
|
||||
|
||||
|
||||
# These sub-class QWidget but aren't themselves sub-classed.
|
||||
_qwidgets = ('QCalendarWidget', 'QDialogButtonBox', 'QDockWidget', 'QGroupBox',
|
||||
'QLineEdit', 'QMainWindow', 'QMenuBar', 'QProgressBar', 'QStatusBar',
|
||||
'QToolBar', 'QWizardPage')
|
||||
|
||||
class QtWidgets(ProxyNamespace):
|
||||
class QApplication(QtCore.QObject):
|
||||
@staticmethod
|
||||
def translate(uiname, text, disambig):
|
||||
return i18n_string(text or "", disambig)
|
||||
|
||||
class QSpacerItem(ProxyClass): pass
|
||||
class QSizePolicy(ProxyClass): pass
|
||||
class QButtonGroup(QtCore.QObject): pass
|
||||
class QLayout(QtCore.QObject): pass
|
||||
class QGridLayout(QLayout): pass
|
||||
class QBoxLayout(QLayout): pass
|
||||
class QHBoxLayout(QBoxLayout): pass
|
||||
class QVBoxLayout(QBoxLayout): pass
|
||||
class QFormLayout(QLayout): pass
|
||||
|
||||
class QWidget(QtCore.QObject):
|
||||
def font(self):
|
||||
return Literal("%s.font()" % self)
|
||||
|
||||
def minimumSizeHint(self):
|
||||
return Literal("%s.minimumSizeHint()" % self)
|
||||
|
||||
def sizePolicy(self):
|
||||
sp = LiteralProxyClass()
|
||||
sp._uic_name = "%s.sizePolicy()" % self
|
||||
return sp
|
||||
|
||||
class QDialog(QWidget): pass
|
||||
class QColorDialog(QDialog): pass
|
||||
class QFileDialog(QDialog): pass
|
||||
class QFontDialog(QDialog): pass
|
||||
class QInputDialog(QDialog): pass
|
||||
class QMessageBox(QDialog): pass
|
||||
class QWizard(QDialog): pass
|
||||
|
||||
class QAbstractSlider(QWidget): pass
|
||||
class QDial(QAbstractSlider): pass
|
||||
class QScrollBar(QAbstractSlider): pass
|
||||
class QSlider(QAbstractSlider): pass
|
||||
|
||||
class QMenu(QWidget):
|
||||
def menuAction(self):
|
||||
return Literal("%s.menuAction()" % self)
|
||||
|
||||
class QTabWidget(QWidget):
|
||||
def addTab(self, *args):
|
||||
text = args[-1]
|
||||
|
||||
if isinstance(text, i18n_string):
|
||||
i18n_print("%s.setTabText(%s.indexOf(%s), %s)" % \
|
||||
(self._uic_name, self._uic_name, args[0], text))
|
||||
args = args[:-1] + ("", )
|
||||
|
||||
ProxyClassMember(self, "addTab", 0)(*args)
|
||||
|
||||
def indexOf(self, page):
|
||||
return Literal("%s.indexOf(%s)" % (self, page))
|
||||
|
||||
class QComboBox(QWidget): pass
|
||||
class QFontComboBox(QComboBox): pass
|
||||
|
||||
class QAbstractSpinBox(QWidget): pass
|
||||
class QDoubleSpinBox(QAbstractSpinBox): pass
|
||||
class QSpinBox(QAbstractSpinBox): pass
|
||||
|
||||
class QDateTimeEdit(QAbstractSpinBox): pass
|
||||
class QDateEdit(QDateTimeEdit): pass
|
||||
class QTimeEdit(QDateTimeEdit): pass
|
||||
|
||||
class QFrame(QWidget): pass
|
||||
class QLabel(QFrame): pass
|
||||
class QLCDNumber(QFrame): pass
|
||||
class QSplitter(QFrame): pass
|
||||
class QStackedWidget(QFrame): pass
|
||||
|
||||
class QToolBox(QFrame):
|
||||
def addItem(self, *args):
|
||||
text = args[-1]
|
||||
|
||||
if isinstance(text, i18n_string):
|
||||
i18n_print("%s.setItemText(%s.indexOf(%s), %s)" % \
|
||||
(self._uic_name, self._uic_name, args[0], text))
|
||||
args = args[:-1] + ("", )
|
||||
|
||||
ProxyClassMember(self, "addItem", 0)(*args)
|
||||
|
||||
def indexOf(self, page):
|
||||
return Literal("%s.indexOf(%s)" % (self, page))
|
||||
|
||||
def layout(self):
|
||||
return QtWidgets.QLayout('%s.layout()' % self)
|
||||
|
||||
class QAbstractScrollArea(QFrame):
|
||||
def viewport(self):
|
||||
return QtWidgets.QWidget('%s.viewport()' % self)
|
||||
|
||||
class QGraphicsView(QAbstractScrollArea): pass
|
||||
class QMdiArea(QAbstractScrollArea): pass
|
||||
class QPlainTextEdit(QAbstractScrollArea): pass
|
||||
class QScrollArea(QAbstractScrollArea): pass
|
||||
|
||||
class QTextEdit(QAbstractScrollArea): pass
|
||||
class QTextBrowser(QTextEdit): pass
|
||||
|
||||
class QAbstractItemView(QAbstractScrollArea): pass
|
||||
class QColumnView(QAbstractItemView): pass
|
||||
class QHeaderView(QAbstractItemView): pass
|
||||
class QListView(QAbstractItemView): pass
|
||||
|
||||
class QTableView(QAbstractItemView):
|
||||
def horizontalHeader(self):
|
||||
return QtWidgets.QHeaderView('%s.horizontalHeader()' % self)
|
||||
|
||||
def verticalHeader(self):
|
||||
return QtWidgets.QHeaderView('%s.verticalHeader()' % self)
|
||||
|
||||
class QTreeView(QAbstractItemView):
|
||||
def header(self):
|
||||
return QtWidgets.QHeaderView('%s.header()' % self)
|
||||
|
||||
class QUndoView(QListView): pass
|
||||
|
||||
class QListWidgetItem(ProxyClass): pass
|
||||
|
||||
class QListWidget(QListView):
|
||||
setSortingEnabled = i18n_void_func("setSortingEnabled")
|
||||
isSortingEnabled = i18n_func("isSortingEnabled")
|
||||
item = i18n_func("item")
|
||||
|
||||
class QTableWidgetItem(ProxyClass): pass
|
||||
|
||||
class QTableWidget(QTableView):
|
||||
setSortingEnabled = i18n_void_func("setSortingEnabled")
|
||||
isSortingEnabled = i18n_func("isSortingEnabled")
|
||||
item = i18n_func("item")
|
||||
horizontalHeaderItem = i18n_func("horizontalHeaderItem")
|
||||
verticalHeaderItem = i18n_func("verticalHeaderItem")
|
||||
|
||||
class QTreeWidgetItem(ProxyClass):
|
||||
def child(self, index):
|
||||
return QtWidgets.QTreeWidgetItem('%s.child(%i)' % (self, index))
|
||||
|
||||
class QTreeWidget(QTreeView):
|
||||
setSortingEnabled = i18n_void_func("setSortingEnabled")
|
||||
isSortingEnabled = i18n_func("isSortingEnabled")
|
||||
|
||||
def headerItem(self):
|
||||
return QtWidgets.QWidget('%s.headerItem()' % self)
|
||||
|
||||
def topLevelItem(self, index):
|
||||
return QtWidgets.QTreeWidgetItem(
|
||||
'%s.topLevelItem(%i)' % (self, index))
|
||||
|
||||
class QAbstractButton(QWidget): pass
|
||||
class QCheckBox(QAbstractButton): pass
|
||||
class QRadioButton(QAbstractButton): pass
|
||||
class QToolButton(QAbstractButton): pass
|
||||
|
||||
class QPushButton(QAbstractButton): pass
|
||||
class QCommandLinkButton(QPushButton): pass
|
||||
class QKeySequenceEdit(QWidget): pass
|
||||
|
||||
# Add all remaining classes.
|
||||
for _class in _qwidgets:
|
||||
if _class not in locals():
|
||||
locals()[_class] = type(_class, (QWidget, ), {})
|
||||
Reference in New Issue
Block a user