Updated Spanish translation
[anjuta-git-plugin.git] / plugins / sourceview / assist-window.c
blob4f882b1f9bde4895317854363e5a3e8a9446ba18
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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);
171 GParamSpec *assist_window_spec_view;
172 GParamSpec *assist_window_spec_column;
174 object_class->finalize = assist_window_finalize;
175 object_class->set_property = assist_window_set_property;
176 object_class->get_property = assist_window_get_property;
178 widget_class->expose_event = assist_window_expose;
180 assist_window_signals[SIGNAL_TYPE_CHOSEN] = g_signal_new ("chosen",
181 G_OBJECT_CLASS_TYPE (object_class),
182 G_SIGNAL_RUN_LAST,
183 G_STRUCT_OFFSET (AssistWindowClass, chosen),
184 NULL, NULL,
185 g_cclosure_marshal_VOID__INT,
186 G_TYPE_NONE,
188 G_TYPE_INT);
189 assist_window_signals[SIGNAL_TYPE_CANCEL] = g_signal_new ("cancel",
190 G_OBJECT_CLASS_TYPE (object_class),
191 G_SIGNAL_RUN_LAST,
192 G_STRUCT_OFFSET (AssistWindowClass, cancel),
193 NULL, NULL,
194 g_cclosure_marshal_VOID__VOID,
195 G_TYPE_NONE,
199 static void
200 assist_activated(GtkTreeView* view, GtkTreePath* path, GtkTreeViewColumn* column,
201 GtkWidget* window)
203 GtkTreeIter iter;
204 gint num;
205 GtkTreeModel* model = gtk_tree_view_get_model(view);
206 gtk_tree_model_get_iter(model, &iter, path);
207 gtk_tree_model_get(model, &iter, ASSIST_WINDOW_COLUMN_NUM, &num, -1);
209 g_signal_emit_by_name(G_OBJECT(window), "chosen", num);
214 static void
215 assist_window_init(AssistWindow *obj)
217 GtkWidget* view;
218 GtkWidget* scroll;
219 GtkTreeViewColumn* column;
220 GtkCellRenderer* renderer;
222 obj->priv = g_new0(AssistWindowPrivate, 1);
224 g_object_set(G_OBJECT(obj), "type", GTK_WINDOW_POPUP, NULL);
226 view = gtk_tree_view_new();
227 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
228 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view), FALSE);
230 g_signal_connect(G_OBJECT(view), "row-activated", G_CALLBACK(assist_activated),
231 obj);
233 scroll = gtk_scrolled_window_new(NULL, NULL);
234 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
235 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
237 gtk_container_set_border_width(GTK_CONTAINER(obj), 2);
238 gtk_container_add(GTK_CONTAINER(obj), scroll);
239 gtk_container_add(GTK_CONTAINER(scroll), view);
241 obj->priv->view = GTK_TREE_VIEW(view);
242 obj->priv->scrolled_window = scroll;
244 obj->priv->suggestions = GTK_TREE_MODEL(gtk_list_store_new(ASSIST_WINDOW_COLUMN_END,
245 GTK_TYPE_STRING, GTK_TYPE_INT));
246 gtk_tree_view_set_model(obj->priv->view, obj->priv->suggestions);
247 renderer = gtk_cell_renderer_text_new();
248 column = gtk_tree_view_column_new_with_attributes("Suggestions",
249 renderer, "text", ASSIST_WINDOW_COLUMN, NULL);
250 gtk_tree_view_append_column(obj->priv->view, column);
252 gtk_window_set_decorated(GTK_WINDOW(obj), FALSE);
253 gtk_window_set_type_hint(GTK_WINDOW(obj), GDK_WINDOW_TYPE_HINT_MENU);
255 gtk_widget_show_all(scroll);
258 static void
259 assist_window_finalize(GObject *object)
261 AssistWindow *cobj;
262 cobj = ASSIST_WINDOW(object);
264 /* Free private members, etc. */
266 g_free(cobj->priv);
267 (* G_OBJECT_CLASS (assist_window_parent_class)->finalize) (object);
270 static gboolean assist_window_select(AssistWindow* assistwin)
272 GtkTreeIter iter;
273 GtkTreeModel* model;
274 GtkTreeSelection* selection;
276 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
277 return FALSE;
279 selection = gtk_tree_view_get_selection(assistwin->priv->view);
281 if (gtk_tree_selection_get_selected(selection, &model, &iter))
283 gint num;
284 gtk_tree_model_get(model, &iter, ASSIST_WINDOW_COLUMN_NUM, &num, -1);
285 g_signal_emit_by_name(assistwin, "chosen",
286 num);
287 return TRUE;
289 else
290 return FALSE;
293 static gboolean assist_window_first(AssistWindow* assistwin)
295 GtkTreeIter iter;
296 GtkTreePath* path;
297 GtkTreeModel* model;
298 GtkTreeSelection* selection;
300 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
301 return FALSE;
303 selection = gtk_tree_view_get_selection(assistwin->priv->view);
305 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
306 return FALSE;
308 model = gtk_tree_view_get_model(assistwin->priv->view);
310 gtk_tree_model_get_iter_first(model, &iter);
311 gtk_tree_selection_select_iter(selection, &iter);
312 path = gtk_tree_model_get_path(model, &iter);
313 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
314 gtk_tree_path_free(path);
315 return TRUE;
318 static gboolean assist_window_last(AssistWindow* assistwin)
320 GtkTreeIter iter;
321 GtkTreeModel* model;
322 GtkTreeSelection* selection;
323 GtkTreePath* path;
324 gint children;
326 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
327 return FALSE;
329 selection = gtk_tree_view_get_selection(assistwin->priv->view);
330 model = gtk_tree_view_get_model(assistwin->priv->view);
332 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
333 return FALSE;
335 children = gtk_tree_model_iter_n_children(model, NULL);
336 if (children > 0)
338 gtk_tree_model_iter_nth_child(model, &iter, NULL, children - 1);
340 gtk_tree_selection_select_iter(selection, &iter);
341 path = gtk_tree_model_get_path(model, &iter);
342 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
343 gtk_tree_path_free(path);
344 return TRUE;
346 return FALSE;
349 static gboolean assist_window_up(AssistWindow* assistwin, gint rows)
351 GtkTreeIter iter;
352 GtkTreePath* path;
353 GtkTreeModel* model;
354 GtkTreeSelection* selection;
356 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
357 return FALSE;
359 selection = gtk_tree_view_get_selection(assistwin->priv->view);
361 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
362 return FALSE;
364 if (gtk_tree_selection_get_selected(selection, &model, &iter))
366 gint i;
367 path = gtk_tree_model_get_path(model, &iter);
368 for (i=0; i < rows; i++)
369 gtk_tree_path_prev(path);
371 if (gtk_tree_model_get_iter(model, &iter, path))
373 gtk_tree_selection_select_iter(selection, &iter);
374 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
376 gtk_tree_path_free(path);
377 return TRUE;
379 return FALSE;
382 static gboolean assist_window_down(AssistWindow* assistwin, gint rows)
384 GtkTreeIter iter;
385 GtkTreeModel* model;
386 GtkTreeSelection* selection;
388 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin)))
389 return FALSE;
391 selection = gtk_tree_view_get_selection(assistwin->priv->view);
393 if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_NONE)
394 return FALSE;
396 if (gtk_tree_selection_get_selected(selection, &model, &iter))
398 gint i;
399 GtkTreePath* path;
400 for (i = 0; i < rows; i++)
402 if (!gtk_tree_model_iter_next(model, &iter))
403 return assist_window_last(assistwin);
406 gtk_tree_selection_select_iter(selection, &iter);
407 path = gtk_tree_model_get_path(model, &iter);
408 gtk_tree_view_scroll_to_cell(assistwin->priv->view, path, NULL, FALSE, 0, 0);
409 gtk_tree_path_free(path);
410 return TRUE;
412 else
414 gtk_tree_model_get_iter_first(model, &iter);
415 gtk_tree_selection_select_iter(selection, &iter);
417 return TRUE;
420 /* Return a tuple containing the (x, y) position of the cursor + 1 line */
421 static void
422 get_coordinates(AnjutaView* view, int offset, int* x, int* y)
424 int xor, yor;
425 /* We need to Rectangles because if we step to the next line
426 the x position is lost */
427 GdkRectangle rectx;
428 GdkRectangle recty;
429 GdkWindow* window;
430 GtkTextIter iter;
431 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
433 gtk_text_buffer_get_iter_at_offset(buffer, &iter,
434 offset);
435 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &rectx);
436 gtk_text_iter_forward_lines(&iter, 1);
437 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(view), &iter, &recty);
438 window = gtk_text_view_get_window(GTK_TEXT_VIEW(view), GTK_TEXT_WINDOW_TEXT);
439 gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(view), GTK_TEXT_WINDOW_TEXT,
440 rectx.x + rectx.width, recty.y, x, y);
442 gdk_window_get_origin(window, &xor, &yor);
443 *x = *x + xor;
444 *y = *y + yor;
447 void
448 assist_window_move(AssistWindow* assist_win, int offset)
450 int x,y;
451 get_coordinates(ANJUTA_VIEW(assist_win->priv->text_view), offset, &x, &y);
452 gtk_window_move(GTK_WINDOW(assist_win), x, y);
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 = node->next)
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_widget_queue_draw(GTK_WIDGET(assistwin));
477 * Return true if the key was processed and does not need to be passed to the textview,
478 * otherwise FALSE
480 gboolean
481 assist_window_filter_keypress(AssistWindow* assist_window, guint keyval)
483 if (assist_window_is_active(assist_window))
485 switch (keyval)
487 case GDK_Down:
488 case GDK_Page_Down:
490 return assist_window_down(assist_window, 1);
492 case GDK_Up:
493 case GDK_Page_Up:
495 return assist_window_up(assist_window, 1);
497 case GDK_Home:
499 return assist_window_first(assist_window);
501 case GDK_End:
503 return assist_window_last(assist_window);
505 case GDK_Return:
506 case GDK_Tab:
508 return assist_window_select(assist_window);
510 case GDK_Escape:
512 g_signal_emit_by_name(G_OBJECT(assist_window), "cancel");
513 return TRUE;
515 case GDK_Right:
516 case GDK_KP_Right:
517 case GDK_Left:
518 case GDK_KP_Left:
520 g_signal_emit_by_name(G_OBJECT(assist_window), "cancel");
521 return FALSE;
523 default:
524 return FALSE;
527 return FALSE;
530 gboolean assist_window_is_active(AssistWindow* assistwin)
532 return GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin));
535 AssistWindow*
536 assist_window_new(GtkTextView* view, gchar* trigger, gint position)
538 GtkTextIter iter;
539 AssistWindow* assist_win = ASSIST_WINDOW(g_object_new(ASSIST_TYPE_WINDOW, NULL));
540 assist_win->priv->text_view = view;
541 if (position == -1)
543 gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(view),
544 &iter,
545 gtk_text_buffer_get_insert(gtk_text_view_get_buffer(view)));
546 assist_win->priv->pos = gtk_text_iter_get_offset(&iter);
548 else
549 assist_win->priv->pos = position;
550 assist_win->priv->trigger = trigger;
552 assist_window_move(assist_win, assist_win->priv->pos);
553 return assist_win;
557 const gchar*
558 assist_window_get_trigger(AssistWindow* assist_win)
560 return assist_win->priv->trigger;
562 gint assist_window_get_position(AssistWindow* assist_win)
564 return assist_win->priv->pos;