~ricotz/valide/valide-svgicons

« back to all changes in this revision

Viewing changes to plugins/completion/valencia-provider/valencia/gtk_util.vala

  • Committer: gege2061
  • Date: 2010-09-03 21:40:48 UTC
  • Revision ID: svn-v4:35bcdfa6-b98f-11dd-bba1-afcbec1a1e1f:trunk:687
Use Afrodite for completion

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2009-2010 Yorba Foundation
 
2
 *
 
3
 * This software is licensed under the GNU Lesser General Public License
 
4
 * (version 2.1 or later).  See the COPYING file in this distribution. 
 
5
 */
 
6
 
 
7
using Gee;
 
8
 
 
9
////////////////////////////////////////////////////////////
 
10
//                    Helper functions                    //
 
11
////////////////////////////////////////////////////////////
 
12
 
 
13
Gtk.TextIter get_insert_iter(Gtk.TextBuffer buffer) {
 
14
    Gtk.TextIter iter;
 
15
    buffer.get_iter_at_mark(out iter, buffer.get_insert());
 
16
    return iter;
 
17
}
 
18
 
 
19
void get_line_start_end(Gtk.TextIter iter, out Gtk.TextIter start, out Gtk.TextIter end) {
 
20
    start = iter;
 
21
    start.set_line_offset(0);
 
22
    end = iter;
 
23
    end.forward_line();
 
24
}
 
25
 
 
26
void append_with_tag(Gtk.TextBuffer buffer, string text, Gtk.TextTag? tag) {
 
27
    Gtk.TextIter end;
 
28
    buffer.get_end_iter(out end);
 
29
    if (tag != null)
 
30
        buffer.insert_with_tags(end, text, -1, tag);
 
31
    else
 
32
        buffer.insert(end, text, -1);
 
33
}
 
34
 
 
35
void append(Gtk.TextBuffer buffer, string text) {
 
36
    append_with_tag(buffer, text, null);
 
37
}
 
38
 
 
39
Gtk.TextIter iter_at_line_offset(Gtk.TextBuffer buffer, int line, int offset) {
 
40
    // We must be careful: TextBuffer.get_iter_at_line_offset() will crash if we give it an
 
41
    // offset greater than the length of the line.
 
42
    Gtk.TextIter iter;
 
43
    buffer.get_iter_at_line(out iter, line);
 
44
    int len = iter.get_chars_in_line() - 1;     // subtract 1 for \n
 
45
    if (len < 0)    // no \n was present, e.g. in an empty file
 
46
        len = 0;
 
47
    int end = int.min(len, offset);
 
48
    Gtk.TextIter ret;
 
49
    buffer.get_iter_at_line_offset(out ret, line, end);
 
50
    return ret;
 
51
}
 
52
 
 
53
unowned string buffer_contents(Gtk.TextBuffer buffer) {
 
54
    Gtk.TextIter start;
 
55
    Gtk.TextIter end;
 
56
    buffer.get_bounds(out start, out end);
 
57
    return buffer.get_text(start, end, true);
 
58
}
 
59
 
 
60
Gtk.MenuItem get_menu_item(Gtk.UIManager manager, string path) {
 
61
    Gtk.MenuItem item = (Gtk.MenuItem) manager.get_widget(path);
 
62
    assert(item != null);
 
63
    return item;
 
64
}
 
65
 
 
66
public void show_error_dialog(string message) {
 
67
    Gtk.MessageDialog err_dialog = new Gtk.MessageDialog(null, Gtk.DialogFlags.MODAL, 
 
68
                                                Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, 
 
69
                                                message, null);
 
70
    err_dialog.set_title("Error");
 
71
    err_dialog.run(); 
 
72
    err_dialog.destroy(); 
 
73
}
 
74
 
 
75
string get_full_line_from_text_iter(Gtk.TextIter iter) {
 
76
    // Move the iterator back to the beginning of its line
 
77
    iter.backward_chars(iter.get_line_offset());
 
78
    // Get an iterator at the end of the line
 
79
    Gtk.TextIter end = iter;
 
80
    end.forward_line();
 
81
    
 
82
    return iter.get_text(end);
 
83
}
 
