mirror of
https://gitlab.gnome.org/jpu/cambalache.git
synced 2025-08-13 00:04:28 -04:00
Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8ce0ccf64b | ||
|
27f3054601 | ||
|
2b5cbff98c | ||
|
b86df04dbf | ||
|
dcac9ba37c | ||
|
a903a27d60 | ||
|
daeabaf319 | ||
|
0a3131f16a | ||
|
fd53a459c1 | ||
|
4753bf8233 | ||
|
abb7e2ffb6 | ||
|
6fc3cbd0dd | ||
|
e56e745b92 | ||
|
b27891ba79 | ||
|
d0da2f0016 | ||
|
fee3885bf8 | ||
|
83d50f05ce | ||
|
f85ab89f75 | ||
|
e5066582cd | ||
|
3ce5f4f13f | ||
|
08507597f2 | ||
|
beeea0fa16 | ||
|
98fa039783 | ||
|
38a57c7f64 | ||
|
3621463d3d | ||
|
4375049d89 | ||
|
a73d2610f4 | ||
|
cbe5a6ab11 | ||
|
d223cbc2b1 | ||
|
32f50abb29 | ||
|
6a22474768 | ||
|
6c406ab960 |
@ -83,8 +83,8 @@
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/jpu/casilda.git",
|
||||
"tag" : "0.9.1",
|
||||
"commit" : "fbc3c034061c5f81a27151d94db33a0a91ed1b0c"
|
||||
"tag" : "0.9.2",
|
||||
"commit" : "4f39e9d5f22f35b16583490a874ecf43db07869e"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -27,7 +27,7 @@ import os
|
||||
import locale
|
||||
import tempfile
|
||||
|
||||
from gi.repository import GLib, GObject, Gio, Gdk, Gtk, Pango, Adw
|
||||
from gi.repository import GLib, GObject, Gio, Gdk, Gtk, Pango, Adw, GtkSource
|
||||
from .cmb_tutor import CmbTutor, CmbTutorState
|
||||
from . import cmb_tutorial
|
||||
|
||||
@ -120,6 +120,9 @@ class CmbWindow(Adw.ApplicationWindow):
|
||||
intro_button = Gtk.Template.Child()
|
||||
menu_button = Gtk.Template.Child()
|
||||
|
||||
# Properties
|
||||
source_style = GObject.Property(type=GtkSource.StyleScheme, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
# Settings
|
||||
completed_intro = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
@ -302,6 +305,10 @@ class CmbWindow(Adw.ApplicationWindow):
|
||||
self.__load_window_state()
|
||||
self.__update_actions()
|
||||
|
||||
self.source_style_manager = GtkSource.StyleSchemeManager.get_default()
|
||||
app.props.style_manager.connect("notify::dark", lambda o, p: self.__update_dark_mode(app.props.style_manager))
|
||||
self.__update_dark_mode(app.props.style_manager)
|
||||
|
||||
# Bind preview
|
||||
hide_placeholders_button = Gtk.ToggleButton(tooltip_text=_("Hide placeholders"), icon_name="view-conceal-symbolic")
|
||||
self.type_chooser.content.append(hide_placeholders_button)
|
||||
@ -472,6 +479,14 @@ class CmbWindow(Adw.ApplicationWindow):
|
||||
self.np_ui_entry.set_sensitive(sensitive)
|
||||
self.__update_action_new()
|
||||
|
||||
def __update_dark_mode(self, style_manager):
|
||||
if style_manager.props.dark:
|
||||
self.source_style = self.source_style_manager.get_scheme("Adwaita-dark")
|
||||
self.add_css_class("dark")
|
||||
else:
|
||||
self.remove_css_class("dark")
|
||||
self.source_style = self.source_style_manager.get_scheme("Adwaita")
|
||||
|
||||
def __np_name_to_ui(self, binding, value):
|
||||
if len(value):
|
||||
return value.lower().rsplit(".", 1)[0] + ".ui"
|
||||
@ -1125,7 +1140,7 @@ class CmbWindow(Adw.ApplicationWindow):
|
||||
details=unsupported_features_list,
|
||||
)
|
||||
|
||||
def __import_file(self, path, autoselect=True):
|
||||
def import_file(self, path, autoselect=True):
|
||||
content_type = utils.content_type_guess(path)
|
||||
|
||||
if content_type in ["application/x-gtk-builder", "application/x-glade", "text/x-blueprint"]:
|
||||
@ -1142,7 +1157,7 @@ class CmbWindow(Adw.ApplicationWindow):
|
||||
def dialog_callback(dialog, res):
|
||||
try:
|
||||
for file in dialog.open_multiple_finish(res):
|
||||
self.__import_file(file.get_path())
|
||||
self.import_file(file.get_path())
|
||||
except Exception as e:
|
||||
logger.warning(f"Error {e}")
|
||||
|
||||
@ -1208,7 +1223,7 @@ class CmbWindow(Adw.ApplicationWindow):
|
||||
for i, path in enumerate(files):
|
||||
progressbar.set_text(path.removeprefix(basedir))
|
||||
progressbar.set_fraction(i/n_files)
|
||||
self.__import_file(path, autoselect=False)
|
||||
self.import_file(path, autoselect=False)
|
||||
|
||||
while main_loop.pending():
|
||||
main_loop.iteration(False)
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
|
||||
<!-- Created with Cambalache 0.97.5 -->
|
||||
<!-- Created with Cambalache 0.97.6 -->
|
||||
<cambalache-project version="0.96.0" target_tk="gtk-4.0">
|
||||
<gresources filename="cambalache.gresource.xml" sha256="fdcf4cd517493f548aa4b4fe206ff7762cee9cdda7ec5a85a718b46eb1c4731b"/>
|
||||
<gresources filename="cambalache.gresource.xml" sha256="f5e5356b0a796d96885a8bb0b363d18339457ea6bfe26e56b6db3f7e4a618b16"/>
|
||||
<gresources filename="app/app.gresource.xml" sha256="3684aa78fce08d8e81d0907317214aeb179c5aea091dd0df405476b43e286941"/>
|
||||
<css filename="cambalache.css" priority="400" is_global="1"/>
|
||||
<css filename="app/cambalache.css" is_global="0"/>
|
||||
@ -232,6 +232,13 @@
|
||||
<ui template-class="CmbPollNotificationView" filename="cmb_poll_notification_view.ui" sha256="8f47a1e503b85eb5ac3ac54962a40fc2237588e1216afba859a3016a1dcfc121"/>
|
||||
<ui template-class="CmbPollOptionCheck" filename="cmb_poll_option_check.ui" sha256="aa433f201dc1863f3727e1baa2c4cc239192a1ae4c53553de69d529ba2cc6fed"/>
|
||||
<ui template-class="CmbNotificationListRow" filename="cmb_notification_list_row.ui" sha256="5ef66fcc24e10d40a91ff0eada84f6aa8a595e368961364d98fde1800755edfc"/>
|
||||
<ui template-class="CmbPropertyChooser">
|
||||
<content><![CDATA[<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="CmbPropertyChooser" parent="GtkComboBox"/>
|
||||
</interface>
|
||||
]]></content>
|
||||
</ui>
|
||||
<ui template-class="CmbPixbufEntry">
|
||||
<requires>CmbFileEntry</requires>
|
||||
<content><![CDATA[<interface>
|
||||
@ -257,7 +264,7 @@
|
||||
<signal id="placeholder-activated"/>
|
||||
<signal id="placeholder-selected"/>
|
||||
</ui>
|
||||
<ui template-class="CmbGResourceEditor" filename="cmb_gresource_editor.ui" sha256="6a0563d827973e129cca2c41e90d931c6d63ec23422e459101e0c120c0937f07">
|
||||
<ui template-class="CmbGResourceEditor" filename="cmb_gresource_editor.ui" sha256="982c596dbe038edac9f4f20a72062b9d8b78b08be7e731395dde1c701d92bcb1">
|
||||
<requires>CmbFileButton</requires>
|
||||
<requires>CmbEntry</requires>
|
||||
</ui>
|
||||
@ -271,6 +278,11 @@
|
||||
<requires>CmbEntry</requires>
|
||||
<requires>CmbToplevelChooser</requires>
|
||||
</ui>
|
||||
<ui template-class="CmbBindingPopover" filename="cmb_binding_popover.ui" sha256="e3138c75d2c45534c1b41acbc3724a760b3a390effebcf0f54df1e04f3e748cc">
|
||||
<requires>CmbObjectChooser</requires>
|
||||
<requires>CmbPropertyChooser</requires>
|
||||
<requires>CmbFlagsEntry</requires>
|
||||
</ui>
|
||||
<ui template-class="CmbWindow" filename="app/cmb_window.ui" sha256="784143e77643d8b03c5149768f9def9020c34aafd323a7073d601f2c1d2e5648">
|
||||
<requires>CmbNotificationListView</requires>
|
||||
<requires>CmbScrolledWindow</requires>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.95.0 -->
|
||||
<!-- Created with Cambalache 0.97.6 -->
|
||||
<gresources>
|
||||
<gresource prefix="/ar/xjuan/Cambalache">
|
||||
<file>cambalache.css</file>
|
||||
@ -27,5 +27,6 @@
|
||||
<file>icons/scalable/actions/binded-symbolic.svg</file>
|
||||
<file>icons/scalable/actions/bind-symbolic.svg</file>
|
||||
<file>cmb_notification_list_row.ui</file>
|
||||
<file>cmb_binding_popover.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
142
cambalache/cmb_binding_popover.py
Normal file
142
cambalache/cmb_binding_popover.py
Normal file
@ -0,0 +1,142 @@
|
||||
#
|
||||
# CmbBindingPopover
|
||||
#
|
||||
# Copyright (C) 2025 Juan Pablo Ugarte
|
||||
#
|
||||
# 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;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GLib, GObject, Gtk
|
||||
from .cmb_property import CmbProperty
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/ar/xjuan/Cambalache/cmb_binding_popover.ui")
|
||||
class CmbBindingPopover(Gtk.Popover):
|
||||
__gtype_name__ = "CmbBindingPopover"
|
||||
|
||||
prop = GObject.Property(type=CmbProperty, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
|
||||
object_chooser = Gtk.Template.Child()
|
||||
property_chooser = Gtk.Template.Child()
|
||||
flags_entry = Gtk.Template.Child()
|
||||
|
||||
# Expression
|
||||
expression_dropdown = Gtk.Template.Child()
|
||||
expression_object_chooser = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
if self.prop is None:
|
||||
return
|
||||
|
||||
# Get bind property to initialize inputs
|
||||
bind_source, bind_property = self.__find_bind_source_property(self.prop.bind_source_id, self.prop.bind_property_id)
|
||||
|
||||
# Object editor (it does not set the object directly to CmbProperty, just choose the object in the prop chooser)
|
||||
self.object_chooser.parent = self.prop.object
|
||||
self.object_chooser.cmb_value = bind_source.object_id if bind_source else 0
|
||||
|
||||
# Update Property editor
|
||||
self.property_chooser.object = bind_source
|
||||
self.property_chooser.target_info = self.prop.info
|
||||
|
||||
# Update active_id after letting the object populate the properties
|
||||
if bind_property:
|
||||
self.property_chooser.props.active_id = bind_property.property_id
|
||||
|
||||
# Flags editor
|
||||
binding_flags_info = self.prop.project.type_info.get("GBindingFlags", None)
|
||||
self.flags_entry.info = binding_flags_info
|
||||
|
||||
GObject.Object.bind_property(
|
||||
self.prop,
|
||||
"bind_flags",
|
||||
self.flags_entry,
|
||||
"cmb-value",
|
||||
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL,
|
||||
)
|
||||
|
||||
self.__updating = True
|
||||
|
||||
# Expression stuff
|
||||
if self.prop.binding_expression_id:
|
||||
expression_source = self.prop.project.get_object_by_id(self.prop.ui_id, self.prop.binding_expression_id)
|
||||
item_index = self.expression_dropdown.props.model.find(expression_source.type_id)
|
||||
self.expression_dropdown.set_selected(item_index if item_index < GLib.MAXUINT else 0)
|
||||
else:
|
||||
self.expression_dropdown.set_selected(0)
|
||||
|
||||
self.expression_object_chooser.parent = self.prop.object
|
||||
self.expression_object_chooser.cmb_value = self.prop.binding_expression_object_id
|
||||
|
||||
self.__updating = False
|
||||
|
||||
@Gtk.Template.Callback("on_clear_clicked")
|
||||
def __on_clear_clicked(self, button):
|
||||
if self.prop:
|
||||
self.prop.clear_binding()
|
||||
|
||||
self.popdown()
|
||||
|
||||
@Gtk.Template.Callback("on_close_clicked")
|
||||
def __on_close_clicked(self, button):
|
||||
self.popdown()
|
||||
|
||||
@Gtk.Template.Callback("on_object_editor_notify")
|
||||
def __on_object_editor_notify(self, object_editor, pspec):
|
||||
object_id = object_editor.cmb_value
|
||||
if object_id:
|
||||
obj = self.prop.project.get_object_by_id(self.prop.ui_id, int(object_id)) if self.prop else None
|
||||
self.property_chooser.object = obj
|
||||
else:
|
||||
self.property_chooser.object = None
|
||||
|
||||
@Gtk.Template.Callback("on_property_editor_changed")
|
||||
def __on_property_editor_changed(self, combo):
|
||||
if self.prop is None:
|
||||
return
|
||||
|
||||
if combo.object:
|
||||
bind_source, bind_property = self.__find_bind_source_property(combo.object.object_id, combo.props.active_id)
|
||||
self.prop.bind_property = bind_property
|
||||
else:
|
||||
self.prop.bind_property = None
|
||||
|
||||
def __find_bind_source_property(self, bind_source_id, bind_property_id):
|
||||
bind_source = self.prop.project.get_object_by_id(self.prop.ui_id, bind_source_id) if bind_source_id else None
|
||||
bind_property = bind_source.properties_dict.get(bind_property_id, None) if bind_source else None
|
||||
|
||||
return bind_source, bind_property
|
||||
|
||||
@Gtk.Template.Callback("on_popover_show")
|
||||
def __on_popover_show(self, combo):
|
||||
if self.prop.binding_expression_id:
|
||||
self.expression_dropdown.grab_focus()
|
||||
else:
|
||||
self.object_chooser.grab_focus()
|
||||
|
||||
# GtkExpression support
|
||||
@Gtk.Template.Callback("on_expression_dropdown_notify")
|
||||
def __on_expression_dropdown_notify(self, dropdown, pspec):
|
||||
if self.prop is None or self.__updating:
|
||||
return
|
||||
|
||||
self.prop.set_binding_expression_type(dropdown.props.selected_item.get_string())
|
188
cambalache/cmb_binding_popover.ui
Normal file
188
cambalache/cmb_binding_popover.ui
Normal file
@ -0,0 +1,188 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.97.6 -->
|
||||
<interface>
|
||||
<!-- interface-name cmb_property_binding_widget.ui -->
|
||||
<requires lib="gtk" version="4.18"/>
|
||||
<template class="CmbBindingPopover" parent="GtkPopover">
|
||||
<property name="css-classes">cmb-binding-popover</property>
|
||||
<property name="position">left</property>
|
||||
<signal name="show" handler="on_popover_show"/>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="column-spacing">4</property>
|
||||
<property name="row-spacing">4</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Type</property>
|
||||
<property name="margin-start">16</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="column-span">1</property>
|
||||
<property name="row">5</property>
|
||||
<property name="row-span">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Object</property>
|
||||
<property name="margin-start">16</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="column-span">1</property>
|
||||
<property name="row">6</property>
|
||||
<property name="row-span">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="CmbObjectChooser" id="expression_object_chooser">
|
||||
<property name="placeholder-text" translatable="yes"><expression object></property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="column-span">1</property>
|
||||
<property name="row">6</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="expression_dropdown">
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item translatable="yes">None</item>
|
||||
<item>GtkConstantExpression</item>
|
||||
<item>GtkPropertyExpression</item>
|
||||
<item>GtkClosureExpression</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
<signal name="notify::selected-item" handler="on_expression_dropdown_notify"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="column-span">1</property>
|
||||
<property name="row">5</property>
|
||||
<property name="row-span">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Source</property>
|
||||
<property name="margin-start">16</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Property</property>
|
||||
<property name="margin-start">16</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Flags</property>
|
||||
<property name="margin-start">16</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="CmbObjectChooser" id="object_chooser">
|
||||
<signal name="notify::cmb-value" handler="on_object_editor_notify"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="column-span">1</property>
|
||||
<property name="row">1</property>
|
||||
<property name="row-span">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="CmbPropertyChooser" id="property_chooser">
|
||||
<signal name="changed" handler="on_property_editor_changed"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
<property name="row-span">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="CmbFlagsEntry" id="flags_entry">
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="column-span">1</property>
|
||||
<property name="row">3</property>
|
||||
<property name="row-span">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes"><b>Gtk Expression</b></property>
|
||||
<property name="margin-top">8</property>
|
||||
<property name="use-markup">True</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="column-span">2</property>
|
||||
<property name="row">4</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes"><b>Property Binding</b></property>
|
||||
<property name="use-markup">True</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="close_button">
|
||||
<property name="css-classes">close</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="icon-name">window-close-symbolic</property>
|
||||
<signal name="clicked" handler="on_close_clicked"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="halign">end</property>
|
||||
<property name="label">Clear</property>
|
||||
<signal name="clicked" handler="on_clear_clicked"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
@ -34,7 +34,7 @@ from lxml.builder import E
|
||||
from graphlib import TopologicalSorter, CycleError
|
||||
from gi.repository import GLib, Gio, GObject
|
||||
from cambalache import config, getLogger, _
|
||||
from . import cmb_db_migration, utils
|
||||
from . import utils
|
||||
from .constants import EXTERNAL_TYPE, GMENU_TYPE, GMENU_SECTION_TYPE, GMENU_SUBMENU_TYPE, GMENU_ITEM_TYPE
|
||||
from .cmb_db_profile import CmbProfileConnection
|
||||
|
||||
@ -318,6 +318,9 @@ class CmbDB(GObject.GObject):
|
||||
if column in unique_constraints_flat:
|
||||
continue
|
||||
|
||||
# Get column index
|
||||
column_index = all_columns.index(column)
|
||||
|
||||
c.execute(
|
||||
f"""
|
||||
CREATE TRIGGER on_{table}_update_{column} AFTER UPDATE OF {column} ON {table}
|
||||
@ -330,8 +333,8 @@ class CmbDB(GObject.GObject):
|
||||
(SELECT command, table_name, columns FROM history WHERE history_id = {history_seq})
|
||||
IS NOT ('UPDATE', '{table}', json_array('{column}'))
|
||||
AND
|
||||
(SELECT command, table_name, columns FROM history WHERE history_id = {history_seq})
|
||||
IS NOT ('INSERT', '{table}', NULL)
|
||||
(SELECT command, table_name, columns, new_values ->> {column_index} IS NULL FROM history WHERE history_id = {history_seq})
|
||||
IS NOT ('INSERT', '{table}', NULL, 0)
|
||||
)
|
||||
)
|
||||
BEGIN
|
||||
@ -364,8 +367,8 @@ class CmbDB(GObject.GObject):
|
||||
NEW.{column} IS NOT OLD.{column} AND {history_is_enabled} AND
|
||||
(SELECT table_pk FROM history WHERE history_id = {history_seq}) IS json_array({old_pk_values})
|
||||
AND
|
||||
(SELECT command, table_name, columns FROM history WHERE history_id = {history_seq})
|
||||
IS ('INSERT', '{table}', NULL)
|
||||
(SELECT command, table_name, columns, new_values ->> {column_index} IS NULL FROM history WHERE history_id = {history_seq})
|
||||
IS ('INSERT', '{table}', NULL, 0)
|
||||
BEGIN
|
||||
UPDATE history SET new_values=json_array({new_values}) WHERE history_id = {history_seq};
|
||||
END;
|
||||
@ -609,46 +612,6 @@ class CmbDB(GObject.GObject):
|
||||
|
||||
return utils.parse_version(version)
|
||||
|
||||
def __ensure_table_data_columns(self, version, table, data):
|
||||
if version is None:
|
||||
return data
|
||||
|
||||
if version < (0, 7, 5):
|
||||
data = cmb_db_migration.ensure_columns_for_0_7_5(table, data)
|
||||
|
||||
if version < (0, 9, 0):
|
||||
data = cmb_db_migration.ensure_columns_for_0_9_0(table, data)
|
||||
|
||||
if version < (0, 11, 2):
|
||||
data = cmb_db_migration.ensure_columns_for_0_11_2(table, data)
|
||||
|
||||
if version < (0, 11, 4):
|
||||
data = cmb_db_migration.ensure_columns_for_0_11_4(table, data)
|
||||
|
||||
if version < (0, 13, 1):
|
||||
data = cmb_db_migration.ensure_columns_for_0_13_1(table, data)
|
||||
|
||||
if version < (0, 17, 3):
|
||||
data = cmb_db_migration.ensure_columns_for_0_17_3(table, data)
|
||||
|
||||
return data
|
||||
|
||||
def __migrate_table_data(self, c, version, table, data):
|
||||
if version is None:
|
||||
return
|
||||
|
||||
if version < (0, 7, 5):
|
||||
cmb_db_migration.migrate_table_data_to_0_7_5(c, table, data)
|
||||
|
||||
if version < (0, 9, 0):
|
||||
cmb_db_migration.migrate_table_data_to_0_9_0(c, table, data)
|
||||
|
||||
if version < (0, 17, 3):
|
||||
cmb_db_migration.migrate_table_data_to_0_17_3(c, table, data)
|
||||
|
||||
if version < (0, 91, 3):
|
||||
cmb_db_migration.migrate_table_data_to_0_91_3(c, table, data)
|
||||
|
||||
def __load_table_from_tuples(self, c, table, tuples, version=None):
|
||||
data = ast.literal_eval(f"[{tuples}]") if tuples else []
|
||||
if len(data) == 0:
|
||||
@ -670,35 +633,12 @@ class CmbDB(GObject.GObject):
|
||||
# Load table data
|
||||
c.executemany(f"INSERT INTO temp.{table} VALUES ({cols})", data)
|
||||
|
||||
# Migrate data to current format
|
||||
self.__migrate_table_data(c, version, table, data)
|
||||
|
||||
# Copy data from temp table
|
||||
c.execute(f"INSERT INTO main.{table} SELECT * FROM temp.{table};")
|
||||
|
||||
# Drop temp table
|
||||
c.execute(f"DROP TABLE temp.{table};")
|
||||
|
||||
def load_old_format(self, root, version):
|
||||
c = self.conn.cursor()
|
||||
|
||||
# Avoid circular dependencies errors
|
||||
self.foreign_keys = False
|
||||
self.ignore_check_constraints = True
|
||||
|
||||
# Support old format
|
||||
all_tables = self.__tables + ["property", "signal"]
|
||||
for child in root.getchildren():
|
||||
if child.tag in all_tables:
|
||||
self.__load_table_from_tuples(c, child.tag, child.text, version)
|
||||
else:
|
||||
raise Exception(f"Unknown tag {child.tag} in project file.")
|
||||
|
||||
self.foreign_keys = True
|
||||
self.ignore_check_constraints = False
|
||||
|
||||
c.close()
|
||||
|
||||
def __load_accessibility_metadata(self, node):
|
||||
data = json.loads(node.text)
|
||||
|
||||
@ -947,6 +887,7 @@ class CmbDB(GObject.GObject):
|
||||
layout=None,
|
||||
position=None,
|
||||
inline_property=None,
|
||||
inline_binding_expression=False,
|
||||
):
|
||||
c = self.conn.cursor()
|
||||
|
||||
@ -1017,18 +958,20 @@ class CmbDB(GObject.GObject):
|
||||
)
|
||||
count = c.fetchone()[0]
|
||||
|
||||
inline_object_property = "binding_expression_id" if inline_binding_expression else "inline_object_id"
|
||||
|
||||
if count:
|
||||
c.execute(
|
||||
"""
|
||||
UPDATE object_property SET inline_object_id=?
|
||||
f"""
|
||||
UPDATE object_property SET {inline_object_property}=?
|
||||
WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id;
|
||||
""",
|
||||
(object_id, ui_id, parent_id, pinfo.owner_id, inline_property),
|
||||
)
|
||||
else:
|
||||
c.execute(
|
||||
"""
|
||||
INSERT INTO object_property (ui_id, object_id, owner_id, property_id, inline_object_id)
|
||||
f"""
|
||||
INSERT INTO object_property (ui_id, object_id, owner_id, property_id, {inline_object_property})
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(ui_id, parent_id, pinfo.owner_id, inline_property, object_id),
|
||||
@ -1124,15 +1067,15 @@ class CmbDB(GObject.GObject):
|
||||
# Initialize to null
|
||||
inline_object_id = None
|
||||
|
||||
# GtkBuilder in Gtk4 supports defining an object in a property
|
||||
obj_node = prop.find("object")
|
||||
if self.target_tk == "gtk-4.0" and pinfo.is_object and obj_node is not None:
|
||||
if self.target_tk == "gtk-4.0" and pinfo.is_object and len(prop) >= 1:
|
||||
if pinfo.disable_inline_object:
|
||||
self.__collect_error("not-inline-object", prop, f"{info.type_id}:{property_id}")
|
||||
return
|
||||
|
||||
inline_object_id = self.__import_object(ui_id, obj_node, object_id)
|
||||
value = None
|
||||
if prop[0].tag == "object" or \
|
||||
(pinfo.type_id == "GtkExpression" and prop[0].tag in ["lookup", "constant", "closure"]):
|
||||
inline_object_id = self.__import_object(ui_id, prop[0], object_id)
|
||||
value = None
|
||||
|
||||
self.__upsert_object_property(
|
||||
c,
|
||||
@ -1153,6 +1096,33 @@ class CmbDB(GObject.GObject):
|
||||
inline_object_id=inline_object_id
|
||||
)
|
||||
|
||||
def __import_binding(self, c, info, ui_id, object_id, prop, object_id_map=None):
|
||||
name, object = self.__node_get(prop, "name", ["object"])
|
||||
|
||||
property_id = name.replace("_", "-")
|
||||
pinfo = self.__get_property_info(info, property_id)
|
||||
|
||||
if pinfo is None:
|
||||
self.__collect_error("unknown-property", prop, f"{info.type_id}:{property_id}")
|
||||
return
|
||||
|
||||
# Get expression object
|
||||
binding_expression_id = self.__import_expression(ui_id, prop[0], object_id)
|
||||
|
||||
self.__upsert_object_property(
|
||||
c,
|
||||
info,
|
||||
pinfo,
|
||||
ui_id,
|
||||
object_id,
|
||||
prop,
|
||||
property_id,
|
||||
None,
|
||||
object_id_map=object_id_map,
|
||||
binding_expression_id=binding_expression_id,
|
||||
binding_expression_object_id=object
|
||||
)
|
||||
|
||||
def __upsert_object_property(
|
||||
self,
|
||||
c,
|
||||
@ -1170,7 +1140,9 @@ class CmbDB(GObject.GObject):
|
||||
bind_source_id=None,
|
||||
bind_property_id=None,
|
||||
bind_flags=None,
|
||||
inline_object_id=None
|
||||
inline_object_id=None,
|
||||
binding_expression_id=None,
|
||||
binding_expression_object_id=None
|
||||
):
|
||||
comment = self.__node_get_comment(prop)
|
||||
|
||||
@ -1191,8 +1163,9 @@ class CmbDB(GObject.GObject):
|
||||
"""
|
||||
INSERT OR REPLACE INTO object_property
|
||||
(ui_id, object_id, owner_id, property_id, value, translatable, comment, translation_context,
|
||||
translation_comments, inline_object_id, bind_source_id, bind_property_id, bind_flags)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
translation_comments, inline_object_id, bind_source_id, bind_property_id, bind_flags,
|
||||
binding_expression_id, binding_expression_object_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""",
|
||||
(
|
||||
ui_id,
|
||||
@ -1208,6 +1181,8 @@ class CmbDB(GObject.GObject):
|
||||
bind_source_id,
|
||||
bind_property_id,
|
||||
bind_flags,
|
||||
binding_expression_id,
|
||||
binding_expression_object_id,
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
@ -1330,9 +1305,9 @@ class CmbDB(GObject.GObject):
|
||||
"""
|
||||
INSERT INTO object_signal
|
||||
(ui_id, object_id, owner_id, signal_id, handler, detail, user_data, swap, after, comment)
|
||||
VALUES (?, ?, ?, ?, ?, ?, (SELECT object_id FROM object WHERE ui_id=? AND name=?), ?, ?, ?);
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""",
|
||||
(ui_id, object_id, owner_id, signal_id, handler, detail, ui_id, user_data, swap, after, comment),
|
||||
(ui_id, object_id, owner_id, signal_id, handler, detail, user_data, swap, after, comment),
|
||||
)
|
||||
except Exception as e:
|
||||
raise Exception(f"XML:{signal.sourceline} - Can not import object {object_id} {owner_id}:{signal_id} signal: {e}")
|
||||
@ -1607,6 +1582,71 @@ class CmbDB(GObject.GObject):
|
||||
else:
|
||||
self.__collect_error("unknown-tag", node, child.tag)
|
||||
|
||||
def __import_expression(self, ui_id, node, parent_id):
|
||||
comment = self.__node_get_comment(node)
|
||||
|
||||
tag = node.tag
|
||||
|
||||
if tag == "constant":
|
||||
klass = "GtkConstantExpression"
|
||||
elif tag == "lookup":
|
||||
klass = "GtkPropertyExpression"
|
||||
elif tag == "closure":
|
||||
klass = "GtkClosureExpression"
|
||||
else:
|
||||
self.__collect_error("unknown-tag", node, tag)
|
||||
return
|
||||
|
||||
info = self.type_info.get(klass, None)
|
||||
|
||||
if not info:
|
||||
logger.warning(f"Error importing expression: {klass} not found")
|
||||
return None
|
||||
|
||||
# Insert menu
|
||||
try:
|
||||
expression_id = self.add_object(ui_id, klass, None, parent_id, None, None, comment)
|
||||
except Exception:
|
||||
logger.warning(f"XML:{node.sourceline} - Error importing expression")
|
||||
return None
|
||||
|
||||
# Get a list of attributes and their values
|
||||
properties = node.attrib.items()
|
||||
|
||||
# Append text as value attribute
|
||||
if klass != "GtkClosureExpression" and node.text:
|
||||
properties.append(("value", node.text))
|
||||
|
||||
c = self.conn.cursor()
|
||||
|
||||
# Import attributes as properties
|
||||
for property_id, value in properties:
|
||||
if property_id not in info.properties:
|
||||
logger.warning(f"XML:{node.sourceline} - Error importing expression, {property_id} attribute is not valid")
|
||||
continue
|
||||
|
||||
c.execute(
|
||||
"""
|
||||
INSERT OR REPLACE INTO object_property
|
||||
(ui_id, object_id, owner_id, property_id, value)
|
||||
VALUES (?, ?, ?, ?, ?);
|
||||
""",
|
||||
(
|
||||
ui_id,
|
||||
expression_id,
|
||||
klass,
|
||||
property_id,
|
||||
value,
|
||||
),
|
||||
)
|
||||
|
||||
c.close()
|
||||
|
||||
for child in node:
|
||||
self.__import_expression(ui_id, child, expression_id)
|
||||
|
||||
return expression_id
|
||||
|
||||
def __import_object(
|
||||
self, ui_id, node, parent_id, internal_child=None, child_type=None, is_template=False, object_id_map=None
|
||||
):
|
||||
@ -1614,6 +1654,8 @@ class CmbDB(GObject.GObject):
|
||||
|
||||
if node.tag == "menu":
|
||||
return self.__import_menu(ui_id, node, parent_id, object_id_map=object_id_map)
|
||||
if node.tag in ["lookup", "constant", "closure"]:
|
||||
return self.__import_expression(ui_id, node, parent_id)
|
||||
|
||||
is_template = node.tag == "template"
|
||||
|
||||
@ -1665,6 +1707,8 @@ class CmbDB(GObject.GObject):
|
||||
for child in node.iterchildren():
|
||||
if child.tag == "property":
|
||||
self.__import_property(c, info, ui_id, object_id, child, object_id_map=object_id_map)
|
||||
elif child.tag == "binding" and self.target_tk == "gtk-4.0":
|
||||
self.__import_binding(c, info, ui_id, object_id, child, object_id_map=object_id_map)
|
||||
elif child.tag == "signal":
|
||||
self.__import_signal(c, info, ui_id, object_id, child, object_id_map=object_id_map)
|
||||
elif child.tag == "child":
|
||||
@ -1782,6 +1826,16 @@ class CmbDB(GObject.GObject):
|
||||
(ui_id,),
|
||||
)
|
||||
|
||||
# Fix signal user_data that refer to an object
|
||||
self.conn.execute(
|
||||
"""
|
||||
UPDATE object_signal AS os SET user_data=o.object_id
|
||||
FROM object AS o
|
||||
WHERE os.ui_id=? AND os.ui_id == o.ui_id AND os.user_data IS NOT NULL AND os.user_data == o.name;
|
||||
""",
|
||||
(ui_id,),
|
||||
)
|
||||
|
||||
# Fix bind source and set bind owner to the object type
|
||||
self.conn.execute(
|
||||
"""
|
||||
@ -1793,6 +1847,52 @@ class CmbDB(GObject.GObject):
|
||||
(ui_id,),
|
||||
)
|
||||
|
||||
# Fix binding expression object references
|
||||
self.conn.execute(
|
||||
"""
|
||||
UPDATE object_property AS op
|
||||
SET binding_expression_object_id=o.object_id
|
||||
FROM object AS o
|
||||
WHERE op.ui_id=? AND binding_expression_object_id IS NOT NULL AND
|
||||
o.ui_id = op.ui_id AND o.name = op.binding_expression_object_id;
|
||||
""",
|
||||
(ui_id,),
|
||||
)
|
||||
|
||||
# Fix GtkPropertyExpression and GtkConstantExpression value properties
|
||||
self.conn.execute(
|
||||
"""
|
||||
UPDATE object_property AS op
|
||||
SET value=o.object_id
|
||||
FROM object AS o
|
||||
WHERE op.ui_id=? AND
|
||||
op.ui_id=o.ui_id AND
|
||||
op.property_id='value' AND
|
||||
op.owner_id IN ('GtkPropertyExpression', 'GtkConstantExpression') AND
|
||||
op.value=o.name AND
|
||||
(
|
||||
(op.ui_id, op.object_id) IN (
|
||||
SELECT op2.ui_id, op2.object_id
|
||||
FROM object_property AS op2, type AS t
|
||||
WHERE op2.ui_id=? AND
|
||||
t.derivable AND
|
||||
op2.owner_id IN ('GtkPropertyExpression', 'GtkConstantExpression') AND
|
||||
op2.property_id='type' AND
|
||||
op2.value = t.type_id
|
||||
)
|
||||
OR
|
||||
(op.ui_id, op.object_id) NOT IN (
|
||||
SELECT op3.ui_id, op3.object_id
|
||||
FROM object_property AS op3
|
||||
WHERE op3.ui_id=? AND
|
||||
op3.owner_id IN ('GtkPropertyExpression', 'GtkConstantExpression') AND
|
||||
op3.property_id='type'
|
||||
)
|
||||
)
|
||||
""",
|
||||
(ui_id, ui_id, ui_id),
|
||||
)
|
||||
|
||||
# Fix a11y CmbAccessibleList references
|
||||
for row in self.conn.execute(
|
||||
"""
|
||||
@ -2143,6 +2243,100 @@ class CmbDB(GObject.GObject):
|
||||
|
||||
return obj
|
||||
|
||||
def __export_expression(self, ui_id, object_id, merengue=False):
|
||||
c = self.conn.cursor()
|
||||
|
||||
c.execute("SELECT type_id FROM object WHERE ui_id=? AND object_id=?;", (ui_id, object_id))
|
||||
type_id, = c.fetchone()
|
||||
|
||||
# Collect properties
|
||||
props = {}
|
||||
for row in c.execute(
|
||||
"""
|
||||
SELECT value, property_id
|
||||
FROM object_property
|
||||
WHERE ui_id=? AND object_id=? AND value IS NOT NULL ORDER BY property_id;
|
||||
""",
|
||||
(ui_id, object_id),
|
||||
):
|
||||
value, property_id = row
|
||||
props[property_id] = value
|
||||
|
||||
if type_id == "GtkConstantExpression":
|
||||
# Do not export incomplete expressions
|
||||
if "value" not in props:
|
||||
return None
|
||||
|
||||
node = E.constant()
|
||||
elif type_id == "GtkPropertyExpression":
|
||||
node = E.lookup()
|
||||
elif type_id == "GtkClosureExpression":
|
||||
# Dont export closure expressions since the function most likely does not exists
|
||||
if merengue:
|
||||
return None
|
||||
|
||||
# Do not export incomplete expressions
|
||||
if "function" not in props:
|
||||
return None
|
||||
|
||||
node = E.closure()
|
||||
else:
|
||||
logger.warning(f"Ignoring object type {type_id} while exporting expression.")
|
||||
return None
|
||||
|
||||
has_children = False
|
||||
|
||||
# Children
|
||||
for row in c.execute(
|
||||
"SELECT object_id, comment FROM object WHERE ui_id=? AND parent_id=? ORDER BY position;",
|
||||
(ui_id, object_id),
|
||||
):
|
||||
child_id, comment = row
|
||||
child_node = self.__export_expression(ui_id, child_id, merengue=merengue)
|
||||
|
||||
if child_node is not None:
|
||||
self.__node_add_comment(child_node, comment)
|
||||
node.append(child_node)
|
||||
has_children = True
|
||||
|
||||
# Do not export incomplete expressions
|
||||
if type_id == "GtkPropertyExpression" and ("value" not in props or not has_children):
|
||||
return None
|
||||
|
||||
# Check if type is an object type
|
||||
is_object = type_id in ["GtkPropertyExpression", "GtkConstantExpression"]
|
||||
|
||||
if "type" in props:
|
||||
# Check if type is an object type
|
||||
info = self.type_info.get(props["type"])
|
||||
is_object = info.is_object if info is not None else False
|
||||
|
||||
# Set attributes from properties
|
||||
for property_id, value in props.items():
|
||||
if property_id == "value":
|
||||
if has_children:
|
||||
continue
|
||||
if is_object:
|
||||
row = self.conn.execute(
|
||||
"SELECT object_id FROM object WHERE ui_id=? AND name=?", (ui_id, value.strip())
|
||||
).fetchone()
|
||||
|
||||
if row is None:
|
||||
continue
|
||||
|
||||
if merengue:
|
||||
node.text = f"__cmb__{ui_id}.{row[0]}"
|
||||
else:
|
||||
node.text = value
|
||||
else:
|
||||
node.text = value
|
||||
else:
|
||||
utils.xml_node_set(node, property_id, value)
|
||||
|
||||
c.close()
|
||||
|
||||
return node
|
||||
|
||||
def __get_object_name(self, ui_id, object_id, merengue=False):
|
||||
if object_id is None:
|
||||
return None
|
||||
@ -2258,16 +2452,14 @@ class CmbDB(GObject.GObject):
|
||||
return n_objs == 0 and n_children == 0 and n_props == 0 and n_layout_props == 0 and n_signals == 0 and n_data == 0
|
||||
|
||||
def __export_object(self, ui_id, object_id, merengue=False, template_id=None, ignore_id=False):
|
||||
target_gtk4 = self.target_tk == "gtk-4.0"
|
||||
target_gtk3 = not target_gtk4
|
||||
|
||||
c = self.conn.cursor()
|
||||
|
||||
c.execute("SELECT type_id, name, custom_fragment FROM object WHERE ui_id=? AND object_id=?;", (ui_id, object_id))
|
||||
type_id, name, custom_fragment = c.fetchone()
|
||||
|
||||
# Special case <menu>
|
||||
if type_id == GMENU_TYPE:
|
||||
c.close()
|
||||
return self.__export_menu(ui_id, object_id, merengue=merengue, ignore_id=ignore_id)
|
||||
|
||||
info = self.type_info.get(type_id, None)
|
||||
|
||||
if info is None:
|
||||
@ -2275,6 +2467,14 @@ class CmbDB(GObject.GObject):
|
||||
c.close()
|
||||
return None
|
||||
|
||||
# Special case <menu>
|
||||
if type_id == GMENU_TYPE:
|
||||
c.close()
|
||||
return self.__export_menu(ui_id, object_id, merengue=merengue, ignore_id=ignore_id)
|
||||
elif info.is_a("GtkExpression"):
|
||||
c.close()
|
||||
return self.__export_expression(ui_id, object_id, merengue=merengue)
|
||||
|
||||
cc = self.conn.cursor()
|
||||
|
||||
merengue_template = merengue and info.library_id is None and info.parent_id is not None
|
||||
@ -2336,6 +2536,7 @@ class CmbDB(GObject.GObject):
|
||||
SELECT op.value, op.property_id, op.inline_object_id, op.comment, op.translatable, op.translation_context,
|
||||
op.translation_comments, p.is_object, p.disable_inline_object,
|
||||
op.bind_source_id, op.bind_owner_id, op.bind_property_id, op.bind_flags,
|
||||
op.binding_expression_id, op.binding_expression_object_id,
|
||||
NULL, NULL, p.type_id
|
||||
FROM object_property AS op, property AS p, type AS t
|
||||
WHERE op.owner_id NOT IN
|
||||
@ -2345,7 +2546,7 @@ class CmbDB(GObject.GObject):
|
||||
{template_check}
|
||||
UNION
|
||||
SELECT p.default_value, p.property_id, NULL, NULL, NULL, NULL, NULL, p.is_object, p.disable_inline_object,
|
||||
NULL, NULL, NULL, NULL, p.required, p.workspace_default, p.type_id
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, p.required, p.workspace_default, p.type_id
|
||||
FROM property AS p, type AS t
|
||||
WHERE p.owner_id == t.type_id AND (required=1 OR save_always=1) AND owner_id IN ({placeholders}) AND
|
||||
property_id NOT IN (SELECT property_id FROM object_property WHERE ui_id=? AND object_id=?)
|
||||
@ -2368,6 +2569,8 @@ class CmbDB(GObject.GObject):
|
||||
bind_owner_id,
|
||||
bind_property_id,
|
||||
bind_flags,
|
||||
binding_expression_id,
|
||||
binding_expression_object_id,
|
||||
required,
|
||||
workspace_default,
|
||||
property_type_id,
|
||||
@ -2377,13 +2580,10 @@ class CmbDB(GObject.GObject):
|
||||
value_node = None
|
||||
pinfo = self.type_info.get(property_type_id, None)
|
||||
|
||||
is_inline_object = not disable_inline_object and self.target_tk == "gtk-4.0"
|
||||
is_inline_object = not disable_inline_object and target_gtk4
|
||||
|
||||
if required and workspace_default:
|
||||
if is_object and is_inline_object:
|
||||
value_node = etree.fromstring(workspace_default)
|
||||
else:
|
||||
value = workspace_default
|
||||
if binding_expression_id:
|
||||
value_node = self.__export_expression(ui_id, binding_expression_id, merengue=merengue)
|
||||
elif is_object:
|
||||
# Ignore object properties with 0/null ID or unknown object references
|
||||
if val is not None and val.isnumeric() and int(val) == 0:
|
||||
@ -2394,7 +2594,7 @@ class CmbDB(GObject.GObject):
|
||||
elif ignore_id:
|
||||
# Ignore references to object in template mode since the object could not exists in this UI
|
||||
continue
|
||||
else:
|
||||
elif val:
|
||||
obj_name = self.__get_object_name(ui_id, val, merengue=merengue)
|
||||
|
||||
# Ignore properties that reference an unknown object
|
||||
@ -2410,7 +2610,24 @@ class CmbDB(GObject.GObject):
|
||||
else:
|
||||
value = val
|
||||
|
||||
node = E.property(name=property_id)
|
||||
if value is None and value_node is None and required and workspace_default:
|
||||
if is_object and is_inline_object:
|
||||
value_node = etree.fromstring(workspace_default)
|
||||
else:
|
||||
value = workspace_default
|
||||
|
||||
if target_gtk4 and binding_expression_id:
|
||||
if value_node is None:
|
||||
continue
|
||||
|
||||
node = E.binding(name=property_id)
|
||||
|
||||
if binding_expression_object_id:
|
||||
object_name = self.__get_object_name(ui_id, binding_expression_object_id, merengue=merengue)
|
||||
utils.xml_node_set(node, "object", object_name)
|
||||
else:
|
||||
node = E.property(name=property_id)
|
||||
|
||||
if value is not None:
|
||||
node.text = value
|
||||
elif value_node is not None:
|
||||
@ -2476,7 +2693,7 @@ class CmbDB(GObject.GObject):
|
||||
accessible_role = None
|
||||
a11y_data = {}
|
||||
|
||||
if self.target_tk == "gtk+-3.0":
|
||||
if target_gtk3:
|
||||
atk_object = E.object()
|
||||
atk_object.set("class", "AtkObject")
|
||||
else:
|
||||
@ -2660,6 +2877,7 @@ class CmbDB(GObject.GObject):
|
||||
SELECT object_id, internal, type, comment, position, custom_child_fragment
|
||||
FROM object
|
||||
WHERE ui_id=? AND parent_id=? AND
|
||||
type_id NOT IN ('GtkPropertyExpression', 'GtkConstantExpression', 'GtkClosureExpression') AND
|
||||
object_id NOT IN (SELECT inline_object_id FROM object_property
|
||||
WHERE inline_object_id IS NOT NULL AND ui_id=? AND object_id=?)
|
||||
ORDER BY position;
|
||||
@ -2674,7 +2892,7 @@ class CmbDB(GObject.GObject):
|
||||
|
||||
if merengue and is_box:
|
||||
# FIXME: On Gtk 3 we get the position from the layout property
|
||||
if self.target_tk == "gtk+-3.0":
|
||||
if target_gtk3:
|
||||
r = cc.execute(
|
||||
"""
|
||||
SELECT value
|
||||
@ -2706,7 +2924,7 @@ class CmbDB(GObject.GObject):
|
||||
|
||||
if linfo is not None:
|
||||
# Packing / Layout
|
||||
layout = E("packing" if self.target_tk == "gtk+-3.0" else "layout")
|
||||
layout = E("packing" if target_gtk3 else "layout")
|
||||
for prop in cc.execute(
|
||||
f"""
|
||||
SELECT value, property_id, comment
|
||||
@ -2727,7 +2945,7 @@ class CmbDB(GObject.GObject):
|
||||
self.__node_add_comment(node, comment)
|
||||
|
||||
if len(layout) > 0:
|
||||
if self.target_tk == "gtk+-3.0":
|
||||
if target_gtk3:
|
||||
child.append(layout)
|
||||
else:
|
||||
child_obj.append(layout)
|
||||
|
@ -1,163 +0,0 @@
|
||||
#
|
||||
# CmbDBmigration - Cambalache DataBase Migration functions
|
||||
#
|
||||
# Copyright (C) 2021-2023 Juan Pablo Ugarte
|
||||
#
|
||||
# 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;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
|
||||
def ensure_columns_for_0_7_5(table, data):
|
||||
if table == "object":
|
||||
# Append position column
|
||||
return [row + (None,) for row in data]
|
||||
elif table in ["object_property", "object_layout_property"]:
|
||||
# Append translation_context, translation_comments columns
|
||||
return [row + (None, None) for row in data]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def migrate_table_data_to_0_7_5(c, table, data):
|
||||
if table == "object":
|
||||
c.execute(
|
||||
"""
|
||||
UPDATE temp.object SET position=new.position - 1
|
||||
FROM (
|
||||
SELECT row_number() OVER (PARTITION BY parent_id ORDER BY object_id) position, ui_id, object_id
|
||||
FROM temp.object
|
||||
WHERE parent_id IS NOT NULL
|
||||
) AS new
|
||||
WHERE temp.object.ui_id=new.ui_id AND temp.object.object_id=new.object_id;
|
||||
"""
|
||||
)
|
||||
c.execute(
|
||||
"""
|
||||
UPDATE temp.object SET position=new.position - 1
|
||||
FROM (
|
||||
SELECT row_number() OVER (PARTITION BY ui_id ORDER BY object_id) position, ui_id, object_id
|
||||
FROM temp.object
|
||||
WHERE parent_id IS NULL
|
||||
) AS new
|
||||
WHERE temp.object.ui_id=new.ui_id AND temp.object.object_id=new.object_id;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def ensure_columns_for_0_9_0(table, data):
|
||||
if table == "object_property":
|
||||
# Append inline_object_id column
|
||||
return [row + (None,) for row in data]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def migrate_table_data_to_0_9_0(c, table, data):
|
||||
if table == "object_property":
|
||||
# Remove all object properties with a 0 as value
|
||||
c.execute(
|
||||
"""
|
||||
DELETE FROM temp.object_property AS op
|
||||
WHERE value = 0 AND
|
||||
(SELECT property_id FROM temp.property WHERE owner_id=op.owner_id AND property_id=op.property_id AND is_object)
|
||||
IS NOT NULL;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def ensure_columns_for_0_11_2(table, data):
|
||||
if table in ["object", "ui"]:
|
||||
# Append custom_text column
|
||||
return [row + (None,) for row in data]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def ensure_columns_for_0_11_4(table, data):
|
||||
if table == "object_property":
|
||||
# Append bind_[source_id owner_id property_id flags] column
|
||||
return [row + (None, None, None, None) for row in data]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def ensure_columns_for_0_13_1(table, data):
|
||||
if table == "object_data":
|
||||
# Append translatable, translation_context, translation_comments columns
|
||||
return [row + (None, None, None) for row in data]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def ensure_columns_for_0_17_3(table, data):
|
||||
if table == "object":
|
||||
# Append custom_child_fragment column
|
||||
return [row + (None,) for row in data]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def migrate_table_data_to_0_17_3(c, table, data):
|
||||
if table in ["object_property", "object_layout_property", "object_data"]:
|
||||
c.executescript(
|
||||
f"""
|
||||
UPDATE temp.{table} SET translatable=1
|
||||
WHERE translatable IS NOT NULL AND lower(translatable) IN (1, 'y', 'yes', 't', 'true');
|
||||
UPDATE temp.{table} SET translatable=NULL
|
||||
WHERE translatable IS NOT NULL AND translatable != 1;
|
||||
"""
|
||||
)
|
||||
|
||||
if table == "object_signal":
|
||||
for prop in ["swap", "after"]:
|
||||
c.executescript(
|
||||
f"""
|
||||
UPDATE temp.object_signal SET {prop}=1
|
||||
WHERE {prop} IS NOT NULL AND lower({prop}) IN (1, 'y', 'yes', 't', 'true');
|
||||
UPDATE temp.object_signal SET {prop}=NULL WHERE {prop} IS NOT NULL AND after != 1;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def migrate_table_data_to_0_91_3(c, table, data):
|
||||
# Ensure every object has a position
|
||||
if table == "object":
|
||||
c.execute(
|
||||
"""
|
||||
UPDATE temp.object SET position=new.position - 1
|
||||
FROM (
|
||||
SELECT row_number() OVER (PARTITION BY ui_id, parent_id ORDER BY position, object_id) position, ui_id, object_id
|
||||
FROM temp.object
|
||||
WHERE parent_id IS NOT NULL
|
||||
) AS new
|
||||
WHERE temp.object.ui_id=new.ui_id AND temp.object.object_id=new.object_id;
|
||||
"""
|
||||
)
|
||||
c.execute(
|
||||
"""
|
||||
UPDATE temp.object SET position=new.position - 1
|
||||
FROM (
|
||||
SELECT row_number() OVER (PARTITION BY ui_id ORDER BY object_id) position, ui_id, object_id
|
||||
FROM temp.object
|
||||
WHERE parent_id IS NULL
|
||||
) AS new
|
||||
WHERE temp.object.ui_id=new.ui_id AND temp.object.object_id=new.object_id;
|
||||
"""
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.95.0 -->
|
||||
<!-- Created with Cambalache 0.97.6 -->
|
||||
<interface>
|
||||
<!-- interface-name cmb_gresource_editor.ui -->
|
||||
<!-- interface-copyright Juan Pablo Ugarte -->
|
||||
|
@ -62,7 +62,6 @@ class CmbObject(CmbBaseObject, Gio.ListModel):
|
||||
self.__signals_dict = None
|
||||
self.__data = None
|
||||
self.__data_dict = None
|
||||
self.inline_property_id = None
|
||||
self.version_warning = None
|
||||
self.__is_template = False
|
||||
|
||||
@ -75,7 +74,6 @@ class CmbObject(CmbBaseObject, Gio.ListModel):
|
||||
if self.project is None:
|
||||
return
|
||||
|
||||
self.__update_inline_property_id()
|
||||
self.__update_version_warning()
|
||||
|
||||
self.connect("notify", self._on_notify)
|
||||
@ -129,7 +127,8 @@ class CmbObject(CmbBaseObject, Gio.ListModel):
|
||||
self.__populate_data()
|
||||
return self.__data_dict
|
||||
|
||||
def __update_inline_property_id(self):
|
||||
@property
|
||||
def inline_property_id(self):
|
||||
ui_id = self.ui_id
|
||||
object_id = self.object_id
|
||||
parent_id = self.parent_id
|
||||
@ -137,9 +136,28 @@ class CmbObject(CmbBaseObject, Gio.ListModel):
|
||||
if parent_id:
|
||||
# Set which parent property makes a reference to this inline object
|
||||
row = self.project.db.execute(
|
||||
"SELECT property_id FROM object_property WHERE ui_id=? AND inline_object_id=?;", (ui_id, object_id)
|
||||
"SELECT property_id FROM object_property WHERE ui_id=? AND object_id=? AND inline_object_id=?;",
|
||||
(ui_id, parent_id, object_id)
|
||||
).fetchone()
|
||||
self.inline_property_id = row[0] if row else None
|
||||
return row[0] if row else None
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def binding_expression_property_id(self):
|
||||
ui_id = self.ui_id
|
||||
object_id = self.object_id
|
||||
parent_id = self.parent_id
|
||||
|
||||
if parent_id:
|
||||
# Set which parent property makes a reference to this binding expression object
|
||||
row = self.project.db.execute(
|
||||
"SELECT property_id FROM object_property WHERE ui_id=? AND object_id=? AND binding_expression_id=?;",
|
||||
(ui_id, parent_id, object_id)
|
||||
).fetchone()
|
||||
return row[0] if row else None
|
||||
|
||||
return None
|
||||
|
||||
def __populate_type_properties(self, name):
|
||||
property_info = self.project.get_type_properties(name)
|
||||
@ -591,11 +609,19 @@ class CmbObject(CmbBaseObject, Gio.ListModel):
|
||||
name = self.name or ""
|
||||
type_id = self.type_id
|
||||
parent_id = self.parent_id
|
||||
expression_property = self.binding_expression_property_id
|
||||
|
||||
if type_id in [GMENU_SECTION_TYPE, GMENU_SUBMENU_TYPE, GMENU_ITEM_TYPE]:
|
||||
prop = self.properties_dict["label"]
|
||||
label = prop.value or ""
|
||||
display_name = f"{type_id} <i>{label}</i>"
|
||||
elif expression_property and type_id in ["GtkPropertyExpression", "GtkConstantExpression", "GtkClosureExpression"]:
|
||||
expression_type = {
|
||||
"GtkPropertyExpression": "lookup",
|
||||
"GtkConstantExpression": "constant",
|
||||
"GtkClosureExpression": "closure"
|
||||
}.get(type_id)
|
||||
display_name = f"<b>{expression_property}</b> ({expression_type} bind)"
|
||||
elif not parent_id and self.ui.template_id == self.object_id:
|
||||
# Translators: This is used for Template classes in the object tree
|
||||
display_name = _("{name} (template)").format(name=name)
|
||||
|
@ -165,7 +165,7 @@ class CmbObjectEditor(Gtk.Box):
|
||||
# Child Type input
|
||||
if parent.info.has_child_types():
|
||||
self.append(self.__create_child_type_editor())
|
||||
else:
|
||||
elif not obj.info.is_a("GtkExpression"):
|
||||
# ID
|
||||
self.append(self.__create_id_editor())
|
||||
|
||||
|
@ -573,6 +573,8 @@ class CmbBaseProperty(CmbBase):
|
||||
bind_owner_id,
|
||||
bind_property_id,
|
||||
bind_flags,
|
||||
binding_expression_id,
|
||||
binding_expression_object_id,
|
||||
):
|
||||
return cls(project=project, ui_id=ui_id, object_id=object_id, owner_id=owner_id, property_id=property_id)
|
||||
|
||||
@ -826,6 +828,56 @@ class CmbBaseProperty(CmbBase):
|
||||
value,
|
||||
)
|
||||
|
||||
@GObject.Property(type=int)
|
||||
def binding_expression_id(self):
|
||||
return self.db_get(
|
||||
"SELECT binding_expression_id FROM object_property WHERE (ui_id, object_id, owner_id, property_id) IS (?, ?, ?, ?);",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
)
|
||||
|
||||
@binding_expression_id.setter
|
||||
def _set_binding_expression_id(self, value):
|
||||
self.db_set(
|
||||
"UPDATE object_property SET binding_expression_id=? WHERE (ui_id, object_id, owner_id, property_id) IS (?, ?, ?, ?);",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
value,
|
||||
)
|
||||
|
||||
@GObject.Property(type=int)
|
||||
def binding_expression_object_id(self):
|
||||
return self.db_get(
|
||||
"SELECT binding_expression_object_id FROM object_property WHERE (ui_id, object_id, owner_id, property_id) IS (?, ?, ?, ?);",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
)
|
||||
|
||||
@binding_expression_object_id.setter
|
||||
def _set_binding_expression_object_id(self, value):
|
||||
self.db_set(
|
||||
"UPDATE object_property SET binding_expression_object_id=? WHERE (ui_id, object_id, owner_id, property_id) IS (?, ?, ?, ?);",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
value,
|
||||
)
|
||||
|
||||
|
||||
class CmbBaseLayoutProperty(CmbBase):
|
||||
__gtype_name__ = "CmbBaseLayoutProperty"
|
||||
|
@ -229,6 +229,12 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
|
||||
return {"names": columns, "types": types, "pks": pks}
|
||||
|
||||
def _get_types(self):
|
||||
retval = []
|
||||
for row in self.db.execute("SELECT type_id FROM type ORDER BY type_id;"):
|
||||
retval.append(row[0])
|
||||
return retval
|
||||
|
||||
def __init_type_info(self, c):
|
||||
for row in c.execute("SELECT * FROM type WHERE parent_id IS NOT NULL ORDER BY type_id;"):
|
||||
type_id = row[0]
|
||||
@ -444,64 +450,59 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
f"File format {version} is not supported by this release,\nplease update to a newer version to open this file."
|
||||
)
|
||||
|
||||
if version > (0, 94, 0):
|
||||
ui_graph = {}
|
||||
ui_node_template = {}
|
||||
if version <= (0, 94, 0):
|
||||
raise Exception(
|
||||
f"Project format {version} is not supported, Open/save with Cambalache 0.96.0 to migrate to the new format."
|
||||
)
|
||||
|
||||
css_list = []
|
||||
gresourses_list = []
|
||||
ui_graph = {}
|
||||
ui_node_template = {}
|
||||
|
||||
for child in root.getchildren():
|
||||
if child.tag == "ui":
|
||||
# Collect template class <-> node relation
|
||||
template = child.get("template-class", None)
|
||||
if template:
|
||||
ui_node_template[template] = child
|
||||
css_list = []
|
||||
gresourses_list = []
|
||||
|
||||
# Collect node dependencies
|
||||
dependencies = []
|
||||
for requires in child.findall("requires"):
|
||||
dependencies.append(requires.text)
|
||||
for child in root.getchildren():
|
||||
if child.tag == "ui":
|
||||
# Collect template class <-> node relation
|
||||
template = child.get("template-class", None)
|
||||
if template:
|
||||
ui_node_template[template] = child
|
||||
|
||||
ui_graph[child] = dependencies
|
||||
elif child.tag == "css":
|
||||
css_list.append(child)
|
||||
elif child.tag == "gresources":
|
||||
gresourses_list.append(child)
|
||||
elif child.tag == "icontheme-search-path":
|
||||
self.icontheme_search_paths.append(child.text)
|
||||
else:
|
||||
raise Exception(f"Unknown tag {child.tag} in project file.")
|
||||
# Collect node dependencies
|
||||
dependencies = []
|
||||
for requires in child.findall("requires"):
|
||||
dependencies.append(requires.text)
|
||||
|
||||
for node in css_list:
|
||||
self.__load_css_from_node(node)
|
||||
ui_graph[child] = dependencies
|
||||
elif child.tag == "css":
|
||||
css_list.append(child)
|
||||
elif child.tag == "gresources":
|
||||
gresourses_list.append(child)
|
||||
elif child.tag == "icontheme-search-path":
|
||||
self.icontheme_search_paths.append(child.text)
|
||||
else:
|
||||
raise Exception(f"Unknown tag {child.tag} in project file.")
|
||||
|
||||
for node in gresourses_list:
|
||||
self.__load_gresource_from_node(node)
|
||||
for node in css_list:
|
||||
self.__load_css_from_node(node)
|
||||
|
||||
# Replace dependencies with nodes
|
||||
ui_node_graph = {}
|
||||
for node, dependencies in ui_graph.items():
|
||||
ui_node_graph[node] = [ui_node_template[key] for key in dependencies]
|
||||
for node in gresourses_list:
|
||||
self.__load_gresource_from_node(node)
|
||||
|
||||
try:
|
||||
ts = TopologicalSorter(ui_node_graph)
|
||||
sorted_ui_nodes = tuple(ts.static_order())
|
||||
except CycleError as e:
|
||||
raise Exception(f"Could not load project because of dependency cycle {e}")
|
||||
# Replace dependencies with nodes
|
||||
ui_node_graph = {}
|
||||
for node, dependencies in ui_graph.items():
|
||||
ui_node_graph[node] = [ui_node_template[key] for key in dependencies]
|
||||
|
||||
# Load UI in topological order
|
||||
for node in sorted_ui_nodes:
|
||||
self.__load_ui_from_node(node)
|
||||
else:
|
||||
self.db.load_old_format(root, version)
|
||||
try:
|
||||
ts = TopologicalSorter(ui_node_graph)
|
||||
sorted_ui_nodes = tuple(ts.static_order())
|
||||
except CycleError as e:
|
||||
raise Exception(f"Could not load project because of dependency cycle {e}")
|
||||
|
||||
for row in self.db.execute("SELECT * FROM ui;"):
|
||||
ui = self.__add_ui(True, *row)
|
||||
ui.notify("n-items")
|
||||
|
||||
for row in self.db.execute("SELECT * FROM css;"):
|
||||
self.__add_css(True, *row)
|
||||
# Load UI in topological order
|
||||
for node in sorted_ui_nodes:
|
||||
self.__load_ui_from_node(node)
|
||||
|
||||
self.history_enabled = True
|
||||
|
||||
@ -1209,6 +1210,7 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
child_type=None,
|
||||
inline_property=None,
|
||||
internal=None,
|
||||
inline_binding_expression=False,
|
||||
):
|
||||
if parent_id:
|
||||
parent = self.get_object_by_id(ui_id, parent_id)
|
||||
@ -1232,6 +1234,7 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
inline_property=inline_property,
|
||||
child_type=child_type,
|
||||
internal=internal,
|
||||
inline_binding_expression=inline_binding_expression,
|
||||
)
|
||||
self.history_pop()
|
||||
self.db.commit()
|
||||
@ -1404,11 +1407,8 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
p = properties.get(property_id, None)
|
||||
|
||||
if p and p.owner_id == owner_id and p.property_id == property_id:
|
||||
print("AAAAAAAAA", p, prop, property_id)
|
||||
p.notify(prop)
|
||||
if layout:
|
||||
obj._layout_property_changed(p)
|
||||
else:
|
||||
obj._property_changed(p)
|
||||
|
||||
def __undo_redo_do(self, undo, update_objects=None):
|
||||
def get_object_position(table, row):
|
||||
@ -2211,6 +2211,8 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
position = obj.position
|
||||
list_position = obj.list_position
|
||||
child_type = obj.type
|
||||
inline_property_id = obj.inline_property_id
|
||||
binding_expression_property_id = obj.binding_expression_property_id
|
||||
|
||||
self.db.ignore_check_constraints = True
|
||||
self.db.execute("UPDATE object SET position=-1 WHERE ui_id=? AND object_id=?;", (ui_id, object_id))
|
||||
@ -2227,6 +2229,19 @@ class CmbProject(GObject.Object, Gio.ListModel):
|
||||
self.db.execute("UPDATE object SET parent_id=? WHERE ui_id=? AND object_id=?;", (new_parent_id, ui_id, object_id))
|
||||
|
||||
self.db.execute("UPDATE object SET position=0 WHERE ui_id=? AND object_id=?;", (ui_id, object_id))
|
||||
|
||||
if inline_property_id:
|
||||
self.db.execute(
|
||||
"UPDATE object_property SET inline_object_id=? WHERE ui_id=? AND object_id=? AND property_id=?;",
|
||||
(new_parent_id, ui_id, grand_parent_id, inline_property_id)
|
||||
)
|
||||
|
||||
if binding_expression_property_id:
|
||||
self.db.execute(
|
||||
"UPDATE object_property SET binding_expression_id=? WHERE ui_id=? AND object_id=? AND property_id=?;",
|
||||
(new_parent_id, ui_id, grand_parent_id, binding_expression_property_id)
|
||||
)
|
||||
|
||||
self.db.ignore_check_constraints = False
|
||||
|
||||
# Move all layout properties from obj to parent
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
from gi.repository import GObject
|
||||
|
||||
from .cmb_objects_base import CmbBaseProperty
|
||||
from .cmb_objects_base import CmbBaseProperty, CmbBaseObject
|
||||
from .cmb_property_info import CmbPropertyInfo
|
||||
from . import utils
|
||||
from cambalache import _, getLogger
|
||||
@ -50,63 +50,94 @@ class CmbProperty(CmbBaseProperty):
|
||||
self.connect("notify", self.__on_notify)
|
||||
|
||||
def __str__(self):
|
||||
return f"CmbProperty<{self.object.type_id} {self.info.owner_id}:{self.property_id}>"
|
||||
return f"CmbProperty<{self.object.type_id} {self.info.owner_id}::{self.property_id}>"
|
||||
|
||||
def __on_notify(self, obj, pspec):
|
||||
self.project._object_property_changed(self.object, self)
|
||||
|
||||
@GObject.Property(type=str)
|
||||
def value(self):
|
||||
c = self.project.db.execute(
|
||||
"SELECT value FROM object_property WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?;",
|
||||
def __db_get(self, column):
|
||||
row = self.project.db.execute(
|
||||
f"SELECT {column} FROM object_property WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?;",
|
||||
(self.ui_id, self.object_id, self.owner_id, self.property_id),
|
||||
).fetchone()
|
||||
return row[0] if row is not None else None
|
||||
|
||||
def __db_set(self, **kwargs):
|
||||
# Do not use REPLACE INTO, to make sure both INSERT and UPDATE triggers are used
|
||||
|
||||
columns = tuple(kwargs.keys())
|
||||
values = tuple(kwargs.values())
|
||||
placeholders = ",".join((["?"] * len(values)))
|
||||
|
||||
count = self.db_get(
|
||||
"SELECT count(ui_id) FROM object_property WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?;",
|
||||
(self.ui_id, self.object_id, self.owner_id, self.property_id),
|
||||
)
|
||||
row = c.fetchone()
|
||||
return row[0] if row is not None else self.info.default_value
|
||||
|
||||
# Ensure row exists
|
||||
if count:
|
||||
# Execute update statement and return row values
|
||||
statement = ",".join([f"{col}=?" for col in columns])
|
||||
row = self.project.db.execute(
|
||||
f"""
|
||||
UPDATE object_property SET {statement} WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?
|
||||
RETURNING
|
||||
value, translatable, comment, translation_context, translation_comments,
|
||||
inline_object_id,
|
||||
bind_source_id, bind_owner_id, bind_property_id, bind_flags,
|
||||
binding_expression_id, binding_expression_object_id;
|
||||
""",
|
||||
values + (self.ui_id, self.object_id, self.owner_id, self.property_id)
|
||||
).fetchone()
|
||||
|
||||
# If all values are none/false we can remove the row
|
||||
if all(not val for val in row):
|
||||
self.reset()
|
||||
else:
|
||||
self.project.db.execute(
|
||||
f"""
|
||||
INSERT INTO object_property (ui_id, object_id, owner_id, property_id, {",".join(columns)})
|
||||
VALUES (?, ?, ?, ?, {placeholders});
|
||||
""",
|
||||
(self.ui_id, self.object_id, self.owner_id, self.property_id) + values,
|
||||
)
|
||||
|
||||
self.__update_internal_child()
|
||||
|
||||
if self._init is False:
|
||||
self.object._property_changed(self)
|
||||
|
||||
@GObject.Property(type=str)
|
||||
def value(self):
|
||||
return self.__db_get("value") or self.info.default_value
|
||||
|
||||
@value.setter
|
||||
def _set_value(self, value):
|
||||
self.__update_values(value, self.translatable, self.translation_context, self.translation_comments, self.bind_property)
|
||||
self.__db_set(value=value)
|
||||
|
||||
@GObject.Property(type=bool, default=False)
|
||||
def translatable(self):
|
||||
return super().translatable
|
||||
return self.__db_get("translatable")
|
||||
|
||||
@translatable.setter
|
||||
def _set_translatable(self, value):
|
||||
self.__update_values(self.value, value, self.translation_context, self.translation_comments, self.bind_property)
|
||||
self.__db_set(translatable=value)
|
||||
|
||||
@GObject.Property(type=str)
|
||||
def translation_context(self):
|
||||
return self.db_get(
|
||||
"SELECT translation_context FROM object_property WHERE (ui_id, object_id, owner_id, property_id) IS (?, ?, ?, ?);",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
)
|
||||
return self.__db_get("translation_context")
|
||||
|
||||
@translation_context.setter
|
||||
def _set_translation_context(self, value):
|
||||
self.__update_values(self.value, self.translatable, value, self.translation_comments, self.bind_property)
|
||||
self.__db_set(translation_context=value)
|
||||
|
||||
@GObject.Property(type=str)
|
||||
def translation_comments(self):
|
||||
return self.db_get(
|
||||
"SELECT translation_comments FROM object_property WHERE (ui_id, object_id, owner_id, property_id) IS (?, ?, ?, ?);",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
)
|
||||
return self.__db_get("translation_comments")
|
||||
|
||||
@translation_comments.setter
|
||||
def _set_translation_comments(self, value):
|
||||
self.__update_values(self.value, self.translatable, self.translation_context, value, self.bind_property)
|
||||
self.__db_set(translation_comments=value)
|
||||
|
||||
def reset(self):
|
||||
if self.info.internal_child:
|
||||
@ -155,122 +186,12 @@ class CmbProperty(CmbBaseProperty):
|
||||
"value": str(value)
|
||||
}
|
||||
|
||||
def __update_values(self, value, translatable, translation_context, translation_comments, bind_property):
|
||||
c = self.project.db.cursor()
|
||||
|
||||
bind_source_id, bind_owner_id, bind_property_id = (None, None, None)
|
||||
if bind_property:
|
||||
bind_source_id = bind_property.object.object_id
|
||||
bind_owner_id = bind_property.owner_id
|
||||
bind_property_id = bind_property.property_id
|
||||
|
||||
if (
|
||||
(value is None or value == self.info.default_value or (self.info.is_object and value == 0)) and
|
||||
bind_property is None and
|
||||
not translatable and
|
||||
translation_context is None and
|
||||
translation_comments is None
|
||||
):
|
||||
self.reset()
|
||||
else:
|
||||
if (
|
||||
value == self.value and
|
||||
translatable == self.translatable and
|
||||
translation_context == self.translation_context and
|
||||
translation_comments == self.translation_comments and
|
||||
bind_source_id == self.bind_source_id and
|
||||
bind_owner_id == self.bind_owner_id and
|
||||
bind_property_id == self.bind_property_id
|
||||
):
|
||||
return
|
||||
|
||||
# Do not use REPLACE INTO, to make sure both INSERT and UPDATE triggers are used
|
||||
count = self.db_get(
|
||||
"SELECT count(ui_id) FROM object_property WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?;",
|
||||
(self.ui_id, self.object_id, self.owner_id, self.property_id),
|
||||
)
|
||||
|
||||
if count:
|
||||
if self.info.internal_child:
|
||||
self.project.history_push(_("Update {obj} {prop} {prop_type} to {value}").format(**self.__get_msgs(value)))
|
||||
|
||||
c.execute(
|
||||
"""
|
||||
UPDATE object_property
|
||||
SET
|
||||
value=?,
|
||||
translatable=?, translation_context=?, translation_comments=?,
|
||||
bind_source_id=?, bind_owner_id=?, bind_property_id=?
|
||||
WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?;
|
||||
""",
|
||||
(
|
||||
value,
|
||||
translatable,
|
||||
translation_context,
|
||||
translation_comments,
|
||||
bind_source_id,
|
||||
bind_owner_id,
|
||||
bind_property_id,
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
),
|
||||
)
|
||||
else:
|
||||
if self.info.internal_child:
|
||||
self.project.history_push(_("Set {obj} {prop} {prop_type} to {value}").format(**self.__get_msgs(value)))
|
||||
|
||||
c.execute(
|
||||
"""
|
||||
INSERT INTO object_property
|
||||
(
|
||||
ui_id, object_id, owner_id, property_id,
|
||||
value,
|
||||
translatable, translation_context, translation_comments,
|
||||
bind_source_id, bind_owner_id, bind_property_id
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""",
|
||||
(
|
||||
self.ui_id,
|
||||
self.object_id,
|
||||
self.owner_id,
|
||||
self.property_id,
|
||||
value,
|
||||
translatable,
|
||||
translation_context,
|
||||
translation_comments,
|
||||
bind_source_id,
|
||||
bind_owner_id,
|
||||
bind_property_id,
|
||||
),
|
||||
)
|
||||
|
||||
self.__update_internal_child()
|
||||
|
||||
if self.info.internal_child:
|
||||
self.project.history_pop()
|
||||
|
||||
if self._init is False:
|
||||
self.object._property_changed(self)
|
||||
|
||||
c.close()
|
||||
|
||||
@GObject.Property(type=CmbBaseProperty)
|
||||
def bind_property(self):
|
||||
c = self.project.db.cursor()
|
||||
row = c.execute(
|
||||
"""
|
||||
SELECT bind_source_id, bind_property_id
|
||||
FROM object_property
|
||||
WHERE ui_id=? AND object_id=? AND owner_id=? AND property_id=?;
|
||||
""",
|
||||
(self.ui_id, self.object_id, self.owner_id, self.property_id),
|
||||
).fetchone()
|
||||
bind_source_id = self.bind_source_id
|
||||
bind_property_id = self.bind_property_id
|
||||
|
||||
if row:
|
||||
bind_source_id, bind_property_id = row
|
||||
if bind_source_id and bind_property_id:
|
||||
source = self.project.get_object_by_id(self.ui_id, bind_source_id) if bind_property_id else None
|
||||
return source.properties_dict.get(bind_property_id, None) if source else None
|
||||
|
||||
@ -278,7 +199,113 @@ class CmbProperty(CmbBaseProperty):
|
||||
|
||||
@bind_property.setter
|
||||
def _set_bind_property(self, bind_property):
|
||||
self.__update_values(self.value, self.translatable, self.translation_context, self.translation_comments, bind_property)
|
||||
bind_source_id, bind_owner_id, bind_property_id, bind_flags = (None, None, None, None)
|
||||
|
||||
if bind_property:
|
||||
obj = bind_property.object
|
||||
|
||||
bind_source_id = obj.object_id
|
||||
bind_owner_id = bind_property.owner_id
|
||||
bind_property_id = bind_property.property_id
|
||||
bind_flags = bind_property.bind_flags
|
||||
|
||||
if obj.ui_id == self.ui_id and obj.object_id == self.bind_source_id and \
|
||||
self.bind_property_id == bind_property.property_id:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Bind {object}::{property} to {bind_object}::{bind_property}").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id,
|
||||
bind_object=obj.display_name_type,
|
||||
bind_property=bind_property.property_id
|
||||
)
|
||||
)
|
||||
else:
|
||||
if not self.bind_source_id and not self.bind_property_id:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Clear {object}::{property} binding").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id
|
||||
)
|
||||
)
|
||||
|
||||
self.__db_set(
|
||||
bind_source_id=bind_source_id,
|
||||
bind_owner_id=bind_owner_id,
|
||||
bind_property_id=bind_property_id,
|
||||
bind_flags=bind_flags
|
||||
)
|
||||
|
||||
self.project.history_pop()
|
||||
self.project._object_property_binding_changed(self.object, self)
|
||||
|
||||
@GObject.Property(type=CmbBaseObject)
|
||||
def binding_expression(self):
|
||||
return self.project.get_object_by_id(self.ui_id, self.binding_expression_id)
|
||||
|
||||
@binding_expression.setter
|
||||
def _set_binding_expression(self, binding_expression):
|
||||
if binding_expression:
|
||||
|
||||
if binding_expression.ui_id == self.ui_id and binding_expression.object_id == self.binding_expression_id:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Bind {object}::{property} to {expression_object}").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id,
|
||||
expression_object=binding_expression.display_name_type
|
||||
)
|
||||
)
|
||||
else:
|
||||
if not self.binding_expression_id:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Clear {object}::{property} binding expression").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id
|
||||
)
|
||||
)
|
||||
|
||||
self.__db_set(binding_expression_id=binding_expression.object_id)
|
||||
|
||||
self.project.history_pop()
|
||||
self.project._object_property_binding_changed(self.object, self)
|
||||
|
||||
@GObject.Property(type=CmbBaseObject)
|
||||
def binding_expression_object(self):
|
||||
return self.project.get_object_by_id(self.ui_id, self.binding_expression_id)
|
||||
|
||||
@binding_expression.setter
|
||||
def _set_binding_expression_object(self, expression_object):
|
||||
if expression_object:
|
||||
if expression_object.ui_id == self.ui_id and expression_object.object_id == self.expression_object_id:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Bind {object}::{property} to {expression_object}").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id,
|
||||
expression_object=expression_object.display_name_type
|
||||
)
|
||||
)
|
||||
else:
|
||||
if not self.binding_expression_id:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Clear {object}::{property} binding expression object").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id
|
||||
)
|
||||
)
|
||||
|
||||
self.__db_set(binding_expression_id=expression_object.object_id)
|
||||
self.project.history_pop()
|
||||
self.project._object_property_binding_changed(self.object, self)
|
||||
|
||||
def _update_version_warning(self):
|
||||
@ -297,3 +324,82 @@ class CmbProperty(CmbBaseProperty):
|
||||
warning += _("Warning: GFile uri needs to be absolute for Gtk < 4.16")
|
||||
|
||||
self.version_warning = warning if len(warning) else None
|
||||
|
||||
def __clear_expression_inline_object(self):
|
||||
binding_expression_id = self.binding_expression_id
|
||||
|
||||
if binding_expression_id:
|
||||
expression_source = self.project.get_object_by_id(self.ui_id, binding_expression_id)
|
||||
self.project.remove_object(expression_source)
|
||||
|
||||
def clear_binding(self):
|
||||
if self.bind_property is None and self.bind_flags is None and self.binding_expression_id is None and \
|
||||
self.binding_expression_object_id is None:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Clear {object}::{property} binding").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id
|
||||
)
|
||||
)
|
||||
|
||||
self.__clear_expression_inline_object()
|
||||
|
||||
bind_source_id = self.bind_source_id != 0
|
||||
bind_owner_id = self.bind_owner_id is not None
|
||||
bind_property_id = self.bind_property_id is not None
|
||||
bind_flags = self.bind_flags is not None
|
||||
binding_expression_id = self.binding_expression_id != 0
|
||||
binding_expression_object_id = self.binding_expression_object_id != 0
|
||||
|
||||
self.__db_set(
|
||||
bind_source_id=None,
|
||||
bind_owner_id=None,
|
||||
bind_property_id=None,
|
||||
bind_flags=None,
|
||||
binding_expression_id=None,
|
||||
binding_expression_object_id=None
|
||||
)
|
||||
|
||||
if bind_source_id:
|
||||
self.notify("bind-source-id")
|
||||
if bind_owner_id:
|
||||
self.notify("bind-owner-id")
|
||||
if bind_property_id:
|
||||
self.notify("bind-property-id")
|
||||
if bind_flags:
|
||||
self.notify("bind-flags")
|
||||
if binding_expression_id:
|
||||
self.notify("binding-expression-id")
|
||||
if binding_expression_object_id:
|
||||
self.notify("binding-expression-object-id")
|
||||
|
||||
self.project.history_pop()
|
||||
|
||||
def set_binding_expression_type(self, expression_type):
|
||||
info = self.project.type_info.get(expression_type)
|
||||
|
||||
if info is None:
|
||||
return
|
||||
|
||||
self.project.history_push(
|
||||
_("Bind {object}::{property} to {expression_type}").format(
|
||||
object=self.object.display_name_type,
|
||||
property=self.property_id,
|
||||
expression_type=expression_type
|
||||
)
|
||||
)
|
||||
|
||||
self.__clear_expression_inline_object()
|
||||
|
||||
self.project.add_object(
|
||||
self.ui_id,
|
||||
info.type_id,
|
||||
parent_id=self.object.object_id,
|
||||
inline_property=self.property_id,
|
||||
inline_binding_expression=True
|
||||
)
|
||||
|
||||
self.notify("binding-expression-id")
|
||||
self.project.history_pop()
|
||||
|
@ -25,12 +25,9 @@
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
|
||||
from .cmb_object import CmbObject
|
||||
from .cmb_property import CmbProperty
|
||||
from .cmb_layout_property import CmbLayoutProperty
|
||||
from .cmb_property_info import CmbPropertyInfo
|
||||
from .control import CmbObjectChooser, CmbFlagsEntry
|
||||
from cambalache import _
|
||||
from .cmb_binding_popover import CmbBindingPopover
|
||||
|
||||
|
||||
class CmbPropertyLabel(Gtk.Button):
|
||||
@ -62,12 +59,11 @@ class CmbPropertyLabel(Gtk.Button):
|
||||
self.label.props.label = self.prop.info.a11y_property_id if self.prop.info.is_a11y else self.prop.property_id
|
||||
|
||||
self.__update_property_label()
|
||||
self.prop.connect("notify::value", lambda o, p: self.__update_property_label())
|
||||
self.prop.connect("notify", self.__on_notify)
|
||||
|
||||
if self.bindable:
|
||||
self.connect("clicked", self.__on_bind_button_clicked)
|
||||
|
||||
if self.layout_prop:
|
||||
elif self.layout_prop:
|
||||
self.bind_icon = None
|
||||
self.label.props.label = self.layout_prop.property_id
|
||||
self.__update_layout_property_label()
|
||||
@ -76,6 +72,18 @@ class CmbPropertyLabel(Gtk.Button):
|
||||
box.append(self.label)
|
||||
self.set_child(box)
|
||||
|
||||
def __on_notify(self, prop, pspec):
|
||||
if pspec.name in {
|
||||
"value",
|
||||
"bind-source-id",
|
||||
"bind-owner-id",
|
||||
"bind-property-id",
|
||||
"bind-flags",
|
||||
"binding-expression-id",
|
||||
"binding-expression-object-id"
|
||||
}:
|
||||
self.__update_property_label()
|
||||
|
||||
def __update_label(self, prop):
|
||||
if prop.value != prop.info.default_value:
|
||||
self.add_css_class("modified")
|
||||
@ -99,172 +107,20 @@ class CmbPropertyLabel(Gtk.Button):
|
||||
if not self.bindable:
|
||||
return
|
||||
|
||||
if self.prop.bind_property_id:
|
||||
if self.prop.bind_property_id or self.prop.binding_expression_id:
|
||||
self.bind_icon.props.icon_name = "binded-symbolic"
|
||||
self.remove_css_class("hidden")
|
||||
else:
|
||||
self.bind_icon.props.icon_name = "bind-symbolic"
|
||||
self.add_css_class("hidden")
|
||||
|
||||
def __on_object_editor_notify(self, object_editor, pspec, property_editor):
|
||||
object_id = object_editor.cmb_value
|
||||
if object_id:
|
||||
property_editor.object = self.prop.project.get_object_by_id(self.prop.ui_id, int(object_id))
|
||||
|
||||
def __on_property_editor_changed(self, combo):
|
||||
bind_source, bind_property = self.__find_bind_source_property(combo.object.object_id, combo.props.active_id)
|
||||
self.prop.bind_property = bind_property
|
||||
self.__update_property_label()
|
||||
|
||||
def __find_bind_source_property(self, bind_source_id, bind_property_id):
|
||||
bind_source = self.prop.project.get_object_by_id(self.prop.ui_id, bind_source_id) if bind_source_id else None
|
||||
bind_property = bind_source.properties_dict.get(bind_property_id, None) if bind_source else None
|
||||
|
||||
return bind_source, bind_property
|
||||
|
||||
def __on_clear_clicked(self, button, popover):
|
||||
self.prop.bind_property = None
|
||||
self.prop.bind_flags = None
|
||||
self.__update_property_label()
|
||||
popover.popdown()
|
||||
|
||||
def __on_close_clicked(self, button, popover):
|
||||
popover.popdown()
|
||||
|
||||
def __on_bind_button_clicked(self, button):
|
||||
popover = Gtk.Popover(position=Gtk.PositionType.LEFT, css_classes=["cmb-binding-popover"])
|
||||
popover = CmbBindingPopover(prop=self.prop)
|
||||
popover.set_parent(self)
|
||||
|
||||
label = Gtk.Label(label="<b>Property Binding</b>", use_markup=True, halign=Gtk.Align.START, hexpand=True)
|
||||
close = Gtk.Button(icon_name="window-close-symbolic", halign=Gtk.Align.END, css_classes=["close"])
|
||||
close.connect("clicked", self.__on_close_clicked, popover)
|
||||
|
||||
box = Gtk.Box(hexpand=True)
|
||||
box.append(label)
|
||||
box.append(close)
|
||||
|
||||
grid = Gtk.Grid(hexpand=True, row_spacing=6, column_spacing=6)
|
||||
grid.attach(box, 0, 0, 2, 1)
|
||||
|
||||
# Get bind property to initialize inputs
|
||||
bind_source, bind_property = self.__find_bind_source_property(self.prop.bind_source_id, self.prop.bind_property_id)
|
||||
|
||||
# Create Property editor
|
||||
property_editor = CmbPropertyChooser(object=bind_source, target_info=self.prop.info)
|
||||
property_editor.connect("changed", self.__on_property_editor_changed)
|
||||
|
||||
# Update active_id after letting the object populate the properties
|
||||
if bind_property:
|
||||
property_editor.props.active_id = bind_property.property_id
|
||||
|
||||
# Object editor (it does not set the object directly to CmbProperty, just choose the object in the prop chooser)
|
||||
object_editor = CmbObjectChooser(parent=self.prop.object, cmb_value=bind_source.object_id if bind_source else 0)
|
||||
object_editor.connect("notify::cmb-value", self.__on_object_editor_notify, property_editor)
|
||||
|
||||
# Flags editor
|
||||
binding_flags_info = self.prop.project.type_info.get("GBindingFlags", None)
|
||||
flags_editor = CmbFlagsEntry(info=binding_flags_info)
|
||||
GObject.Object.bind_property(
|
||||
self.prop,
|
||||
"bind_flags",
|
||||
flags_editor,
|
||||
"cmb-value",
|
||||
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL,
|
||||
)
|
||||
|
||||
i = 1
|
||||
for prop_label, editor in [("source", object_editor), ("property", property_editor), ("flags", flags_editor)]:
|
||||
label = Gtk.Label(label=prop_label, xalign=0)
|
||||
|
||||
grid.attach(label, 0, i, 1, 1)
|
||||
grid.attach(editor, 1, i, 1, 1)
|
||||
i += 1
|
||||
|
||||
clear = Gtk.Button(label=_("Clear"), halign=Gtk.Align.END)
|
||||
clear.connect("clicked", self.__on_clear_clicked, popover)
|
||||
grid.attach(clear, 0, i, 2, 1)
|
||||
|
||||
object_editor.grab_focus()
|
||||
|
||||
popover.set_child(grid)
|
||||
# Destroy popup on close
|
||||
popover.connect("closed", lambda p: p.unparent())
|
||||
popover.popup()
|
||||
|
||||
|
||||
Gtk.WidgetClass.set_css_name(CmbPropertyLabel, "CmbPropertyLabel")
|
||||
|
||||
|
||||
class CmbPropertyChooser(Gtk.ComboBoxText):
|
||||
__gtype_name__ = "CmbPropertyChooser"
|
||||
|
||||
object = GObject.Property(type=CmbObject, flags=GObject.ParamFlags.READWRITE)
|
||||
target_info = GObject.Property(type=CmbPropertyInfo, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.__populate()
|
||||
self.connect("notify::object", self.__on_object_notify)
|
||||
|
||||
def __on_object_notify(self, obj, pspec):
|
||||
self.__populate()
|
||||
|
||||
def __populate(self):
|
||||
self.remove_all()
|
||||
|
||||
if self.object is None:
|
||||
return
|
||||
|
||||
target_info = self.target_info
|
||||
target_type = target_info.type_id
|
||||
target_type_info = self.object.project.type_info.get(target_type, None)
|
||||
target_is_object = target_info.is_object
|
||||
target_is_iface = target_type_info.parent_id == "interface" if target_type_info else False
|
||||
|
||||
for prop in sorted(self.object.properties, key=lambda p: p.property_id):
|
||||
info = prop.info
|
||||
|
||||
if info.is_a11y:
|
||||
continue
|
||||
|
||||
# Ignore construct only properties
|
||||
if info.construct_only:
|
||||
continue
|
||||
|
||||
source_type_info = self.object.project.type_info.get(info.type_id, None)
|
||||
source_is_object = info.is_object
|
||||
source_is_iface = source_type_info.parent_id == "interface" if source_type_info else False
|
||||
|
||||
if target_is_object or target_is_iface:
|
||||
# Ignore non object properties
|
||||
if not source_is_object and not source_is_iface:
|
||||
continue
|
||||
|
||||
# Ignore object properties of a different type
|
||||
if source_type_info and not source_type_info.is_a(target_info.type_id):
|
||||
continue
|
||||
elif source_is_object or source_is_iface:
|
||||
continue
|
||||
|
||||
# Enums and Flags has to be the same type
|
||||
if target_type_info and target_type_info.parent_id in ["flags", "enum"] and info.type_id != target_type:
|
||||
continue
|
||||
|
||||
if source_type_info and source_type_info.parent_id in ["flags", "enum"] and info.type_id != target_type:
|
||||
continue
|
||||
|
||||
compatible = info.type_id == target_type
|
||||
|
||||
if not compatible:
|
||||
try:
|
||||
gtype_id = GObject.type_from_name(info.type_id)
|
||||
gtarget_id = GObject.type_from_name(target_type)
|
||||
if gtype_id and gtarget_id:
|
||||
compatible = GObject.Value.type_compatible(gtype_id, gtarget_id)
|
||||
if not compatible:
|
||||
compatible = GObject.Value.type_transformable(gtype_id, gtarget_id)
|
||||
except Exception as e: # noqa F841
|
||||
self.append(prop.property_id, prop.property_id + "*")
|
||||
continue
|
||||
|
||||
if compatible:
|
||||
self.append(prop.property_id, prop.property_id)
|
||||
|
@ -73,6 +73,11 @@ class CmbTypeChooserWidget(Gtk.Box):
|
||||
def __type_info_should_append(self, info):
|
||||
retval = False
|
||||
|
||||
# Special case GtkExpression they are not instantiable but can be created as part of
|
||||
# a GtkExpression property as an inline object that Cambalache will serialize as a builder expression
|
||||
if self.derived_type_id == "GtkExpression" and info.parent_id == "GtkExpression":
|
||||
return True
|
||||
|
||||
if not info.instantiable or info.layout not in [None, "container"]:
|
||||
return False
|
||||
|
||||
|
@ -30,7 +30,7 @@ import time
|
||||
import atexit
|
||||
import socket
|
||||
|
||||
gi.require_version('Casilda', '0.1')
|
||||
gi.require_version('Casilda', '0.2')
|
||||
from gi.repository import GObject, GLib, Gio, Gdk, Gtk, Casilda
|
||||
|
||||
from . import config
|
||||
|
@ -29,6 +29,7 @@ from .cmb_file_button import CmbFileButton
|
||||
from .cmb_file_entry import CmbFileEntry
|
||||
from .cmb_icon_name_entry import CmbIconNameEntry
|
||||
from .cmb_pixbuf_entry import CmbPixbufEntry
|
||||
from .cmb_property_chooser import CmbPropertyChooser
|
||||
from .cmb_spin_button import CmbSpinButton
|
||||
from .cmb_text_buffer import CmbTextBuffer
|
||||
from .cmb_toplevel_chooser import CmbToplevelChooser
|
||||
@ -41,4 +42,5 @@ from .cmb_source_view import CmbSourceView
|
||||
from .cmb_switch import CmbSwitch
|
||||
from .cmb_text_view import CmbTextView
|
||||
from .cmb_translatable_popover import CmbTranslatablePopover
|
||||
from .cmb_suggestion_entry import CmbSuggestionEntry
|
||||
from .cmb_create_editor import cmb_create_editor
|
||||
|
@ -39,6 +39,7 @@ from .cmb_object_chooser import CmbObjectChooser
|
||||
from .cmb_object_list_editor import CmbObjectListEditor
|
||||
from .cmb_switch import CmbSwitch
|
||||
from .cmb_text_view import CmbTextView
|
||||
from .cmb_suggestion_entry import CmbSuggestionEntry
|
||||
|
||||
|
||||
def cmb_create_editor(project, type_id, prop=None, data=None, parent=None):
|
||||
@ -141,17 +142,18 @@ def cmb_create_editor(project, type_id, prop=None, data=None, parent=None):
|
||||
parent=prop.object if prop else parent,
|
||||
type_id="GtkAccessible",
|
||||
)
|
||||
elif type_id == "gtype":
|
||||
editor = CmbSuggestionEntry()
|
||||
editor.set_suggestions(project._get_types())
|
||||
elif info:
|
||||
if info.is_object or info.parent_id == "interface":
|
||||
if info.is_object or info.parent_id == "interface" or type_id == "GtkExpression":
|
||||
if prop is None:
|
||||
editor = CmbObjectChooser(
|
||||
project=project,
|
||||
parent=parent,
|
||||
type_id=type_id,
|
||||
)
|
||||
else:
|
||||
editor = CmbObjectChooser(
|
||||
project=project,
|
||||
parent=prop.object,
|
||||
is_inline=project.target_tk == "gtk-4.0" and not prop.info.disable_inline_object,
|
||||
inline_object_id=prop.inline_object_id,
|
||||
|
@ -30,15 +30,16 @@ from ..cmb_type_info import CmbTypeInfo
|
||||
class CmbFlagsEntry(Gtk.Entry):
|
||||
__gtype_name__ = "CmbFlagsEntry"
|
||||
|
||||
info = GObject.Property(type=CmbTypeInfo, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
id_column = GObject.Property(type=int, default=1, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
text_column = GObject.Property(type=int, default=1, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
value_column = GObject.Property(type=int, default=2, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
separator = GObject.Property(type=str, default="|", flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
info = GObject.Property(type=CmbTypeInfo, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
id_column = GObject.Property(type=int, default=1, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
text_column = GObject.Property(type=int, default=1, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
value_column = GObject.Property(type=int, default=2, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
separator = GObject.Property(type=str, default="|", flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.flags = {}
|
||||
self._checks = {}
|
||||
self._popover = None
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@ -47,9 +48,10 @@ class CmbFlagsEntry(Gtk.Entry):
|
||||
|
||||
self.connect("icon-release", self.__on_icon_release)
|
||||
|
||||
self.__init_popover()
|
||||
|
||||
def __init_popover(self):
|
||||
if self._popover:
|
||||
return
|
||||
|
||||
self._popover = Gtk.Popover()
|
||||
self._popover.set_parent(self)
|
||||
|
||||
@ -78,6 +80,7 @@ class CmbFlagsEntry(Gtk.Entry):
|
||||
self.notify("cmb-value")
|
||||
|
||||
def __on_icon_release(self, obj, pos):
|
||||
self.__init_popover()
|
||||
self._popover.popup()
|
||||
|
||||
def __to_string(self):
|
||||
|
@ -27,33 +27,30 @@ from cambalache import _
|
||||
from gi.repository import GObject, Gdk, Gtk
|
||||
|
||||
from ..cmb_object import CmbObject
|
||||
from ..cmb_project import CmbProject
|
||||
from ..cmb_type_chooser_popover import CmbTypeChooserPopover
|
||||
|
||||
|
||||
class CmbObjectChooser(Gtk.Entry):
|
||||
__gtype_name__ = "CmbObjectChooser"
|
||||
|
||||
project = GObject.Property(type=CmbProject, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
parent = GObject.Property(type=CmbObject, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
is_inline = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
parent = GObject.Property(type=CmbObject, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
is_inline = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
inline_object_id = GObject.Property(type=str, default=None, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
inline_property_id = GObject.Property(type=str, default=None, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
type_id = GObject.Property(type=str, default=None, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY)
|
||||
inline_property_id = GObject.Property(type=str, default=None, flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
type_id = GObject.Property(type=str, default="GObject", flags=GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.__object_id = None
|
||||
self.__updating = None
|
||||
super().__init__(**kwargs)
|
||||
self.connect("notify::text", self.__on_text_notify)
|
||||
|
||||
if self.type_id is None:
|
||||
self.props.placeholder_text = "<GObject>"
|
||||
return
|
||||
self.connect("notify::parent", self.__on_parent_notify)
|
||||
self.connect("notify::text", self.__on_text_notify)
|
||||
|
||||
if self.is_inline:
|
||||
self.connect("icon-press", self.__on_icon_pressed)
|
||||
self.parent.connect("property-changed", self.__on_parent_property_changed)
|
||||
if self.parent:
|
||||
self.parent.connect("property-changed", self.__on_parent_property_changed)
|
||||
self.__update_icons()
|
||||
else:
|
||||
self.props.placeholder_text = f"<{self.type_id}>"
|
||||
@ -66,8 +63,27 @@ class CmbObjectChooser(Gtk.Entry):
|
||||
drop_target.connect("drop", self.__on_drop_drop)
|
||||
self.add_controller(drop_target)
|
||||
|
||||
def __on_parent_notify(self, obj, pspec):
|
||||
if self.parent:
|
||||
self.parent.connect("property-changed", self.__on_parent_property_changed)
|
||||
|
||||
def __on_text_notify(self, obj, pspec):
|
||||
if self.inline_object_id:
|
||||
return
|
||||
|
||||
if self.__updating:
|
||||
self.__updating = False
|
||||
return
|
||||
|
||||
obj = self.parent.project.get_object_by_name(self.parent.ui_id, self.props.text)
|
||||
value = obj.object_id if obj else None
|
||||
|
||||
if self.__object_id != value:
|
||||
self.__object_id = value
|
||||
self.notify("cmb-value")
|
||||
|
||||
def __on_parent_property_changed(self, parent, prop):
|
||||
if prop.property_id != self.inline_property_id:
|
||||
if not self.is_inline or prop.property_id != self.inline_property_id:
|
||||
return
|
||||
|
||||
self.inline_object_id = prop.inline_object_id
|
||||
@ -112,17 +128,6 @@ class CmbObjectChooser(Gtk.Entry):
|
||||
# Select dragged object id
|
||||
self.cmb_value = origin_item.object_id
|
||||
|
||||
def __on_text_notify(self, obj, pspec):
|
||||
if self.__updating or self.inline_object_id:
|
||||
return
|
||||
|
||||
obj = self.parent.project.get_object_by_name(self.parent.ui_id, self.props.text)
|
||||
value = obj.object_id if obj else None
|
||||
|
||||
if self.__object_id != value:
|
||||
self.__object_id = value
|
||||
self.notify("cmb-value")
|
||||
|
||||
@GObject.Property(type=str)
|
||||
def cmb_value(self):
|
||||
return str(self.__object_id) if self.__object_id else None
|
||||
@ -143,7 +148,6 @@ class CmbObjectChooser(Gtk.Entry):
|
||||
self.props.text = obj.name if obj else ""
|
||||
else:
|
||||
self.props.text = ""
|
||||
self.__updating = False
|
||||
|
||||
def __update_icons(self):
|
||||
if not self.is_inline:
|
||||
@ -174,6 +178,9 @@ class CmbObjectChooser(Gtk.Entry):
|
||||
self.__update_icons()
|
||||
|
||||
def __on_icon_pressed(self, widget, icon_pos):
|
||||
if not self.is_inline:
|
||||
return
|
||||
|
||||
parent = self.parent
|
||||
project = parent.project
|
||||
|
||||
|
107
cambalache/control/cmb_property_chooser.py
Normal file
107
cambalache/control/cmb_property_chooser.py
Normal file
@ -0,0 +1,107 @@
|
||||
#
|
||||
# CmbPropertyChooser
|
||||
#
|
||||
# Copyright (C) 2023-2024 Juan Pablo Ugarte
|
||||
#
|
||||
# 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;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
|
||||
from ..cmb_object import CmbObject
|
||||
from ..cmb_property_info import CmbPropertyInfo
|
||||
|
||||
|
||||
class CmbPropertyChooser(Gtk.ComboBoxText):
|
||||
__gtype_name__ = "CmbPropertyChooser"
|
||||
|
||||
object = GObject.Property(type=CmbObject, flags=GObject.ParamFlags.READWRITE)
|
||||
target_info = GObject.Property(type=CmbPropertyInfo, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.__populate()
|
||||
self.connect("notify", self.__on_notify)
|
||||
|
||||
def __on_notify(self, obj, pspec):
|
||||
if pspec.name in ["object", "target-info"]:
|
||||
self.__populate()
|
||||
|
||||
def __populate(self):
|
||||
self.remove_all()
|
||||
|
||||
if self.object is None or self.target_info is None:
|
||||
return
|
||||
|
||||
target_info = self.target_info
|
||||
target_type = target_info.type_id
|
||||
target_type_info = self.object.project.type_info.get(target_type, None)
|
||||
target_is_object = target_info.is_object
|
||||
target_is_iface = target_type_info.parent_id == "interface" if target_type_info else False
|
||||
|
||||
for prop in sorted(self.object.properties, key=lambda p: p.property_id):
|
||||
info = prop.info
|
||||
|
||||
if info.is_a11y:
|
||||
continue
|
||||
|
||||
# Ignore construct only properties
|
||||
if info.construct_only:
|
||||
continue
|
||||
|
||||
source_type_info = self.object.project.type_info.get(info.type_id, None)
|
||||
source_is_object = info.is_object
|
||||
source_is_iface = source_type_info.parent_id == "interface" if source_type_info else False
|
||||
|
||||
if target_is_object or target_is_iface:
|
||||
# Ignore non object properties
|
||||
if not source_is_object and not source_is_iface:
|
||||
continue
|
||||
|
||||
# Ignore object properties of a different type
|
||||
if source_type_info and not source_type_info.is_a(target_info.type_id):
|
||||
continue
|
||||
elif source_is_object or source_is_iface:
|
||||
continue
|
||||
|
||||
# Enums and Flags has to be the same type
|
||||
if target_type_info and target_type_info.parent_id in ["flags", "enum"] and info.type_id != target_type:
|
||||
continue
|
||||
|
||||
if source_type_info and source_type_info.parent_id in ["flags", "enum"] and info.type_id != target_type:
|
||||
continue
|
||||
|
||||
compatible = info.type_id == target_type
|
||||
|
||||
if not compatible:
|
||||
try:
|
||||
gtype_id = GObject.type_from_name(info.type_id)
|
||||
gtarget_id = GObject.type_from_name(target_type)
|
||||
if gtype_id and gtarget_id:
|
||||
compatible = GObject.Value.type_compatible(gtype_id, gtarget_id)
|
||||
if not compatible:
|
||||
compatible = GObject.Value.type_transformable(gtype_id, gtarget_id)
|
||||
except Exception as e: # noqa F841
|
||||
self.append(prop.property_id, prop.property_id + "*")
|
||||
continue
|
||||
|
||||
if compatible:
|
||||
self.append(prop.property_id, prop.property_id)
|
@ -23,7 +23,7 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, GtkSource
|
||||
from gi.repository import GObject, Gtk, GtkSource
|
||||
|
||||
|
||||
class CmbSourceView(GtkSource.View):
|
||||
@ -38,6 +38,27 @@ class CmbSourceView(GtkSource.View):
|
||||
self.props.buffer = self.buffer
|
||||
self.buffer.connect("changed", self.__on_buffer_changed)
|
||||
|
||||
self.connect("notify::root", self.__on_parent_notify)
|
||||
self.__source_style_binding = None
|
||||
|
||||
def __on_parent_notify(self, obj, pspec):
|
||||
if self.__source_style_binding:
|
||||
self.__source_style_binding.unbind()
|
||||
self.__source_style_binding = None
|
||||
|
||||
root = self.props.root
|
||||
if root is None:
|
||||
return
|
||||
|
||||
if isinstance(root, Gtk.ApplicationWindow) and hasattr(root, "source_style"):
|
||||
self.__source_style_binding = GObject.Object.bind_property(
|
||||
root,
|
||||
"source-style",
|
||||
self.buffer,
|
||||
"style-scheme",
|
||||
GObject.BindingFlags.SYNC_CREATE,
|
||||
)
|
||||
|
||||
@GObject.Property(type=str)
|
||||
def lang(self):
|
||||
language = self.buffer.get_language()
|
||||
|
64
cambalache/control/cmb_suggestion_entry.py
Normal file
64
cambalache/control/cmb_suggestion_entry.py
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# CmbSuggestionEntry
|
||||
#
|
||||
# Copyright (C) 2025 Juan Pablo Ugarte
|
||||
#
|
||||
# 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;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
from .cmb_entry import CmbEntry
|
||||
|
||||
|
||||
class CmbSuggestionEntry(CmbEntry):
|
||||
__gtype_name__ = "CmbSuggestionEntry"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._filters = {}
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# GObject.Object.bind_property(self, "cmb-value", self.props.buffer, "text", GObject.BindingFlags.SYNC_CREATE)
|
||||
|
||||
self.type_model = Gtk.ListStore(str)
|
||||
|
||||
# Completion
|
||||
self.__completion = Gtk.EntryCompletion()
|
||||
self.__completion.props.model = self.type_model
|
||||
self.__completion.props.text_column = 0
|
||||
self.__completion.props.inline_completion = True
|
||||
self.__completion.props.inline_selection = True
|
||||
self.__completion.props.popup_set_width = True
|
||||
self.props.completion = self.__completion
|
||||
|
||||
# self.__completion.set_match_func(lambda o, key, iter, d: key in self.type_model[iter][0], None)
|
||||
|
||||
# String
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
self.__completion.pack_start(renderer_text, False)
|
||||
self.__completion.add_attribute(renderer_text, "text", 0)
|
||||
|
||||
def set_suggestions(self, suggestions):
|
||||
self.type_model.clear()
|
||||
for suggestion in suggestions:
|
||||
self.type_model.append([suggestion])
|
||||
|
||||
def __model_filter_func(self, model, iter, data):
|
||||
return model[iter][0] == data
|
@ -15,8 +15,10 @@ install_data([
|
||||
'cmb_object_chooser.py',
|
||||
'cmb_object_list_editor.py',
|
||||
'cmb_pixbuf_entry.py',
|
||||
'cmb_property_chooser.py',
|
||||
'cmb_source_view.py',
|
||||
'cmb_spin_button.py',
|
||||
'cmb_suggestion_entry.py',
|
||||
'cmb_switch.py',
|
||||
'cmb_text_buffer.py',
|
||||
'cmb_text_view.py',
|
||||
|
@ -262,9 +262,13 @@ CREATE TABLE object_property (
|
||||
bind_owner_id TEXT REFERENCES type ON UPDATE CASCADE,
|
||||
bind_property_id TEXT,
|
||||
bind_flags TEXT,
|
||||
binding_expression_id INTEGER,
|
||||
binding_expression_object_id INTEGER,
|
||||
PRIMARY KEY(ui_id, object_id, owner_id, property_id),
|
||||
FOREIGN KEY(ui_id, object_id) REFERENCES object(ui_id, object_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(ui_id, inline_object_id) REFERENCES object(ui_id, object_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(ui_id, binding_expression_id) REFERENCES object(ui_id, object_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(ui_id, binding_expression_object_id) REFERENCES object(ui_id, object_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(owner_id, property_id) REFERENCES property,
|
||||
FOREIGN KEY(ui_id, bind_source_id) REFERENCES object(ui_id, object_id),
|
||||
FOREIGN KEY(bind_owner_id, bind_property_id) REFERENCES property(owner_id, property_id) ON DELETE SET NULL
|
||||
|
@ -93,6 +93,8 @@ install_data([
|
||||
'mrg_adw/mrg_adw_bin.py',
|
||||
'mrg_adw/mrg_adw_carousel.py',
|
||||
'mrg_adw/mrg_adw_dialog.py',
|
||||
'mrg_adw/mrg_adw_view_stack.py',
|
||||
'mrg_adw/mrg_adw_view_stack_page.py',
|
||||
'mrg_adw/mrg_adw_window.py',
|
||||
],
|
||||
install_dir: join_paths(moduledir, 'mrg_adw')
|
||||
|
@ -34,4 +34,6 @@ from .mrg_adw_bin import MrgAdwBin
|
||||
from .mrg_adw_carousel import MrgAdwCarousel
|
||||
from .mrg_adw_window import MrgAdwWindow
|
||||
from .mrg_adw_dialog import MrgAdwDialog
|
||||
from .mrg_adw_view_stack import MrgAdwViewStack
|
||||
from .mrg_adw_view_stack_page import MrgAdwViewStackPage
|
||||
|
||||
|
40
cambalache/merengue/mrg_adw/mrg_adw_view_stack.py
Normal file
40
cambalache/merengue/mrg_adw/mrg_adw_view_stack.py
Normal file
@ -0,0 +1,40 @@
|
||||
# MrgAdwViewStack Controller
|
||||
#
|
||||
# Copyright (C) 2025 Juan Pablo Ugarte
|
||||
#
|
||||
# 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;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, Adw
|
||||
from merengue.mrg_gtk import MrgGtkStack
|
||||
|
||||
|
||||
class MrgAdwViewStack(MrgGtkStack):
|
||||
object = GObject.Property(type=Adw.ViewStack, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def add(self, child):
|
||||
if self.object is None:
|
||||
return
|
||||
|
||||
self.object.add(child)
|
||||
|
33
cambalache/merengue/mrg_adw/mrg_adw_view_stack_page.py
Normal file
33
cambalache/merengue/mrg_adw/mrg_adw_view_stack_page.py
Normal file
@ -0,0 +1,33 @@
|
||||
# MrgAdwViewStack Controller
|
||||
#
|
||||
# Copyright (C) 2025 Juan Pablo Ugarte
|
||||
#
|
||||
# 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;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, Adw
|
||||
from merengue.mrg_gtk import MrgGtkStackPage
|
||||
|
||||
|
||||
class MrgAdwViewStackPage(MrgGtkStackPage):
|
||||
object = GObject.Property(type=Adw.ViewStackPage, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
@ -258,10 +258,10 @@ class MrgApplication(Gtk.Application):
|
||||
controller.remove_placeholder(modifier)
|
||||
|
||||
def load_namespace(self, namespace, version, object_types):
|
||||
if version:
|
||||
gi.require_version(namespace, version)
|
||||
|
||||
try:
|
||||
if version:
|
||||
gi.require_version(namespace, version)
|
||||
|
||||
mod = importlib.import_module(f"gi.repository.{namespace}")
|
||||
except Exception as e:
|
||||
logger.warning(e)
|
||||
|
@ -22,10 +22,4 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject
|
||||
|
||||
from .mrg_webkit_web_view import MrgWebKitWebView
|
||||
from .mrg_webkit_web_view import MrgDummyWebView
|
||||
from .mrg_webkit_web_view import MrgDummyWebViewProxy
|
||||
|
||||
GObject.type_ensure(MrgDummyWebViewProxy.__gtype__)
|
||||
|
@ -22,7 +22,7 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, Gtk, WebKit
|
||||
from gi.repository import GObject, WebKit
|
||||
|
||||
from merengue.mrg_gtk import MrgGtkWidget
|
||||
|
||||
@ -36,7 +36,6 @@ class MrgWebKitWebView(MrgGtkWidget):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
logger.warning("MrgWebKitWebView __init__")
|
||||
|
||||
def object_changed(self, old, new):
|
||||
super().object_changed(old, new)
|
||||
@ -53,20 +52,21 @@ class MrgWebKitWebView(MrgGtkWidget):
|
||||
|
||||
<style>
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
|
||||
div.content {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border: 3px groove lightgray;
|
||||
border: 3px solid lightgray;
|
||||
border-radius: 1em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
min-height: calc(100vh - 2em);
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -85,14 +85,15 @@ function open_url() {
|
||||
<div class="content">
|
||||
<h3>WebKit Test Page</h3>
|
||||
<span>URL:</span>
|
||||
<input type="text" id="url_entry" />
|
||||
<input type="text" id="url_entry" placeholder="Enter a URL" />
|
||||
<input type="button" value="Open" onclick="open_url()" />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<a href="https://gitlab.gnome.org/jpu/cambalache">Cambalache</a>
|
||||
<a href="https://webkitgtk.org/">WebKitGtk</a>
|
||||
<a href="https://gitlab.gnome.org/jpu/cambalache" title="gitlab.gnome.org/jpu/cambalache">Cambalache</a>
|
||||
<a href="https://webkitgtk.org" title="webkitgtk.org">WebKitGtk</a>
|
||||
<a href="https://browserbench.org/Speedometer3.1" title="browserbench.org/Speedometer3.1">Speedometer</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -100,47 +101,3 @@ function open_url() {
|
||||
".",
|
||||
)
|
||||
|
||||
|
||||
class MrgDummyWebViewProxy(Gtk.Label):
|
||||
__gtype_name__ = "MrgDummyWebViewProxy"
|
||||
|
||||
automation_presentation_type = GObject.Property(
|
||||
type=WebKit.AutomationBrowsingContextPresentation,
|
||||
default=WebKit.AutomationBrowsingContextPresentation.WINDOW,
|
||||
flags=GObject.ParamFlags.READWRITE,
|
||||
)
|
||||
camera_capture_state = GObject.Property(
|
||||
type=WebKit.MediaCaptureState, default=WebKit.MediaCaptureState.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
default_content_security_policy = GObject.Property(type=str, flags=GObject.ParamFlags.READWRITE)
|
||||
display_capture_state = GObject.Property(
|
||||
type=WebKit.MediaCaptureState, default=WebKit.MediaCaptureState.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
editable = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
is_controlled_by_automation = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
is_ephemeral = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
is_muted = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
microphone_capture_state = GObject.Property(
|
||||
type=WebKit.MediaCaptureState, default=WebKit.MediaCaptureState.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
related_view = GObject.Property(type=WebKit.WebView, flags=GObject.ParamFlags.READWRITE)
|
||||
settings = GObject.Property(type=WebKit.Settings, flags=GObject.ParamFlags.READWRITE)
|
||||
user_content_manager = GObject.Property(type=WebKit.UserContentManager, flags=GObject.ParamFlags.READWRITE)
|
||||
web_context = GObject.Property(type=WebKit.WebContext, flags=GObject.ParamFlags.READWRITE)
|
||||
web_extension_mode = GObject.Property(
|
||||
type=WebKit.WebExtensionMode, default=WebKit.WebExtensionMode.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
website_policies = GObject.Property(type=WebKit.WebsitePolicies, flags=GObject.ParamFlags.READWRITE)
|
||||
zoom_level = GObject.Property(type=float, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.props.label = "WebKit.WebView\nplaceholder"
|
||||
self.props.justify = Gtk.Justification.CENTER
|
||||
|
||||
|
||||
class MrgDummyWebView(MrgGtkWidget):
|
||||
object = GObject.Property(type=MrgDummyWebViewProxy, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
@ -22,10 +22,4 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject
|
||||
|
||||
from .mrg_webkit_web_view import MrgWebKitWebView
|
||||
from .mrg_webkit_web_view import MrgDummyWebView
|
||||
from .mrg_webkit_web_view import MrgDummyWebViewProxy
|
||||
|
||||
GObject.type_ensure(MrgDummyWebViewProxy.__gtype__)
|
||||
|
@ -22,7 +22,7 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-only
|
||||
#
|
||||
|
||||
from gi.repository import GObject, Gtk, WebKit2
|
||||
from gi.repository import GObject, WebKit2
|
||||
|
||||
from merengue.mrg_gtk import MrgGtkWidget
|
||||
|
||||
@ -36,7 +36,6 @@ class MrgWebKitWebView(MrgGtkWidget):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
logger.warning("MrgWebKitWebView __init__")
|
||||
|
||||
def object_changed(self, old, new):
|
||||
super().object_changed(old, new)
|
||||
@ -53,20 +52,21 @@ class MrgWebKitWebView(MrgGtkWidget):
|
||||
|
||||
<style>
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
|
||||
div.content {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border: 3px groove lightgray;
|
||||
border: 3px solid lightgray;
|
||||
border-radius: 1em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
min-height: calc(100vh - 2em);
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -85,14 +85,15 @@ function open_url() {
|
||||
<div class="content">
|
||||
<h3>WebKit Test Page</h3>
|
||||
<span>URL:</span>
|
||||
<input type="text" id="url_entry" />
|
||||
<input type="text" id="url_entry" placeholder="Enter a URL" />
|
||||
<input type="button" value="Open" onclick="open_url()" />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<a href="https://gitlab.gnome.org/jpu/cambalache">Cambalache</a>
|
||||
<a href="https://webkitgtk.org/">WebKitGtk</a>
|
||||
<a href="https://gitlab.gnome.org/jpu/cambalache" title="gitlab.gnome.org/jpu/cambalache">Cambalache</a>
|
||||
<a href="https://webkitgtk.org" title="webkitgtk.org">WebKitGtk</a>
|
||||
<a href="https://browserbench.org/Speedometer3.1" title="browserbench.org/Speedometer3.1">Speedometer</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -100,47 +101,3 @@ function open_url() {
|
||||
".",
|
||||
)
|
||||
|
||||
|
||||
class MrgDummyWebViewProxy(Gtk.Label):
|
||||
__gtype_name__ = "MrgDummyWebViewProxy"
|
||||
|
||||
automation_presentation_type = GObject.Property(
|
||||
type=WebKit2.AutomationBrowsingContextPresentation,
|
||||
default=WebKit2.AutomationBrowsingContextPresentation.WINDOW,
|
||||
flags=GObject.ParamFlags.READWRITE,
|
||||
)
|
||||
camera_capture_state = GObject.Property(
|
||||
type=WebKit2.MediaCaptureState, default=WebKit2.MediaCaptureState.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
default_content_security_policy = GObject.Property(type=str, flags=GObject.ParamFlags.READWRITE)
|
||||
display_capture_state = GObject.Property(
|
||||
type=WebKit2.MediaCaptureState, default=WebKit2.MediaCaptureState.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
editable = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
is_controlled_by_automation = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
is_ephemeral = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
is_muted = GObject.Property(type=bool, default=False, flags=GObject.ParamFlags.READWRITE)
|
||||
microphone_capture_state = GObject.Property(
|
||||
type=WebKit2.MediaCaptureState, default=WebKit2.MediaCaptureState.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
related_view = GObject.Property(type=WebKit2.WebView, flags=GObject.ParamFlags.READWRITE)
|
||||
settings = GObject.Property(type=WebKit2.Settings, flags=GObject.ParamFlags.READWRITE)
|
||||
user_content_manager = GObject.Property(type=WebKit2.UserContentManager, flags=GObject.ParamFlags.READWRITE)
|
||||
web_context = GObject.Property(type=WebKit2.WebContext, flags=GObject.ParamFlags.READWRITE)
|
||||
web_extension_mode = GObject.Property(
|
||||
type=WebKit2.WebExtensionMode, default=WebKit2.WebExtensionMode.NONE, flags=GObject.ParamFlags.READWRITE
|
||||
)
|
||||
website_policies = GObject.Property(type=WebKit2.WebsitePolicies, flags=GObject.ParamFlags.READWRITE)
|
||||
zoom_level = GObject.Property(type=float, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.props.label = "WebKit2.WebView\nplaceholder"
|
||||
self.props.justify = Gtk.Justification.CENTER
|
||||
|
||||
|
||||
class MrgDummyWebView(MrgGtkWidget):
|
||||
object = GObject.Property(type=MrgDummyWebViewProxy, flags=GObject.ParamFlags.READWRITE)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
@ -26,13 +26,13 @@ configure_file(
|
||||
install_data([
|
||||
'cmb_accessible_editor.py',
|
||||
'cmb_base.py',
|
||||
'cmb_binding_popover.py',
|
||||
'cmb_blueprint.py',
|
||||
'cmb_context_menu.py',
|
||||
'cmb_css.py',
|
||||
'cmb_css_editor.py',
|
||||
'cmb_db.py',
|
||||
'cmb_db_inspector.py',
|
||||
'cmb_db_migration.py',
|
||||
'cmb_db_profile.py',
|
||||
'cmb_fragment_editor.py',
|
||||
'cmb_gresource.py',
|
||||
|
@ -2,8 +2,6 @@ CMB_CATALOG_GEN=flatpak run --devel \
|
||||
--command=cmb-catalog-gen \
|
||||
ar.xjuan.Cambalache
|
||||
|
||||
# CMB_CATALOG_GEN=../run-cmb-catalog-gen.sh
|
||||
|
||||
BASE_CATALOG_FILES = \
|
||||
glib/gobject-2.0.xml \
|
||||
glib/gio-2.0.xml \
|
||||
|
@ -492,11 +492,11 @@
|
||||
("GResourceFlags","G_RESOURCE_FLAGS_NONE","none",None,"No flags set."),
|
||||
("GResourceLookupFlags","G_RESOURCE_LOOKUP_FLAGS_NONE","none",None,"No flags set."),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_DEFAULT","default",None,"Equivalent to `G_SETTINGS_BIND_GET|G_SETTINGS_BIND_SET`"),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_GET","get",1,"Update the #GObject property when the setting changes. It is an error to use this flag if the property is not writable."),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_GET_NO_CHANGES","get-no-changes",8,"When set in addition to %G_SETTINGS_BIND_GET, set the #GObject property value initially from the setting, but do not listen for changes of the setting"),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_INVERT_BOOLEAN","invert-boolean",16,"When passed to g_settings_bind(), uses a pair of mapping functions that invert the boolean value when mapping between the setting and the property. The setting and property must both be booleans. You cannot pass this flag to g_settings_bind_with_mapping()."),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_NO_SENSITIVITY","no-sensitivity",4,"Do not try to bind a \"sensitivity\" property to the writability of the setting"),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_SET","set",2,"Update the setting when the #GObject property changes. It is an error to use this flag if the property is not readable."),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_GET","get",1,"Update the [class@GObject.Object] property when the setting changes. It is an error to use this flag if the property is not writable."),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_GET_NO_CHANGES","get-no-changes",8,"When set in addition to [flags@Gio.SettingsBindFlags.GET], set the [class@GObject.Object] property value initially from the setting, but do not listen for changes of the setting"),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_INVERT_BOOLEAN","invert-boolean",16,"When passed to [method@Gio.Settings.bind], uses a pair of mapping functions that invert the boolean value when mapping between the setting and the property. The setting and property must both be booleans. You cannot pass this flag to [method@Gio.Settings.bind_with_mapping]."),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_NO_SENSITIVITY","no-sensitivity",4,"Do not try to bind a ‘sensitivity’ property to the writability of the setting"),
|
||||
("GSettingsBindFlags","G_SETTINGS_BIND_SET","set",2,"Update the setting when the [class@GObject.Object] property changes. It is an error to use this flag if the property is not readable."),
|
||||
("GSocketMsgFlags","G_SOCKET_MSG_DONTROUTE","dontroute",4,"Don't use a gateway to send out the packet, only send to hosts on directly connected networks."),
|
||||
("GSocketMsgFlags","G_SOCKET_MSG_NONE","none",None,"No flags."),
|
||||
("GSocketMsgFlags","G_SOCKET_MSG_OOB","oob",1,"Request to send/receive out of band data."),
|
||||
|
@ -5,10 +5,6 @@
|
||||
Copyright (C) 2022 Juan Pablo Ugarte
|
||||
-->
|
||||
<meta>
|
||||
<types>
|
||||
<WebKitWebView workspace-type="MrgDummyWebViewProxy"/>
|
||||
</types>
|
||||
|
||||
<categories>
|
||||
|
||||
<category name="hidden">
|
||||
|
@ -610,6 +610,7 @@
|
||||
("AdwClampScrollable","unit","AdwLengthUnit",None,None,None,"sp",None,None,"1.4",None,None,None,None,None,None,None,None),
|
||||
("AdwComboRow","accessible-role","GtkAccessibleRole",None,1,None,"combo-box",None,None,None,None,None,None,None,None,None,"GtkAccessible",None),
|
||||
("AdwComboRow","enable-search","gboolean",None,None,None,"False",None,None,"1.4",None,None,None,None,None,None,None,None),
|
||||
("AdwComboRow","expression","GtkExpression",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("AdwComboRow","factory","GtkListItemFactory",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("AdwComboRow","header-factory","GtkListItemFactory",1,None,None,None,None,None,"1.6",None,None,None,None,None,None,None,None),
|
||||
("AdwComboRow","list-factory","GtkListItemFactory",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
|
@ -50,7 +50,7 @@
|
||||
("WebKitWebExtensionMatchPatternOptions","flags","webkit2gtk",None,None,None,None,None,None,None),
|
||||
("WebKitWebExtensionMode","enum","webkit2gtk",None,None,None,None,None,None,None),
|
||||
("WebKitWebProcessTerminationReason","enum","webkit2gtk",None,None,None,None,None,None,None),
|
||||
("WebKitWebView","WebKitWebViewBase","webkit2gtk",None,None,None,1,"container",None,"MrgDummyWebViewProxy"),
|
||||
("WebKitWebView","WebKitWebViewBase","webkit2gtk",None,None,None,1,"container",None,None),
|
||||
("WebKitWebViewBase","GtkContainer","webkit2gtk",None,None,None,1,"container","hidden",None),
|
||||
("WebKitWebsiteDataTypes","flags","webkit2gtk",None,None,None,None,None,None,None)
|
||||
</type>
|
||||
|
@ -49,7 +49,7 @@
|
||||
("WebKitWebExtensionMatchPatternOptions","flags","webkitgtk",None,None,None,None,None,None,None),
|
||||
("WebKitWebExtensionMode","enum","webkitgtk",None,None,None,None,None,None,None),
|
||||
("WebKitWebProcessTerminationReason","enum","webkitgtk",None,None,None,None,None,None,None),
|
||||
("WebKitWebView","WebKitWebViewBase","webkitgtk",None,None,None,1,"container",None,"MrgDummyWebViewProxy"),
|
||||
("WebKitWebView","WebKitWebViewBase","webkitgtk",None,None,None,1,"container",None,None),
|
||||
("WebKitWebViewBase","GtkWidget","webkitgtk",None,None,None,1,None,"hidden",None),
|
||||
("WebKitWebsiteDataTypes","flags","webkitgtk",None,None,None,None,None,None,None)
|
||||
</type>
|
||||
|
@ -18,6 +18,22 @@
|
||||
</properties>
|
||||
</GtkWidget>
|
||||
|
||||
<GtkPropertyExpression target='Gtk-4.0'>
|
||||
<children-constraints>
|
||||
<constraint shortcut="True">GtkConstantExpression</constraint>
|
||||
<constraint shortcut="True">GtkPropertyExpression</constraint>
|
||||
<constraint shortcut="True">GtkClosureExpression</constraint>
|
||||
</children-constraints>
|
||||
</GtkPropertyExpression>
|
||||
|
||||
<GtkClosureExpression target='Gtk-4.0'>
|
||||
<children-constraints>
|
||||
<constraint shortcut="True">GtkConstantExpression</constraint>
|
||||
<constraint shortcut="True">GtkPropertyExpression</constraint>
|
||||
<constraint shortcut="True">GtkClosureExpression</constraint>
|
||||
</children-constraints>
|
||||
</GtkClosureExpression>
|
||||
|
||||
<GtkAccessible>
|
||||
<properties>
|
||||
<property id="accessible-role" construct-only="True"/>
|
||||
|
@ -2278,7 +2278,7 @@
|
||||
("GtkSettings","gtk-modules","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-overlay-scrolling","gboolean",None,None,None,"True",None,None,"3.24.9",None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-primary-button-warps-slider","gboolean",None,None,None,"True",None,None,"3.6",None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-print-backends","gchararray",None,None,None,"file,lpr,cups",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-print-backends","gchararray",None,None,None,"file,cups",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-print-preview-command","gchararray",None,None,None,"evince --unlink-tempfile --preview --print-settings %s %f",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-recent-files-enabled","gboolean",None,None,None,"True",None,None,"3.8",None,None,None,None,None,None,None,None),
|
||||
("GtkSettings","gtk-recent-files-limit","gint",None,None,None,"50","-1","2147483647",None,"3.10",None,None,None,None,None,None,None),
|
||||
|
@ -63,7 +63,6 @@
|
||||
("GtkBuilderScope","interface","gtk",None,None,None,None,None,None,None),
|
||||
("GtkButton","GtkWidget","gtk",None,None,None,1,"container","control",None),
|
||||
("GtkButtonsType","enum","gtk",None,None,None,None,None,None,None),
|
||||
("GtkCClosureExpression","GtkExpression","gtk",None,None,None,None,None,None,None),
|
||||
("GtkCalendar","GtkWidget","gtk",None,None,None,None,"container","display",None),
|
||||
("GtkCallbackAction","GtkShortcutAction","gtk",None,None,None,1,None,None,None),
|
||||
("GtkCellArea","GObject","gtk",None,"4.10",1,1,"container",None,None),
|
||||
@ -261,7 +260,6 @@
|
||||
("GtkNothingAction","GtkShortcutAction","gtk",None,None,None,1,None,None,None),
|
||||
("GtkNumberUpLayout","enum","gtk",None,None,None,None,None,None,None),
|
||||
("GtkNumericSorter","GtkSorter","gtk",None,None,None,1,None,None,None),
|
||||
("GtkObjectExpression","GtkExpression","gtk",None,None,None,None,None,None,None),
|
||||
("GtkOrdering","enum","gtk",None,None,None,None,None,None,None),
|
||||
("GtkOrientable","interface","gtk",None,None,None,None,None,None,None),
|
||||
("GtkOrientation","enum","gtk",None,None,None,None,None,None,None),
|
||||
@ -278,7 +276,6 @@
|
||||
("GtkPageSetupUnixDialog","GtkDialog","gtk",None,None,None,None,"container",None,None),
|
||||
("GtkPanDirection","enum","gtk",None,None,None,None,None,None,None),
|
||||
("GtkPaned","GtkWidget","gtk",None,None,None,None,"container","layout",None),
|
||||
("GtkParamSpecExpression","GObject","gtk",None,None,None,None,None,None,None),
|
||||
("GtkPasswordEntry","GtkWidget","gtk",None,None,None,1,"container",None,None),
|
||||
("GtkPasswordEntryBuffer","GtkEntryBuffer","gtk",None,None,None,1,None,None,None),
|
||||
("GtkPickFlags","flags","gtk",None,None,None,None,None,None,None),
|
||||
@ -1378,7 +1375,7 @@
|
||||
("GtkPrintError","GTK_PRINT_ERROR_NOMEM","nomem",2,"A memory allocation failed."),
|
||||
("GtkPrintOperationAction","GTK_PRINT_OPERATION_ACTION_EXPORT","export",3,"Export to a file. This requires the export-filename property to be set."),
|
||||
("GtkPrintOperationAction","GTK_PRINT_OPERATION_ACTION_PREVIEW","preview",2,"Show the print preview."),
|
||||
("GtkPrintOperationAction","GTK_PRINT_OPERATION_ACTION_PRINT","print",1,"Start to print without showing the print dialog, based on the current print settings."),
|
||||
("GtkPrintOperationAction","GTK_PRINT_OPERATION_ACTION_PRINT","print",1,"Start to print without showing the print dialog, based on the current print settings, if possible. Depending on the platform, a print dialog might appear anyway."),
|
||||
("GtkPrintOperationAction","GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG","print-dialog",None,"Show the print dialog."),
|
||||
("GtkPrintOperationResult","GTK_PRINT_OPERATION_RESULT_APPLY","apply",1,"The print settings should be stored."),
|
||||
("GtkPrintOperationResult","GTK_PRINT_OPERATION_RESULT_CANCEL","cancel",2,"The print operation has been canceled, the print settings should not be stored."),
|
||||
@ -1755,6 +1752,12 @@
|
||||
("GtkWindow","titlebar",1,None)
|
||||
</type_child_type>
|
||||
<type_child_constraint>
|
||||
("GtkClosureExpression","GtkClosureExpression",1,1),
|
||||
("GtkClosureExpression","GtkConstantExpression",1,1),
|
||||
("GtkClosureExpression","GtkPropertyExpression",1,1),
|
||||
("GtkPropertyExpression","GtkClosureExpression",1,1),
|
||||
("GtkPropertyExpression","GtkConstantExpression",1,1),
|
||||
("GtkPropertyExpression","GtkPropertyExpression",1,1),
|
||||
("GtkStack","GtkStackPage",1,1)
|
||||
</type_child_constraint>
|
||||
<type_internal_child>
|
||||
@ -1885,6 +1888,7 @@
|
||||
("GtkBookmarkList","attributes","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkBookmarkList","filename","gchararray",None,1,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkBookmarkList","io-priority","gint",None,None,None,"0","-2147483647","2147483647",None,None,None,None,None,None,None,None,None),
|
||||
("GtkBoolFilter","expression","GtkExpression",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkBoolFilter","invert","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkBox","baseline-child","gint",None,None,None,"-1","-1","2147483647","4.12",None,None,None,None,None,None,None,None),
|
||||
("GtkBox","baseline-position","GtkBaselinePosition",None,None,None,"center",None,None,None,None,None,None,None,None,None,None,None),
|
||||
@ -2038,6 +2042,8 @@
|
||||
("GtkCheckButton","inconsistent","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkCheckButton","label","gchararray",None,None,None,None,None,None,None,None,1,None,None,None,None,None,None),
|
||||
("GtkCheckButton","use-underline","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkClosureExpression","function","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkClosureExpression","type","gtype",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkColorButton","css-name","gchararray",None,1,None,"colorbutton",None,None,None,None,None,None,None,None,None,"GtkWidget",None),
|
||||
("GtkColorButton","modal","gboolean",None,None,None,"True",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkColorButton","show-editor","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
@ -2099,6 +2105,8 @@
|
||||
("GtkComboBox","popup-fixed-width","gboolean",None,None,None,"True",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkComboBoxText","entry-text-column","gint",None,None,None,"0","-1","2147483647",None,None,None,None,None,None,None,"GtkComboBox",None),
|
||||
("GtkComboBoxText","id-column","gint",None,None,None,"1","-1","2147483647",None,None,None,None,None,None,None,"GtkComboBox",None),
|
||||
("GtkConstantExpression","type","gtype",None,None,None,"GObject",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkConstantExpression","value","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkConstraint","constant","gdouble",None,1,None,"0.0","-1.79769313486232e+308","1.79769313486232e+308",None,None,None,None,None,None,None,None,None),
|
||||
("GtkConstraint","multiplier","gdouble",None,1,None,"1.0","-1.79769313486232e+308","1.79769313486232e+308",None,None,None,None,None,None,None,None,None),
|
||||
("GtkConstraint","relation","GtkConstraintRelation",None,1,None,"eq",None,None,None,None,None,None,None,None,None,None,None),
|
||||
@ -2131,6 +2139,7 @@
|
||||
("GtkDropDown","accessible-role","GtkAccessibleRole",None,None,None,"combo-box",None,None,None,None,None,None,None,None,None,"GtkAccessible",None),
|
||||
("GtkDropDown","css-name","gchararray",None,1,None,"dropdown",None,None,None,None,None,None,None,None,None,"GtkWidget",None),
|
||||
("GtkDropDown","enable-search","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkDropDown","expression","GtkExpression",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkDropDown","factory","GtkListItemFactory",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkDropDown","header-factory","GtkListItemFactory",1,None,None,None,None,None,"4.12",None,None,None,None,None,None,None,None),
|
||||
("GtkDropDown","list-factory","GtkListItemFactory",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
@ -2469,7 +2478,6 @@
|
||||
("GtkMediaStream","loop","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkMediaStream","muted","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkMediaStream","playing","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkMediaStream","prepared","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkMediaStream","volume","gdouble",None,None,None,"1.0","0.0","1.0",None,None,None,None,None,None,None,None,None),
|
||||
("GtkMenuButton","accessible-role","GtkAccessibleRole",None,None,None,"button",None,None,None,None,None,None,None,None,None,"GtkAccessible",None),
|
||||
("GtkMenuButton","active","gboolean",None,None,None,"False",None,None,"4.10",None,None,None,None,None,None,None,None),
|
||||
@ -2522,6 +2530,7 @@
|
||||
("GtkNotebookPage","tab-expand","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkNotebookPage","tab-fill","gboolean",None,None,None,"True",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkNotebookPage","tab-label","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkNumericSorter","expression","GtkExpression",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkNumericSorter","sort-order","GtkSortType",None,None,None,"ascending",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkOrientable","orientation","GtkOrientation",None,None,None,"horizontal",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkOverlay","child","GtkWidget",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
@ -2620,6 +2629,9 @@
|
||||
("GtkProgressBar","pulse-step","gdouble",None,None,None,"0.1","0.0","1.0",None,None,None,None,None,None,None,None,None),
|
||||
("GtkProgressBar","show-text","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkProgressBar","text","gchararray",None,None,None,None,None,None,None,None,1,None,None,None,None,None,None),
|
||||
("GtkPropertyExpression","name","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkPropertyExpression","type","gtype",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkPropertyExpression","value","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkRange","adjustment","GtkAdjustment",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkRange","css-name","gchararray",None,1,None,"range",None,None,None,None,None,None,None,None,None,"GtkWidget",None),
|
||||
("GtkRange","fill-level","gdouble",None,None,None,"1.79769313486232e+308","-1.79769313486232e+308","1.79769313486232e+308",None,None,None,None,None,None,None,None,None),
|
||||
@ -2830,11 +2842,13 @@
|
||||
("GtkStackSwitcher","css-name","gchararray",None,1,None,"stackswitcher",None,None,None,None,None,None,None,None,None,"GtkWidget",None),
|
||||
("GtkStackSwitcher","stack","GtkStack",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkStatusbar","css-name","gchararray",None,1,None,"statusbar",None,None,None,None,None,None,None,None,None,"GtkWidget",None),
|
||||
("GtkStringFilter","expression","GtkExpression",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkStringFilter","ignore-case","gboolean",None,None,None,"True",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkStringFilter","match-mode","GtkStringFilterMatchMode",None,None,None,"substring",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkStringFilter","search","gchararray",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkStringList","strings","GStrv",None,1,None,None,None,None,"4.10",None,None,None,None,None,None,None,None),
|
||||
("GtkStringSorter","collation","GtkCollation",None,None,None,"unicode",None,None,"4.10",None,None,None,None,None,None,None,None),
|
||||
("GtkStringSorter","expression","GtkExpression",1,None,None,None,None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkStringSorter","ignore-case","gboolean",None,None,None,"True",None,None,None,None,None,None,None,None,None,None,None),
|
||||
("GtkSwitch","accessible-role","GtkAccessibleRole",None,None,None,"switch",None,None,None,None,None,None,None,None,None,"GtkAccessible",None),
|
||||
("GtkSwitch","active","gboolean",None,None,None,"False",None,None,None,None,None,None,None,None,None,None,None),
|
||||
|
@ -1,6 +1,6 @@
|
||||
project(
|
||||
'cambalache', 'c',
|
||||
version: '0.97.6',
|
||||
version: '0.97.7',
|
||||
meson_version: '>= 1.1.0',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
|
||||
<cambalache-project version="0.13.1" target_tk="gtk+-3.0">
|
||||
<ui>
|
||||
(1,None,None,"test_0.17.3.ui",None,None,None,None,None,None,None)
|
||||
</ui>
|
||||
<ui_library>
|
||||
(1,"gtk","3.24",None)
|
||||
</ui_library>
|
||||
<object>
|
||||
(1,1,"GtkWindow",None,None,None,None,None,-1,None),
|
||||
(1,2,"GtkButton",None,1,None,None,None,-1,None),
|
||||
</object>
|
||||
<object_property>
|
||||
(1,1,"GtkWindow","title","nice translatable title",1,None,None,None,None,None,None,None,None),
|
||||
(1,2,"GtkButton","label","another tranlatable string",1,None,None,None,None,None,None,None,None),
|
||||
</object_property>
|
||||
<object_signal>
|
||||
(1,1,1,"GtkWindow","activate-default","test_swap",None,None,1,None,None),
|
||||
(2,1,1,"GtkWindow","activate-focus","test_after",None,None,None,1,None)
|
||||
</object_signal>
|
||||
</cambalache-project>
|
@ -1,39 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
|
||||
<cambalache-project version="0.10.3" target_tk="gtk+-3.0">
|
||||
<ui>
|
||||
(1,None,"test_format.ui","test_format.ui",None,None,None,None,None,None)
|
||||
</ui>
|
||||
<object>
|
||||
(1,1,"GtkWindow",None,None,None,None,None,None),
|
||||
(1,2,"GtkGrid",None,1,None,None,None,-1),
|
||||
(1,3,"GtkLabel",None,2,None,None,None,None),
|
||||
(1,4,"GtkEntry",None,2,None,None,None,1),
|
||||
(1,5,"GtkButton",None,2,None,None,None,4),
|
||||
(1,6,"GtkEntryBuffer","abuffer",None,None,None,None,None)
|
||||
</object>
|
||||
<object_property>
|
||||
(1,3,"GtkLabel","label","hello world",None,None,None,None,None),
|
||||
(1,4,"GtkEntry","max-width-chars","21",None,None,None,None,None),
|
||||
(1,4,"GtkEntry","placeholder-text","Hola Mundo",None,None,None,None,None),
|
||||
(1,5,"GtkButton","label","button",None,None,None,None,None),
|
||||
(1,6,"GtkEntryBuffer","text","lorem ipsum",None,None,None,None,None)
|
||||
</object_property>
|
||||
<object_layout_property>
|
||||
(1,2,3,"GtkGridLayoutChild","height","1",None,None,None,None),
|
||||
(1,2,3,"GtkGridLayoutChild","left-attach","0",None,None,None,None),
|
||||
(1,2,3,"GtkGridLayoutChild","top-attach","0",None,None,None,None),
|
||||
(1,2,3,"GtkGridLayoutChild","width","1",None,None,None,None),
|
||||
(1,2,4,"GtkGridLayoutChild","height","1",None,None,None,None),
|
||||
(1,2,4,"GtkGridLayoutChild","left-attach","1",None,None,None,None),
|
||||
(1,2,4,"GtkGridLayoutChild","top-attach","1",None,None,None,None),
|
||||
(1,2,4,"GtkGridLayoutChild","width","1",None,None,None,None),
|
||||
(1,2,5,"GtkGridLayoutChild","height","1",None,None,None,None),
|
||||
(1,2,5,"GtkGridLayoutChild","left-attach","2",None,None,None,None),
|
||||
(1,2,5,"GtkGridLayoutChild","top-attach","2",None,None,None,None),
|
||||
(1,2,5,"GtkGridLayoutChild","width","1",None,None,None,None)
|
||||
</object_layout_property>
|
||||
<object_signal>
|
||||
(1,1,5,"GtkButton","clicked","on_button_clicked",None,None,None,None,None)
|
||||
</object_signal>
|
||||
</cambalache-project>
|
42
tests/gtk-4.0/expression.ui
Normal file
42
tests/gtk-4.0/expression.ui
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.97.6 -->
|
||||
<interface>
|
||||
<!-- interface-name expression.ui -->
|
||||
<requires lib="gio" version="2.0"/>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<object class="GtkWindow" id="win1">
|
||||
<property name="title">Window Title</property>
|
||||
<property name="tooltip-text">hola test</property>
|
||||
</object>
|
||||
<object class="GtkDropDown" id="drop1">
|
||||
<property name="expression">
|
||||
<constant type="gchararray">A simple constant expression</constant>
|
||||
</property>
|
||||
</object>
|
||||
<object class="GtkDropDown" id="drop2">
|
||||
<property name="expression">
|
||||
<lookup name="title" type="GtkWindow">win1</lookup>
|
||||
</property>
|
||||
</object>
|
||||
<object class="GtkDropDown" id="drop3">
|
||||
<property name="expression">
|
||||
<closure function="combine_args_somehow" type="gchararray">
|
||||
<constant type="gchararray">search term: </constant>
|
||||
<lookup name="expression" type="GtkDropDown">drop1</lookup>
|
||||
</closure>
|
||||
</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="win2">
|
||||
<property name="title">Another Window Title</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="win3">
|
||||
<binding name="title">
|
||||
<lookup name="title">win1</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
<object class="GtkWindow" id="win4">
|
||||
<binding name="title" object="win2">
|
||||
<lookup name="title">win1</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</interface>
|
@ -1,19 +1,37 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
|
||||
<cambalache-project version="0.12.0" target_tk="gtk-4.0">
|
||||
<!-- Created with Cambalache 0.96.1 -->
|
||||
<cambalache-project version="0.96.0" target_tk="gtk-4.0">
|
||||
<ui>
|
||||
(1,None,"template_inline_object.ui","template_inline_object.ui",None,None,None,None,None,None,None),
|
||||
(2,1,None,"my-window.ui",None,None,None,None,None,None,None)
|
||||
</ui>
|
||||
<object>
|
||||
(1,1,"MyWindow",None,None,None,None,None,None,None),
|
||||
(2,1,"GtkWindow","MyWindow",None,None,None,None,None,None),
|
||||
(2,2,"GtkBox",None,1,None,None,None,None,None),
|
||||
(2,3,"GtkLabel",None,2,None,None,None,1,None)
|
||||
<requires>MyWindow</requires>
|
||||
<content><![CDATA[<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.96.1 -->
|
||||
<interface>
|
||||
<!-- interface-name template_inline_object.ui -->
|
||||
<requires lib="gtk" version="4.6"/>
|
||||
<object class="MyWindow">
|
||||
<property name="title">This window should have a label inside a inline box as child</property>
|
||||
</object>
|
||||
<object_property>
|
||||
(1,1,"GtkWindow","title","This window should have a label inside a inline box as child",None,None,None,None,None,None,None,None,None),
|
||||
(2,1,"GtkWindow","child",None,None,None,None,None,2,None,None,None,None),
|
||||
(2,3,"GtkLabel","label","a label inside an inline object",None,None,None,None,None,None,None,None,None)
|
||||
</object_property>
|
||||
</interface>
|
||||
]]></content>
|
||||
</ui>
|
||||
<ui template-class="MyWindow">
|
||||
<content><![CDATA[<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Created with Cambalache 0.96.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.6"/>
|
||||
<template class="MyWindow" parent="GtkWindow">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">a label inside an inline object</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></content>
|
||||
</ui>
|
||||
</cambalache-project>
|
||||
|
@ -1,29 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
|
||||
<cambalache-project version="0.13.1" target_tk="gtk-4.0">
|
||||
<ui>
|
||||
(1,None,None,"test_0.17.3.ui",None,None,None,None,None,None,None)
|
||||
</ui>
|
||||
<ui_library>
|
||||
(1,"gtk","4.12",None)
|
||||
</ui_library>
|
||||
<object>
|
||||
(1,1,"GtkWindow",None,None,None,None,None,-1,None),
|
||||
(1,2,"GtkButton",None,1,None,None,None,-1,None),
|
||||
(1,3,"GtkStringList",None,None,None,None,None,-1,None)
|
||||
</object>
|
||||
<object_property>
|
||||
(1,1,"GtkWindow","title","nice translatable title",1,None,None,None,None,None,None,None,None),
|
||||
(1,2,"GtkButton","label","another tranlatable string",1,None,None,None,None,None,None,None,None),
|
||||
(1,3,"GtkStringList","strings","lorem\nipsum",None,None,None,None,None,None,None,None,None)
|
||||
</object_property>
|
||||
<object_signal>
|
||||
(1,1,1,"GtkWindow","activate-default","test_swap",None,None,1,None,None),
|
||||
(2,1,1,"GtkWindow","activate-focus","test_after",None,None,None,1,None)
|
||||
</object_signal>
|
||||
<object_data>
|
||||
(1,1,"GtkWidget",2,2,None,1,None,None,None,None),
|
||||
(1,3,"GtkStringList",1,1,None,None,None,None,None,None),
|
||||
(1,3,"GtkStringList",2,2,"translatable item",1,None,1,None,None)
|
||||
</object_data>
|
||||
</cambalache-project>
|
@ -1,87 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
|
||||
<cambalache-project version="0.10.3" target_tk="gtk-4.0">
|
||||
<ui>
|
||||
(1,1,"main.ui","main.ui",None,None,None,None,None,None)
|
||||
</ui>
|
||||
<object>
|
||||
(1,1,"GtkApplicationWindow","EfibootsMainWindow",None,None,None,None,None),
|
||||
(1,2,"GtkHeaderBar",None,1,None,"titlebar",None,1),
|
||||
(1,3,"GtkBox",None,1,None,None,None,None),
|
||||
(1,4,"GtkButton","refresh_button",2,None,"end",None,None),
|
||||
(1,5,"GtkButton","save_button",2,None,"end",None,None),
|
||||
(1,6,"GtkColumnView","column_view",3,None,None,None,None),
|
||||
(1,7,"GtkBox",None,3,None,None,None,1),
|
||||
(1,8,"GtkBox",None,3,None,None,None,2),
|
||||
(1,9,"GtkButton","up",7,None,None,None,None),
|
||||
(1,10,"GtkButton","down",7,None,None,None,1),
|
||||
(1,11,"GtkButton","add",7,None,None,None,2),
|
||||
(1,12,"GtkButton","remove",7,None,None,None,3),
|
||||
(1,13,"GtkLabel",None,8,None,None,None,None),
|
||||
(1,14,"GtkSpinButton","timeout_spin",8,None,None,None,1),
|
||||
(1,15,"GtkColumnViewColumn","column_current",6,None,None,None,None),
|
||||
(1,16,"GtkColumnViewColumn","column_number",6,None,None,None,1),
|
||||
(1,17,"GtkColumnViewColumn","column_label",6,None,None,None,2),
|
||||
(1,18,"GtkColumnViewColumn","column_path",6,None,None,None,3),
|
||||
(1,20,"GtkColumnViewColumn","column_parameters",6,None,None,None,4),
|
||||
(1,21,"GtkColumnViewColumn","column_active",6,None,None,None,5),
|
||||
(1,22,"GtkColumnViewColumn","column_next",6,None,None,None,6),
|
||||
(1,23,"GtkSortListModel",None,None,None,None,None,None),
|
||||
(1,24,"GtkSorter",None,None,None,None,None,None)
|
||||
</object>
|
||||
<object_property>
|
||||
(1,1,"GtkWindow","default-height","260",None,None,None,None,None),
|
||||
(1,1,"GtkWindow","default-width","300",None,None,None,None,None),
|
||||
(1,3,"GtkBox","spacing","12",None,None,None,None,None),
|
||||
(1,3,"GtkOrientable","orientation","vertical",None,None,None,None,None),
|
||||
(1,3,"GtkWidget","margin-bottom","10",None,None,None,None,None),
|
||||
(1,3,"GtkWidget","margin-end","10",None,None,None,None,None),
|
||||
(1,3,"GtkWidget","margin-start","10",None,None,None,None,None),
|
||||
(1,3,"GtkWidget","margin-top","10",None,None,None,None,None),
|
||||
(1,4,"GtkButton","icon-name","edit-clear-all-symbolic",None,None,None,None,None),
|
||||
(1,4,"GtkWidget","tooltip-text","Reset",None,None,None,None,None),
|
||||
(1,5,"GtkButton","icon-name","document-save-symbolic",None,None,None,None,None),
|
||||
(1,5,"GtkWidget","tooltip-text","Save",None,None,None,None,None),
|
||||
(1,6,"GtkColumnView","show-column-separators","True",None,None,None,None,None),
|
||||
(1,6,"GtkWidget","margin-bottom","10",None,None,None,None,None),
|
||||
(1,7,"GtkBox","homogeneous","True",None,None,None,None,None),
|
||||
(1,7,"GtkWidget","css-classes","linked",None,None,None,None,None),
|
||||
(1,8,"GtkBox","spacing","8",None,None,None,None,None),
|
||||
(1,9,"GtkButton","icon-name","go-up-symbolic",None,None,None,None,None),
|
||||
(1,9,"GtkWidget","tooltip-text","Move up",None,None,None,None,None),
|
||||
(1,10,"GtkButton","icon-name","go-down-symbolic",None,None,None,None,None),
|
||||
(1,10,"GtkWidget","tooltip-text","Move down",None,None,None,None,None),
|
||||
(1,11,"GtkButton","icon-name","list-add-symbolic",None,None,None,None,None),
|
||||
(1,11,"GtkWidget","tooltip-text","Add new entry",None,None,None,None,None),
|
||||
(1,12,"GtkButton","icon-name","list-remove-symbolic",None,None,None,None,None),
|
||||
(1,12,"GtkWidget","tooltip-text","Remove entry",None,None,None,None,None),
|
||||
(1,13,"GtkLabel","label","Boot manager timeout in seconds:",None,None,None,None,None),
|
||||
(1,14,"GtkSpinButton","climb-rate","1.0",None,None,None,None,None),
|
||||
(1,14,"GtkSpinButton","numeric","True",None,None,None,None,None),
|
||||
(1,14,"GtkSpinButton","update-policy","if-valid",None,None,None,None,None),
|
||||
(1,15,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,15,"GtkColumnViewColumn","title","Current",None,None,None,None,None),
|
||||
(1,16,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,16,"GtkColumnViewColumn","title","Number",None,None,None,None,None),
|
||||
(1,17,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,17,"GtkColumnViewColumn","title","Label",None,None,None,None,None),
|
||||
(1,18,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,18,"GtkColumnViewColumn","title","Path",None,None,None,None,None),
|
||||
(1,20,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,20,"GtkColumnViewColumn","title","Parameters",None,None,None,None,None),
|
||||
(1,21,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,21,"GtkColumnViewColumn","title","Active",None,None,None,None,None),
|
||||
(1,22,"GtkColumnViewColumn","resizable","True",None,None,None,None,None),
|
||||
(1,22,"GtkColumnViewColumn","title","Boot Next",None,None,None,None,None)
|
||||
</object_property>
|
||||
<object_signal>
|
||||
(1,1,5,"GtkButton","clicked","on_clicked_save",None,None,None,None,None),
|
||||
(2,1,4,"GtkButton","clicked","on_clicked_reset",None,None,None,None,None),
|
||||
(3,1,9,"GtkButton","clicked","on_clicked_up",None,None,None,None,None),
|
||||
(4,1,10,"GtkButton","clicked","on_clicked_down",None,None,None,None,None),
|
||||
(5,1,11,"GtkButton","clicked","on_clicked_add",None,None,None,None,None),
|
||||
(6,1,12,"GtkButton","clicked","on_clicked_remove",None,None,None,None,None),
|
||||
(7,1,14,"GtkSpinButton","value-changed","on_value_changed_timeout",None,None,None,None,None),
|
||||
(8,1,1,"GtkWindow","close-request","on_close_request",None,None,None,None,None)
|
||||
</object_signal>
|
||||
</cambalache-project>
|
@ -1,33 +0,0 @@
|
||||
#!/usr/bin/pytest
|
||||
|
||||
"""
|
||||
Test Old format loading
|
||||
"""
|
||||
import os
|
||||
|
||||
from cambalache import CmbProject
|
||||
|
||||
basedir = os.path.dirname(__file__)
|
||||
|
||||
|
||||
def migration_test(target, filename):
|
||||
project_path = os.path.join(basedir, target, filename)
|
||||
project = CmbProject(filename=project_path)
|
||||
|
||||
assert project is not None
|
||||
|
||||
|
||||
def test_gtk3_format_0_10_3():
|
||||
migration_test("gtk+-3.0", "test_project_0.10.3.cmb")
|
||||
|
||||
|
||||
def test_gtk4_format_0_10_3():
|
||||
migration_test("gtk-4.0", "test_project_0.10.3.cmb")
|
||||
|
||||
|
||||
def test_gtk3_column_constraint_changes_0_17_3():
|
||||
migration_test("gtk+-3.0", "test_column_constraint_changes_0.17.3.cmb")
|
||||
|
||||
|
||||
def test_gtk4_column_constraint_changes_0_17_3():
|
||||
migration_test("gtk-4.0", "test_column_constraint_changes_0.17.3.cmb")
|
@ -47,7 +47,8 @@ from cambalache import CmbProject, config
|
||||
("gtk-4.0", "menu.ui"),
|
||||
("gtk-4.0", "string_list.ui"),
|
||||
("gtk-4.0", "accessibility.ui"),
|
||||
("gtk-4.0", "ui_comments.ui")
|
||||
("gtk-4.0", "ui_comments.ui"),
|
||||
("gtk-4.0", "expression.ui"),
|
||||
])
|
||||
def test_(target_tk, filename):
|
||||
"""
|
||||
|
@ -76,6 +76,7 @@ class CmbGirData:
|
||||
"GParamGType": "gtype",
|
||||
"GParamBoxed": "boxed",
|
||||
"GParamVariant": "variant",
|
||||
"GtkParamSpecExpression": "object",
|
||||
}
|
||||
|
||||
# GtkBuilder native object types
|
||||
@ -585,6 +586,64 @@ class CmbGirData:
|
||||
)
|
||||
])
|
||||
|
||||
# Add GtkExpression type properties
|
||||
|
||||
# To create a constant expression, use the <constant> element. If the type attribute is specified, the element content
|
||||
# is interpreted as a value of that type. Otherwise, it is assumed to be an object. For instance:
|
||||
#
|
||||
# <constant>string_filter</constant>
|
||||
# <constant type='gchararray'>Hello, world</constant>
|
||||
#
|
||||
self.__add_type("GtkConstantExpression", "GtkExpression", [
|
||||
("type", "gtype", "GObject"),
|
||||
("value", "gchararray", None),
|
||||
])
|
||||
|
||||
# To create a property expression, use the <lookup> element. It can have a type attribute to specify the object type,
|
||||
# and a name attribute to specify the property to look up.
|
||||
# The content of <lookup> can either be a string that specifies the name of the object to use, an element specifying and
|
||||
# expression to provide an object, or empty to use the this object.
|
||||
#
|
||||
# <lookup name='search'>string_filter</lookup>
|
||||
#
|
||||
self.__add_type("GtkPropertyExpression", "GtkExpression", [
|
||||
("type", "gtype", None),
|
||||
("value", "gchararray", None),
|
||||
("name", "gchararray", None),
|
||||
])
|
||||
|
||||
# To create a closure expression, use the <closure> element. The function attribute specifies what function to use for
|
||||
# the closure, and the type attribute specifies its return type.
|
||||
# The content of the element contains the expressions for the parameters. For instance:
|
||||
#
|
||||
# <closure type='gchararray' function='combine_args_somehow'>
|
||||
# <constant type='gchararray'>File size:</constant>
|
||||
# <lookup type='GFile' name='size'>myfile</lookup>
|
||||
# </closure>
|
||||
#
|
||||
self.__add_type("GtkClosureExpression", "GtkExpression", [
|
||||
("type", "gtype", None),
|
||||
("function", "gchararray", None),
|
||||
])
|
||||
|
||||
def __add_type(self, type_name, parent_type, properties):
|
||||
self.types.update({
|
||||
type_name: {
|
||||
"parent": parent_type,
|
||||
"properties": {
|
||||
prop: {
|
||||
"type": type_name,
|
||||
"default_value": default,
|
||||
"is_object": False,
|
||||
"version": None,
|
||||
"deprecated_version": None,
|
||||
"construct": None,
|
||||
"translatable": False,
|
||||
} for (prop, type_name, default) in properties
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def __a11y_add_ifaces_from_enum(self, accessible_ifaces):
|
||||
accessible_types = {}
|
||||
|
||||
@ -727,10 +786,14 @@ class CmbGirData:
|
||||
def _get_type_data(self, element, name, use_instance=True, skip_types=[]):
|
||||
parent = element.get("parent")
|
||||
|
||||
if parent and parent.find(".") < 0:
|
||||
if parent == "Expression" and name not in ["GtkConstantExpression", "GtkPropertyExpression", "GtkClosureExpression"]:
|
||||
return None
|
||||
elif parent and parent.find(".") < 0:
|
||||
parent = self.prefix + parent
|
||||
elif parent is None:
|
||||
parent = "object"
|
||||
elif parent == "GObject.ParamSpec":
|
||||
return None
|
||||
else:
|
||||
parent = self.external_types.get(parent, "GObject")
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user