Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / sourceview / anjuta-view.c
blobe1abd52c93bb3f73d7f4429388a9b2ce8470bfee
1 /*
2 * anjuta-view.c
4 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
5 * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi
6 * Copyright (C) 2003-2005 Paolo Maggi
7 * Copyright (C) 2006 Johannes Schmid
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
26 * Modified by the anjuta Team, 1998-2005. See the AUTHORS file for a
27 * list of people on the anjuta Team.
28 * See the ChangeLog files for a list of changes.
30 * $Id$
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #include <string.h>
38 #include <stdlib.h>
40 #include <gdk/gdkkeysyms.h>
42 #include <glib/gi18n.h>
43 #include <glib.h>
45 #include <libanjuta/anjuta-debug.h>
46 #include <libanjuta/anjuta-encodings.h>
48 #include "anjuta-view.h"
49 #include "sourceview.h"
50 #include "sourceview-private.h"
51 #include "anjuta-marshal.h"
53 #define ANJUTA_VIEW_SCROLL_MARGIN 0.02
55 #define ANJUTA_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), ANJUTA_TYPE_VIEW, AnjutaViewPrivate))
57 enum
59 ANJUTA_VIEW_POPUP = 1
62 struct _AnjutaViewPrivate
64 GtkWidget* popup;
65 guint scroll_idle;
66 Sourceview* sv;
69 static void anjuta_view_destroy (GtkObject *object);
70 static void anjuta_view_finalize (GObject *object);
71 static void anjuta_view_move_cursor (GtkTextView *text_view,
72 GtkMovementStep step,
73 gint count,
74 gboolean extend_selection);
75 static gint anjuta_view_focus_out (GtkWidget *widget,
76 GdkEventFocus *event);
78 static gint anjuta_view_expose (GtkWidget *widget,
79 GdkEventExpose *event);
81 static gboolean anjuta_view_key_press_event (GtkWidget *widget,
82 GdkEventKey *event);
83 static gboolean anjuta_view_button_press_event (GtkWidget *widget,
84 GdkEventButton *event);
86 G_DEFINE_TYPE(AnjutaView, anjuta_view, GTK_TYPE_SOURCE_VIEW)
88 static gboolean
89 scroll_to_cursor_real (AnjutaView *view)
91 GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
92 g_return_val_if_fail (buffer != NULL, FALSE);
94 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
95 gtk_text_buffer_get_insert (buffer),
96 0.25,
97 FALSE,
98 0.0,
99 0.0);
101 view->priv->scroll_idle = 0;
102 return FALSE;
105 static void
106 anjuta_view_set_property (GObject * object,
107 guint property_id,
108 const GValue * value, GParamSpec * pspec)
110 AnjutaView *self = ANJUTA_VIEW (object);
111 g_return_if_fail(value != NULL);
112 g_return_if_fail(pspec != NULL);
114 switch (property_id)
116 case ANJUTA_VIEW_POPUP:
118 GtkWidget* widget;
119 self->priv->popup = g_value_get_object (value);
120 widget = gtk_menu_get_attach_widget(GTK_MENU(self->priv->popup));
121 /* This is a very ugly hack, maybe somebody more familiar with gtk menus
122 can fix this */
123 if (widget != NULL)
124 gtk_menu_detach(GTK_MENU(self->priv->popup));
125 gtk_menu_attach_to_widget(GTK_MENU(self->priv->popup), GTK_WIDGET(self), NULL);
126 break;
128 default:
130 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
131 break;
136 static void
137 anjuta_view_get_property (GObject * object,
138 guint property_id,
139 GValue * value, GParamSpec * pspec)
141 AnjutaView *self = ANJUTA_VIEW (object);
143 g_return_if_fail(value != NULL);
144 g_return_if_fail(pspec != NULL);
146 switch (property_id)
148 case ANJUTA_VIEW_POPUP:
150 g_value_set_object (value, self->priv->popup);
151 break;
153 default:
155 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
156 break;
161 static void
162 anjuta_view_class_init (AnjutaViewClass *klass)
164 GObjectClass *object_class = G_OBJECT_CLASS (klass);
165 GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass);
166 GtkTextViewClass *textview_class = GTK_TEXT_VIEW_CLASS (klass);
167 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
168 GtkBindingSet *binding_set;
169 GParamSpec *anjuta_view_spec_popup;
171 gtkobject_class->destroy = anjuta_view_destroy;
172 object_class->finalize = anjuta_view_finalize;
173 object_class->set_property = anjuta_view_set_property;
174 object_class->get_property = anjuta_view_get_property;
176 widget_class->focus_out_event = anjuta_view_focus_out;
177 widget_class->expose_event = anjuta_view_expose;
178 widget_class->key_press_event = anjuta_view_key_press_event;
179 widget_class->button_press_event = anjuta_view_button_press_event;
181 textview_class->move_cursor = anjuta_view_move_cursor;
183 g_type_class_add_private (klass, sizeof (AnjutaViewPrivate));
185 anjuta_view_spec_popup = g_param_spec_object ("popup",
186 "Popup menu",
187 "The popup-menu to show",
188 GTK_TYPE_WIDGET,
189 G_PARAM_READWRITE);
190 g_object_class_install_property (object_class,
191 ANJUTA_VIEW_POPUP,
192 anjuta_view_spec_popup);
194 binding_set = gtk_binding_set_by_class (klass);
197 static void
198 move_cursor (GtkTextView *text_view,
199 const GtkTextIter *new_location,
200 gboolean extend_selection)
202 GtkTextBuffer *buffer = text_view->buffer;
204 if (extend_selection)
205 gtk_text_buffer_move_mark_by_name (buffer,
206 "insert",
207 new_location);
208 else
209 gtk_text_buffer_place_cursor (buffer, new_location);
211 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (text_view),
212 gtk_text_buffer_get_insert (buffer),
213 ANJUTA_VIEW_SCROLL_MARGIN,
214 FALSE,
215 0.0,
216 0.0);
219 static void
220 anjuta_view_move_cursor (GtkTextView *text_view,
221 GtkMovementStep step,
222 gint count,
223 gboolean extend_selection)
225 GtkTextBuffer *buffer = text_view->buffer;
226 GtkTextMark *mark;
227 GtkTextIter cur, iter;
229 /* really make sure gtksourceview's home/end is disabled */
230 g_return_if_fail (!gtk_source_view_get_smart_home_end (
231 GTK_SOURCE_VIEW (text_view)));
233 mark = gtk_text_buffer_get_insert (buffer);
234 gtk_text_buffer_get_iter_at_mark (buffer, &cur, mark);
235 iter = cur;
237 if (step == GTK_MOVEMENT_DISPLAY_LINE_ENDS &&
238 (count == -1) && gtk_text_iter_starts_line (&iter))
240 /* Find the iter of the first character on the line. */
241 while (!gtk_text_iter_ends_line (&cur))
243 gunichar c;
245 c = gtk_text_iter_get_char (&cur);
246 if (g_unichar_isspace (c))
247 gtk_text_iter_forward_char (&cur);
248 else
249 break;
252 /* if we are clearing selection, we need to move_cursor even
253 * if we are at proper iter because selection_bound may need
254 * to be moved */
255 if (!gtk_text_iter_equal (&cur, &iter) || !extend_selection)
256 move_cursor (text_view, &cur, extend_selection);
258 else if (step == GTK_MOVEMENT_DISPLAY_LINE_ENDS &&
259 (count == 1) && gtk_text_iter_ends_line (&iter))
261 /* Find the iter of the last character on the line. */
262 while (!gtk_text_iter_starts_line (&cur))
264 gunichar c;
266 gtk_text_iter_backward_char (&cur);
267 c = gtk_text_iter_get_char (&cur);
268 if (!g_unichar_isspace (c))
270 /* We've gone one character too far. */
271 gtk_text_iter_forward_char (&cur);
272 break;
276 /* if we are clearing selection, we need to move_cursor even
277 * if we are at proper iter because selection_bound may need
278 * to be moved */
279 if (!gtk_text_iter_equal (&cur, &iter) || !extend_selection)
280 move_cursor (text_view, &cur, extend_selection);
282 else
284 /* note that we chain up to GtkTextView skipping GtkSourceView */
285 (* GTK_TEXT_VIEW_CLASS (anjuta_view_parent_class)->move_cursor) (text_view,
286 step,
287 count,
288 extend_selection);
292 static void
293 anjuta_view_init (AnjutaView *view)
295 view->priv = ANJUTA_VIEW_GET_PRIVATE (view);
298 * Set tab, fonts, wrap mode, colors, etc. according
299 * to preferences
302 g_object_set (G_OBJECT (view),
303 "wrap-mode", FALSE,
304 "show-line-numbers", TRUE,
305 "auto-indent", TRUE,
306 "tab-width", 4,
307 "insert-spaces-instead-of-tabs", FALSE,
308 "highlight-current-line", TRUE,
309 "indent-on-tab", TRUE, /* Fix #388727 */
310 "smart-home-end", FALSE, /* Never changes this */
311 NULL);
314 static void
315 anjuta_view_destroy (GtkObject *object)
317 AnjutaView *view;
319 view = ANJUTA_VIEW (object);
321 (* GTK_OBJECT_CLASS (anjuta_view_parent_class)->destroy) (object);
324 static void
325 anjuta_view_finalize (GObject *object)
327 AnjutaView *view;
329 view = ANJUTA_VIEW (object);
331 if (view->priv->popup != NULL)
333 GtkWidget* widget = gtk_menu_get_attach_widget (GTK_MENU (view->priv->popup));
334 if (widget != NULL)
335 gtk_menu_detach (GTK_MENU (view->priv->popup));
338 (* G_OBJECT_CLASS (anjuta_view_parent_class)->finalize) (object);
341 static gint
342 anjuta_view_focus_out (GtkWidget *widget, GdkEventFocus *event)
344 AnjutaView *view = ANJUTA_VIEW (widget);
345 AssistWindow* assist_win = view->priv->sv->priv->assist_win;
346 AssistTip* assist_tip = view->priv->sv->priv->assist_tip;
348 if (assist_win)
349 gtk_widget_destroy(GTK_WIDGET(assist_win));
351 if (assist_tip)
352 gtk_widget_destroy(GTK_WIDGET(assist_tip));
354 gtk_widget_queue_draw (widget);
357 (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->focus_out_event) (widget, event);
359 return FALSE;
364 * anjuta_view_new:
365 * @sv: a #Sourceview
367 * Creates a new #AnjutaView object displaying the @sv->priv->doc document.
368 * @doc cannot be NULL.
370 * Return value: a new #AnjutaView
372 GtkWidget *
373 anjuta_view_new (Sourceview *sv)
375 GtkWidget *view;
377 view = GTK_WIDGET (g_object_new (ANJUTA_TYPE_VIEW, NULL));
379 gtk_text_view_set_buffer (GTK_TEXT_VIEW (view),
380 GTK_TEXT_BUFFER (sv->priv->document));
382 gtk_widget_show_all (view);
384 ANJUTA_VIEW(view)->priv->sv = sv;
386 return view;
389 void
390 anjuta_view_cut_clipboard (AnjutaView *view)
392 GtkTextBuffer *buffer;
393 GtkClipboard *clipboard;
395 g_return_if_fail (ANJUTA_IS_VIEW (view));
397 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
398 g_return_if_fail (buffer != NULL);
400 if (!gtk_text_view_get_editable (GTK_TEXT_VIEW(view)))
401 return;
403 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
404 GDK_SELECTION_CLIPBOARD);
406 /* FIXME: what is default editability of a buffer? */
407 gtk_text_buffer_cut_clipboard (buffer,
408 clipboard,
409 TRUE);
411 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
412 gtk_text_buffer_get_insert (buffer),
413 ANJUTA_VIEW_SCROLL_MARGIN,
414 FALSE,
415 0.0,
416 0.0);
419 void
420 anjuta_view_copy_clipboard (AnjutaView *view)
422 GtkTextBuffer *buffer;
423 GtkClipboard *clipboard;
425 g_return_if_fail (ANJUTA_IS_VIEW (view));
427 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
428 g_return_if_fail (buffer != NULL);
430 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
431 GDK_SELECTION_CLIPBOARD);
433 gtk_text_buffer_copy_clipboard (buffer, clipboard);
435 /* on copy do not scroll, we are already on screen */
438 void
439 anjuta_view_paste_clipboard (AnjutaView *view)
441 GtkTextBuffer *buffer;
442 GtkClipboard *clipboard;
444 g_return_if_fail (ANJUTA_IS_VIEW (view));
446 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
447 g_return_if_fail (buffer != NULL);
449 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
450 GDK_SELECTION_CLIPBOARD);
452 /* FIXME: what is default editability of a buffer? */
453 gtk_text_buffer_paste_clipboard (buffer,
454 clipboard,
455 NULL,
456 TRUE);
458 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
459 gtk_text_buffer_get_insert (buffer),
460 ANJUTA_VIEW_SCROLL_MARGIN,
461 FALSE,
462 0.0,
463 0.0);
466 void
467 anjuta_view_delete_selection (AnjutaView *view)
469 GtkTextBuffer *buffer = NULL;
471 g_return_if_fail (ANJUTA_IS_VIEW (view));
473 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
474 g_return_if_fail (buffer != NULL);
476 /* FIXME: what is default editability of a buffer? */
477 gtk_text_buffer_delete_selection (buffer,
478 TRUE,
479 TRUE);
481 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
482 gtk_text_buffer_get_insert (buffer),
483 ANJUTA_VIEW_SCROLL_MARGIN,
484 FALSE,
485 0.0,
486 0.0);
489 void
490 anjuta_view_select_all (AnjutaView *view)
492 GtkTextBuffer *buffer = NULL;
493 GtkTextIter start, end;
495 g_return_if_fail (ANJUTA_IS_VIEW (view));
497 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
498 g_return_if_fail (buffer != NULL);
500 gtk_text_buffer_get_bounds (buffer, &start, &end);
501 gtk_text_buffer_select_range (buffer, &start, &end);
504 void
505 anjuta_view_scroll_to_cursor (AnjutaView *view)
507 g_return_if_fail (ANJUTA_IS_VIEW (view));
509 view->priv->scroll_idle = g_idle_add ((GSourceFunc) scroll_to_cursor_real, view);
512 void
513 anjuta_view_set_font (AnjutaView *view,
514 gboolean def,
515 const gchar *font_name)
518 g_return_if_fail (ANJUTA_IS_VIEW (view));
520 if (!def)
522 PangoFontDescription *font_desc = NULL;
524 g_return_if_fail (font_name != NULL);
526 font_desc = pango_font_description_from_string (font_name);
527 g_return_if_fail (font_desc != NULL);
529 gtk_widget_modify_font (GTK_WIDGET (view), font_desc);
531 pango_font_description_free (font_desc);
533 else
535 GtkRcStyle *rc_style;
537 rc_style = gtk_widget_get_modifier_style (GTK_WIDGET (view));
539 if (rc_style->font_desc)
540 pango_font_description_free (rc_style->font_desc);
542 rc_style->font_desc = NULL;
544 gtk_widget_modify_style (GTK_WIDGET (view), rc_style);
548 static gint
549 anjuta_view_expose (GtkWidget *widget,
550 GdkEventExpose *event)
552 GtkTextView *text_view;
553 GtkTextBuffer *doc;
555 text_view = GTK_TEXT_VIEW (widget);
557 doc = gtk_text_view_get_buffer (text_view);
559 if ((event->window == gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT)))
561 GdkRectangle visible_rect;
562 GtkTextIter iter1, iter2;
564 gtk_text_view_get_visible_rect (text_view, &visible_rect);
565 gtk_text_view_get_line_at_y (text_view, &iter1,
566 visible_rect.y, NULL);
567 gtk_text_view_get_line_at_y (text_view, &iter2,
568 visible_rect.y
569 + visible_rect.height, NULL);
570 gtk_text_iter_forward_line (&iter2);
573 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->expose_event)(widget, event);
576 static gboolean
577 anjuta_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
579 GtkTextBuffer *buffer;
580 AnjutaView* view = ANJUTA_VIEW(widget);
581 AssistWindow* assist_win;
582 AssistTip* assist_tip;
584 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
586 assist_win = view->priv->sv->priv->assist_win;
587 if (assist_win)
589 if (assist_window_filter_keypress(assist_win, event->keyval))
591 DEBUG_PRINT("key filtered: %d", event->keyval);
592 return TRUE;
595 assist_tip = view->priv->sv->priv->assist_tip;
596 if (assist_tip)
598 switch (event->keyval)
600 case GDK_Escape:
601 case GDK_Up:
602 case GDK_Down:
603 case GDK_Page_Up:
604 case GDK_Page_Down:
605 gtk_widget_destroy (GTK_WIDGET(assist_tip));
606 break;
609 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->key_press_event)(widget, event);
612 static gboolean
613 anjuta_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
615 AnjutaView* view = ANJUTA_VIEW(widget);
617 /* If we have a calltip shown - hide it */
618 AssistTip* assist_tip = view->priv->sv->priv->assist_tip;
619 AssistWindow* assist_win = view->priv->sv->priv->assist_win;
620 if (assist_win)
622 gtk_widget_destroy (GTK_WIDGET (assist_win));
624 if (assist_tip)
626 gtk_widget_destroy (GTK_WIDGET (assist_tip));
629 switch(event->button)
631 case 3: /* Right Button */
633 GtkTextBuffer* buffer = GTK_TEXT_BUFFER (view->priv->sv->priv->document);
634 if (!gtk_text_buffer_get_has_selection (buffer))
636 /* Move cursor to set breakpoints at correct line (#530689) */
637 GtkTextIter iter;
638 gint buffer_x, buffer_y;
639 GtkTextWindowType type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (view),
640 event->window);
641 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
642 type,
643 event->x,
644 event->y,
645 &buffer_x,
646 &buffer_y);
647 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view),
648 &iter, buffer_x, buffer_y);
649 gtk_text_buffer_place_cursor (buffer, &iter);
651 gtk_menu_popup (GTK_MENU (view->priv->popup), NULL, NULL, NULL, NULL,
652 event->button, event->time);
653 return TRUE;
655 default:
656 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->button_press_event)(widget, event);