Commit e0d70141 authored by Kai Willadsen's avatar Kai Willadsen

preferences: Migrate list widgets to templates and resource loading

This is a big commit because the old separation between the
ListWidget class and the actually-used subclasses was kind of wild.

Now, EditableListWidget is much simpler and exists mostly to handle
sensitivity setting and simple treemodel manipulation. Everything else
lives on the actual list widgets themselves, which are now real widgets
that do nice, normal GObject property things.
parent 1d7275e6
......@@ -10,6 +10,14 @@
padding: 3px 2px 2px 2px;
}
.prefs-list-widget-toolbar {
background-image: none;
background-color: @theme_bg_color;
border-width: 0 1px 1px 1px;
border-style: solid;
border-color: @borders;
}
link-map {
border-width: 0 0 1px 0;
border-style: solid;
......
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="ColumnsListStore">
<columns>
<!-- column-name Active -->
<column type="gboolean"/>
<!-- column-name ID -->
<column type="gchararray"/>
<!-- column-name Label -->
<column type="gchararray"/>
</columns>
<signal name="row-inserted" handler="_update_sensitivity" swapped="no"/>
<signal name="rows-reordered" handler="_update_sensitivity" swapped="no"/>
</object>
<object class="GtkWindow" id="ColumnsListWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Editable List</property>
<child>
<object class="GtkAlignment" id="columns_ta">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkVBox" id="columns_tab">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="columns_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">ColumnsListStore</property>
<property name="headers_clickable">False</property>
<property name="reorderable">True</property>
<property name="search_column">0</property>
<property name="show_expanders">False</property>
<property name="rubber_banding">True</property>
<child>
<object class="GtkTreeViewColumn" id="active_column">
<property name="title" translatable="yes">Active</property>
<child>
<object class="GtkCellRendererToggle" id="cr_active">
<signal name="toggled" handler="on_cellrenderertoggle_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="active">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="name_column">
<property name="title" translatable="yes">Column Name</property>
<child>
<object class="GtkCellRendererText" id="cr_name"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="list_toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<property name="icon_size_set">True</property>
<child>
<object class="GtkToolButton" id="add">
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Add</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add</property>
<signal name="clicked" handler="on_add_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="remove">
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Remove</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove</property>
<signal name="clicked" handler="on_remove_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="up_down_sep">
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="move_up">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Move item up</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Move _Up</property>
<property name="use_underline">True</property>
<property name="icon_name">go-up</property>
<signal name="clicked" handler="on_move_up_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="move_down">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Move item down</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Move _Down</property>
<property name="use_underline">True</property>
<property name="icon_name">go-down</property>
<signal name="clicked" handler="on_move_down_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkListStore" id="EditableListStore">
<columns>
<!-- column-name Name -->
<column type="gchararray"/>
<!-- column-name Active -->
<column type="gboolean"/>
<!-- column-name Pattern -->
<column type="gchararray"/>
<!-- column-name ValidPattern -->
<column type="gboolean"/>
</columns>
<signal name="row-inserted" handler="_update_sensitivity" swapped="no"/>
<signal name="rows-reordered" handler="_update_sensitivity" swapped="no"/>
</object>
<object class="GtkWindow" id="EditableListWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Editable List</property>
<child>
<object class="GtkVBox" id="list_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="EditableList">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">EditableListStore</property>
<property name="headers_clickable">False</property>
<property name="reorderable">True</property>
<property name="search_column">0</property>
<property name="show_expanders">False</property>
<property name="rubber_banding">True</property>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
<property name="title" translatable="yes">Active</property>
<child>
<object class="GtkCellRendererToggle" id="cellrenderertoggle1">
<signal name="toggled" handler="on_cellrenderertoggle_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="activatable">3</attribute>
<attribute name="active">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn2">
<property name="title" translatable="yes">Name</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1">
<property name="editable">True</property>
<signal name="edited" handler="on_name_edited" swapped="no"/>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="pattern_column">
<property name="title" translatable="yes">Pattern</property>
<child>
<object class="GtkCellRendererPixbuf" id="validity_renderer">
<property name="width">16</property>
<property name="height">16</property>
</object>
</child>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2">
<property name="editable">True</property>
<signal name="edited" handler="on_pattern_edited" swapped="no"/>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="list_toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<property name="icon_size_set">True</property>
<child>
<object class="GtkToolButton" id="add">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Add new filter</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Add</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add</property>
<signal name="clicked" handler="on_add_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="remove">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Remove selected filter</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Remove</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove</property>
<signal name="clicked" handler="on_remove_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="up_down_sep">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="move_up">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Move item up</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Move _Up</property>
<property name="use_underline">True</property>
<property name="icon_name">go-up</property>
<signal name="clicked" handler="on_move_up_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="move_down">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Move item down</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Move _Down</property>
<property name="use_underline">True</property>
<property name="icon_name">go-down</property>
<signal name="clicked" handler="on_move_down_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
......@@ -23,25 +23,54 @@ from gi.repository import GtkSource
from meld.conf import _
from meld.filters import FilterEntry
from meld.settings import settings
from meld.ui._gtktemplate import Template
from meld.ui.gnomeglade import Component
from meld.ui.listwidget import ListWidget
class FilterList(ListWidget):
def __init__(self, key, filter_type):
default_entry = [_("label"), False, _("pattern"), True]
super().__init__(
"EditableList.ui", "list_vbox", ["EditableListStore"],
"EditableList", default_entry)
self.key = key
self.filter_type = filter_type
from meld.ui.listwidget import EditableListWidget
@Template(resource_path='/org/gnome/meld/ui/filter-list.ui')
class FilterList(Gtk.VBox, EditableListWidget):
__gtype_name__ = "FilterList"
treeview = Template.Child("treeview")
remove = Template.Child("remove")
move_up = Template.Child("move_up")
move_down = Template.Child("move_down")
pattern_column = Template.Child("pattern_column")
validity_renderer = Template.Child("validity_renderer")
default_entry = [_("label"), False, _("pattern"), True]
filter_type = GObject.Property(
type=int,
flags=(
GObject.ParamFlags.READABLE |
GObject.ParamFlags.WRITABLE |
GObject.ParamFlags.CONSTRUCT_ONLY
),
)
settings_key = GObject.Property(
type=str,
flags=(
GObject.ParamFlags.READABLE |
GObject.ParamFlags.WRITABLE |
GObject.ParamFlags.CONSTRUCT_ONLY
),
)
def __init__(self, **kwargs):
super().__init__(self, **kwargs)
FilterList.init_template(self)
self.model = self.treeview.get_model()
self.pattern_column.set_cell_data_func(
self.validity_renderer, self.valid_icon_celldata)
for filter_params in settings.get_value(self.key):
filt = FilterEntry.new_from_gsetting(filter_params, filter_type)
for filter_params in settings.get_value(self.settings_key):
filt = FilterEntry.new_from_gsetting(
filter_params, self.filter_type)
if filt is None:
continue
valid = filt.filter is not None
......@@ -52,19 +81,38 @@ class FilterList(ListWidget):
'rows-reordered'):
self.model.connect(signal, self._update_filter_string)
self._update_sensitivity()
self.setup_sensitivity_handling()
def valid_icon_celldata(self, col, cell, model, it, user_data=None):
is_valid = model.get_value(it, 3)
icon_name = "gtk-dialog-warning" if not is_valid else None
cell.set_property("stock-id", icon_name)
@Template.Callback()
def on_add_clicked(self, button):
self.add_entry()
@Template.Callback()
def on_remove_clicked(self, button):
self.remove_selected_entry()
@Template.Callback()
def on_move_up_clicked(self, button):
self.move_up_selected_entry()
@Template.Callback()
def on_move_down_clicked(self, button):
self.move_down_selected_entry()
@Template.Callback()
def on_name_edited(self, ren, path, text):
self.model[path][0] = text
@Template.Callback()
def on_cellrenderertoggle_toggled(self, ren, path):
self.model[path][1] = not ren.get_active()
@Template.Callback()
def on_pattern_edited(self, ren, path, text):
valid = FilterEntry.check_filter(text, self.filter_type)
self.model[path][2] = text
......@@ -72,10 +120,20 @@ class FilterList(ListWidget):
def _update_filter_string(self, *args):
value = [(row[0], row[1], row[2]) for row in self.model]
settings.set_value(self.key, GLib.Variant('a(sbs)', value))
settings.set_value(self.settings_key, GLib.Variant('a(sbs)', value))
class ColumnList(ListWidget):
@Template(resource_path='/org/gnome/meld/ui/column-list.ui')
class ColumnList(Gtk.VBox, EditableListWidget):
__gtype_name__ = "ColumnList"
treeview = Template.Child("treeview")
remove = Template.Child("remove")
move_up = Template.Child("move_up")
move_down = Template.Child("move_down")
default_entry = [_("label"), False, _("pattern"), True]
available_columns = {
"size": _("Size"),
......@@ -83,14 +141,24 @@ class ColumnList(ListWidget):
"permissions": _("Permissions"),
}
def __init__(self, key):
super().__init__(
"EditableList.ui", "columns_ta", ["ColumnsListStore"],
"columns_treeview")
self.key = key
settings_key = GObject.Property(
type=str,
flags=(
GObject.ParamFlags.READABLE |
GObject.ParamFlags.WRITABLE |
GObject.ParamFlags.CONSTRUCT_ONLY
),
)
def __init__(self, **kwargs):
super().__init__(self, **kwargs)
ColumnList.init_template(self)
self.model = self.treeview.get_model()
# Unwrap the variant
prefs_columns = [(k, v) for k, v in settings.get_value(self.key)]
prefs_columns = [
(k, v) for k, v in settings.get_value(self.settings_key)
]
column_vis = {}
column_order = {}
for sort_key, (column_name, visibility) in enumerate(prefs_columns):
......@@ -110,14 +178,23 @@ class ColumnList(ListWidget):
'rows-reordered'):
self.model.connect(signal, self._update_columns)
self._update_sensitivity()
self.setup_sensitivity_handling()
@Template.Callback()
def on_move_up_clicked(self, button):
self.move_up_selected_entry()
@Template.Callback()
def on_move_down_clicked(self, button):
self.move_down_selected_entry()
@Template.Callback()
def on_cellrenderertoggle_toggled(self, ren, path):
self.model[path][0] = not ren.get_active()
def _update_columns(self, *args):
value = [(c[1].lower(), c[0]) for c in self.model]
settings.set_value(self.key, GLib.Variant('a(sb)', value))
settings.set_value(self.settings_key, GLib.Variant('a(sb)', value))
class GSettingsComboBox(Gtk.ComboBox):
......@@ -237,14 +314,20 @@ class PreferencesDialog(Component):
self.checkbutton_wrap_text.set_active(wrap_mode != Gtk.WrapMode.NONE)
self.checkbutton_wrap_word.set_active(wrap_mode == Gtk.WrapMode.WORD)
filefilter = FilterList("filename-filters", FilterEntry.SHELL)
self.file_filters_vbox.pack_start(filefilter.widget, True, True, 0)
filefilter = FilterList(
filter_type=FilterEntry.SHELL,
settings_key="filename-filters",
)
self.file_filters_vbox.pack_start(filefilter, True, True, 0)
textfilter = FilterList("text-filters", FilterEntry.REGEX)
self.text_filters_vbox.pack_start(textfilter.widget, True, True, 0)
textfilter = FilterList(
filter_type=FilterEntry.REGEX,
settings_key="text-filters",
)
self.text_filters_vbox.pack_start(textfilter, True, True, 0)
columnlist = ColumnList("folder-columns")
self.column_list_vbox.pack_start(columnlist.widget, True, True, 0)
columnlist = ColumnList(settings_key="folder-columns")
self.column_list_vbox.pack_start(columnlist, True, True, 0)
self.combo_timestamp.bind_to('folder-time-resolution')
self.combo_file_order.bind_to('vc-left-is-local')
......
......@@ -9,8 +9,10 @@
<file>icons/16x16/actions/meld-change-delete.png</file>
<file>ui/about-dialog.ui</file>
<file>ui/appwindow.ui</file>
<file>ui/column-list.ui</file>
<file>ui/commit-dialog.ui</file>
<file>ui/encoding-selector.ui</file>
<file>ui/filter-list.ui</file>
<file>ui/language-selector.ui</file>
<file>ui/patch-dialog.ui</file>
<file>ui/push-dialog.ui</file>
......
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkListStore" id="column_list_store">
<columns>
<!-- column-name Active -->
<column type="gboolean"/>
<!-- column-name ID -->
<column type="gchararray"/>
<!-- column-name Label -->
<column type="gchararray"/>
</columns>
</object>
<template class="ColumnList" parent="GtkVBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">column_list_store</property>
<property name="headers_clickable">False</property>
<property name="reorderable">True</property>
<property name="search_column">0</property>
<property name="show_expanders">False</property>
<property name="rubber_banding">True</property>
<child>
<object class="GtkTreeViewColumn" id="active_column">
<property name="title" translatable="yes">Active</property>
<child>
<object class="GtkCellRendererToggle" id="cr_active">
<signal name="toggled" handler="on_cellrenderertoggle_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="active">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="name_column">
<property name="title" translatable="yes">Column Name</property>
<child>
<object class="GtkCellRendererText" id="cr_name"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="list_toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<property name="icon_size_set">True</property>
<style>
<class name="prefs-list-widget-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="add">
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Add</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add</property>
<signal name="clicked" handler="on_add_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="remove">
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Remove</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove</property>
<signal name="clicked" handler="on_remove_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="up_down_sep">
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="move_up">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Move item up</property>
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Move _Up</property>
<property name="use_underline">True</property>
<property name="icon_name">go-up</property>
<signal name="clicked" handler="on_move_up_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>