summaryrefslogtreecommitdiff
path: root/core/completion.vala
blob: f8b90f5779104e4a357e24e63c078ad648fe39c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 Copyright (C) 2012-2018 Christian Dywan <christian@twotoasts.de>

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 See the file COPYING for the full license text.
*/

namespace Midori {
    public class SuggestionItem : DatabaseItem {
        public string? search { get; protected set; }

        SuggestionItem (string uri, string? title) {
            base (uri, title, 0);
        }

        public SuggestionItem.for_input (string uri, string? title) {
            base (uri, title, 0);
            this.search = uri;
        }
    }

    public interface CompletionActivatable : Peas.ExtensionBase {
        public abstract Completion completion { owned get; set; }
        public abstract void activate ();
    }

    public class Completion : Object, ListModel {
        List<ListModel> models = new List<ListModel> ();
        public bool incognito { get; construct set; default = false; }
        public string? key { get; set; default = null; }

        construct {
            var model = new ListStore (typeof (DatabaseItem));
            var settings = CoreSettings.get_default ();
            model.append (new SuggestionItem.for_input (settings.location_entry_search, _("_Search the Web")));
            models.append (model);

            try {
                add (HistoryDatabase.get_default (incognito));
            } catch (DatabaseError error) {
                debug ("Failed to initialize completion model: %s", error.message);
            }

            var extensions = Plugins.get_default ().plug<CompletionActivatable> ("completion", this);
            extensions.extension_added.connect ((info, extension) => ((CompletionActivatable)extension).activate ());
            extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); });
        }

        public Completion (bool incognito) {
            Object (incognito: incognito);
        }

        /*
         * Add a model to complete from. Items need to be based on DatabaseItem
         * and filtered by key if set.
         */
        public void add (ListModel model) {
            if (model is Database) {
                bind_property ("key", model, "key");
            }
            model.items_changed.connect (model_changed);
            models.append (model);
        }

        void model_changed (ListModel model, uint position, uint removed, uint added) {
            uint index = 0;
            foreach (var other in models) {
                if (model == other) {
                    items_changed (position + index, removed, added);
                    break;
                }
                index += other.get_n_items ();
            }
        }

        public Type get_item_type () {
            return typeof (DatabaseItem);
        }

        public Object? get_item (uint position) {
            uint index = 0;
            foreach (var model in models) {
                uint count = model.get_n_items ();
                if (position < index + count) {
                    return model.get_item (position - index);
                }
                index += count;
            }
            return null;
        }

        public uint get_n_items () {
            uint count = 0;
            foreach (var model in models) {
                count += model.get_n_items ();
            }
            return count;
        }
    }
}