4 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
5 * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
6 * Copyright (C) 2002-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.
40 #include <glib/gi18n.h>
41 #include <libgnomevfs/gnome-vfs.h>
42 #include <libanjuta/anjuta-debug.h>
44 #include "anjuta-encodings.h"
45 #include "anjuta-document.h"
46 #include "anjuta-document-loader.h"
47 #include "anjuta-document-saver.h"
48 #include "anjuta-marshal.h"
49 #include "anjuta-utils.h"
51 #include <gtksourceview/gtksourceiter.h>
54 #define ANJUTA_MAX_PATH_LEN 2048
56 #define ANJUTA_DOCUMENT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), ANJUTA_TYPE_DOCUMENT, AnjutaDocumentPrivate))
58 static void anjuta_document_set_readonly (AnjutaDocument
*doc
,
61 static void delete_range_cb (AnjutaDocument
*doc
,
65 struct _AnjutaDocumentPrivate
68 gint last_save_was_manually
: 1;
69 gint language_set_by_user
: 1;
70 gint is_saving_as
: 1;
71 gint stop_cursor_moved_emission
: 1;
78 const AnjutaEncoding
*encoding
;
82 GTimeVal time_of_last_save_or_load
;
84 /* Temp data while loading */
85 AnjutaDocumentLoader
*loader
;
86 gboolean create
; /* Create file if uri points
87 * to a non existing file */
88 const AnjutaEncoding
*requested_encoding
;
89 gint requested_line_pos
;
92 AnjutaDocumentSaver
*saver
;
114 static guint document_signals
[LAST_SIGNAL
] = { 0 };
116 G_DEFINE_TYPE(AnjutaDocument
, anjuta_document
, GTK_TYPE_SOURCE_BUFFER
)
119 anjuta_document_error_quark (void)
121 static GQuark quark
= 0;
123 if (G_UNLIKELY (quark
== 0))
124 quark
= g_quark_from_static_string ("anjuta_io_load_error");
129 static GHashTable
*allocated_untitled_numbers
= NULL
;
132 get_untitled_number (void)
136 if (allocated_untitled_numbers
== NULL
)
137 allocated_untitled_numbers
= g_hash_table_new (NULL
, NULL
);
139 g_return_val_if_fail (allocated_untitled_numbers
!= NULL
, -1);
143 if (g_hash_table_lookup (allocated_untitled_numbers
, GINT_TO_POINTER (i
)) == NULL
)
145 g_hash_table_insert (allocated_untitled_numbers
,
147 GINT_TO_POINTER (i
));
157 release_untitled_number (gint n
)
159 g_return_if_fail (allocated_untitled_numbers
!= NULL
);
161 g_hash_table_remove (allocated_untitled_numbers
, GINT_TO_POINTER (n
));
165 anjuta_document_finalize (GObject
*object
)
167 AnjutaDocument
*doc
= ANJUTA_DOCUMENT (object
);
169 if (doc
->priv
->untitled_number
> 0)
171 g_return_if_fail (doc
->priv
->uri
== NULL
);
172 release_untitled_number (doc
->priv
->untitled_number
);
175 if (doc
->priv
->uri
!= NULL
)
180 gtk_text_buffer_get_iter_at_mark (
181 GTK_TEXT_BUFFER (doc
),
183 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (doc
)));
186 g_free (doc
->priv
->uri
);
187 if (doc
->priv
->vfs_uri
!= NULL
)
188 gnome_vfs_uri_unref (doc
->priv
->vfs_uri
);
190 if (doc
->priv
->loader
)
191 g_object_unref (doc
->priv
->loader
);
195 anjuta_document_get_property (GObject
*object
,
200 AnjutaDocument
*doc
= ANJUTA_DOCUMENT (object
);
205 g_value_set_string (value
, doc
->priv
->uri
);
208 g_value_take_string (value
, anjuta_document_get_short_name_for_display (doc
));
211 g_value_set_boolean (value
, doc
->priv
->readonly
);
214 g_value_set_boxed (value
, doc
->priv
->encoding
);
217 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
223 anjuta_document_set_property (GObject
*object
,
228 // AnjutaDocument *doc = ANJUTA_DOCUMENT (object);
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
239 emit_cursor_moved (AnjutaDocument
*doc
)
241 if (!doc
->priv
->stop_cursor_moved_emission
)
244 document_signals
[CURSOR_MOVED
],
250 anjuta_document_mark_set (GtkTextBuffer
*buffer
,
251 const GtkTextIter
*iter
,
254 AnjutaDocument
*doc
= ANJUTA_DOCUMENT (buffer
);
256 if (GTK_TEXT_BUFFER_CLASS (anjuta_document_parent_class
)->mark_set
)
257 GTK_TEXT_BUFFER_CLASS (anjuta_document_parent_class
)->mark_set (buffer
,
261 if (mark
== gtk_text_buffer_get_insert (buffer
))
263 emit_cursor_moved (doc
);
268 anjuta_document_changed (GtkTextBuffer
*buffer
)
270 emit_cursor_moved (ANJUTA_DOCUMENT (buffer
));
272 GTK_TEXT_BUFFER_CLASS (anjuta_document_parent_class
)->changed (buffer
);
276 anjuta_document_class_init (AnjutaDocumentClass
*klass
)
278 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
279 GtkTextBufferClass
*buf_class
= GTK_TEXT_BUFFER_CLASS (klass
);
281 object_class
->finalize
= anjuta_document_finalize
;
282 object_class
->get_property
= anjuta_document_get_property
;
283 object_class
->set_property
= anjuta_document_set_property
;
285 buf_class
->mark_set
= anjuta_document_mark_set
;
286 buf_class
->changed
= anjuta_document_changed
;
288 g_object_class_install_property (object_class
, PROP_URI
,
289 g_param_spec_string ("uri",
291 "The document's URI",
294 g_object_class_install_property (object_class
, PROP_SHORTNAME
,
295 g_param_spec_string ("shortname",
297 "The document's short name",
300 g_object_class_install_property (object_class
, PROP_READ_ONLY
,
301 g_param_spec_boolean ("read-only",
303 "Whether the document is read only or not",
306 g_object_class_install_property (object_class
, PROP_ENCODING
,
307 g_param_spec_boxed ("encoding",
309 "The AnjutaEncoding used for the document",
310 ANJUTA_TYPE_ENCODING
,
313 /* This signal is used to update the cursor position is the statusbar,
314 * it's emitted either when the insert mark is moved explicitely or
315 * when the buffer changes (insert/delete).
316 * We prevent the emission of the signal during replace_all to
317 * improve performance.
319 document_signals
[CURSOR_MOVED
] =
320 g_signal_new ("cursor-moved",
321 G_OBJECT_CLASS_TYPE (object_class
),
323 G_STRUCT_OFFSET (AnjutaDocumentClass
, cursor_moved
),
325 g_cclosure_marshal_VOID__VOID
,
329 document_signals
[LOADING
] =
330 g_signal_new ("loading",
331 G_OBJECT_CLASS_TYPE (object_class
),
333 G_STRUCT_OFFSET (AnjutaDocumentClass
, loading
),
335 anjuta_marshal_VOID__UINT64_UINT64
,
341 document_signals
[LOADED
] =
342 g_signal_new ("loaded",
343 G_OBJECT_CLASS_TYPE (object_class
),
345 G_STRUCT_OFFSET (AnjutaDocumentClass
, loaded
),
347 g_cclosure_marshal_VOID__POINTER
,
352 document_signals
[SAVING
] =
353 g_signal_new ("saving",
354 G_OBJECT_CLASS_TYPE (object_class
),
356 G_STRUCT_OFFSET (AnjutaDocumentClass
, saving
),
358 anjuta_marshal_VOID__UINT64_UINT64
,
364 document_signals
[SAVED
] =
365 g_signal_new ("saved",
366 G_OBJECT_CLASS_TYPE (object_class
),
368 G_STRUCT_OFFSET (AnjutaDocumentClass
, saved
),
370 g_cclosure_marshal_VOID__POINTER
,
375 g_type_class_add_private (object_class
, sizeof(AnjutaDocumentPrivate
));
380 set_encoding (AnjutaDocument
*doc
,
381 const AnjutaEncoding
*encoding
,
382 gboolean set_by_user
)
384 g_return_if_fail (encoding
!= NULL
);
386 if (doc
->priv
->encoding
== encoding
)
389 doc
->priv
->encoding
= encoding
;
393 const gchar
*charset
;
395 charset
= anjuta_encoding_get_charset (encoding
);
398 g_object_notify (G_OBJECT (doc
), "encoding");
402 anjuta_document_init (AnjutaDocument
*doc
)
405 doc
->priv
= ANJUTA_DOCUMENT_GET_PRIVATE (doc
);
407 doc
->priv
->uri
= NULL
;
408 doc
->priv
->vfs_uri
= NULL
;
409 doc
->priv
->untitled_number
= get_untitled_number ();
411 doc
->priv
->readonly
= FALSE
;
413 doc
->priv
->stop_cursor_moved_emission
= FALSE
;
415 doc
->priv
->last_save_was_manually
= TRUE
;
416 doc
->priv
->language_set_by_user
= FALSE
;
418 doc
->priv
->mtime
= 0;
420 g_get_current_time (&doc
->priv
->time_of_last_save_or_load
);
422 doc
->priv
->encoding
= anjuta_encoding_get_utf8 ();
424 gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (doc
),
427 g_signal_connect_after (doc
,
429 G_CALLBACK (delete_range_cb
),
434 anjuta_document_new (void)
437 return ANJUTA_DOCUMENT (g_object_new (ANJUTA_TYPE_DOCUMENT
, NULL
));
441 set_uri (AnjutaDocument
*doc
,
445 g_return_if_fail ((uri
== NULL
) || anjuta_utils_is_valid_uri (uri
));
449 if (doc
->priv
->uri
== uri
)
452 g_free (doc
->priv
->uri
);
453 doc
->priv
->uri
= g_strdup (uri
);
455 if (doc
->priv
->vfs_uri
!= NULL
)
456 gnome_vfs_uri_unref (doc
->priv
->vfs_uri
);
458 /* Note: vfs_uri may be NULL for some valid but
459 * unsupported uris */
460 doc
->priv
->vfs_uri
= gnome_vfs_uri_new (uri
);
462 if (doc
->priv
->untitled_number
> 0)
464 release_untitled_number (doc
->priv
->untitled_number
);
465 doc
->priv
->untitled_number
= 0;
468 g_object_notify (G_OBJECT (doc
), "uri");
469 g_object_notify (G_OBJECT (doc
), "shortname");
473 anjuta_document_get_uri (AnjutaDocument
*doc
)
475 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), NULL
);
477 return g_strdup (doc
->priv
->uri
);
480 /* Never returns NULL */
482 anjuta_document_get_uri_for_display (AnjutaDocument
*doc
)
484 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), "");
486 if (doc
->priv
->uri
== NULL
)
487 return g_strdup_printf (_("Unsaved Document %d"),
488 doc
->priv
->untitled_number
);
490 return gnome_vfs_format_uri_for_display (doc
->priv
->uri
);
493 /* move to anjuta-utils? */
495 get_uri_shortname_for_display (GnomeVFSURI
*uri
)
502 name
= gnome_vfs_uri_extract_short_name (uri
);
506 name
= gnome_vfs_uri_to_string (uri
, GNOME_VFS_URI_HIDE_PASSWORD
);
508 else if (g_ascii_strcasecmp (uri
->method_string
, "file") == 0)
512 text_uri
= gnome_vfs_uri_to_string (uri
, GNOME_VFS_URI_HIDE_PASSWORD
);
513 local_file
= gnome_vfs_get_local_path_from_uri (text_uri
);
515 if (local_file
!= NULL
)
518 name
= g_filename_display_basename (local_file
);
525 else if (!gnome_vfs_uri_has_parent (uri
))
529 method
= uri
->method_string
;
532 strcmp (name
, GNOME_VFS_URI_PATH_STR
) == 0)
535 name
= g_strdup (method
);
543 name = g_strdup_printf ("%s: %s", method, name);
549 if (!validated
&& !g_utf8_validate (name
, -1, NULL
))
553 utf8_name
= anjuta_utils_make_valid_utf8 (name
);
561 /* Never returns NULL */
563 anjuta_document_get_short_name_for_display (AnjutaDocument
*doc
)
565 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), "");
567 if (doc
->priv
->uri
== NULL
)
568 return g_strdup_printf (_("Unsaved Document %d"),
569 doc
->priv
->untitled_number
);
570 else if (doc
->priv
->vfs_uri
== NULL
)
571 return g_strdup (doc
->priv
->uri
);
573 return get_uri_shortname_for_display (doc
->priv
->vfs_uri
);
576 /* Note: do not emit the notify::read-only signal */
578 set_readonly (AnjutaDocument
*doc
,
581 readonly
= (readonly
!= FALSE
);
583 if (doc
->priv
->readonly
== readonly
)
586 doc
->priv
->readonly
= readonly
;
590 anjuta_document_set_readonly (AnjutaDocument
*doc
,
593 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
595 set_readonly (doc
, readonly
);
597 g_object_notify (G_OBJECT (doc
), "read-only");
601 anjuta_document_get_readonly (AnjutaDocument
*doc
)
603 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), TRUE
);
605 return doc
->priv
->readonly
;
609 reset_temp_loading_data (AnjutaDocument
*doc
)
611 /* the loader has been used, throw it away */
612 g_object_unref (doc
->priv
->loader
);
613 doc
->priv
->loader
= NULL
;
615 doc
->priv
->requested_encoding
= NULL
;
616 doc
->priv
->requested_line_pos
= 0;
620 document_loader_loaded (AnjutaDocumentLoader
*loader
,
624 /* load was successful */
629 doc
->priv
->mtime
= anjuta_document_loader_get_mtime (loader
);
631 g_get_current_time (&doc
->priv
->time_of_last_save_or_load
);
634 anjuta_document_loader_get_readonly (loader
));
637 anjuta_document_loader_get_encoding (loader
),
638 (doc
->priv
->requested_encoding
!= NULL
));
640 /* We already set the uri */
643 /* move the cursor at the requested line if any */
644 if (doc
->priv
->requested_line_pos
> 0)
646 /* line_pos - 1 because get_iter_at_line counts from 0 */
647 gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc
),
649 doc
->priv
->requested_line_pos
- 1);
652 gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc
),
654 gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc
), &iter
);
657 /* special case creating a named new doc */
658 else if (doc
->priv
->create
&&
659 (error
->code
== GNOME_VFS_ERROR_NOT_FOUND
))
661 reset_temp_loading_data (doc
);
662 // FIXME: do other stuff??
665 document_signals
[LOADED
],
673 document_signals
[LOADED
],
677 reset_temp_loading_data (doc
);
681 document_loader_loading (AnjutaDocumentLoader
*loader
,
688 document_loader_loaded (loader
, error
, doc
);
692 GnomeVFSFileSize size
;
693 GnomeVFSFileSize read
;
695 size
= anjuta_document_loader_get_file_size (loader
);
696 read
= anjuta_document_loader_get_bytes_read (loader
);
699 document_signals
[LOADING
],
707 anjuta_document_load (AnjutaDocument
*doc
,
709 const AnjutaEncoding
*encoding
,
713 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
714 g_return_if_fail (uri
!= NULL
);
715 g_return_if_fail (anjuta_utils_is_valid_uri (uri
));
717 g_return_if_fail (doc
->priv
->loader
== NULL
);
719 /* create a loader. It will be destroyed when loading is completed */
720 doc
->priv
->loader
= anjuta_document_loader_new (doc
);
722 g_signal_connect (doc
->priv
->loader
,
724 G_CALLBACK (document_loader_loading
),
727 doc
->priv
->create
= create
;
728 doc
->priv
->requested_encoding
= encoding
;
729 doc
->priv
->requested_line_pos
= line_pos
;
733 anjuta_document_loader_load (doc
->priv
->loader
,
739 anjuta_document_load_cancel (AnjutaDocument
*doc
)
741 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), FALSE
);
743 if (doc
->priv
->loader
== NULL
)
746 return anjuta_document_loader_cancel (doc
->priv
->loader
);
750 document_saver_saving (AnjutaDocumentSaver
*saver
,
758 /* save was successful */
763 uri
= anjuta_document_saver_get_uri (saver
);
765 doc
->priv
->mtime
= anjuta_document_saver_get_mtime (saver
);
767 g_get_current_time (&doc
->priv
->time_of_last_save_or_load
);
769 anjuta_document_set_readonly (doc
, FALSE
);
771 gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc
),
777 doc
->priv
->requested_encoding
,
781 /* the saver has been used, throw it away */
782 g_object_unref (doc
->priv
->saver
);
783 doc
->priv
->saver
= NULL
;
784 doc
->priv
->is_saving_as
= FALSE
;
787 document_signals
[SAVED
],
793 GnomeVFSFileSize size
= 0;
794 GnomeVFSFileSize written
= 0;
796 size
= anjuta_document_saver_get_file_size (saver
);
797 written
= anjuta_document_saver_get_bytes_written (saver
);
800 document_signals
[SAVING
],
808 document_save_real (AnjutaDocument
*doc
,
810 const AnjutaEncoding
*encoding
,
812 AnjutaDocumentSaveFlags flags
)
814 g_return_if_fail (doc
->priv
->saver
== NULL
);
816 /* create a saver, it will be destroyed once saving is complete */
817 doc
->priv
->saver
= anjuta_document_saver_new (doc
);
819 g_signal_connect (doc
->priv
->saver
,
821 G_CALLBACK (document_saver_saving
),
824 doc
->priv
->requested_encoding
= encoding
;
826 anjuta_document_saver_save (doc
->priv
->saver
,
834 anjuta_document_save (AnjutaDocument
*doc
,
835 AnjutaDocumentSaveFlags flags
)
837 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
838 g_return_if_fail (doc
->priv
->uri
!= NULL
);
840 document_save_real (doc
,
848 anjuta_document_save_as (AnjutaDocument
*doc
,
850 const AnjutaEncoding
*encoding
,
851 AnjutaDocumentSaveFlags flags
)
853 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
854 g_return_if_fail (uri
!= NULL
);
855 g_return_if_fail (encoding
!= NULL
);
857 doc
->priv
->is_saving_as
= TRUE
;
859 document_save_real (doc
, uri
, encoding
, 0, flags
);
863 * If @line is bigger than the lines of the document, the cursor is moved
864 * to the last line and FALSE is returned.
867 anjuta_document_goto_line (AnjutaDocument
*doc
,
874 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), FALSE
);
875 g_return_val_if_fail (line
>= -1, FALSE
);
877 line_count
= gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (doc
));
879 if (line
>= line_count
)
882 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc
),
887 gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc
),
892 gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc
), &iter
);
897 const AnjutaEncoding
*
898 anjuta_document_get_encoding (AnjutaDocument
*doc
)
900 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), NULL
);
902 return doc
->priv
->encoding
;
907 wordcharacters_contains (gchar c
)
909 const gchar
* wordcharacters
=
910 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
913 for (pos
= 0; pos
< strlen(wordcharacters
); pos
++)
915 if (wordcharacters
[pos
] == c
)
923 gchar
* anjuta_document_get_current_word(AnjutaDocument
* doc
, gboolean end_position
)
927 GtkTextBuffer
* buffer
= GTK_TEXT_BUFFER(doc
);
933 const int maxlength
= 100;
935 gtk_text_buffer_get_iter_at_mark (buffer
, &begin
,
936 gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(buffer
)));
937 gtk_text_buffer_get_iter_at_mark (buffer
, &end
,
938 gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(buffer
)));
939 startword
= gtk_text_iter_get_line_offset (&begin
);
940 endword
= gtk_text_iter_get_line_offset (&end
);
942 gtk_text_iter_set_line_offset (&begin
, 0);
943 gtk_text_iter_forward_to_line_end (&end
);
945 region
= gtk_text_buffer_get_text (buffer
, &begin
, &end
, FALSE
);
947 while (startword
> 0 && wordcharacters_contains(region
[startword
- 1]))
949 while (!end_position
&& region
[endword
] && wordcharacters_contains(region
[endword
]))
951 if(startword
== endword
)
954 region
[endword
] = '\0';
955 cplen
= (maxlength
< (endword
-startword
+1))?maxlength
:(endword
-startword
+1);
956 word
= g_strndup (region
+ startword
, cplen
);
958 DEBUG_PRINT ("region: %s\n start: %d end: %d word: %s", region
, startword
, endword
, word
);
965 delete_range_cb (AnjutaDocument
*doc
,