Updated Spanish translation
[anjuta-git-plugin.git] / plugins / sourceview / assist-window.c
blob7cb9fa7444bd7e39e446f5662fa0c048fcd724b2
1 /***************************************************************************
2 * assist-window.c
4 * Mi Mär 29 23:23:09 2006
5 * Copyright 2006 Johannes Schmid
6 * jhs@gnome.org
7 ***************************************************************************/
9 /*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "assist-window.h"
26 #include "anjuta-view.h"
28 #include <gtk/gtk.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/resources.h>
32 #include <string.h>
34 /* Properties */
35 enum
37 ASSIST_WINDOW_COLUMN,
38 ASSIST_WINDOW_COLUMN_NUM,
39 ASSIST_WINDOW_COLUMN_END
42 static void assist_window_finalize(GObject *object);
44 struct _AssistWindowPrivate {
45 GtkTreeView* view;
46 GtkTreeModel* suggestions;
47 GtkWidget* scrolled_window;
48 GtkTextView* text_view;
49 gchar* trigger;
50 gint pos;
53 typedef struct _AssistWindowSignal AssistWindowSignal;
54 typedef enum _AssistWindowSignalType AssistWindowSignalType;
56 enum _AssistWindowSignalType {
57 /* Place Signal Types Here */
58 SIGNAL_TYPE_CHOSEN,
59 SIGNAL_TYPE_CANCEL,
60 LAST_SIGNAL
63 static guint assist_window_signals[LAST_SIGNAL] = { 0 };
65 G_DEFINE_TYPE(AssistWindow, assist_window, GTK_TYPE_WINDOW);
67 static gboolean
68 assist_window_expose(GtkWidget* widget, GdkEventExpose* event)
70 GtkWidget *text_view;
71 gint width;
72 gint total_items, items, height;
73 GdkScreen *screen;
74 gint monitor_num;
75 GdkRectangle monitor;
76 GtkRequisition popup_req;
77 gint vert_separator;
78 AssistWindow* assistwin = ASSIST_WINDOW(widget);
79 GtkTreeModel* model = gtk_tree_view_get_model(assistwin->priv->view);
80 GtkTreeViewColumn* column = gtk_tree_view_get_column(assistwin->priv->view, 0);
82 g_return_val_if_fail (assistwin->priv->text_view != NULL, FALSE);
83 text_view = GTK_WIDGET(assistwin->priv->text_view);
85 total_items = gtk_tree_model_iter_n_children (model, NULL);
86 items = MIN (total_items, 5);
88 gtk_tree_view_column_cell_get_size (column, NULL,
89 NULL, NULL, NULL, &height);
91 screen = gtk_widget_get_screen (text_view);
92 monitor_num = gdk_screen_get_monitor_at_window (screen, text_view->window);
93 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
95 gtk_widget_style_get (GTK_WIDGET (assistwin->priv->view),
96 "vertical-separator", &vert_separator,
97 NULL);
99 gtk_widget_size_request (GTK_WIDGET (assistwin->priv->view), &popup_req);
100 width = popup_req.width;
102 if (total_items > items)
104 int scrollbar_spacing;
105 GtkRequisition scrollbar_req;
106 gtk_widget_size_request (GTK_SCROLLED_WINDOW(assistwin->priv->scrolled_window)->vscrollbar,
107 &scrollbar_req);
108 gtk_widget_style_get (GTK_WIDGET (assistwin->priv->scrolled_window),
109 "scrollbar-spacing", &scrollbar_spacing, NULL);
110 width += scrollbar_req.width + scrollbar_spacing;
113 width = MAX (width, 100);
114 width = MIN (monitor.width, width);
115 height = items * (height + vert_separator);
117 gtk_widget_set_size_request (GTK_WIDGET (assistwin->priv->view),
118 -1, height);
119 gtk_widget_set_size_request (GTK_WIDGET (assistwin->priv->scrolled_window),
120 width, -1);
122 gtk_window_resize(GTK_WINDOW(assistwin), width, height);
124 return (* GTK_WIDGET_CLASS (assist_window_parent_class)->expose_event)(widget, event);
127 static void
128 assist_window_set_property (GObject * object,
129 guint property_id,
130 const GValue * value, GParamSpec * pspec)
132 // AssistWindow *self = ASSIST_WINDOW (object);
133 g_return_if_fail(value != NULL);
134 g_return_if_fail(pspec != NULL);
136 switch (property_id)
138 default:
140 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
141 break;
146 static void
147 assist_window_get_property (GObject * object,
148 guint property_id,
149 GValue * value, GParamSpec * pspec)
151 // AssistWindow *self = ASSIST_WINDOW (object);
153 g_return_if_fail(value != NULL);
154 g_return_if_fail(pspec != NULL);
156 switch (property_id)
158 default:
160 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
161 break;
166 static void
167 assist_window_class_init(AssistWindowClass *klass)
169 GObjectClass *object_class = G_OBJECT_CLASS(klass);
170 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
172 object_class->finalize = assist_window_finalize;
173 object_class->set_property = assist_window_set_property;
174 object_class->get_property = assist_window_get_property;
176 widget_class->expose_event = assist_window_expose;
178 assist_window_signals[SIGNAL_TYPE_CHOSEN] = g_signal_new ("chosen",
179 G_OBJECT_CLASS_TYPE (object_class),
180 G_SIGNAL_RUN_LAST,
181 G_STRUCT_OFFSET (AssistWindowClass, chosen),
182 NULL, NULL,
183 g_cclosure_marshal_VOID__INT,
184 G_TYPE_NONE,
186 G_TYPE_INT);
187 assist_window_signals[SIGNAL_TYPE_CANCEL] = g_signal_new ("cancel",
188 G_OBJECT_CLASS_TYPE (object_class),
189 G_SIGNAL_RUN_LAST,
190 G_STRUCT_OFFSET (AssistWindowClass, cancel),
191 NULL, NULL,
192 g_cclosure_marshal_VOID__VOID,
193 G_TYPE_NONE,
197 static void
198 assist_activated(GtkTreeView* view, GtkTreePath* path, GtkTreeViewColumn* column,
199 GtkWidget* window)
201 GtkTreeIter iter;
202 gint num;
203 GtkTreeModel* model = gtk_tree_view_get_model(view);
204 gtk_tree_model_get_iter(model, &iter, path);
205 gtk_tree_model_get(model, &iter, ASSIST_WINDOW_COLUMN_NUM, &num, -1);
207 g_signal_emit_by_name(G_OBJECT(window), "chosen", num);
212 static void
213 assist_window_init(AssistWindow *obj)
215 GtkWidget* view;
216 GtkWidget* scroll;
217 GtkTreeViewColumn* column;
218 GtkCellRenderer* renderer;
220 obj->priv = g_new0(AssistWindowPrivate, 1);
222 view = gtk_tree_view_new();
223 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
224 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view), FALSE);
226 g_signal_connect(G_OBJECT(view), "row-activated", G_CALLBACK(assist_activated),
227 obj);
229 scroll = gtk_scrolled_window_new(NULL, NULL);
230 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
231 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
233 gtk_container_set_border_width(GTK_CONTAINER(obj), 2);
234 gtk_container_add(GTK_CONTAINER(obj), scroll);
235 gtk_container_add(GTK_CONTAINER(scroll), view);
237 obj->priv->view = GTK_TREE_VIEW(view);
238 obj->priv->scrolled_window = scroll;
240 obj->priv->suggestions = GTK_TREE_MODEL(gtk_list_store_new(ASSIST_WINDOW_COLUMN_END,
241 GTK_TYPE_STRING, GTK_TYPE_INT));
242 gtk_tree_view_set_model(obj->priv->view, obj->priv->suggestions);
243 renderer = gtk_cell_renderer_text_new();
244 column = gtk_tree_view_column_new_with_attributes("Suggestions",
245 renderer, "text", ASSIST_WINDOW_COLUMN, NULL);
246 gtk_tree_view_append_column(obj->priv->view, column);
248 gtk_window_set_decorated(GTK_WINDOW(obj), FALSE);
249 gtk_window_set_type_hint(GTK_WINDOW(obj), GDK_WINDOW_TYPE_HINT_MENU);
251 gtk_widget_show_all(scroll);
254 static void
255 assist_window_finalize(GObject *object)
257 AssistWindow *cobj;
258 cobj = ASSIST_WINDOW(object);
260 /* Free private members, etc. */
262 g_free(cobj->priv);
263 (* G_OBJECT_CLASS (assist_window_parent_class)->finalize) (object);
266 static gboolean assist_window_select(AssistWindow* assistwin)
268 GtkTreeIter iter;
269 GtkTreeModel* model;
270 GtkTreeSelection* selection;
272 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
273 return FALSE;
275 selection = gtk_tree_view_get_selection(assistwin->priv->view);
277 if (gtk_tree_selection_get_selected(selection, &model, &iter))
279 gint num;
280 gtk_tree_model_get(model, &iter, ASSIST_WINDOW_COLUMN_NUM, &num, -1);
281 g_signal_emit_by_name(assistwin, "chosen",
282 num);
283 return TRUE;
285 else
286 return FALSE;
289 static gboolean assist_window_first(AssistWindow* assistwin)
291 GtkTreeIter iter;
292 GtkTreePath* path;
293 GtkTreeModel* model;
294 GtkTreeSelection* selection;
296 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
297 return FALSE;
299 selection = gtk_tree_view_get_selection(assistwin->priv->view);
301 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
302 return FALSE;
304 model = gtk_tree_view_get_model(assistwin->priv->view);
306 gtk_tree_model_get_iter_first(model, &iter);
307 gtk_tree_selection_select_iter(selection, &iter);
308 path = gtk_tree_model_get_path(model, &iter);
309 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
310 gtk_tree_path_free(path);
311 return TRUE;
314 static gboolean assist_window_last(AssistWindow* assistwin)
316 GtkTreeIter iter;
317 GtkTreeModel* model;
318 GtkTreeSelection* selection;
319 GtkTreePath* path;
320 gint children;
322 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
323 return FALSE;
325 selection = gtk_tree_view_get_selection(assistwin->priv->view);
326 model = gtk_tree_view_get_model(assistwin->priv->view);
328 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
329 return FALSE;
331 children = gtk_tree_model_iter_n_children(model, NULL);
332 if (children > 0)
334 gtk_tree_model_iter_nth_child(model, &iter, NULL, children - 1);
336 gtk_tree_selection_select_iter(selection, &iter);
337 path = gtk_tree_model_get_path(model, &iter);
338 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
339 gtk_tree_path_free(path);
340 return TRUE;
342 return FALSE;
345 static gboolean assist_window_up(AssistWindow* assistwin, gint rows)
347 GtkTreeIter iter;
348 GtkTreePath* path;
349 GtkTreeModel* model;
350 GtkTreeSelection* selection;
352 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
353 return FALSE;
355 selection = gtk_tree_view_get_selection(assistwin->priv->view);
357 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
358 return FALSE;
360 if (gtk_tree_selection_get_selected(selection, &model, &iter))
362 gint i;
363 path = gtk_tree_model_get_path(model, &iter);
364 for (i=0; i < rows; i++)
365 gtk_tree_path_prev(path);
367 if (gtk_tree_model_get_iter(model, &iter, path))
369 gtk_tree_selection_select_iter(selection, &iter);
370 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
372 gtk_tree_path_free(path);
373 return TRUE;
375 return FALSE;
378 static gboolean assist_window_down(AssistWindow* assistwin, gint rows)
380 GtkTreeIter iter;
381 GtkTreeModel* model;
382 GtkTreeSelection* selection;
384 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
385 return FALSE;
387 selection = gtk_tree_view_get_selection(assistwin->priv->view);
389 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
390 return FALSE;
392 if (gtk_tree_selection_get_selected(selection, &model, &iter))
394 gint i;
395 GtkTreePath* path;
396 for (i = 0; i < rows; i++)
398 if (!gtk_tree_model_iter_next(model, &iter))
399 return assist_window_last(assistwin);
402 gtk_tree_selection_select_iter(selection, &iter);
403 path = gtk_tree_model_get_path(model, &iter);
404 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
405 gtk_tree_path_free(path);
406 return TRUE;
408 else
410 gtk_tree_model_get_iter_first(model, &iter);
411 gtk_tree_selection_select_iter(selection, &iter);
413 return TRUE;
416 /* Return a tuple containing the (x, y) position of the cursor + 1 line */
417 static void
418 get_coordinates(AnjutaView* view, int offset, int* x, int* y)
420 int xor, yor;
421 /* We need to Rectangles because if we step to the next line
422 the x position is lost */
423 GdkRectangle rectx;
424 GdkRectangle recty;
425 GdkWindow* window;
426 GtkTextIter iter;
427 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
429 gtk_text_buffer_get_iter_at_offset(buffer, &iter,
430 offset);
431 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &rectx);
432 gtk_text_iter_forward_lines(&iter, 1);
433 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &recty);
434 window = gtk_text_view_get_window(GTK_TEXT_VIEW(view), GTK_TEXT_WINDOW_TEXT);
435 gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(view), GTK_TEXT_WINDOW_TEXT,
436 rectx.x + rectx.width, recty.y, x, y);
438 gdk_window_get_origin(window, &xor, &yor);
439 *x = *x + xor;
440 *y = *y + yor;
443 void
444 assist_window_move(AssistWindow* assist_win, int offset)
446 int x,y;
447 get_coordinates(ANJUTA_VIEW(assist_win->priv->text_view), offset, &x, &y);
448 gtk_window_move(GTK_WINDOW(assist_win), x, y);
449 /* Make it slightly transparent */
450 #if (GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 12))
451 gtk_window_set_opacity (GTK_WINDOW (assist_win), 0.90);
452 #endif
456 void assist_window_update(AssistWindow* assistwin, GList* suggestions)
458 g_return_if_fail(assistwin != NULL);
459 GtkListStore* list = GTK_LIST_STORE(assistwin->priv->suggestions);
460 GtkTreeIter iter;
461 GtkTreeSelection* selection;
462 GList* node;
463 gtk_list_store_clear(list);
464 int i = 0;
465 for (node = suggestions; node != NULL; node = g_list_next(node))
467 gtk_list_store_append(list, &iter);
468 gtk_list_store_set(list, &iter, ASSIST_WINDOW_COLUMN, (gchar*) node->data,
469 ASSIST_WINDOW_COLUMN_NUM, i++, -1);
471 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(assistwin->priv->view));
472 gtk_tree_selection_unselect_all(selection);
473 gtk_tree_model_get_iter_first (GTK_TREE_MODEL(list), &iter);
474 gtk_tree_selection_select_iter (selection, &iter);
475 gtk_widget_queue_draw(GTK_WIDGET(assistwin));
479 * Return true if the key was processed and does not need to be passed to the textview,
480 * otherwise FALSE
482 gboolean
483 assist_window_filter_keypress(AssistWindow* assist_window, guint keyval)
485 if (assist_window_is_active(assist_window))
487 switch (keyval)
489 case GDK_Down:
490 case GDK_Page_Down:
492 return assist_window_down(assist_window, 1);
494 case GDK_Up:
495 case GDK_Page_Up:
497 return assist_window_up(assist_window, 1);
499 case GDK_Home:
501 return assist_window_first(assist_window);
503 case GDK_End:
505 return assist_window_last(assist_window);
507 case GDK_Return:
508 case GDK_Tab:
510 return assist_window_select(assist_window);
512 case GDK_Escape:
514 g_signal_emit_by_name(G_OBJECT(assist_window), "cancel");
515 return TRUE;
517 case GDK_Right:
518 case GDK_KP_Right:
519 case GDK_Left:
520 case GDK_KP_Left:
522 g_signal_emit_by_name(G_OBJECT(assist_window), "cancel");
523 return FALSE;
525 default:
526 return FALSE;
529 return FALSE;
532 gboolean assist_window_is_active(AssistWindow* assistwin)
534 return GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin));
537 AssistWindow*
538 assist_window_new(GtkTextView* view, gchar* trigger, gint position)
540 GtkTextIter iter;
541 AssistWindow* assist_win = ASSIST_WINDOW(g_object_new(ASSIST_TYPE_WINDOW,
542 "type", GTK_WINDOW_POPUP, NULL));
543 assist_win->priv->text_view = view;
544 if (position == -1)
546 gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(view),
547 &iter,
548 gtk_text_buffer_get_insert(gtk_text_view_get_buffer(view)));
549 assist_win->priv->pos = gtk_text_iter_get_offset(&iter);
551 else
552 assist_win->priv->pos = position;
553 assist_win->priv->trigger = trigger;
555 assist_window_move(assist_win, assist_win->priv->pos);
556 return assist_win;
560 const gchar*
561 assist_window_get_trigger(AssistWindow* assist_win)
563 return assist_win->priv->trigger;
565 gint assist_window_get_position(AssistWindow* assist_win)
567 return assist_win->priv->pos;