1 /***************************************************************************
4 * Mi Mär 29 23:23:09 2006
5 * Copyright 2006 Johannes Schmid
7 ***************************************************************************/
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"
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/resources.h>
38 ASSIST_WINDOW_COLUMN_NUM
,
39 ASSIST_WINDOW_COLUMN_END
42 static void assist_window_finalize(GObject
*object
);
44 struct _AssistWindowPrivate
{
46 GtkTreeModel
* suggestions
;
47 GtkWidget
* scrolled_window
;
48 GtkTextView
* text_view
;
53 typedef struct _AssistWindowSignal AssistWindowSignal
;
54 typedef enum _AssistWindowSignalType AssistWindowSignalType
;
56 enum _AssistWindowSignalType
{
57 /* Place Signal Types Here */
63 static guint assist_window_signals
[LAST_SIGNAL
] = { 0 };
65 G_DEFINE_TYPE(AssistWindow
, assist_window
, GTK_TYPE_WINDOW
);
68 assist_window_expose(GtkWidget
* widget
, GdkEventExpose
* event
)
72 gint total_items
, items
, height
;
76 GtkRequisition popup_req
;
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
,
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
,
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
),
119 gtk_widget_set_size_request (GTK_WIDGET (assistwin
->priv
->scrolled_window
),
122 gtk_window_resize(GTK_WINDOW(assistwin
), width
, height
);
124 return (* GTK_WIDGET_CLASS (assist_window_parent_class
)->expose_event
)(widget
, event
);
128 assist_window_set_property (GObject
* object
,
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
);
140 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
147 assist_window_get_property (GObject
* object
,
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
);
160 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
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
),
183 G_STRUCT_OFFSET (AssistWindowClass
, chosen
),
185 g_cclosure_marshal_VOID__INT
,
189 assist_window_signals
[SIGNAL_TYPE_CANCEL
] = g_signal_new ("cancel",
190 G_OBJECT_CLASS_TYPE (object_class
),
192 G_STRUCT_OFFSET (AssistWindowClass
, cancel
),
194 g_cclosure_marshal_VOID__VOID
,
200 assist_activated(GtkTreeView
* view
, GtkTreePath
* path
, GtkTreeViewColumn
* column
,
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
);
215 assist_window_init(AssistWindow
*obj
)
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
),
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
);
259 assist_window_finalize(GObject
*object
)
262 cobj
= ASSIST_WINDOW(object
);
264 /* Free private members, etc. */
267 (* G_OBJECT_CLASS (assist_window_parent_class
)->finalize
) (object
);
270 static gboolean
assist_window_select(AssistWindow
* assistwin
)
274 GtkTreeSelection
* selection
;
276 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
279 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
281 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
284 gtk_tree_model_get(model
, &iter
, ASSIST_WINDOW_COLUMN_NUM
, &num
, -1);
285 g_signal_emit_by_name(assistwin
, "chosen",
293 static gboolean
assist_window_first(AssistWindow
* assistwin
)
298 GtkTreeSelection
* selection
;
300 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
303 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
305 if (gtk_tree_selection_get_mode(selection
) == GTK_SELECTION_NONE
)
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
);
318 static gboolean
assist_window_last(AssistWindow
* assistwin
)
322 GtkTreeSelection
* selection
;
326 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
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
)
335 children
= gtk_tree_model_iter_n_children(model
, NULL
);
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
);
349 static gboolean
assist_window_up(AssistWindow
* assistwin
, gint rows
)
354 GtkTreeSelection
* selection
;
356 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
359 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
361 if (gtk_tree_selection_get_mode(selection
) == GTK_SELECTION_NONE
)
364 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
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
);
382 static gboolean
assist_window_down(AssistWindow
* assistwin
, gint rows
)
386 GtkTreeSelection
* selection
;
388 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
391 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
393 if (gtk_tree_selection_get_mode(selection
) == GTK_SELECTION_NONE
)
396 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
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
);
414 gtk_tree_model_get_iter_first(model
, &iter
);
415 gtk_tree_selection_select_iter(selection
, &iter
);
420 /* Return a tuple containing the (x, y) position of the cursor + 1 line */
422 get_coordinates(AnjutaView
* view
, int offset
, int* x
, int* y
)
425 /* We need to Rectangles because if we step to the next line
426 the x position is lost */
431 GtkTextBuffer
* buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(view
));
433 gtk_text_buffer_get_iter_at_offset(buffer
, &iter
,
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
);
448 assist_window_move(AssistWindow
* assist_win
, int offset
)
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
);
461 GtkTreeSelection
* selection
;
463 gtk_list_store_clear(list
);
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,
481 assist_window_filter_keypress(AssistWindow
* assist_window
, guint keyval
)
483 if (assist_window_is_active(assist_window
))
490 return assist_window_down(assist_window
, 1);
495 return assist_window_up(assist_window
, 1);
499 return assist_window_first(assist_window
);
503 return assist_window_last(assist_window
);
508 return assist_window_select(assist_window
);
512 g_signal_emit_by_name(G_OBJECT(assist_window
), "cancel");
520 g_signal_emit_by_name(G_OBJECT(assist_window
), "cancel");
530 gboolean
assist_window_is_active(AssistWindow
* assistwin
)
532 return GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
));
536 assist_window_new(GtkTextView
* view
, gchar
* trigger
, gint position
)
539 AssistWindow
* assist_win
= ASSIST_WINDOW(g_object_new(ASSIST_TYPE_WINDOW
, NULL
));
540 assist_win
->priv
->text_view
= view
;
543 gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(view
),
545 gtk_text_buffer_get_insert(gtk_text_view_get_buffer(view
)));
546 assist_win
->priv
->pos
= gtk_text_iter_get_offset(&iter
);
549 assist_win
->priv
->pos
= position
;
550 assist_win
->priv
->trigger
= trigger
;
552 assist_window_move(assist_win
, assist_win
->priv
->pos
);
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
;