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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
);
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
),
181 G_STRUCT_OFFSET (AssistWindowClass
, chosen
),
183 g_cclosure_marshal_VOID__INT
,
187 assist_window_signals
[SIGNAL_TYPE_CANCEL
] = g_signal_new ("cancel",
188 G_OBJECT_CLASS_TYPE (object_class
),
190 G_STRUCT_OFFSET (AssistWindowClass
, cancel
),
192 g_cclosure_marshal_VOID__VOID
,
198 assist_activated(GtkTreeView
* view
, GtkTreePath
* path
, GtkTreeViewColumn
* column
,
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
);
213 assist_window_init(AssistWindow
*obj
)
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
),
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
);
255 assist_window_finalize(GObject
*object
)
258 cobj
= ASSIST_WINDOW(object
);
260 /* Free private members, etc. */
263 (* G_OBJECT_CLASS (assist_window_parent_class
)->finalize
) (object
);
266 static gboolean
assist_window_select(AssistWindow
* assistwin
)
270 GtkTreeSelection
* selection
;
272 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
275 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
277 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
280 gtk_tree_model_get(model
, &iter
, ASSIST_WINDOW_COLUMN_NUM
, &num
, -1);
281 g_signal_emit_by_name(assistwin
, "chosen",
289 static gboolean
assist_window_first(AssistWindow
* assistwin
)
294 GtkTreeSelection
* selection
;
296 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
299 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
301 if (gtk_tree_selection_get_mode(selection
) == GTK_SELECTION_NONE
)
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
);
314 static gboolean
assist_window_last(AssistWindow
* assistwin
)
318 GtkTreeSelection
* selection
;
322 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
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
)
331 children
= gtk_tree_model_iter_n_children(model
, NULL
);
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
);
345 static gboolean
assist_window_up(AssistWindow
* assistwin
, gint rows
)
350 GtkTreeSelection
* selection
;
352 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
355 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
357 if (gtk_tree_selection_get_mode(selection
) == GTK_SELECTION_NONE
)
360 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
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
);
378 static gboolean
assist_window_down(AssistWindow
* assistwin
, gint rows
)
382 GtkTreeSelection
* selection
;
384 if (!GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
)))
387 selection
= gtk_tree_view_get_selection(assistwin
->priv
->view
);
389 if (gtk_tree_selection_get_mode(selection
) == GTK_SELECTION_NONE
)
392 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
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
);
410 gtk_tree_model_get_iter_first(model
, &iter
);
411 gtk_tree_selection_select_iter(selection
, &iter
);
416 /* Return a tuple containing the (x, y) position of the cursor + 1 line */
418 get_coordinates(AnjutaView
* view
, int offset
, int* x
, int* y
)
421 /* We need to Rectangles because if we step to the next line
422 the x position is lost */
427 GtkTextBuffer
* buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(view
));
429 gtk_text_buffer_get_iter_at_offset(buffer
, &iter
,
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
);
444 assist_window_move(AssistWindow
* assist_win
, int offset
)
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);
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
= 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,
483 assist_window_filter_keypress(AssistWindow
* assist_window
, guint keyval
)
485 if (assist_window_is_active(assist_window
))
492 return assist_window_down(assist_window
, 1);
497 return assist_window_up(assist_window
, 1);
501 return assist_window_first(assist_window
);
505 return assist_window_last(assist_window
);
510 return assist_window_select(assist_window
);
514 g_signal_emit_by_name(G_OBJECT(assist_window
), "cancel");
522 g_signal_emit_by_name(G_OBJECT(assist_window
), "cancel");
532 gboolean
assist_window_is_active(AssistWindow
* assistwin
)
534 return GTK_WIDGET_VISIBLE(GTK_WIDGET(assistwin
));
538 assist_window_new(GtkTextView
* view
, gchar
* trigger
, gint position
)
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
;
546 gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(view
),
548 gtk_text_buffer_get_insert(gtk_text_view_get_buffer(view
)));
549 assist_win
->priv
->pos
= gtk_text_iter_get_offset(&iter
);
552 assist_win
->priv
->pos
= position
;
553 assist_win
->priv
->trigger
= trigger
;
555 assist_window_move(assist_win
, assist_win
->priv
->pos
);
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
;