[meld/deprecation-cleanup: 22/48] ui._gtktemplate: Add in template support from upstream



commit 83aeeea79eec32c4b0343be4b1c40bcedcffe9e1
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Wed Jul 4 07:04:22 2018 +1000

    ui._gtktemplate: Add in template support from upstream

 meld/ui/_gtktemplate.py | 232 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 232 insertions(+)
---
diff --git a/meld/ui/_gtktemplate.py b/meld/ui/_gtktemplate.py
new file mode 100644
index 00000000..efaca339
--- /dev/null
+++ b/meld/ui/_gtktemplate.py
@@ -0,0 +1,232 @@
+# Copyright 2015 Dustin Spicuzza <dustin virtualroadside com>
+#           2018 Nikita Churaev <lamefun x0r gmail com>
+#           2018 Christoph Reiter <reiter christoph gmail com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+# USA
+
+from gi.repository import GLib, GObject, Gio
+
+
+def connect_func(builder, obj, signal_name, handler_name,
+                 connect_object, flags, cls):
+
+    if handler_name not in cls.__gtktemplate_methods__:
+        return
+
+    method_name = cls.__gtktemplate_methods__[handler_name]
+    template_inst = builder.get_object(cls.__gtype_name__)
+    template_inst.__gtktemplate_handlers__.add(handler_name)
+    handler = getattr(template_inst, method_name)
+
+    after = int(flags & GObject.ConnectFlags.AFTER)
+    swapped = int(flags & GObject.ConnectFlags.SWAPPED)
+    if swapped:
+        raise RuntimeError(
+            "%r not supported" % GObject.ConnectFlags.SWAPPED)
+
+    if connect_object is not None:
+        if after:
+            func = obj.connect_object_after
+        else:
+            func = obj.connect_object
+        func(signal_name, handler, connect_object)
+    else:
+        if after:
+            func = obj.connect_after
+        else:
+            func = obj.connect
+        func(signal_name, handler)
+
+
+def register_template(cls):
+    bound_methods = {}
+    bound_widgets = {}
+
+    for attr_name, obj in list(cls.__dict__.items()):
+        if isinstance(obj, CallThing):
+            setattr(cls, attr_name, obj._func)
+            handler_name = obj._name
+            if handler_name is None:
+                handler_name = attr_name
+
+            if handler_name in bound_methods:
+                old_attr_name = bound_methods[handler_name]
+                raise RuntimeError(
+                    "Error while exposing handler %r as %r, "
+                    "already available as %r" % (
+                        handler_name, attr_name, old_attr_name))
+            else:
+                bound_methods[handler_name] = attr_name
+        elif isinstance(obj, Child):
+            widget_name = obj._name
+            if widget_name is None:
+                widget_name = attr_name
+
+            if widget_name in bound_widgets:
+                old_attr_name = bound_widgets[widget_name]
+                raise RuntimeError(
+                    "Error while exposing child %r as %r, "
+                    "already available as %r" % (
+                        widget_name, attr_name, old_attr_name))
+            else:
+                bound_widgets[widget_name] = attr_name
+                cls.bind_template_child_full(widget_name, obj._internal, 0)
+
+    cls.__gtktemplate_methods__ = bound_methods
+    cls.__gtktemplate_widgets__ = bound_widgets
+
+    cls.set_connect_func(connect_func, cls)
+
+    base_init_template = cls.init_template
+    cls.__dontuse_ginstance_init__ = \
+        lambda s: init_template(s, cls, base_init_template)
+    # To make this file work with older PyGObject we expose our init code
+    # as init_template() but make it a noop when we call it ourselves first
+    cls.init_template = cls.__dontuse_ginstance_init__
+
+
+def init_template(self, cls, base_init_template):
+    self.init_template = lambda s: None
+
+    if self.__class__ is not cls:
+        raise TypeError(
+            "Inheritance from classes with @Gtk.Template decorators "
+            "is not allowed at this time")
+
+    self.__gtktemplate_handlers__ = set()
+
+    base_init_template(self)
+
+    for widget_name, attr_name in self.__gtktemplate_widgets__.items():
+        self.__dict__[attr_name] = self.get_template_child(cls, widget_name)
+
+    for handler_name, attr_name in self.__gtktemplate_methods__.items():
+        if handler_name not in self.__gtktemplate_handlers__:
+            raise RuntimeError(
+                "Handler '%s' was declared with @Gtk.Template.Callback "
+                "but was not present in template" % handler_name)
+
+
+class Child(object):
+
+    def __init__(self, name=None, **kwargs):
+        self._name = name
+        self._internal = kwargs.pop("internal", False)
+        if kwargs:
+            raise TypeError("Unhandled arguments: %r" % kwargs)
+
+
+class CallThing(object):
+
+    def __init__(self, name, func):
+        self._name = name
+        self._func = func
+
+
+class Callback(object):
+
+    def __init__(self, name=None):
+        self._name = name
+
+    def __call__(self, func):
+        return CallThing(self._name, func)
+
+
+def validate_resource_path(path):
+    """Raises GLib.Error in case the resource doesn't exist"""
+
+    try:
+        Gio.resources_get_info(path, Gio.ResourceLookupFlags.NONE)
+    except GLib.Error:
+        # resources_get_info() doesn't handle overlays but we keep using it
+        # as a fast path.
+        # https://gitlab.gnome.org/GNOME/pygobject/issues/230
+        Gio.resources_lookup_data(path, Gio.ResourceLookupFlags.NONE)
+
+
+class Template(object):
+
+    def __init__(self, **kwargs):
+        self.string = None
+        self.filename = None
+        self.resource_path = None
+        if "string" in kwargs:
+            self.string = kwargs.pop("string")
+        elif "filename" in kwargs:
+            self.filename = kwargs.pop("filename")
+        elif "resource_path" in kwargs:
+            self.resource_path = kwargs.pop("resource_path")
+        else:
+            raise TypeError(
+                "Requires one of the following arguments: "
+                "string, filename, resource_path")
+
+        if kwargs:
+            raise TypeError("Unhandled keyword arguments %r" % kwargs)
+
+    @classmethod
+    def from_file(cls, filename):
+        return cls(filename=filename)
+
+    @classmethod
+    def from_string(cls, string):
+        return cls(string=string)
+
+    @classmethod
+    def from_resource(cls, resource_path):
+        return cls(resource_path=resource_path)
+
+    Callback = Callback
+
+    Child = Child
+
+    def __call__(self, cls):
+        from gi.repository import Gtk
+
+        if not isinstance(cls, type) or not issubclass(cls, Gtk.Widget):
+            raise TypeError("Can only use @Gtk.Template on Widgets")
+
+        if "__gtype_name__" not in cls.__dict__:
+            raise TypeError(
+                "%r does not have a __gtype_name__. Set it to the name "
+                "of the class in your template" % cls.__name__)
+
+        if hasattr(cls, "__gtktemplate_methods__"):
+            raise TypeError("Cannot nest template classes")
+
+        if self.string is not None:
+            data = self.string
+            if not isinstance(data, bytes):
+                data = data.encode("utf-8")
+            bytes_ = GLib.Bytes.new(data)
+            cls.set_template(bytes_)
+            register_template(cls)
+            return cls
+        elif self.resource_path is not None:
+            validate_resource_path(self.resource_path)
+            cls.set_template_from_resource(self.resource_path)
+            register_template(cls)
+            return cls
+        else:
+            assert self.filename is not None
+            file_ = Gio.File.new_for_path(self.filename)
+            bytes_ = GLib.Bytes.new(file_.load_contents()[1])
+            cls.set_template(bytes_)
+            register_template(cls)
+            return cls
+
+
+__all__ = ["Template"]


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]