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 <libanjuta/anjuta-encodings.h>
46 #include "anjuta-document.h"
47 #include "anjuta-document-loader.h"
48 #include "anjuta-document-saver.h"
49 #include "anjuta-marshal.h"
50 #include "anjuta-utils.h"
52 #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
;
113 static guint document_signals
[LAST_SIGNAL
] = { 0 };
115 G_DEFINE_TYPE(AnjutaDocument
, anjuta_document
, GTK_TYPE_SOURCE_BUFFER
)
118 anjuta_document_error_quark (void)
120 static GQuark quark
= 0;
122 if (G_UNLIKELY (quark
== 0))
123 quark
= g_quark_from_static_string ("anjuta_io_load_error");
128 static GHashTable
*allocated_untitled_numbers
= NULL
;
131 get_untitled_number (void)
135 if (allocated_untitled_numbers
== NULL
)
136 allocated_untitled_numbers
= g_hash_table_new (NULL
, NULL
);
138 g_return_val_if_fail (allocated_untitled_numbers
!= NULL
, -1);
142 if (g_hash_table_lookup (allocated_untitled_numbers
, GINT_TO_POINTER (i
)) == NULL
)
144 g_hash_table_insert (allocated_untitled_numbers
,
146 GINT_TO_POINTER (i
));
156 release_untitled_number (gint n
)
158 g_return_if_fail (allocated_untitled_numbers
!= NULL
);
160 g_hash_table_remove (allocated_untitled_numbers
, GINT_TO_POINTER (n
));
164 anjuta_document_finalize (GObject
*object
)
166 AnjutaDocument
*doc
= ANJUTA_DOCUMENT (object
);
168 if (doc
->priv
->untitled_number
> 0)
170 g_return_if_fail (doc
->priv
->uri
== NULL
);
171 release_untitled_number (doc
->priv
->untitled_number
);
174 if (doc
->priv
->uri
!= NULL
)
179 gtk_text_buffer_get_iter_at_mark (
180 GTK_TEXT_BUFFER (doc
),
182 gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (doc
)));
185 g_free (doc
->priv
->uri
);
186 if (doc
->priv
->vfs_uri
!= NULL
)
187 gnome_vfs_uri_unref (doc
->priv
->vfs_uri
);
189 if (doc
->priv
->loader
)
190 g_object_unref (doc
->priv
->loader
);
194 anjuta_document_get_property (GObject
*object
,
199 AnjutaDocument
*doc
= ANJUTA_DOCUMENT (object
);
204 g_value_set_string (value
, doc
->priv
->uri
);
207 g_value_take_string (value
, anjuta_document_get_short_name_for_display (doc
));
210 g_value_set_boolean (value
, doc
->priv
->readonly
);
213 g_value_set_boxed (value
, doc
->priv
->encoding
);
216 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
222 anjuta_document_set_property (GObject
*object
,
227 // AnjutaDocument *doc = ANJUTA_DOCUMENT (object);
232 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
238 emit_cursor_moved (AnjutaDocument
*doc
)
240 if (!doc
->priv
->stop_cursor_moved_emission
)
243 document_signals
[CURSOR_MOVED
],
249 anjuta_document_mark_set (GtkTextBuffer
*buffer
,
250 const GtkTextIter
*iter
,
253 AnjutaDocument
*doc
= ANJUTA_DOCUMENT (buffer
);
255 if (GTK_TEXT_BUFFER_CLASS (anjuta_document_parent_class
)->mark_set
)
256 GTK_TEXT_BUFFER_CLASS (anjuta_document_parent_class
)->mark_set (buffer
,
260 if (mark
== gtk_text_buffer_get_insert (buffer
))
262 emit_cursor_moved (doc
);
267 anjuta_document_changed (GtkTextBuffer
*buffer
)
269 emit_cursor_moved (ANJUTA_DOCUMENT (buffer
));
271 GTK_TEXT_BUFFER_CLASS (anjuta_document_parent_class
)->changed (buffer
);
275 anjuta_document_class_init (AnjutaDocumentClass
*klass
)
277 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
278 GtkTextBufferClass
*buf_class
= GTK_TEXT_BUFFER_CLASS (klass
);
280 object_class
->finalize
= anjuta_document_finalize
;
281 object_class
->get_property
= anjuta_document_get_property
;
282 object_class
->set_property
= anjuta_document_set_property
;
284 buf_class
->mark_set
= anjuta_document_mark_set
;
285 buf_class
->changed
= anjuta_document_changed
;
287 g_object_class_install_property (object_class
, PROP_URI
,
288 g_param_spec_string ("uri",
290 "The document's URI",
293 g_object_class_install_property (object_class
, PROP_SHORTNAME
,
294 g_param_spec_string ("shortname",
296 "The document's short name",
299 g_object_class_install_property (object_class
, PROP_READ_ONLY
,
300 g_param_spec_boolean ("read-only",
302 "Whether the document is read only or not",
305 g_object_class_install_property (object_class
, PROP_ENCODING
,
306 g_param_spec_boxed ("encoding",
308 "The AnjutaEncoding used for the document",
309 ANJUTA_TYPE_ENCODING
,
312 /* This signal is used to update the cursor position is the statusbar,
313 * it's emitted either when the insert mark is moved explicitely or
314 * when the buffer changes (insert/delete).
315 * We prevent the emission of the signal during replace_all to
316 * improve performance.
318 document_signals
[CURSOR_MOVED
] =
319 g_signal_new ("cursor-moved",
320 G_OBJECT_CLASS_TYPE (object_class
),
322 G_STRUCT_OFFSET (AnjutaDocumentClass
, cursor_moved
),
324 g_cclosure_marshal_VOID__VOID
,
328 document_signals
[LOADING
] =
329 g_signal_new ("loading",
330 G_OBJECT_CLASS_TYPE (object_class
),
332 G_STRUCT_OFFSET (AnjutaDocumentClass
, loading
),
334 anjuta_marshal_VOID__UINT64_UINT64
,
340 document_signals
[LOADED
] =
341 g_signal_new ("loaded",
342 G_OBJECT_CLASS_TYPE (object_class
),
344 G_STRUCT_OFFSET (AnjutaDocumentClass
, loaded
),
346 g_cclosure_marshal_VOID__POINTER
,
351 document_signals
[SAVING
] =
352 g_signal_new ("saving",
353 G_OBJECT_CLASS_TYPE (object_class
),
355 G_STRUCT_OFFSET (AnjutaDocumentClass
, saving
),
357 anjuta_marshal_VOID__UINT64_UINT64
,
363 document_signals
[SAVED
] =
364 g_signal_new ("saved",
365 G_OBJECT_CLASS_TYPE (object_class
),
367 G_STRUCT_OFFSET (AnjutaDocumentClass
, saved
),
369 g_cclosure_marshal_VOID__POINTER
,
374 g_type_class_add_private (object_class
, sizeof(AnjutaDocumentPrivate
));
379 set_encoding (AnjutaDocument
*doc
,
380 const AnjutaEncoding
*encoding
,
381 gboolean set_by_user
)
383 g_return_if_fail (encoding
!= NULL
);
385 if (doc
->priv
->encoding
== encoding
)
388 doc
->priv
->encoding
= encoding
;
392 const gchar
*charset
;
394 charset
= anjuta_encoding_get_charset (encoding
);
397 g_object_notify (G_OBJECT (doc
), "encoding");
401 anjuta_document_init (AnjutaDocument
*doc
)
404 doc
->priv
= ANJUTA_DOCUMENT_GET_PRIVATE (doc
);
406 doc
->priv
->uri
= NULL
;
407 doc
->priv
->vfs_uri
= NULL
;
408 doc
->priv
->untitled_number
= get_untitled_number ();
410 doc
->priv
->readonly
= FALSE
;
412 doc
->priv
->stop_cursor_moved_emission
= FALSE
;
414 doc
->priv
->last_save_was_manually
= TRUE
;
415 doc
->priv
->language_set_by_user
= FALSE
;
417 doc
->priv
->mtime
= 0;
419 g_get_current_time (&doc
->priv
->time_of_last_save_or_load
);
421 doc
->priv
->encoding
= anjuta_encoding_get_utf8 ();
423 gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (doc
),
426 g_signal_connect_after (doc
,
428 G_CALLBACK (delete_range_cb
),
433 anjuta_document_new (void)
436 return ANJUTA_DOCUMENT (g_object_new (ANJUTA_TYPE_DOCUMENT
, NULL
));
440 set_uri (AnjutaDocument
*doc
,
444 g_return_if_fail ((uri
== NULL
) || anjuta_utils_is_valid_uri (uri
));
448 if (doc
->priv
->uri
== uri
)
451 g_free (doc
->priv
->uri
);
452 doc
->priv
->uri
= g_strdup (uri
);
454 if (doc
->priv
->vfs_uri
!= NULL
)
455 gnome_vfs_uri_unref (doc
->priv
->vfs_uri
);
457 /* Note: vfs_uri may be NULL for some valid but
458 * unsupported uris */
459 doc
->priv
->vfs_uri
= gnome_vfs_uri_new (uri
);
461 if (doc
->priv
->untitled_number
> 0)
463 release_untitled_number (doc
->priv
->untitled_number
);
464 doc
->priv
->untitled_number
= 0;
467 g_object_notify (G_OBJECT (doc
), "uri");
468 g_object_notify (G_OBJECT (doc
), "shortname");
472 anjuta_document_get_uri (AnjutaDocument
*doc
)
474 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), NULL
);
476 return g_strdup (doc
->priv
->uri
);
479 /* Never returns NULL */
481 anjuta_document_get_uri_for_display (AnjutaDocument
*doc
)
483 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), "");
485 if (doc
->priv
->uri
== NULL
)
486 return g_strdup_printf (_("Unsaved Document %d"),
487 doc
->priv
->untitled_number
);
489 return gnome_vfs_format_uri_for_display (doc
->priv
->uri
);
492 /* move to anjuta-utils? */
494 get_uri_shortname_for_display (GnomeVFSURI
*uri
)
501 name
= gnome_vfs_uri_extract_short_name (uri
);
505 name
= gnome_vfs_uri_to_string (uri
, GNOME_VFS_URI_HIDE_PASSWORD
);
507 else if (g_ascii_strcasecmp (uri
->method_string
, "file") == 0)
511 text_uri
= gnome_vfs_uri_to_string (uri
, GNOME_VFS_URI_HIDE_PASSWORD
);
512 local_file
= gnome_vfs_get_local_path_from_uri (text_uri
);
514 if (local_file
!= NULL
)
517 name
= g_filename_display_basename (local_file
);
524 else if (!gnome_vfs_uri_has_parent (uri
))
528 method
= uri
->method_string
;
531 strcmp (name
, GNOME_VFS_URI_PATH_STR
) == 0)
534 name
= g_strdup (method
);
542 name = g_strdup_printf ("%s: %s", method, name);
548 if (!validated
&& !g_utf8_validate (name
, -1, NULL
))
552 utf8_name
= anjuta_utils_make_valid_utf8 (name
);
560 /* Never returns NULL */
562 anjuta_document_get_short_name_for_display (AnjutaDocument
*doc
)
564 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), "");
566 if (doc
->priv
->uri
== NULL
)
567 return g_strdup_printf (_("Unsaved Document %d"),
568 doc
->priv
->untitled_number
);
569 else if (doc
->priv
->vfs_uri
== NULL
)
570 return g_strdup (doc
->priv
->uri
);
572 return get_uri_shortname_for_display (doc
->priv
->vfs_uri
);
575 /* Note: do not emit the notify::read-only signal */
577 set_readonly (AnjutaDocument
*doc
,
580 readonly
= (readonly
!= FALSE
);
582 if (doc
->priv
->readonly
== readonly
)
585 doc
->priv
->readonly
= readonly
;
589 anjuta_document_set_readonly (AnjutaDocument
*doc
,
592 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
594 set_readonly (doc
, readonly
);
596 g_object_notify (G_OBJECT (doc
), "read-only");
600 anjuta_document_get_readonly (AnjutaDocument
*doc
)
602 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), TRUE
);
604 return doc
->priv
->readonly
;
608 reset_temp_loading_data (AnjutaDocument
*doc
)
610 /* the loader has been used, throw it away */
611 g_object_unref (doc
->priv
->loader
);
612 doc
->priv
->loader
= NULL
;
614 doc
->priv
->requested_encoding
= NULL
;
615 doc
->priv
->requested_line_pos
= 0;
619 document_loader_loaded (AnjutaDocumentLoader
*loader
,
623 /* load was successful */
628 doc
->priv
->mtime
= anjuta_document_loader_get_mtime (loader
);
630 g_get_current_time (&doc
->priv
->time_of_last_save_or_load
);
633 anjuta_document_loader_get_readonly (loader
));
636 anjuta_document_loader_get_encoding (loader
),
637 (doc
->priv
->requested_encoding
!= NULL
));
639 /* We already set the uri */
642 /* move the cursor at the requested line if any */
643 if (doc
->priv
->requested_line_pos
> 0)
645 /* line_pos - 1 because get_iter_at_line counts from 0 */
646 gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc
),
648 doc
->priv
->requested_line_pos
- 1);
651 gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc
),
653 gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc
), &iter
);
656 /* special case creating a named new doc */
657 else if (doc
->priv
->create
&&
658 (error
->code
== GNOME_VFS_ERROR_NOT_FOUND
))
660 reset_temp_loading_data (doc
);
661 // FIXME: do other stuff??
664 document_signals
[LOADED
],
672 document_signals
[LOADED
],
676 reset_temp_loading_data (doc
);
680 document_loader_loading (AnjutaDocumentLoader
*loader
,
687 document_loader_loaded (loader
, error
, doc
);
691 GnomeVFSFileSize size
;
692 GnomeVFSFileSize read
;
694 size
= anjuta_document_loader_get_file_size (loader
);
695 read
= anjuta_document_loader_get_bytes_read (loader
);
698 document_signals
[LOADING
],
706 anjuta_document_load (AnjutaDocument
*doc
,
708 const AnjutaEncoding
*encoding
,
712 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
713 g_return_if_fail (uri
!= NULL
);
714 g_return_if_fail (anjuta_utils_is_valid_uri (uri
));
716 g_return_if_fail (doc
->priv
->loader
== NULL
);
718 /* create a loader. It will be destroyed when loading is completed */
719 doc
->priv
->loader
= anjuta_document_loader_new (doc
);
721 g_signal_connect (doc
->priv
->loader
,
723 G_CALLBACK (document_loader_loading
),
726 doc
->priv
->create
= create
;
727 doc
->priv
->requested_encoding
= encoding
;
728 doc
->priv
->requested_line_pos
= line_pos
;
732 anjuta_document_loader_load (doc
->priv
->loader
,
738 anjuta_document_load_cancel (AnjutaDocument
*doc
)
740 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), FALSE
);
742 if (doc
->priv
->loader
== NULL
)
745 return anjuta_document_loader_cancel (doc
->priv
->loader
);
749 document_saver_saving (AnjutaDocumentSaver
*saver
,
757 /* save was successful */
762 uri
= anjuta_document_saver_get_uri (saver
);
764 doc
->priv
->mtime
= anjuta_document_saver_get_mtime (saver
);
766 g_get_current_time (&doc
->priv
->time_of_last_save_or_load
);
768 anjuta_document_set_readonly (doc
, FALSE
);
770 gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc
),
776 doc
->priv
->requested_encoding
,
780 /* the saver has been used, throw it away */
781 g_object_unref (doc
->priv
->saver
);
782 doc
->priv
->saver
= NULL
;
783 doc
->priv
->is_saving_as
= FALSE
;
786 document_signals
[SAVED
],
792 GnomeVFSFileSize size
= 0;
793 GnomeVFSFileSize written
= 0;
795 size
= anjuta_document_saver_get_file_size (saver
);
796 written
= anjuta_document_saver_get_bytes_written (saver
);
799 document_signals
[SAVING
],
807 document_save_real (AnjutaDocument
*doc
,
809 const AnjutaEncoding
*encoding
,
811 AnjutaDocumentSaveFlags flags
)
813 g_return_if_fail (doc
->priv
->saver
== NULL
);
815 /* create a saver, it will be destroyed once saving is complete */
816 doc
->priv
->saver
= anjuta_document_saver_new (doc
);
818 g_signal_connect (doc
->priv
->saver
,
820 G_CALLBACK (document_saver_saving
),
823 doc
->priv
->requested_encoding
= encoding
;
825 anjuta_document_saver_save (doc
->priv
->saver
,
833 anjuta_document_save (AnjutaDocument
*doc
,
834 AnjutaDocumentSaveFlags flags
)
836 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
837 g_return_if_fail (doc
->priv
->uri
!= NULL
);
839 document_save_real (doc
,
847 anjuta_document_save_as (AnjutaDocument
*doc
,
849 const AnjutaEncoding
*encoding
,
850 AnjutaDocumentSaveFlags flags
)
852 g_return_if_fail (ANJUTA_IS_DOCUMENT (doc
));
853 g_return_if_fail (uri
!= NULL
);
854 g_return_if_fail (encoding
!= NULL
);
856 doc
->priv
->is_saving_as
= TRUE
;
858 document_save_real (doc
, uri
, encoding
, 0, flags
);
862 * If @line is bigger than the lines of the document, the cursor is moved
863 * to the last line and FALSE is returned.
866 anjuta_document_goto_line (AnjutaDocument
*doc
,
873 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), FALSE
);
874 g_return_val_if_fail (line
>= -1, FALSE
);
876 line_count
= gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (doc
));
878 if (line
>= line_count
)
881 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc
),
886 gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc
),
891 gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc
), &iter
);
896 const AnjutaEncoding
*
897 anjuta_document_get_encoding (AnjutaDocument
*doc
)
899 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), NULL
);
901 return doc
->priv
->encoding
;
906 wordcharacters_contains (gchar c
)
908 const gchar
* wordcharacters
=
909 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
912 for (pos
= 0; pos
< strlen(wordcharacters
); pos
++)
914 if (wordcharacters
[pos
] == c
)
922 gchar
* anjuta_document_get_current_word(AnjutaDocument
* doc
, gboolean end_position
)
926 GtkTextBuffer
* buffer
= GTK_TEXT_BUFFER(doc
);
932 const int maxlength
= 100;
934 gtk_text_buffer_get_iter_at_mark (buffer
, &begin
,
935 gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(buffer
)));
936 gtk_text_buffer_get_iter_at_mark (buffer
, &end
,
937 gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(buffer
)));
938 startword
= gtk_text_iter_get_line_offset (&begin
);
939 endword
= gtk_text_iter_get_line_offset (&end
);
941 gtk_text_iter_set_line_offset (&begin
, 0);
942 gtk_text_iter_forward_to_line_end (&end
);
944 region
= gtk_text_buffer_get_text (buffer
, &begin
, &end
, FALSE
);
946 while (startword
> 0 && wordcharacters_contains(region
[startword
- 1]))
948 while (!end_position
&& region
[endword
] && wordcharacters_contains(region
[endword
]))
950 if(startword
== endword
)
953 region
[endword
] = '\0';
954 cplen
= (maxlength
< (endword
-startword
+1))?maxlength
:(endword
-startword
+1);
955 word
= g_strndup (region
+ startword
, cplen
);
957 DEBUG_PRINT ("region: %s\n start: %d end: %d word: %s", region
, startword
, endword
, word
);
964 delete_range_cb (AnjutaDocument
*doc
,