summaryrefslogtreecommitdiff
path: root/src/plugins/ManifestWidget.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/ManifestWidget.vala')
-rw-r--r--src/plugins/ManifestWidget.vala412
1 files changed, 187 insertions, 225 deletions
diff --git a/src/plugins/ManifestWidget.vala b/src/plugins/ManifestWidget.vala
index 8fb0ba2..55ccdc3 100644
--- a/src/plugins/ManifestWidget.vala
+++ b/src/plugins/ManifestWidget.vala
@@ -10,10 +10,7 @@ namespace Plugins {
[GtkTemplate (ui = "/org/gnome/Shotwell/ui/manifest_widget.ui")]
public class ManifestWidgetMediator : Gtk.Box {
[GtkChild]
- private Gtk.Button about_button;
-
- [GtkChild]
- private Gtk.ScrolledWindow list_bin;
+ private unowned Gtk.ScrolledWindow list_bin;
private ManifestListView list = new ManifestListView();
@@ -21,247 +18,212 @@ public class ManifestWidgetMediator : Gtk.Box {
Object();
list_bin.add(list);
-
- about_button.clicked.connect(on_about);
- list.get_selection().changed.connect(on_selection_changed);
-
- set_about_button_sensitivity();
+ }
+}
+
+private class CollectionModel<G> : GLib.ListModel, Object {
+ private Gee.Collection<G> target;
+ private unowned Gee.List<G>? as_list = null;
+
+ public CollectionModel(Gee.Collection<G> target) {
+ Object();
+ this.target = target.read_only_view;
+ if (this.target is Gee.List) {
+ this.as_list = (Gee.List<G>)this.target;
+ }
}
-
- private void on_about() {
- string[] ids = list.get_selected_ids();
- if (ids.length == 0)
- return;
-
- string id = ids[0];
-
- Spit.PluggableInfo info = Spit.PluggableInfo();
- if (!get_pluggable_info(id, ref info)) {
- warning("Unable to retrieve information for plugin %s", id);
-
- return;
+
+ GLib.Object? get_item(uint position) {
+ if (position >= this.target.size) {
+ return null;
}
-
- // prepare authors names (which are comma-delimited by the plugin) for the about box
- // (which wants an array of names)
- string[]? authors = null;
- if (info.authors != null) {
- string[] split = info.authors.split(",");
- for (int ctr = 0; ctr < split.length; ctr++) {
- string stripped = split[ctr].strip();
- if (!is_string_empty(stripped)) {
- if (authors == null)
- authors = new string[0];
-
- authors += stripped;
- }
+
+ if (this.as_list != null) {
+ return (GLib.Object) this.as_list.@get((int) position);
+ }
+
+ var count = 0U;
+ foreach (var g in this.target) {
+ if (count == position) {
+ return (GLib.Object)g;
}
+ count++;
}
-
- Gtk.AboutDialog about_dialog = new Gtk.AboutDialog();
- about_dialog.authors = authors;
- about_dialog.comments = info.brief_description;
- about_dialog.copyright = info.copyright;
- about_dialog.license = info.license;
- about_dialog.wrap_license = info.is_license_wordwrapped;
- about_dialog.logo = (info.icons != null && info.icons.length > 0) ? info.icons[0] :
- Resources.get_icon(Resources.ICON_GENERIC_PLUGIN);
- about_dialog.program_name = get_pluggable_name(id);
- about_dialog.translator_credits = info.translators;
- about_dialog.version = info.version;
- about_dialog.website = info.website_url;
- about_dialog.website_label = info.website_name;
-
- about_dialog.run();
-
- about_dialog.destroy();
+
+ return null;
}
-
- private void on_selection_changed() {
- set_about_button_sensitivity();
+
+ GLib.Type get_item_type() {
+ return typeof(G);
}
-
- private void set_about_button_sensitivity() {
- // have to get the array and then get its length rather than do so in one call due to a
- // bug in Vala 0.10:
- // list.get_selected_ids().length -> uninitialized value
- // this appears to be fixed in Vala 0.11
- string[] ids = list.get_selected_ids();
- about_button.sensitive = (ids.length == 1);
+
+ uint get_n_items() {
+ return this.target.size;
}
+
}
-private class ManifestListView : Gtk.TreeView {
- private const int ICON_SIZE = 24;
- private const int ICON_X_PADDING = 6;
- private const int ICON_Y_PADDING = 2;
-
- private enum Column {
- ENABLED,
- CAN_ENABLE,
- ICON,
- NAME,
- ID,
- N_COLUMNS
+private class Selection : Object {
+ public signal void changed();
+}
+
+private class PluggableRow : Gtk.Box {
+ public Spit.Pluggable pluggable { get; construct; }
+ public bool enabled {get; construct; }
+
+ public PluggableRow(Spit.Pluggable pluggable_, bool enable_) {
+ Object(orientation: Gtk.Orientation.VERTICAL, pluggable: pluggable_,
+ enabled: enable_, margin_top: 6, margin_bottom:6, margin_start:6, margin_end:6);
}
-
- private Gtk.TreeStore store = new Gtk.TreeStore(Column.N_COLUMNS,
- typeof(bool), // ENABLED
- typeof(bool), // CAN_ENABLE
- typeof(Gdk.Pixbuf), // ICON
- typeof(string), // NAME
- typeof(string) // ID
- );
-
- public ManifestListView() {
- set_model(store);
-
- Gtk.CellRendererToggle checkbox_renderer = new Gtk.CellRendererToggle();
- checkbox_renderer.radio = false;
- checkbox_renderer.activatable = true;
-
- Gtk.CellRendererPixbuf icon_renderer = new Gtk.CellRendererPixbuf();
- icon_renderer.stock_size = Gtk.IconSize.MENU;
- icon_renderer.xpad = ICON_X_PADDING;
- icon_renderer.ypad = ICON_Y_PADDING;
-
- Gtk.CellRendererText text_renderer = new Gtk.CellRendererText();
-
- Gtk.TreeViewColumn column = new Gtk.TreeViewColumn();
- column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE);
- column.pack_start(checkbox_renderer, false);
- column.pack_start(icon_renderer, false);
- column.pack_end(text_renderer, true);
-
- column.add_attribute(checkbox_renderer, "active", Column.ENABLED);
- column.add_attribute(checkbox_renderer, "visible", Column.CAN_ENABLE);
- column.add_attribute(icon_renderer, "pixbuf", Column.ICON);
- column.add_attribute(text_renderer, "text", Column.NAME);
-
- append_column(column);
+
+ public override void constructed() {
+ base.constructed();
+ var content = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
+ pack_start(content, true);
+
+ var revealer = new Gtk.Revealer();
+ revealer.margin_top = 6;
+ pack_end(revealer, true);
- set_headers_visible(false);
- set_enable_search(false);
- set_show_expanders(true);
- set_reorderable(false);
- set_enable_tree_lines(false);
- set_grid_lines(Gtk.TreeViewGridLines.NONE);
- get_selection().set_mode(Gtk.SelectionMode.BROWSE);
+ var info = pluggable.get_info();
- Gtk.IconTheme icon_theme = Resources.get_icon_theme_engine();
+ var image = new Gtk.Image.from_icon_name(info.icon_name, Gtk.IconSize.BUTTON);
+ content.pack_start(image, false, false, 6);
+ image.hexpand = false;
+
+ var label = new Gtk.Label(pluggable.get_pluggable_name());
+ label.halign = Gtk.Align.START;
+ content.pack_start(label, true, true, 6);
+
+ var button = new Gtk.ToggleButton();
+ button.get_style_context().add_class("flat");
+ content.pack_end(button, false, false, 6);
+ button.bind_property("active", revealer, "reveal-child", BindingFlags.DEFAULT);
+ image = new Gtk.Image.from_icon_name("go-down-symbolic", Gtk.IconSize.SMALL_TOOLBAR);
+ button.add(image);
+
+ var plugin_enabled = new Gtk.Switch();
+ plugin_enabled.hexpand = false;
+ plugin_enabled.vexpand = false;
+ plugin_enabled.valign = Gtk.Align.CENTER;
+ plugin_enabled.set_active(enabled);
+
+ content.pack_end(plugin_enabled, false, false, 6);
+ plugin_enabled.notify["active"].connect(() => {
+ var id = pluggable.get_id();
+ set_pluggable_enabled(id, plugin_enabled.active);
+ });
+
+ if (pluggable is Spit.Publishing.Service) {
+#if 0
+ var manage = new Gtk.Button.from_icon_name("avatar-default-symbolic", Gtk.IconSize.SMALL_TOOLBAR);
+ manage.get_style_context().add_class("flat");
+ // TRANSLATORS: %s is the name of an online service such as YouTube, Mastodon, ...
+ manage.set_tooltip_text(_("Manage accounts for %s").printf(pluggable.get_pluggable_name()));
+ content.pack_start(manage, false, false, 6);
+#endif
+ }
+
+ var grid = new Gtk.Grid();
+ grid.get_style_context().add_class("content");
+ grid.set_row_spacing(12);
+ grid.set_column_spacing(6);
+ revealer.add(grid);
+ label = new Gtk.Label(info.copyright);
+ label.hexpand = true;
+ label.halign = Gtk.Align.START;
+ grid.attach(label, 0, 0, 2, 1);
+ label = new Gtk.Label(_("Authors"));
+ label.get_style_context().add_class("dim-label");
+ label.halign = Gtk.Align.END;
+ label.margin_start = 12;
+ grid.attach(label, 0, 1, 1, 1);
+ label = new Gtk.Label(info.authors);
+ label.halign = Gtk.Align.START;
+ label.hexpand = true;
+ grid.attach(label, 1, 1, 1, 1);
+
+ label = new Gtk.Label(_("Version"));
+ label.get_style_context().add_class("dim-label");
+ label.halign = Gtk.Align.END;
+ label.margin_start = 12;
+ grid.attach(label, 0, 2, 1, 1);
+ label = new Gtk.Label(info.version);
+ label.halign = Gtk.Align.START;
+ label.hexpand = true;
+ grid.attach(label, 1, 2, 1, 1);
+
+ label = new Gtk.Label(_("License"));
+ label.get_style_context().add_class("dim-label");
+ label.halign = Gtk.Align.END;
+ label.margin_start = 12;
+ grid.attach(label, 0, 3, 1, 1);
+ var link = new Gtk.LinkButton.with_label(info.license_url, info.license_blurp);
+ link.halign = Gtk.Align.START;
+ // remove the annoying padding around the link
+ link.get_style_context().remove_class("text-button");
+ link.get_style_context().add_class("shotwell-plain-link");
+ grid.attach(link, 1, 3, 1, 1);
+
+ label = new Gtk.Label(_("Website"));
+ label.get_style_context().add_class("dim-label");
+ label.halign = Gtk.Align.END;
+ label.margin_start = 12;
+ grid.attach(label, 0, 4, 1, 1);
+ link = new Gtk.LinkButton.with_label(info.website_url, info.website_name);
+ link.halign = Gtk.Align.START;
+ // remove the annoying padding around the link
+ link.get_style_context().remove_class("text-button");
+ link.get_style_context().add_class("shotwell-plain-link");
+ grid.attach(link, 1, 4, 1, 1);
- // create a list of plugins (sorted by name) that are separated by extension points (sorted
- // by name)
- foreach (ExtensionPoint extension_point in get_extension_points(compare_extension_point_names)) {
- Gtk.TreeIter category_iter;
- store.append(out category_iter, null);
-
- Gdk.Pixbuf? icon = null;
- if (extension_point.icon_name != null) {
- Gtk.IconInfo? icon_info = icon_theme.lookup_by_gicon(
- new ThemedIcon(extension_point.icon_name), ICON_SIZE, 0);
- if (icon_info != null) {
- try {
- icon = icon_info.load_icon();
- } catch (Error err) {
- warning("Unable to load icon %s: %s", extension_point.icon_name, err.message);
- }
- }
- }
-
- store.set(category_iter, Column.NAME, extension_point.name, Column.CAN_ENABLE, false,
- Column.ICON, icon);
-
- Gee.Collection<Spit.Pluggable> pluggables = get_pluggables_for_type(
- extension_point.pluggable_type, compare_pluggable_names, true);
- foreach (Spit.Pluggable pluggable in pluggables) {
+ }
+}
+
+private class ManifestListView : Gtk.Box {
+ public ManifestListView() {
+ Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6);
+ }
+
+ public signal void row_selected(Spit.Pluggable? pluggable);
+
+ public override void constructed() {
+ base.constructed();
+
+ foreach (var extension_point in get_extension_points(compare_extension_point_names)) {
+ var label = new Gtk.Label(null);
+ label.set_markup("<span weight=\"bold\">%s</span>".printf(extension_point.name));
+ label.halign = Gtk.Align.START;
+ label.hexpand = true;
+ add(label);
+
+ var pluggables = get_pluggables_for_type(extension_point.pluggable_type, compare_pluggable_names, true);
+ var box = new Gtk.ListBox();
+ box.set_selection_mode(Gtk.SelectionMode.NONE);
+ box.hexpand = true;
+ box.margin_start = 12;
+ box.margin_end = 12;
+
+ var added = 0;
+ foreach (var pluggable in pluggables) {
bool enabled;
+
if (!get_pluggable_enabled(pluggable.get_id(), out enabled))
continue;
-
- Spit.PluggableInfo info = Spit.PluggableInfo();
- pluggable.get_info(ref info);
-
- icon = (info.icons != null && info.icons.length > 0)
- ? info.icons[0]
- : Resources.get_icon(Resources.ICON_GENERIC_PLUGIN, ICON_SIZE);
-
- Gtk.TreeIter plugin_iter;
- store.append(out plugin_iter, category_iter);
-
- store.set(plugin_iter, Column.ENABLED, enabled, Column.NAME, pluggable.get_pluggable_name(),
- Column.ID, pluggable.get_id(), Column.CAN_ENABLE, true, Column.ICON, icon);
+
+ var pluggable_row = new PluggableRow(pluggable, enabled);
+
+ added++;
+ box.insert(pluggable_row, -1);
+ }
+ if (added > 0) {
+ add(box);
}
}
-
- expand_all();
- }
-
- public string[] get_selected_ids() {
- string[] ids = new string[0];
-
- List<Gtk.TreePath> selected = get_selection().get_selected_rows(null);
- foreach (Gtk.TreePath path in selected) {
- Gtk.TreeIter iter;
- string? id = get_id_at_path(path, out iter);
- if (id != null)
- ids += id;
- }
-
- return ids;
- }
-
- private string? get_id_at_path(Gtk.TreePath path, out Gtk.TreeIter iter) {
- if (!store.get_iter(out iter, path))
- return null;
-
- unowned string id;
- store.get(iter, Column.ID, out id);
-
- return id;
- }
- // Because we want each row to left-align and not for each column to line up in a grid
- // (otherwise the checkboxes -- hidden or not -- would cause the rest of the row to line up
- // along the icon's left edge), we put all the renderers into a single column. However, the
- // checkbox renderer then triggers its "toggle" signal any time the row is single-clicked,
- // whether or not the actual checkbox hit-tests.
- //
- // The only way found to work around this is to capture the button-down event and do our own
- // hit-testing.
- public override bool button_press_event(Gdk.EventButton event) {
- Gtk.TreePath path;
- Gtk.TreeViewColumn col;
- int cellx;
- int celly;
- if (!get_path_at_pos((int) event.x, (int) event.y, out path, out col, out cellx,
- out celly))
- return base.button_press_event(event);
-
- // Perform custom hit testing as described above. The first cell in the column is offset
- // from the left edge by whatever size the group description icon is allocated (including
- // padding).
- if (cellx < (ICON_SIZE + ICON_X_PADDING) || cellx > (2 * (ICON_X_PADDING + ICON_SIZE)))
- return base.button_press_event(event);
-
- Gtk.TreeIter iter;
- string? id = get_id_at_path(path, out iter);
- if (id == null)
- return base.button_press_event(event);
-
- bool enabled;
- if (!get_pluggable_enabled(id, out enabled))
- return base.button_press_event(event);
-
- // toggle and set
- enabled = !enabled;
- set_pluggable_enabled(id, enabled);
-
- store.set(iter, Column.ENABLED, enabled);
-
- return true;
+ show_all();
}
-}
+}
}