Skip to content

Commit 78089f8

Browse files
committed
meld.ui: Add a prototype encoding selector
Currently this is UI-only, and doesn't actually change any document encoding stuff.
1 parent cbb3968 commit 78089f8

3 files changed

Lines changed: 209 additions & 0 deletions

File tree

data/ui/encoding-selector.ui

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<interface>
3+
<!-- interface-requires gtk+ 3.8 -->
4+
<object class="GtkListStore" id="liststore">
5+
<columns>
6+
<!-- column-name name -->
7+
<column type="gchararray"/>
8+
<!-- column-name encoding -->
9+
<column type="GtkSourceEncoding"/>
10+
</columns>
11+
</object>
12+
<object class="GtkTreeModelFilter" id="treemodelfilter">
13+
<property name="child_model">liststore</property>
14+
</object>
15+
<template class="EncodingSelector" parent="GtkGrid">
16+
<property name="width_request">300</property>
17+
<property name="height_request">400</property>
18+
<property name="visible">True</property>
19+
<property name="can_focus">False</property>
20+
<property name="has_focus">False</property>
21+
<property name="is_focus">False</property>
22+
<property name="row_spacing">3</property>
23+
<property name="border_width">6</property>
24+
<child>
25+
<object class="GtkSearchEntry" id="entry">
26+
<property name="visible">True</property>
27+
<property name="can_focus">True</property>
28+
<property name="has_focus">True</property>
29+
<property name="is_focus">False</property>
30+
<property name="activates_default">True</property>
31+
<property name="placeholder_text" translatable="yes">Search text encoding...</property>
32+
</object>
33+
<packing>
34+
<property name="left_attach">0</property>
35+
<property name="top_attach">0</property>
36+
<property name="width">1</property>
37+
<property name="height">1</property>
38+
</packing>
39+
</child>
40+
<child>
41+
<object class="GtkScrolledWindow" id="scrolledwindow1">
42+
<property name="visible">True</property>
43+
<property name="can_focus">True</property>
44+
<property name="has_focus">False</property>
45+
<property name="is_focus">False</property>
46+
<property name="hexpand">True</property>
47+
<property name="vexpand">True</property>
48+
<property name="shadow_type">in</property>
49+
<child>
50+
<object class="GtkTreeView" id="treeview">
51+
<property name="visible">True</property>
52+
<property name="can_focus">True</property>
53+
<property name="has_focus">False</property>
54+
<property name="is_focus">False</property>
55+
<property name="model">treemodelfilter</property>
56+
<property name="headers_visible">False</property>
57+
<property name="headers_clickable">False</property>
58+
<property name="enable_search">False</property>
59+
<child internal-child="selection">
60+
<object class="GtkTreeSelection" id="treeview_selection"/>
61+
</child>
62+
<child>
63+
<object class="GtkTreeViewColumn" id="treeviewcolumn">
64+
<child>
65+
<object class="GtkCellRendererText" id="cellrenderertext"/>
66+
<attributes>
67+
<attribute name="text">0</attribute>
68+
</attributes>
69+
</child>
70+
</object>
71+
</child>
72+
</object>
73+
</child>
74+
</object>
75+
<packing>
76+
<property name="left_attach">0</property>
77+
<property name="top_attach">1</property>
78+
<property name="width">1</property>
79+
<property name="height">1</property>
80+
</packing>
81+
</child>
82+
</template>
83+
</interface>

