[polari/nick-completion] mainWindow: Implement nick completion



commit d6d564cfee19eef2ef65727386c33361ed96d087
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Aug 8 17:06:56 2013 +0200

    mainWindow: Implement nick completion
    
    Add simple tab completion that presents matching nicks in a popup
    (or inserts the matched nick directly in case of a single match).
    We should add some smarts about the order in which matches are
    presented in the future, but for now having basic functionality
    in place is still better than nothing ...

 src/mainWindow.js |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 79 insertions(+), 0 deletions(-)
---
diff --git a/src/mainWindow.js b/src/mainWindow.js
index d784922..dbefff5 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -2,6 +2,7 @@ const Gdk = imports.gi.Gdk;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Gtk = imports.gi.Gtk;
+const Pango = imports.gi.Pango;
 const Tp = imports.gi.TelepathyGLib;
 
 const AccountsMonitor = imports.accountsMonitor;
@@ -93,6 +94,15 @@ const MainWindow = new Lang.Class({
                 this._ircParser.process(this._entry.text);
                 this._entry.text = '';
             }));
+        this._entry.connect_after('key-press-event', Lang.bind(this,
+            function(w, event) {
+                let [, keyval] = event.get_keyval();
+                if (keyval == Gdk.KEY_Tab) {
+                    this._completeNick(event.get_time());
+                    return true;
+                }
+                return false;
+            }));
 
         this._nickEntry.connect('activate', Lang.bind(this,
             function() {
@@ -293,6 +303,75 @@ const MainWindow = new Lang.Class({
         this._userListStack.set_visible_child_name(this._room.id);
     },
 
+    _insertCompletion: function(nick) {
+        let pos = this._entry.get_position();
+        let text = this._entry.text.substr(0, pos);
+        let wordPos = text.lastIndexOf(' ') + 1;
+        this._entry.delete_text(wordPos, pos);
+        this._entry.insert_text(nick, -1, wordPos);
+        this._entry.set_position(wordPos + nick.length);
+    },
+
+    _positionPopup: function(menu) {
+        let win = this._entry.get_window();
+        let monitor = this._entry.get_screen().get_monitor_at_window(win);
+        menu.set_monitor(monitor);
+
+        let layout = this._entry.get_layout();
+        let text = this._entry.text.substr(0, this._entry.get_position());
+        let wordIndex = text.lastIndexOf(' ') + 1;
+        let layoutIndex = this._entry.text_index_to_layout_index(wordIndex);
+        let wordPos = layout.index_to_pos(layoutIndex);
+        let [layoutX,] = this._entry.get_layout_offsets();
+
+        let allocation = this._entry.get_allocation();
+        let [ret, x, y] = win.get_origin();
+        x += allocation.x + (layoutX + wordPos.x) / Pango.SCALE;
+        y += allocation.y - menu.get_allocated_height();
+
+        return [x, y, false]
+    },
+
+    _popupCompletions: function(nicks, time) {
+        let menu = new Gtk.Menu({ attach_widget: this._entry, visible: true });
+
+        for (let i = 0; i < nicks.length; i++) {
+            let item = new Gtk.MenuItem({ label: nicks[i], visible: true });
+            item.connect('activate', Lang.bind(this,
+                function(item) {
+                    this._insertCompletion(item.label);
+                }));
+            menu.append(item);
+        }
+        menu.select_first(false);
+        menu.popup(null, null, Lang.bind(this, this._positionPopup), 0, time);
+    },
+
+    _completeNick: function(time) {
+       if (!this._room ||
+           !this._room.channel.has_interface(Tp.IFACE_CHANNEL_INTERFACE_GROUP))
+           return;
+
+        let text = this._entry.text.substr(0, this._entry.get_position());
+        let wordPos = text.lastIndexOf(' ') + 1;
+        let key = text.substr(wordPos);
+        if (!key.length)
+            return;
+
+        let members = this._room.channel.group_dup_members_contacts();
+        let nicks = members.map(function(member) { return member.alias; });
+        let matches = nicks.filter(function(nick) {
+            return nick.startsWith(key);
+        });
+
+        if (matches.length == 0)
+            return;
+        else if (matches.length == 1)
+            this._insertCompletion(matches[0]);
+        else
+            this._popupCompletions(matches, time);
+    },
+
     _setNick: function(nick) {
         this._nickEntry.placeholder_text = nick;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]