84
 
 
85
void get_coords_at_buffer_offset(Gedit.Window window, int offset, bool above, bool beside,
 
86
                                 out int x, out int y) {
 
87
    Gedit.Document buffer = window.get_active_document();
 
88
    Gtk.TextIter method_iter;
 
89
    buffer.get_iter_at_offset(out method_iter, offset);
 
90
    
 
91
    Gedit.View active_view = window.get_active_view();
 
92
    Gdk.Rectangle rect;
 
93
    active_view.get_iter_location(method_iter, out rect);
 
94
    int win_x, win_y;
 
95
    active_view.buffer_to_window_coords(Gtk.TextWindowType.WIDGET, rect.x, rect.y, 
 
96
                                        out win_x, out win_y);
 
97
    int widget_x = active_view.allocation.x;
 
98
    int widget_y = active_view.allocation.y; 
 
99
    int orig_x, orig_y;
 
100
    window.window.get_origin(out orig_x, out orig_y);
 
101
 
 
102
    x = win_x + widget_x + orig_x;
 
103
    y = win_y + widget_y + orig_y;
 
104
    x += beside ? rect.height : 0; 
 
105
    y -= above ? rect.height : 0;
 
106
}
 
107
 
 
108
////////////////////////////////////////////////////////////
 
109
//                        Classes                         //
 
110
////////////////////////////////////////////////////////////
 
111
 
 
112
class Tooltip {
 
113
    weak Gedit.Window parent;
 
114
    Gtk.Window window;
 
115
    Gtk.Label tip_text;
 
116
    Gtk.TextMark method_mark;
 
117
    string method_name;
 
118
    bool visible;
 
119
 
 
120
    public Tooltip(Gedit.Window parent_win) {
 
121
        parent = parent_win;
 
122
        visible = false;
 
123
        tip_text = new Gtk.Label("");
 
124
        window = new Gtk.Window(Gtk.WindowType.POPUP);
 
125
        
 
126
        window.add(tip_text);
 
127
        window.set_default_size(1, 1);
 
128
        window.set_transient_for(parent);
 
129
        window.set_destroy_with_parent(true);
 
130
        
 
131
        Gdk.Color background;
 
132
        Gdk.Color.parse("#FFFF99", out background);
 
133
        window.modify_bg(Gtk.StateType.NORMAL, background);
 
134
    }
 
135
 
 
136
    public void show(string qualified_method_name, string prototype, int method_pos) {
 
137
        method_name = qualified_method_name;
 
138
        visible = true;
 
139
 
 
140
        Gedit.Document document = parent.get_active_document();
 
141
        Gtk.TextIter method_iter;
 
142
        document.get_iter_at_offset(out method_iter, method_pos);
 
143
        method_mark = document.create_mark(null, method_iter, true);
 
144
        tip_text.set_text(prototype);
 
145
 
 
146
        int x, y;
 
147
        get_coords_at_buffer_offset(parent, method_pos, true, false, out x, out y);
 
148
        window.move(x, y);
 
149
        window.resize(1, 1);
 
150
        window.show_all();
 
151
    }
 
152
 
 
153
    public void hide() {
 
154
        if (!visible)
 
155
            return;
 
156
 
 
157
        assert(!method_mark.get_deleted());
 
158
        Gtk.TextBuffer doc = method_mark.get_buffer();
 
159
        doc.delete_mark(method_mark);
 
160
        
 
161
        visible = false;
 
162
        window.hide_all();
 
163
    }
 
164
    
 
165
    public bool is_visible() {
 
166
        return visible;
 
167
    }
 
168
    
 
169
    public string get_method_line() {
 
170
        assert(!method_mark.get_deleted());
 
171
        Gtk.TextBuffer doc = method_mark.get_buffer();
 
172
        Gtk.TextIter iter;
 
173
        doc.get_iter_at_mark(out iter, method_mark);
 
174
        return get_full_line_from_text_iter(iter);
 
175
    }
 
176
 
 
177
    public Gtk.TextIter get_iter_at_method() {
 
178
        assert(!method_mark.get_deleted());
 
179
        Gtk.TextBuffer doc = method_mark.get_buffer();
 
180
        Gtk.TextIter iter;
 
181
        doc.get_iter_at_mark(out iter, method_mark);
 
182
        return iter;
 
183
    }
 
184
    
 
185
    public string get_method_name() {
 
186
        return method_name;
 
187
    }
 
188
}
 