meld/ui/bufferselectors.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
from gi.repository import GLib
3+
from gi.repository import GObject
4+
from gi.repository import Gtk
5+
from gi.repository import GtkSource
6+
7+
from meld.conf import _, ui_file
8+
from meld.ui.listselector import FilteredListSelector
9+
10+
11+
class EncodingSelector(FilteredListSelector, Gtk.Grid):
12+
# The subclassing here is weird; the Selector must directly
13+
# subclass Gtk.Grid, or the template building explodes.
14+
15+
__gtype_name__ = 'EncodingSelector'
16+
17+
__gsignals__ = {
18+
'encoding-selected': (
19+
GObject.SignalFlags.RUN_FIRST | GObject.SignalFlags.ACTION,
20+
None, (GtkSource.Encoding,)),
21+
}
22+
23+
# These exist solely to make subclassing easier.
24+
value_accessor = 'get_charset'
25+
change_signal_name = 'encoding-selected'
26+
27+
def populate_model(self):
28+
for enc in GtkSource.Encoding.get_all():
29+
self.liststore.append((self.get_value_label(enc), enc))
30+
31+
def get_value_label(self, enc):
32+
return _('{name} ({charset})').format(
33+
name=enc.get_name(), charset=enc.get_charset())
34+
35+
36+
template = open(ui_file('encoding-selector.ui'), 'rb').read()
37+
template_bytes = GLib.Bytes.new(template)
38+
EncodingSelector.set_template(template_bytes)

meld/ui/listselector.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
2+
from gi.repository import Gtk
3+
4+
5+
class TemplateHackMixin(object):
6+
7+
def get_template_child(self, widget_type, name):
8+
# Taken from an in-progress patch on bgo#701843
9+
10+
def get_template_child(widget, widget_type, name):
11+
# Explicitly use gtk_buildable_get_name() because it is masked by
12+
# gtk_widget_get_name() in GI.
13+
if isinstance(widget, widget_type) and \
14+
isinstance(widget, Gtk.Buildable) and \
15+
Gtk.Buildable.get_name(widget) == name:
16+
return widget
17+
18+
if isinstance(widget, Gtk.Container):
19+
for child in widget.get_children():
20+
result = get_template_child(child, widget_type, name)
21+
if result is not None:
22+
return result
23+
24+
return get_template_child(self, widget_type, name)
25+
26+
27+
class FilteredListSelector(TemplateHackMixin):
28+
29+
__gtype_name__ = 'FilteredListSelector'
30+
31+
NAME_COLUMN, VALUE_COLUMN = 0, 1
32+
33+
def __init__(self):
34+
Gtk.Grid.__init__(self)
35+
self.init_template()
36+
37+
self.entry = self.get_template_child(Gtk.SearchEntry, 'entry')
38+
self.treeview = self.get_template_child(Gtk.TreeView, 'treeview')
39+
self.treeview_selection = self.treeview.get_selection()
40+
# FIXME: Should be able to access as a template child, but can't.
41+
self.listfilter = self.treeview.get_model()
42+
self.liststore = self.listfilter.get_model()
43+
44+
self.populate_model()
45+
self.filter_string = ''
46+
self.entry.connect('changed', self.on_entry_changed)
47+
self.listfilter.set_visible_func(self.name_filter)
48+
49+
self.entry.connect('activate', self.on_activate)
50+
self.treeview.connect('row-activated', self.on_activate)
51+
52+
def populate_model(self):
53+
raise NotImplementedError
54+
55+
def select_value(self, value):
56+
if not value:
57+
return
58+
59+
new_value_getter = getattr(value, self.value_accessor)
60+
for row in self.liststore:
61+
row_value = row[self.VALUE_COLUMN]
62+
if not row_value:
63+
continue
64+
old_value_getter = getattr(row_value, self.value_accessor)
65+
if old_value_getter() != new_value_getter():
66+
continue
67+
self.treeview_selection.select_path(row.path)
68+
self.treeview.scroll_to_cell(row.path, None, True, 0.5, 0)
69+
70+
def name_filter(self, model, it, *args):
71+
if not self.filter_string:
72+
return True
73+
name = model.get_value(it, self.NAME_COLUMN).lower()
74+
return self.filter_string.lower() in name
75+
76+
def on_entry_changed(self, entry):
77+
self.filter_string = entry.get_text()
78+
self.listfilter.refilter()
79+
first = self.listfilter.get_iter_first()
80+
if first:
81+
self.treeview_selection.select_iter(first)
82+
83+
def on_activate(self, *args):
84+
model, it = self.treeview_selection.get_selected()
85+
if not it:
86+
return
87+
value = model.get_value(it, self.VALUE_COLUMN)
88+
self.emit(self.change_signal_name, value)

0 commit comments

Comments
 (0)