diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2018-07-09 12:10:38 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2018-07-09 12:10:38 +0200 |
commit | 709e2d6f5652ec90c194a4ec2b530bebc6f952cb (patch) | |
tree | 496b2f3899e1d5728ee9ae76095cc5056c317447 /src/dialogs/EntryMultiCompletion.vala | |
parent | f1353e9ffd34db5f755c7da0b3f9c10638fbfd38 (diff) | |
parent | 5c8be07095cc04a6d8a95204b0504fd7ab030154 (diff) |
Merge branch 'release/0.28.3-1'0.28.3-1
Diffstat (limited to 'src/dialogs/EntryMultiCompletion.vala')
-rw-r--r-- | src/dialogs/EntryMultiCompletion.vala | 97 |
1 files changed, 97 insertions, 0 deletions
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 ""; + } + } +} |