189
 
 
190
class ProgressBarDialog : Gtk.Window {
 
191
    Gtk.ProgressBar bar;
 
192
 
 
193
    public ProgressBarDialog(Gtk.Window parent_win, string text) {
 
194
        bar = new Gtk.ProgressBar();
 
195
        Gtk.VBox vbox = new Gtk.VBox(true, 0);
 
196
        Gtk.HBox hbox = new Gtk.HBox(true, 0);
 
197
 
 
198
        bar.set_text(text);
 
199
        bar.set_size_request(226, 25);
 
200
        set_size_request(250, 49);
 
201
 
 
202
        vbox.pack_start(bar, true, false, 0);
 
203
        hbox.pack_start(vbox, true, false, 0);   
 
204
        add(hbox);
 
205
        set_title(text);
 
206
 
 
207
        set_resizable(false);
 
208
        set_transient_for(parent_win);
 
209
        set_position(Gtk.WindowPosition.CENTER_ON_PARENT);
 
210
        set_modal(true);
 
211
        show_all();
 
212
    }
 
213
    
 
214
    public void set_percentage(double percent) {
 
215
        bar.set_fraction(percent);
 
216
    }
 
217
    
 
218
    public void close() {
 
219
        hide();
 
220
    }
 
221
}
 
222
 
 
223
class SignalConnection : Object {
 
224
    public class SignalIDPair {
 
225
        public weak Object object;
 
226
        public ulong id;
 
227
        
 
228
        public SignalIDPair(Object object, ulong id) {
 
229
            this.object = object;
 
230
            this.id = id;
 
231
        }
 
232
    }
 
233
 
 
234
    public weak Object base_instance;
 
235
    ArrayList<SignalIDPair> instance_signal_id_pair;
 
236
 
 
237
    public SignalConnection(Object base_instance) {
 
238
        this.base_instance = base_instance;
 
239
        instance_signal_id_pair = new ArrayList<SignalIDPair>();
 
240
    }
 
241
 
 
242
    ~SignalConnection() {
 
243
        foreach (SignalIDPair pair in instance_signal_id_pair) {
 
244
            if (SignalHandler.is_connected(pair.object, pair.id))
 
245
                SignalHandler.disconnect(pair.object, pair.id);
 
246
        }
 
247
    }
 
248
 
 
249
    public void add_signal(Object instance, string signal_name, Callback cb, void *data,
 
250
                           bool after = false) {
 
251
        ulong id;
 
252
        if (after)
 
253
            id = Signal.connect_after(instance, signal_name, cb, data);
 
254
        else id = Signal.connect(instance, signal_name, cb, data);
 
255
        instance_signal_id_pair.add(new SignalIDPair(instance, id));
 
256
    }
 
257
}
 
