[shotwell] Extract TextEntry dialog
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [shotwell] Extract TextEntry dialog
- Date: Wed, 20 Dec 2017 21:49:44 +0000 (UTC)
commit 70215a717702713711332f9270255d4f8edd455c
Author: Jens Georg <mail jensge org>
Date: Wed Dec 20 16:40:55 2017 +0100
Extract TextEntry dialog
org.gnome.Shotwell.gresource.xml | 1 +
src/Dialogs.vala | 166 ---------------------------------
src/dialogs/EntryMultiCompletion.vala | 97 +++++++++++++++++++
src/dialogs/TextEntry.vala | 68 +++++++++++++
src/meson.build | 2 +
ui/shotwell.ui | 36 -------
ui/textentrydialog.ui | 104 ++++++++++++++++++++
7 files changed, 272 insertions(+), 202 deletions(-)
---
diff --git a/org.gnome.Shotwell.gresource.xml b/org.gnome.Shotwell.gresource.xml
index d68f8e6..3d432fc 100644
--- a/org.gnome.Shotwell.gresource.xml
+++ b/org.gnome.Shotwell.gresource.xml
@@ -26,6 +26,7 @@
<file preprocess="xml-stripblanks">ui/slideshow_settings.ui</file>
<file preprocess="xml-stripblanks">ui/tag_sidebar_context.ui</file>
<file preprocess="xml-stripblanks">ui/tags.ui</file>
+ <file preprocess="xml-stripblanks">ui/textentrydialog.ui</file>
<file preprocess="xml-stripblanks">ui/trash.ui</file>
<!-- Icons -->
<file>icons/about-aachen.jpg</file>
diff --git a/src/Dialogs.vala b/src/Dialogs.vala
index 21954e2..80c4fc0 100644
--- a/src/Dialogs.vala
+++ b/src/Dialogs.vala
@@ -939,10 +939,7 @@ public abstract class TextEntryDialogMediator {
public TextEntryDialogMediator(string title, string label, string? initial_text = null,
Gee.Collection<string>? completion_list = null, string? completion_delimiter = null) {
- Gtk.Builder builder = AppWindow.create_builder();
dialog = new TextEntryDialog();
- dialog.get_content_area().add((Gtk.Box) builder.get_object("dialog-vbox2"));
- dialog.set_builder(builder);
dialog.setup(on_modify_validate, title, label, initial_text, completion_list, completion_delimiter);
}
@@ -989,170 +986,7 @@ public string build_alert_body_text(string? primary_text, string? secondary_text
guarded_markup_escape_text(primary_text), secondary_text);
}
-// Entry completion for values separated by separators (e.g. comma in the case of tags)
-// Partly inspired by the class of the same name in gtkmm-utils by Marko Anastasov
-public class EntryMultiCompletion : Gtk.EntryCompletion {
- private string delimiter;
-
- public EntryMultiCompletion(Gee.Collection<string> completion_list, string? delimiter) {
- assert(delimiter == null || delimiter.length == 1);
- this.delimiter = delimiter;
-
- set_model(create_completion_store(completion_list));
- set_text_column(0);
- set_match_func(match_func);
- }
-
- private static Gtk.ListStore create_completion_store(Gee.Collection<string> completion_list) {
- Gtk.ListStore completion_store = new Gtk.ListStore(1, typeof(string));
- Gtk.TreeIter store_iter;
- Gee.Iterator<string> completion_iter = completion_list.iterator();
- while (completion_iter.next()) {
- completion_store.append(out store_iter);
- completion_store.set(store_iter, 0, completion_iter.get(), -1);
- }
-
- return completion_store;
- }
-
- private bool match_func(Gtk.EntryCompletion completion, string key, Gtk.TreeIter iter) {
- Gtk.TreeModel model = completion.get_model();
- string possible_match;
- model.get(iter, 0, out possible_match);
-
- // Normalize key and possible matches to allow comparison of non-ASCII characters.
- // Use a "COMPOSE" normalization to allow comparison to the position value returned by
- // Gtk.Entry, i.e. one character=one position. Using the default normalization a character
- // like "é" or "ö" would have a length of two.
- possible_match = possible_match.casefold().normalize(-1, NormalizeMode.ALL_COMPOSE);
- string normed_key = key.normalize(-1, NormalizeMode.ALL_COMPOSE);
-
- if (delimiter == null) {
- return possible_match.has_prefix(normed_key.strip());
- } else {
- if (normed_key.contains(delimiter)) {
- // check whether cursor is before last delimiter
- int offset = normed_key.char_count(normed_key.last_index_of_char(delimiter[0]));
- int position = ((Gtk.Entry) get_entry()).get_position();
- if (position <= offset)
- return false; // TODO: Autocompletion for tags not last in list
- }
-
- string last_part = get_last_part(normed_key.strip(), delimiter);
-
- if (last_part.length == 0)
- return false; // need at least one character to show matches
-
- return possible_match.has_prefix(last_part.strip());
- }
- }
- public override bool match_selected(Gtk.TreeModel model, Gtk.TreeIter iter) {
- string match;
- model.get(iter, 0, out match);
-
- Gtk.Entry entry = (Gtk.Entry)get_entry();
-
- string old_text = entry.get_text().normalize(-1, NormalizeMode.ALL_COMPOSE);
- if (old_text.length > 0) {
- if (old_text.contains(delimiter)) {
- old_text = old_text.substring(0, old_text.last_index_of_char(delimiter[0]) + 1) + (delimiter
!= " " ? " " : "");
- } else
- old_text = "";
- }
-
- string new_text = old_text + match + delimiter + (delimiter != " " ? " " : "");
- entry.set_text(new_text);
- entry.set_position((int) new_text.length);
-
- return true;
- }
-
- // Find last string after any delimiter
- private static string get_last_part(string s, string delimiter) {
- string[] split = s.split(delimiter);
-
- if((split != null) && (split[0] != null)) {
- return split[split.length - 1];
- } else {
- return "";
- }
- }
-}
-
-
-
-
-
-public class TextEntryDialog : Gtk.Dialog {
- public delegate bool OnModifyValidateType(string text);
-
- private unowned OnModifyValidateType on_modify_validate;
- private Gtk.Entry entry;
- private Gtk.Builder builder;
- private Gtk.Button button1;
- private Gtk.Button button2;
-
- public TextEntryDialog() {
- bool use_header;
- Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
- Object (use_header_bar: use_header ? 1 : 0);
- }
-
- public void set_builder(Gtk.Builder builder) {
- this.builder = builder;
- }
-
- public void setup(OnModifyValidateType? modify_validate, string title, string label,
- string? initial_text, Gee.Collection<string>? completion_list, string? completion_delimiter) {
- set_title(title);
- set_resizable(true);
- set_parent_window(AppWindow.get_instance().get_parent_window());
- set_transient_for(AppWindow.get_instance());
- on_modify_validate = modify_validate;
-
- Gtk.Label name_label = builder.get_object("label") as Gtk.Label;
- name_label.set_text(label);
-
- entry = builder.get_object("entry") as Gtk.Entry;
- entry.set_text(initial_text != null ? initial_text : "");
- entry.grab_focus();
- entry.changed.connect(on_entry_changed);
-
- button1 = (Gtk.Button) add_button(Resources.CANCEL_LABEL, Gtk.ResponseType.CANCEL);
- button2 = (Gtk.Button) add_button(Resources.SAVE_LABEL, Gtk.ResponseType.OK);
- set_default_response(Gtk.ResponseType.OK);
-
- if (completion_list != null) { // Textfield with autocompletion
- EntryMultiCompletion completion = new EntryMultiCompletion(completion_list,
- completion_delimiter);
- entry.set_completion(completion);
- }
-
- set_default_response(Gtk.ResponseType.OK);
- }
-
- public string? execute() {
- string? text = null;
-
- // validate entry to start with
- set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
-
- show_all();
-
- if (run() == Gtk.ResponseType.OK)
- text = entry.get_text();
-
- entry.changed.disconnect(on_entry_changed);
- destroy();
-
- return text;
- }
-
- public void on_entry_changed() {
- set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
- }
-}
public class MultiTextEntryDialog : Gtk.Dialog {
public delegate bool OnModifyValidateType(string text);
diff --git a/src/dialogs/EntryMultiCompletion.vala b/src/dialogs/EntryMultiCompletion.vala
new file mode 100644
index 0000000..8700f21
--- /dev/null
+++ b/src/dialogs/EntryMultiCompletion.vala
@@ -0,0 +1,97 @@
+/* Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2017 Jens Georg <mail jensge org>
+ *
+ * This software is licensed under the GNU LGPL (version 2.1 or later).
+ * See the COPYING file in this distribution.
+ */
+
+// Entry completion for values separated by separators (e.g. comma in the case of tags)
+// Partly inspired by the class of the same name in gtkmm-utils by Marko Anastasov
+public class EntryMultiCompletion : Gtk.EntryCompletion {
+ private string delimiter;
+
+ public EntryMultiCompletion(Gee.Collection<string> completion_list, string? delimiter) {
+ assert(delimiter == null || delimiter.length == 1);
+ this.delimiter = delimiter;
+
+ set_model(create_completion_store(completion_list));
+ set_text_column(0);
+ set_match_func(match_func);
+ }
+
+ private static Gtk.ListStore create_completion_store(Gee.Collection<string> completion_list) {
+ Gtk.ListStore completion_store = new Gtk.ListStore(1, typeof(string));
+ Gtk.TreeIter store_iter;
+ Gee.Iterator<string> completion_iter = completion_list.iterator();
+ while (completion_iter.next()) {
+ completion_store.append(out store_iter);
+ completion_store.set(store_iter, 0, completion_iter.get(), -1);
+ }
+
+ return completion_store;
+ }
+
+ private bool match_func(Gtk.EntryCompletion completion, string key, Gtk.TreeIter iter) {
+ Gtk.TreeModel model = completion.get_model();
+ string possible_match;
+ model.get(iter, 0, out possible_match);
+
+ // Normalize key and possible matches to allow comparison of non-ASCII characters.
+ // Use a "COMPOSE" normalization to allow comparison to the position value returned by
+ // Gtk.Entry, i.e. one character=one position. Using the default normalization a character
+ // like "é" or "ö" would have a length of two.
+ possible_match = possible_match.casefold().normalize(-1, NormalizeMode.ALL_COMPOSE);
+ string normed_key = key.normalize(-1, NormalizeMode.ALL_COMPOSE);
+
+ if (delimiter == null) {
+ return possible_match.has_prefix(normed_key.strip());
+ } else {
+ if (normed_key.contains(delimiter)) {
+ // check whether cursor is before last delimiter
+ int offset = normed_key.char_count(normed_key.last_index_of_char(delimiter[0]));
+ int position = ((Gtk.Entry) get_entry()).get_position();
+ if (position <= offset)
+ return false; // TODO: Autocompletion for tags not last in list
+ }
+
+ string last_part = get_last_part(normed_key.strip(), delimiter);
+
+ if (last_part.length == 0)
+ return false; // need at least one character to show matches
+
+ return possible_match.has_prefix(last_part.strip());
+ }
+ }
+
+ public override bool match_selected(Gtk.TreeModel model, Gtk.TreeIter iter) {
+ string match;
+ model.get(iter, 0, out match);
+
+ Gtk.Entry entry = (Gtk.Entry)get_entry();
+
+ string old_text = entry.get_text().normalize(-1, NormalizeMode.ALL_COMPOSE);
+ if (old_text.length > 0) {
+ if (old_text.contains(delimiter)) {
+ old_text = old_text.substring(0, old_text.last_index_of_char(delimiter[0]) + 1) + (delimiter
!= " " ? " " : "");
+ } else
+ old_text = "";
+ }
+
+ string new_text = old_text + match + delimiter + (delimiter != " " ? " " : "");
+ entry.set_text(new_text);
+ entry.set_position((int) new_text.length);
+
+ return true;
+ }
+
+ // Find last string after any delimiter
+ private static string get_last_part(string s, string delimiter) {
+ string[] split = s.split(delimiter);
+
+ if((split != null) && (split[0] != null)) {
+ return split[split.length - 1];
+ } else {
+ return "";
+ }
+ }
+}
diff --git a/src/dialogs/TextEntry.vala b/src/dialogs/TextEntry.vala
new file mode 100644
index 0000000..a133b66
--- /dev/null
+++ b/src/dialogs/TextEntry.vala
@@ -0,0 +1,68 @@
+/* Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2017 Jens Georg <mail jensge org>
+ *
+ * This software is licensed under the GNU LGPL (version 2.1 or later).
+ * See the COPYING file in this distribution.
+ */
+
+[GtkTemplate (ui = "/org/gnome/Shotwell/ui/textentrydialog.ui")]
+public class TextEntryDialog : Gtk.Dialog {
+ public delegate bool OnModifyValidateType(string text);
+
+ private unowned OnModifyValidateType on_modify_validate;
+
+ [GtkChild]
+ private Gtk.Entry entry;
+
+ [GtkChild]
+ private Gtk.Label label;
+
+ public TextEntryDialog() {
+ bool use_header;
+ Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header);
+ Object (use_header_bar: use_header ? 1 : 0);
+ }
+
+ public void setup(OnModifyValidateType? modify_validate, string title, string label,
+ string? initial_text, Gee.Collection<string>? completion_list, string? completion_delimiter) {
+ set_title(title);
+ set_parent_window(AppWindow.get_instance().get_parent_window());
+ set_transient_for(AppWindow.get_instance());
+ on_modify_validate = modify_validate;
+
+ this.label.set_text(label);
+
+ entry.set_text(initial_text != null ? initial_text : "");
+ entry.grab_focus();
+ entry.changed.connect(on_entry_changed);
+
+ if (completion_list != null) { // Textfield with autocompletion
+ EntryMultiCompletion completion = new EntryMultiCompletion(completion_list,
+ completion_delimiter);
+ entry.set_completion(completion);
+ }
+
+ set_default_response(Gtk.ResponseType.OK);
+ }
+
+ public string? execute() {
+ string? text = null;
+
+ // validate entry to start with
+ set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
+
+ show_all();
+
+ if (run() == Gtk.ResponseType.OK)
+ text = entry.get_text();
+
+ entry.changed.disconnect(on_entry_changed);
+ destroy();
+
+ return text;
+ }
+
+ public void on_entry_changed() {
+ set_response_sensitive(Gtk.ResponseType.OK, on_modify_validate(entry.get_text()));
+ }
+}
diff --git a/src/meson.build b/src/meson.build
index 6911cd5..d539586 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -192,8 +192,10 @@ executable('shotwell',
'MediaViewTracker.vala',
'UnityProgressBar.vala',
'Upgrades.vala',
+ 'dialogs/EntryMultiCompletion.vala',
'dialogs/SetBackgroundSlideshow.vala',
'dialogs/SetBackground.vala',
+ 'dialogs/TextEntry.vala',
'.unitize/_UnitInternals.vala',
'.unitize/_UtilInternals.vala',
'.unitize/_ThreadsInternals.vala',
diff --git a/ui/shotwell.ui b/ui/shotwell.ui
index 7eb7efe..332f3db 100644
--- a/ui/shotwell.ui
+++ b/ui/shotwell.ui
@@ -170,34 +170,6 @@
</packing>
</child>
</object>
- <object class="GtkBox" id="dialog-vbox2">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="border_width">3</property>
- <property name="orientation">vertical</property>
- <property name="spacing">3</property>
- <child>
- <object class="GtkLabel" id="label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">label</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">●</property>
- <property name="activates_default">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
@@ -231,14 +203,6 @@
</object>
<packing>
<property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
<object class="GtkBox" id="plugin-manifest">
<property name="visible">True</property>
<property name="can_focus">False</property>
diff --git a/ui/textentrydialog.ui b/ui/textentrydialog.ui
new file mode 100644
index 0000000..6a2dc78
--- /dev/null
+++ b/ui/textentrydialog.ui
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="shotwell">
+ <requires lib="gtk+" version="3.18"/>
+ <template class="TextEntryDialog" parent="GtkDialog">
+ <property name="can_focus">False</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label" translatable="yes">_Save</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">3</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">label</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button1</action-widget>
+ <action-widget response="-5">button2</action-widget>
+ </action-widgets>
+ </template>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]