Initial commit: Core Teletext Editor functionality
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.
|
||||
##
|
||||
#############################################################################
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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