258
 
 
259
class ListViewString : Object {
 
260
    Gtk.ListStore list;
 
261
    Gtk.TreeView treeview;
 
262
    Gtk.TreeViewColumn column_view;
 
263
    public Gtk.ScrolledWindow scrolled_window;
 
264
    
 
265
    public signal void row_activated();
 
266
    public signal void received_focus(Gtk.TreePath? path);
 
267
 
 
268
    public ListViewString(Gtk.TreeViewColumnSizing sizing, int fixed_width) {
 
269
        list = new Gtk.ListStore(1, GLib.Type.from_name("gchararray"));
 
270
 
 
271
        Gtk.CellRendererText renderer = new Gtk.CellRendererText();
 
272
        if (sizing == Gtk.TreeViewColumnSizing.FIXED)
 
273
            renderer.ellipsize = Pango.EllipsizeMode.END;
 
274
        column_view = new Gtk.TreeViewColumn();
 
275
        column_view.pack_start(renderer, true); 
 
276
        column_view.set_sizing(sizing);
 
277
        column_view.set_fixed_width(fixed_width);
 
278
        column_view.set_attributes(renderer, "text", 0, null);
 
279
        treeview = new Gtk.TreeView.with_model(list);
 
280
        treeview.append_column(column_view);
 
281
        treeview.headers_visible = false;
 
282
        treeview.focus_in_event.connect(on_received_focus);
 
283
 
 
284
        scrolled_window = new Gtk.ScrolledWindow(null, null); 
 
285
        scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
 
286
        scrolled_window.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
 
287
        scrolled_window.add(treeview);
 
288
        
 
289
        Signal.connect(treeview, "row-activated", (Callback) row_activated_callback, this);
 
290
    }
 
291
    
 
292
    bool on_received_focus() {
 
293
        Gtk.TreePath? path = get_path_at_cursor();
 
294
        received_focus(path);
 
295
        return false;
 
296
    }
 
297
    
 
298
    static void row_activated_callback(Gtk.TreeView view, Gtk.TreePath path, 
 
299
                                       Gtk.TreeViewColumn column, ListViewString list) {
 
300
        list.row_activated();
 
301
    }
 
302
    
 
303
    public void clear() {
 
304
        list.clear();
 
305
    }
 
306
    
 
307
    public void append(string item) {
 
308
        Gtk.TreeIter iterator;
 
309
        list.append(out iterator);
 
310
        list.set(iterator, 0, item, -1);
 
311
    }
 
312
    
 
313
    public int size() {
 
314
        return list.iter_n_children(null);
 
315
    }
 
316
    
 
317
    public void set_vscrollbar_policy(Gtk.PolicyType policy) {
 
318
        scrolled_window.vscrollbar_policy = policy;
 
319
    }
 
320
 
 
321
    /////////////////////////////////
 
322
    // Treeview selection movement //
 
323
    /////////////////////////////////
 
324
 
 
325
    void select(Gtk.TreePath path, bool scroll = true) {
 
326
        treeview.set_cursor(path, null, false);
 
327
        if (scroll)
 
328
            treeview.scroll_to_cell(path, null, false, 0.0f, 0.0f);
 
329
    }
 
330
    
 
331
    void scroll_to_and_select_cell(double adjustment_value, int y) {
 
332
        scrolled_window.vadjustment.set_value(adjustment_value);        
 
333
        
 
334
        Gtk.TreePath path;
 
335
        int cell_x, cell_y;
 
336
        treeview.get_path_at_pos(0, y, out path, null, out cell_x, out cell_y);
 
337
        select(path, false);
 
338
    }
 
339
    
 
340
    Gtk.TreePath? get_path_at_cursor() {
 
341
        Gtk.TreePath path;
 
342
        Gtk.TreeViewColumn column;
 
343
        treeview.get_cursor(out path, out column);
 
344
        return path;
 
345
    }
 
346
    
 
347
    public Gtk.TreePath select_first_cell() {
 
348
        treeview.get_vadjustment().set_value(0);
 
349
        Gtk.TreePath start = new Gtk.TreePath.first();
 
350
        select(start);
 
351
        return start;
 
352
    }
 
353
 
 
354
    public void select_last_cell() {
 
355
        // The list index is 0-based, the last element is 'size - 1'
 
356
        int size = list.iter_n_children(null) - 1;
 
357
        select(new Gtk.TreePath.from_string(size.to_string()));
 
358
    }
 
359
 
 
360
    public void select_previous() {
 
361
        Gtk.TreePath path = get_path_at_cursor();
 
362
        
 
363
        if (path != null) {
 
364
            if (path.prev())
 
365
                select(path);
 
366
            else select_last_cell();
 
367
        }
 
368
    }
 
369
 
 
370
    public void select_next() {
 
371
        Gtk.TreePath path = get_path_at_cursor();
 
372
        
 
373
        if (path != null) {
 
374
            Gtk.TreeIter iter;
 
375
            path.next();
 
376
 
 
377
            // Make sure the next element iterator is valid
 
378
            if (list.get_iter(out iter, path))
 
379
                select(path);
 
380
            else select_first_cell();
 
381
        }
 
382
    }
 
383
 
 
384
    public void page_up() {
 
385
        // Save the current y position of the selection
 
386
        Gtk.TreePath cursor_path = get_path_at_cursor();
 
387
        Gdk.Rectangle rect;
 
388
        treeview.get_cell_area(cursor_path, null, out rect);
 
389
        
 
390
        // Don't wrap page_up
 
391
        if (!cursor_path.prev()) {
 
392
            return;
 
393
        }
 
394
 
 
395
        double adjust_value = scrolled_window.vadjustment.get_value();
 
396
        double page_size = scrolled_window.vadjustment.get_page_size();
 
397
        // If the current page is the top page, just select the top cell
 
398
        if (adjust_value == scrolled_window.vadjustment.lower) {
 
399
            select_first_cell();
 
400
            return;
 
401
        }
 
402
 
 
403
        // it is 'y + 1' because only 'y' would be the element before the one we want
 
404
        scroll_to_and_select_cell(adjust_value - (page_size - rect.height), rect.y + 1);
 
405
    }
 
406
 
 
407
    public void page_down() {
 
408
        // Save the current y position of the selection
 
409
        Gtk.TreePath cursor_path = get_path_at_cursor();
 
410
        Gdk.Rectangle rect;
 
411
        treeview.get_cell_area(cursor_path, null, out rect);
 
412
        
 
413
        // Don't wrap page_down
 
414
        cursor_path.next();
 
415
        Gtk.TreeIter iter;
 
416
        if (!list.get_iter(out iter, cursor_path)) {
 
417
            return;
 
418
        }
 
419
 
 
420
        double adjust_value = scrolled_window.vadjustment.get_value();
 
421
        double page_size = scrolled_window.vadjustment.get_page_size();
 
422
        // If the current page is the bottom page, just select the last cell
 
423
        if (adjust_value >= scrolled_window.vadjustment.upper - page_size) {
 
424
            select_last_cell();
 
425
            return;
 
426
        }
 
427
 
 
428
        scroll_to_and_select_cell(adjust_value + (page_size - rect.height), rect.y + 1);
 
429
    }
 
430
 
 
431
    string? get_item_at_path(Gtk.TreePath path) {
 
432
        Gtk.TreeIter iter;
 
433
        if (!list.get_iter(out iter, path))
 
434
            return null;
 
435
 
 
436
        GLib.Value v;
 
437
        list.get_value(iter, 0, out v);
 
438
 
 
439
        return v.get_string().substring(0);
 
440
    }
 
441
 
 
442
    public string get_selected_item() {
 
443
        Gtk.TreePath path;
 
444
        Gtk.TreeViewColumn column;
 
445
        treeview.get_cursor(out path, out column);
 
446
        
 
447
        return get_item_at_path(path);
 
448
    }
 
449
 
 
450
    bool path_exists(Gtk.TreePath path) {
 
451
        Gtk.TreeIter iter;
 
452
        if (list.get_iter(out iter, path))
 
453
            return true;
 
454
        else return false;
 
455
    }
 
456
 
 
457
    public void select_path(Gtk.TreePath path) {
 
458
        if (path_exists(path))
 
459
            select(path);
 
460
    }
 
461
    
 
462
    void insert_before(string item, Gtk.TreePath path) {
 
463
        Gtk.TreeIter new_iter;
 
464
        Gtk.TreeIter sibling;
 
465
        list.get_iter(out sibling, path);
 
466
        list.insert_before(out new_iter, sibling);
 
467
        list.set(new_iter, 0, item, -1);
 
468
    }
 
469
 
 
470
    void remove(Gtk.TreePath path) {
 
471
        Gtk.TreeIter iter;
 
472
        list.get_iter(out iter, path);
 
473
        list.remove(iter);
 
474
    }
 
475
 
 
476
    public void collate(string[] new_list) {
 
477
        Gtk.TreePath current_path = new Gtk.TreePath.first();
 
478
        int new_list_index = 0;
 
479
        while (true) {
 
480
            string? item = get_item_at_path(current_path);
 
481
            if (item == null || new_list_index == new_list.length)
 
482
                break;
 
483
            string new_item = new_list[new_list_index];
 
484
 
 
485
            int result = strcmp(item, new_item);
 
486
            if (result > 0) {
 
487
                remove(current_path);
 
488
            } else {
 
489
                if (result != 0)
 
490
                    insert_before(new_list[new_list_index], current_path);
 
491
                current_path.next();
 
492
                ++new_list_index;
 
493
            }
 
494
        }
 
495
 
 
496
        // The rest of the items in the old list are not present, so remove them
 
497
        while (true) {
 
498
            if (!path_exists(current_path))
 
499
                break;
 
500
            remove(current_path);
 
501
        }
 
502
 
 
503
        // The rest of the items in the other list must be new, so add them
 
504
        for (; new_list_index < new_list.length; ++new_list_index)
 
505
            append(new_list[new_list_index]);
 
506
        
 
507
    }
 
508
    
 
509
}
 
510
 
 
511
//// Gedit helper functions ////
 
512
 
 
513
string? document_filename(Gedit.Document document) {
 
514
    string uri = document.get_uri();
 
515
    if (uri == null)
 
516
        return null;
 
517
    try {
 
518
        return Filename.from_uri(uri);
 
519
    } catch (ConvertError e) { return null; }
 
520
}
 
521
 
 
522
Gedit.Tab? find_tab(string filename, out Gedit.Window window) {
 
523
    string uri = filename_to_uri(filename);
 
524
    
 
525
    foreach (Gedit.Window w in Gedit.App.get_default().get_windows()) {
 
526
        Gedit.Tab tab = w.get_tab_from_uri(uri);
 
527
        if (tab != null) {
 
528
            window = w;
 
529
            return tab;
 
530
        }
 
531
    }
 
532
    return null;
 
533
}