1 /*
2  * xed-document.c
3  * This file is part of xed
4  *
5  * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
6  * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
7  * Copyright (C) 2002-2005 Paolo Maggi
8  *
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.
13  *
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.
18  *
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 St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 /*
26  * Modified by the xed Team, 1998-2005. See the AUTHORS file for a
27  * list of people on the xed Team.
28  * See the ChangeLog files for a list of changes.
29  *
30  * $Id$
31  */
32 
33 #include <config.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <glib/gi18n.h>
37 #include <gtk/gtk.h>
38 
39 #include "xed-document.h"
40 #include "xed-document-private.h"
41 #include "xed-settings.h"
42 #include "xed-debug.h"
43 #include "xed-utils.h"
44 #include "xed-metadata-manager.h"
45 
46 #define METADATA_QUERY "metadata::*"
47 
48 #define NO_LANGUAGE_NAME "_NORMAL_"
49 
50 static void xed_document_loaded_real (XedDocument  *doc);
51 static void xed_document_saved_real (XedDocument  *doc);
52 
53 typedef struct
54 {
55     GtkSourceFile *file;
56 
57     GSettings *editor_settings;
58 
59     gint   untitled_number;
60     gchar *short_name;
61 
62     GFileInfo *metadata_info;
63 
64     gchar *content_type;
65 
66     GTimeVal time_of_last_save_or_load;
67 
68     GtkSourceSearchContext *search_context;
69 
70     guint user_action;
71 
72     guint last_save_was_manually : 1;
73     guint language_set_by_user : 1;
74     guint stop_cursor_moved_emission : 1;
75     guint use_gvfs_metadata : 1;
76 
77     /* Create file if location points to a non existing file (for example
78      * when opened from the command line).
79      */
80     guint create : 1;
81 } XedDocumentPrivate;
82 
83 enum
84 {
85     PROP_0,
86     PROP_SHORTNAME,
87     PROP_CONTENT_TYPE,
88     PROP_MIME_TYPE,
89     PROP_READ_ONLY,
90     PROP_USE_GVFS_METADATA,
91     LAST_PROP
92 };
93 
94 static GParamSpec *properties[LAST_PROP];
95 
96 enum
97 {
98     CURSOR_MOVED,
99     LOAD,
100     LOADED,
101     SAVE,
102     SAVED,
103     LAST_SIGNAL
104 };
105 
106 static guint document_signals[LAST_SIGNAL];
107 
108 static GHashTable *allocated_untitled_numbers = NULL;
109 
G_DEFINE_TYPE_WITH_PRIVATE(XedDocument,xed_document,GTK_SOURCE_TYPE_BUFFER)110 G_DEFINE_TYPE_WITH_PRIVATE (XedDocument, xed_document, GTK_SOURCE_TYPE_BUFFER)
111 
112 static gint
113 get_untitled_number (void)
114 {
115     gint i = 1;
116 
117     if (allocated_untitled_numbers == NULL)
118     {
119         allocated_untitled_numbers = g_hash_table_new (NULL, NULL);
120     }
121 
122     g_return_val_if_fail (allocated_untitled_numbers != NULL, -1);
123 
124     while (TRUE)
125     {
126         if (g_hash_table_lookup (allocated_untitled_numbers, GINT_TO_POINTER (i)) == NULL)
127         {
128             g_hash_table_insert (allocated_untitled_numbers, GINT_TO_POINTER (i), GINT_TO_POINTER (i));
129 
130             return i;
131         }
132 
133         ++i;
134     }
135 }
136 
137 static void
release_untitled_number(gint n)138 release_untitled_number (gint n)
139 {
140     g_return_if_fail (allocated_untitled_numbers != NULL);
141 
142     g_hash_table_remove (allocated_untitled_numbers, GINT_TO_POINTER (n));
143 }
144 
145 static const gchar *
get_language_string(XedDocument * doc)146 get_language_string (XedDocument *doc)
147 {
148     GtkSourceLanguage *lang = xed_document_get_language (doc);
149 
150     return lang != NULL ? gtk_source_language_get_id (lang) : NO_LANGUAGE_NAME;
151 }
152 
153 static void
save_metadata(XedDocument * doc)154 save_metadata (XedDocument *doc)
155 {
156     XedDocumentPrivate *priv;
157     const gchar *language = NULL;
158     GtkTextIter iter;
159     gchar *position;
160 
161     priv = xed_document_get_instance_private (doc);
162     if (priv->language_set_by_user)
163     {
164         language = get_language_string (doc);
165     }
166 
167     gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
168                                       &iter,
169                                       gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (doc)));
170 
171     position = g_strdup_printf ("%d", gtk_text_iter_get_offset (&iter));
172 
173     if (language == NULL)
174     {
175         xed_document_set_metadata (doc,
176                                    XED_METADATA_ATTRIBUTE_POSITION, position,
177                                    NULL);
178     }
179     else
180     {
181         xed_document_set_metadata (doc,
182                                    XED_METADATA_ATTRIBUTE_POSITION, position,
183                                    XED_METADATA_ATTRIBUTE_LANGUAGE, language,
184                                    NULL);
185     }
186 
187     g_free (position);
188 }
189 
190 static void
xed_document_dispose(GObject * object)191 xed_document_dispose (GObject *object)
192 {
193     XedDocumentPrivate *priv;
194 
195     xed_debug (DEBUG_DOCUMENT);
196 
197     priv = xed_document_get_instance_private (XED_DOCUMENT (object));
198 
199     /* Metadata must be saved here and not in finalize because the language
200     * is gone by the time finalize runs.
201     */
202     if (priv->file != NULL)
203     {
204         save_metadata (XED_DOCUMENT (object));
205 
206         g_object_unref (priv->file);
207         priv->file = NULL;
208     }
209 
210     g_clear_object (&priv->editor_settings);
211     g_clear_object (&priv->metadata_info);
212     g_clear_object (&priv->search_context);
213 
214     G_OBJECT_CLASS (xed_document_parent_class)->dispose (object);
215 }
216 
217 static void
xed_document_finalize(GObject * object)218 xed_document_finalize (GObject *object)
219 {
220     XedDocumentPrivate *priv;
221 
222     xed_debug (DEBUG_DOCUMENT);
223 
224     priv = xed_document_get_instance_private (XED_DOCUMENT (object));
225 
226     if (priv->untitled_number > 0)
227     {
228         release_untitled_number (priv->untitled_number);
229     }
230 
231     g_free (priv->content_type);
232     g_free (priv->short_name);
233 
234     G_OBJECT_CLASS (xed_document_parent_class)->finalize (object);
235 }
236 
237 static void
xed_document_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)238 xed_document_get_property (GObject    *object,
239                            guint       prop_id,
240                            GValue     *value,
241                            GParamSpec *pspec)
242 {
243     XedDocument *doc = XED_DOCUMENT (object);
244     XedDocumentPrivate *priv;
245 
246     priv = xed_document_get_instance_private (doc);
247 
248     switch (prop_id)
249     {
250         case PROP_SHORTNAME:
251             g_value_take_string (value, xed_document_get_short_name_for_display (doc));
252             break;
253         case PROP_CONTENT_TYPE:
254             g_value_take_string (value, xed_document_get_content_type (doc));
255             break;
256         case PROP_MIME_TYPE:
257             g_value_take_string (value, xed_document_get_mime_type (doc));
258             break;
259         case PROP_READ_ONLY:
260             g_value_set_boolean (value, gtk_source_file_is_readonly (priv->file));
261             break;
262         case PROP_USE_GVFS_METADATA:
263             g_value_set_boolean (value, priv->use_gvfs_metadata);
264             break;
265         default:
266             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267             break;
268     }
269 }
270 
271 static void
xed_document_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)272 xed_document_set_property (GObject      *object,
273                            guint         prop_id,
274                            const GValue *value,
275                            GParamSpec   *pspec)
276 {
277     XedDocument *doc = XED_DOCUMENT (object);
278     XedDocumentPrivate *priv;
279 
280     priv = xed_document_get_instance_private (doc);
281 
282     switch (prop_id)
283     {
284         case PROP_SHORTNAME:
285             xed_document_set_short_name_for_display (doc, g_value_get_string (value));
286             break;
287         case PROP_CONTENT_TYPE:
288             xed_document_set_content_type (doc, g_value_get_string (value));
289             break;
290         case PROP_USE_GVFS_METADATA:
291             priv->use_gvfs_metadata = g_value_get_boolean (value);
292             break;
293         default:
294             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
295             break;
296     }
297 }
298 
299 static void
xed_document_begin_user_action(GtkTextBuffer * buffer)300 xed_document_begin_user_action (GtkTextBuffer *buffer)
301 {
302     XedDocumentPrivate *priv;
303 
304     priv = xed_document_get_instance_private (XED_DOCUMENT (buffer));
305 
306     ++priv->user_action;
307 
308     if (GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->begin_user_action != NULL)
309     {
310         GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->begin_user_action (buffer);
311     }
312 }
313 
314 static void
xed_document_end_user_action(GtkTextBuffer * buffer)315 xed_document_end_user_action (GtkTextBuffer *buffer)
316 {
317     XedDocumentPrivate *priv;
318 
319     priv = xed_document_get_instance_private (XED_DOCUMENT (buffer));
320 
321     --priv->user_action;
322 
323     if (GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->end_user_action != NULL)
324     {
325         GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->end_user_action (buffer);
326     }
327 }
328 
329 static void
emit_cursor_moved(XedDocument * doc)330 emit_cursor_moved (XedDocument *doc)
331 {
332     XedDocumentPrivate *priv;
333 
334     priv = xed_document_get_instance_private (doc);
335 
336     if (!priv->stop_cursor_moved_emission)
337     {
338         g_signal_emit (doc, document_signals[CURSOR_MOVED], 0);
339     }
340 }
341 
342 static void
xed_document_mark_set(GtkTextBuffer * buffer,const GtkTextIter * iter,GtkTextMark * mark)343 xed_document_mark_set (GtkTextBuffer     *buffer,
344                        const GtkTextIter *iter,
345                        GtkTextMark       *mark)
346 {
347     XedDocument *doc = XED_DOCUMENT (buffer);
348     XedDocumentPrivate *priv;
349 
350     priv = xed_document_get_instance_private (doc);
351 
352     if (GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->mark_set != NULL)
353     {
354         GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->mark_set (buffer, iter, mark);
355     }
356 
357     if (mark == gtk_text_buffer_get_insert (buffer) && (priv->user_action == 0))
358     {
359         emit_cursor_moved (doc);
360     }
361 }
362 
363 static void
xed_document_changed(GtkTextBuffer * buffer)364 xed_document_changed (GtkTextBuffer *buffer)
365 {
366     emit_cursor_moved (XED_DOCUMENT (buffer));
367 
368     GTK_TEXT_BUFFER_CLASS (xed_document_parent_class)->changed (buffer);
369 }
370 
371 static void
xed_document_constructed(GObject * object)372 xed_document_constructed (GObject *object)
373 {
374     XedDocument *doc = XED_DOCUMENT (object);
375     XedDocumentPrivate *priv;
376 
377     priv = xed_document_get_instance_private (doc);
378 
379     g_settings_bind (priv->editor_settings,
380                      XED_SETTINGS_ENSURE_TRAILING_NEWLINE,
381                      doc,
382                      "implicit-trailing-newline",
383                      G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
384 
385     G_OBJECT_CLASS (xed_document_parent_class)->constructed (object);
386 }
387 
388 static void
xed_document_class_init(XedDocumentClass * klass)389 xed_document_class_init (XedDocumentClass *klass)
390 {
391     GObjectClass *object_class = G_OBJECT_CLASS (klass);
392     GtkTextBufferClass *buf_class = GTK_TEXT_BUFFER_CLASS (klass);
393 
394     object_class->dispose = xed_document_dispose;
395     object_class->finalize = xed_document_finalize;
396     object_class->get_property = xed_document_get_property;
397     object_class->set_property = xed_document_set_property;
398     object_class->constructed = xed_document_constructed;
399 
400     buf_class->begin_user_action = xed_document_begin_user_action;
401     buf_class->end_user_action = xed_document_end_user_action;
402     buf_class->mark_set = xed_document_mark_set;
403     buf_class->changed = xed_document_changed;
404 
405     klass->loaded = xed_document_loaded_real;
406     klass->saved = xed_document_saved_real;
407 
408     /**
409      * XedDocument:shortname:
410      *
411      * The documents short name.
412      */
413     properties[PROP_SHORTNAME] =
414         g_param_spec_string ("shortname",
415                              "Short Name",
416                              "The documents short name",
417                              NULL,
418                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
419 
420     /**
421      * XedDocument:content-type:
422      *
423      * The documents content type.
424      */
425     properties[PROP_CONTENT_TYPE] =
426         g_param_spec_string ("content-type",
427                              "Content Type",
428                              "The documents content type",
429                              NULL,
430                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
431 
432     /**
433      * XedDocument:mime-type:
434      *
435      * The documents MIME type.
436      */
437     properties[PROP_MIME_TYPE] =
438         g_param_spec_string ("mime-type",
439                              "MIME Type",
440                              "The documents MIME type",
441                              "text/plain",
442                              G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
443 
444     properties[PROP_READ_ONLY] =
445         g_param_spec_boolean ("read-only",
446                               "Read Only",
447                               "Whether the document is read-only or not",
448                               FALSE,
449                               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
450 
451     /**
452      * XedDocument:use-gvfs-metadata:
453      *
454      * Whether to use GVFS metadata. If %FALSE, use the xed metadata
455      * manager that stores the metadata in an XML file in the user cache
456      * directory.
457      *
458      * <warning>
459      * The property is used internally by xed. It must not be used in a
460      * xed plugin. The property can be modified or removed at any time.
461      * </warning>
462      */
463     properties[PROP_USE_GVFS_METADATA] =
464         g_param_spec_boolean ("use-gvfs-metadata",
465                               "Use GVFS metadata",
466                               "",
467                               TRUE,
468                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
469 
470     g_object_class_install_properties (object_class, LAST_PROP, properties);
471 
472     /* This signal is used to update the cursor position is the statusbar,
473      * it's emitted either when the insert mark is moved explicitely or
474      * when the buffer changes (insert/delete).
475      * We prevent the emission of the signal during replace_all to
476      * improve performance.
477      */
478     document_signals[CURSOR_MOVED] =
479         g_signal_new ("cursor-moved",
480                       G_OBJECT_CLASS_TYPE (object_class),
481                       G_SIGNAL_RUN_LAST,
482                       G_STRUCT_OFFSET (XedDocumentClass, cursor_moved),
483                       NULL, NULL, NULL,
484                       G_TYPE_NONE,
485                       0);
486 
487     /**
488      * XedDocument::load:
489      * @document: the #XedDocument.
490      *
491      * The "load" signal is emitted at the beginning of file loading.
492      */
493     document_signals[LOAD] =
494         g_signal_new ("load",
495                       G_OBJECT_CLASS_TYPE (object_class),
496                       G_SIGNAL_RUN_LAST,
497                       G_STRUCT_OFFSET (XedDocumentClass, load),
498                       NULL, NULL, NULL,
499                       G_TYPE_NONE, 0);
500 
501     /**
502      * XedDocument::loaded:
503      * @document: the #XedDocument.
504      *
505      * The "loaded" signal is emitted at the end of a successful loading.
506      */
507     document_signals[LOADED] =
508         g_signal_new ("loaded",
509                       G_OBJECT_CLASS_TYPE (object_class),
510                       G_SIGNAL_RUN_FIRST,
511                       G_STRUCT_OFFSET (XedDocumentClass, loaded),
512                       NULL, NULL, NULL,
513                       G_TYPE_NONE, 0);
514 
515     /**
516      * XedDocument::save:
517      * @document: the #XedDocument.
518      *
519      * The "save" signal is emitted at the beginning of file saving.
520      */
521     document_signals[SAVE] =
522         g_signal_new ("save",
523                       G_OBJECT_CLASS_TYPE (object_class),
524                       G_SIGNAL_RUN_LAST,
525                       G_STRUCT_OFFSET (XedDocumentClass, save),
526                       NULL, NULL, NULL,
527                       G_TYPE_NONE, 0);
528 
529     /**
530      * XedDocument::saved:
531      * @document: the #XedDocument.
532      *
533      * The "saved" signal is emitted at the end of a successful file saving.
534      */
535     document_signals[SAVED] =
536         g_signal_new ("saved",
537                       G_OBJECT_CLASS_TYPE (object_class),
538                       G_SIGNAL_RUN_FIRST,
539                       G_STRUCT_OFFSET (XedDocumentClass, saved),
540                       NULL, NULL, NULL,
541                       G_TYPE_NONE, 0);
542 }
543 
544 static void
set_language(XedDocument * doc,GtkSourceLanguage * lang,gboolean set_by_user)545 set_language (XedDocument       *doc,
546               GtkSourceLanguage *lang,
547               gboolean           set_by_user)
548 {
549     XedDocumentPrivate *priv;
550     GtkSourceLanguage *old_lang;
551 
552     xed_debug (DEBUG_DOCUMENT);
553 
554     priv = xed_document_get_instance_private (doc);
555 
556     old_lang = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc));
557 
558     if (old_lang == lang)
559     {
560         return;
561     }
562 
563     gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (doc), lang);
564 
565     if (set_by_user)
566     {
567         const gchar *language = get_language_string (doc);
568 
569         xed_document_set_metadata (doc, XED_METADATA_ATTRIBUTE_LANGUAGE, language, NULL);
570     }
571 
572     priv->language_set_by_user = set_by_user;
573 }
574 
575 static void
save_encoding_metadata(XedDocument * doc)576 save_encoding_metadata (XedDocument *doc)
577 {
578     XedDocumentPrivate *priv;
579     const GtkSourceEncoding *encoding;
580     const gchar *charset;
581 
582     xed_debug (DEBUG_DOCUMENT);
583 
584     priv = xed_document_get_instance_private (doc);
585 
586     encoding = gtk_source_file_get_encoding (priv->file);
587 
588     if (encoding == NULL)
589     {
590         encoding = gtk_source_encoding_get_utf8 ();
591     }
592 
593     charset = gtk_source_encoding_get_charset (encoding);
594 
595     xed_document_set_metadata (doc, XED_METADATA_ATTRIBUTE_ENCODING, charset, NULL);
596 }
597 
598 static GtkSourceStyleScheme *
get_default_style_scheme(GSettings * editor_settings)599 get_default_style_scheme (GSettings *editor_settings)
600 {
601     GtkSourceStyleSchemeManager *manager;
602     gchar *scheme_id;
603     GtkSourceStyleScheme *def_style;
604 
605     manager = gtk_source_style_scheme_manager_get_default ();
606     scheme_id = g_settings_get_string (editor_settings, XED_SETTINGS_SCHEME);
607     def_style = gtk_source_style_scheme_manager_get_scheme (manager, scheme_id);
608 
609     if (def_style == NULL)
610     {
611         g_warning ("Default style scheme '%s' cannot be found, falling back to 'classic' style scheme ", scheme_id);
612 
613         def_style = gtk_source_style_scheme_manager_get_scheme (manager, "classic");
614         if (def_style == NULL)
615         {
616             g_warning ("Style scheme 'classic' cannot be found, check your GtkSourceView installation.");
617         }
618     }
619 
620     g_free (scheme_id);
621 
622     return def_style;
623 }
624 
625 static GtkSourceLanguage *
guess_language(XedDocument * doc)626 guess_language (XedDocument *doc)
627 {
628     XedDocumentPrivate *priv;
629     gchar *data;
630     GtkSourceLanguageManager *manager = gtk_source_language_manager_get_default ();
631     GtkSourceLanguage *language = NULL;
632 
633     priv = xed_document_get_instance_private (doc);
634 
635     data = xed_document_get_metadata (doc, XED_METADATA_ATTRIBUTE_LANGUAGE);
636 
637     if (data != NULL)
638     {
639         xed_debug_message (DEBUG_DOCUMENT, "Language from metadata: %s", data);
640 
641         if (!g_str_equal (data, NO_LANGUAGE_NAME))
642         {
643             language = gtk_source_language_manager_get_language (manager, data);
644         }
645 
646         g_free (data);
647     }
648     else
649     {
650         GFile *location;
651         gchar *basename = NULL;
652 
653         location = gtk_source_file_get_location (priv->file);
654         xed_debug_message (DEBUG_DOCUMENT, "Sniffing Language");
655 
656         if (location != NULL)
657         {
658             basename = g_file_get_basename (location);
659         }
660         else if (priv->short_name != NULL)
661         {
662             basename = g_strdup (priv->short_name);
663         }
664 
665         language = gtk_source_language_manager_guess_language (manager, basename, priv->content_type);
666 
667         g_free (basename);
668     }
669 
670     return language;
671 }
672 
673 static void
on_content_type_changed(XedDocument * doc,GParamSpec * pspec,gpointer useless)674 on_content_type_changed (XedDocument *doc,
675                          GParamSpec  *pspec,
676                          gpointer     useless)
677 {
678     XedDocumentPrivate *priv;
679 
680     priv = xed_document_get_instance_private (doc);
681 
682     if (!priv->language_set_by_user)
683     {
684         GtkSourceLanguage *language = guess_language (doc);
685 
686         xed_debug_message (DEBUG_DOCUMENT, "Language: %s",
687                            language != NULL ? gtk_source_language_get_name (language) : "None");
688 
689         set_language (doc, language, FALSE);
690     }
691 }
692 
693 static gchar *
get_default_content_type(void)694 get_default_content_type (void)
695 {
696     return g_content_type_from_mime_type ("text/plain");
697 }
698 
699 static void
on_location_changed(GtkSourceFile * file,GParamSpec * pspec,XedDocument * doc)700 on_location_changed (GtkSourceFile *file,
701                      GParamSpec    *pspec,
702                      XedDocument   *doc)
703 {
704     XedDocumentPrivate *priv;
705     GFile *location;
706 
707     xed_debug (DEBUG_DOCUMENT);
708 
709     priv = xed_document_get_instance_private (doc);
710 
711     location = gtk_source_file_get_location (file);
712 
713     if (location != NULL && priv->untitled_number > 0)
714     {
715         release_untitled_number (priv->untitled_number);
716         priv->untitled_number = 0;
717     }
718 
719     if (priv->short_name == NULL)
720     {
721         g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_SHORTNAME]);
722     }
723 
724     /* Load metadata for this location: we load sync since metadata is
725      * always local so it should be fast and we need the information
726      * right after the location was set.
727      */
728     if (priv->use_gvfs_metadata && location != NULL)
729     {
730         GError *error = NULL;
731 
732         if (priv->metadata_info != NULL)
733         {
734             g_object_unref (priv->metadata_info);
735         }
736 
737         priv->metadata_info = g_file_query_info (location,
738                                                  METADATA_QUERY,
739                                                  G_FILE_QUERY_INFO_NONE,
740                                                  NULL,
741                                                  &error);
742 
743         if (error != NULL)
744         {
745             /* Do not complain about metadata if we are opening a
746              * non existing file.
747              */
748             if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ISDIR) &&
749                 !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOTDIR) &&
750                 !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) &&
751                 !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
752              {
753                  g_warning ("%s", error->message);
754              }
755 
756             g_error_free (error);
757         }
758 
759         if (priv->metadata_info == NULL)
760         {
761             priv->metadata_info = g_file_info_new ();
762         }
763     }
764 }
765 
766 static void
on_readonly_changed(GtkSourceFile * file,GParamSpec * pspec,XedDocument * doc)767 on_readonly_changed (GtkSourceFile *file,
768                      GParamSpec    *pspec,
769                      XedDocument   *doc)
770 {
771     g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_READ_ONLY]);
772 }
773 
774 static void
xed_document_init(XedDocument * doc)775 xed_document_init (XedDocument *doc)
776 {
777     XedDocumentPrivate *priv;
778     GtkSourceStyleScheme *style_scheme;
779 
780     xed_debug (DEBUG_DOCUMENT);
781 
782     priv = xed_document_get_instance_private (doc);
783 
784     priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
785     priv->untitled_number = get_untitled_number ();
786     priv->content_type = get_default_content_type ();
787     priv->stop_cursor_moved_emission = FALSE;
788     priv->last_save_was_manually = TRUE;
789     priv->language_set_by_user = FALSE;
790 
791     g_get_current_time (&priv->time_of_last_save_or_load);
792 
793     priv->file = gtk_source_file_new ();
794     priv->metadata_info = g_file_info_new ();
795 
796     g_signal_connect_object (priv->file, "notify::location",
797                              G_CALLBACK (on_location_changed), doc, 0);
798 
799     g_signal_connect_object (priv->file, "notify::read-only",
800                              G_CALLBACK (on_readonly_changed), doc, 0);
801 
802     g_settings_bind (priv->editor_settings,
803                      XED_SETTINGS_SYNTAX_HIGHLIGHTING,
804                      doc,
805                      "highlight-syntax",
806                      G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
807 
808     g_settings_bind (priv->editor_settings,
809                      XED_SETTINGS_MAX_UNDO_ACTIONS,
810                      doc,
811                      "max-undo-levels",
812                      G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
813 
814     g_settings_bind (priv->editor_settings,
815                      XED_SETTINGS_BRACKET_MATCHING,
816                      doc,
817                      "highlight-matching-brackets",
818                      G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
819 
820     style_scheme = get_default_style_scheme (priv->editor_settings);
821     if (style_scheme != NULL)
822     {
823         gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (doc), style_scheme);
824     }
825 
826     g_signal_connect (doc, "notify::content-type", G_CALLBACK (on_content_type_changed), NULL);
827 }
828 
829 XedDocument *
xed_document_new(void)830 xed_document_new (void)
831 {
832     gboolean use_gvfs_metadata;
833 
834 #ifdef ENABLE_GVFS_METADATA
835     use_gvfs_metadata = TRUE;
836 #else
837     use_gvfs_metadata = FALSE;
838 #endif
839 
840     return g_object_new (XED_TYPE_DOCUMENT,
841                          "use-gvfs-metadata", use_gvfs_metadata,
842                          NULL);
843 }
844 
845 static void
set_content_type_no_guess(XedDocument * doc,const gchar * content_type)846 set_content_type_no_guess (XedDocument *doc,
847                            const gchar *content_type)
848 {
849     XedDocumentPrivate *priv;
850     xed_debug (DEBUG_DOCUMENT);
851 
852     priv = xed_document_get_instance_private (doc);
853 
854     if (priv->content_type != NULL && content_type != NULL &&
855         g_str_equal (priv->content_type, content_type))
856     {
857         return;
858     }
859 
860     g_free (priv->content_type);
861 
862     if (content_type == NULL || g_content_type_is_unknown (content_type))
863     {
864         priv->content_type = get_default_content_type ();
865     }
866     else
867     {
868         priv->content_type = g_strdup (content_type);
869     }
870 
871     g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_CONTENT_TYPE]);
872 }
873 
874 /**
875  * xed_document_set_content_type:
876  * @doc:
877  * @content_type: (allow-none):
878  */
879 void
xed_document_set_content_type(XedDocument * doc,const gchar * content_type)880 xed_document_set_content_type (XedDocument *doc,
881                                const gchar *content_type)
882 {
883     XedDocumentPrivate *priv;
884 
885     g_return_if_fail (XED_IS_DOCUMENT (doc));
886 
887     xed_debug (DEBUG_DOCUMENT);
888 
889     priv = xed_document_get_instance_private (doc);
890 
891     if (content_type == NULL)
892     {
893         GFile *location;
894         gchar *guessed_type = NULL;
895 
896         /* If content type is null, we guess from the filename */
897         location = gtk_source_file_get_location (priv->file);
898         if (location != NULL)
899         {
900             gchar *basename;
901 
902             basename = g_file_get_basename (location);
903             guessed_type = g_content_type_guess (basename, NULL, 0, NULL);
904 
905             g_free (basename);
906         }
907 
908         set_content_type_no_guess (doc, guessed_type);
909         g_free (guessed_type);
910     }
911     else
912     {
913         set_content_type_no_guess (doc, content_type);
914     }
915 }
916 
917 /**
918  * xed_document_get_location:
919  * @doc: a #XedDocument
920  *
921  * Returns: (allow-none) (transfer full): a new #GFile
922  */
923 GFile *
xed_document_get_location(XedDocument * doc)924 xed_document_get_location (XedDocument *doc)
925 {
926     XedDocumentPrivate *priv;
927     GFile *location;
928 
929     priv = xed_document_get_instance_private (doc);
930 
931     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
932 
933     location = gtk_source_file_get_location (priv->file);
934 
935     return location != NULL ? g_object_ref (location) : NULL;
936 }
937 
938 void
xed_document_set_location(XedDocument * doc,GFile * location)939 xed_document_set_location (XedDocument *doc,
940                            GFile       *location)
941 {
942     XedDocumentPrivate *priv;
943 
944     g_return_if_fail (XED_IS_DOCUMENT (doc));
945     g_return_if_fail (G_IS_FILE (location));
946 
947     priv = xed_document_get_instance_private (doc);
948 
949     gtk_source_file_set_location (priv->file, location);
950     xed_document_set_content_type (doc, NULL);
951 }
952 
953 /**
954  * xed_document_get_uri_for_display:
955  * @doc: a #XedDocument
956  *
957  * Note: this never returns %NULL.
958  **/
959 gchar *
xed_document_get_uri_for_display(XedDocument * doc)960 xed_document_get_uri_for_display (XedDocument *doc)
961 {
962     XedDocumentPrivate *priv;
963     GFile *location;
964 
965     g_return_val_if_fail (XED_IS_DOCUMENT (doc), g_strdup (""));
966 
967     priv = xed_document_get_instance_private (doc);
968 
969     location = gtk_source_file_get_location (priv->file);
970 
971     if (location == NULL)
972     {
973         return g_strdup_printf (_("Unsaved Document %d"), priv->untitled_number);
974     }
975     else
976     {
977         return g_file_get_parse_name (location);
978     }
979 }
980 
981 /**
982  * xed_document_get_short_name_for_display:
983  * @doc: a #XedDocument
984  *
985  * Note: this never returns %NULL.
986  **/
987 gchar *
xed_document_get_short_name_for_display(XedDocument * doc)988 xed_document_get_short_name_for_display (XedDocument *doc)
989 {
990     XedDocumentPrivate *priv;
991     GFile *location;
992 
993     g_return_val_if_fail (XED_IS_DOCUMENT (doc), g_strdup (""));
994 
995     priv = xed_document_get_instance_private (doc);
996 
997     location = gtk_source_file_get_location (priv->file);
998 
999     if (priv->short_name != NULL)
1000     {
1001         return g_strdup (priv->short_name);
1002     }
1003     else if (location == NULL)
1004     {
1005         return g_strdup_printf (_("Unsaved Document %d"), priv->untitled_number);
1006     }
1007     else
1008     {
1009         return xed_utils_basename_for_display (location);
1010     }
1011 }
1012 
1013 /**
1014  * xed_document_set_short_name_for_display:
1015  * @doc: a #XedDocument
1016  * @short_name: (allow-none): the short name to use
1017  */
1018 void
xed_document_set_short_name_for_display(XedDocument * doc,const gchar * short_name)1019 xed_document_set_short_name_for_display (XedDocument *doc,
1020                                          const gchar *short_name)
1021 {
1022     XedDocumentPrivate *priv;
1023 
1024     g_return_if_fail (XED_IS_DOCUMENT (doc));
1025 
1026     priv = xed_document_get_instance_private (doc);
1027 
1028     g_free (priv->short_name);
1029     priv->short_name = g_strdup (short_name);
1030 
1031     g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_SHORTNAME]);
1032 }
1033 
1034 gchar *
xed_document_get_content_type(XedDocument * doc)1035 xed_document_get_content_type (XedDocument *doc)
1036 {
1037     XedDocumentPrivate *priv;
1038 
1039     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1040 
1041     priv = xed_document_get_instance_private (doc);
1042 
1043     return g_strdup (priv->content_type);
1044 }
1045 
1046 /**
1047  * xed_document_get_mime_type:
1048  * @doc: a #XedDocument
1049  *
1050  * Note: this never returns %NULL.
1051  **/
1052 gchar *
xed_document_get_mime_type(XedDocument * doc)1053 xed_document_get_mime_type (XedDocument *doc)
1054 {
1055     XedDocumentPrivate *priv;
1056 
1057     g_return_val_if_fail (XED_IS_DOCUMENT (doc), g_strdup ("text/plain"));
1058 
1059     priv = xed_document_get_instance_private (doc);
1060 
1061     if (priv->content_type != NULL &&
1062         !g_content_type_is_unknown (priv->content_type))
1063     {
1064         return g_content_type_get_mime_type (priv->content_type);
1065     }
1066 
1067     return g_strdup ("text/plain");
1068 }
1069 
1070 gboolean
xed_document_get_readonly(XedDocument * doc)1071 xed_document_get_readonly (XedDocument *doc)
1072 {
1073     XedDocumentPrivate *priv;
1074 
1075     g_return_val_if_fail (XED_IS_DOCUMENT (doc), TRUE);
1076 
1077     priv = xed_document_get_instance_private (doc);
1078 
1079     return gtk_source_file_is_readonly (priv->file);
1080 }
1081 
1082 static void
loaded_query_info_cb(GFile * location,GAsyncResult * result,XedDocument * doc)1083 loaded_query_info_cb (GFile        *location,
1084                       GAsyncResult *result,
1085                       XedDocument  *doc)
1086 {
1087     GFileInfo *info;
1088     GError *error = NULL;
1089 
1090     info = g_file_query_info_finish (location, result, &error);
1091 
1092     if (error != NULL)
1093     {
1094         /* Ignore not found error as it can happen when opening a
1095          * non-existent file from the command line.
1096          */
1097         if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_NOT_FOUND)
1098         {
1099             g_warning ("Document loading: query info error: %s", error->message);
1100         }
1101 
1102         g_error_free (error);
1103         error = NULL;
1104     }
1105 
1106     if (info != NULL && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
1107     {
1108         const gchar *content_type;
1109 
1110         content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1111 
1112         xed_document_set_content_type (doc, content_type);
1113     }
1114 
1115     g_clear_object (&info);
1116 
1117     /* Async operation finished. */
1118     g_object_unref (doc);
1119 }
1120 
1121 static void
xed_document_loaded_real(XedDocument * doc)1122 xed_document_loaded_real (XedDocument *doc)
1123 {
1124     XedDocumentPrivate *priv;
1125     GFile *location;
1126 
1127     priv = xed_document_get_instance_private (doc);
1128 
1129     if (!priv->language_set_by_user)
1130     {
1131         GtkSourceLanguage *language = guess_language (doc);
1132 
1133         xed_debug_message (DEBUG_DOCUMENT, "Language: %s",
1134                            language != NULL ? gtk_source_language_get_name (language) : "None");
1135 
1136         set_language (doc, language, FALSE);
1137     }
1138 
1139     g_get_current_time (&priv->time_of_last_save_or_load);
1140 
1141     xed_document_set_content_type (doc, NULL);
1142 
1143     location = gtk_source_file_get_location (priv->file);
1144 
1145     if (location != NULL)
1146     {
1147         /* Keep the doc alive during the async operation. */
1148         g_object_ref (doc);
1149 
1150         g_file_query_info_async (location,
1151                                  G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
1152                                  G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
1153                                  G_FILE_QUERY_INFO_NONE,
1154                                  G_PRIORITY_DEFAULT,
1155                                  NULL,
1156                                  (GAsyncReadyCallback) loaded_query_info_cb,
1157                                  doc);
1158     }
1159 }
1160 
1161 static void
saved_query_info_cb(GFile * location,GAsyncResult * result,XedDocument * doc)1162 saved_query_info_cb (GFile        *location,
1163                      GAsyncResult *result,
1164                      XedDocument  *doc)
1165 {
1166     XedDocumentPrivate *priv;
1167     GFileInfo *info;
1168     const gchar *content_type = NULL;
1169     GError *error = NULL;
1170 
1171     priv = xed_document_get_instance_private (doc);
1172 
1173     info = g_file_query_info_finish (location, result, &error);
1174 
1175     if (error != NULL)
1176     {
1177         g_warning ("Document saving: query info error: %s", error->message);
1178         g_error_free (error);
1179         error = NULL;
1180     }
1181 
1182     if (info != NULL && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
1183     {
1184         content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1185     }
1186 
1187     xed_document_set_content_type (doc, content_type);
1188 
1189     if (info != NULL)
1190     {
1191         g_object_unref (info);
1192     }
1193 
1194     g_get_current_time (&priv->time_of_last_save_or_load);
1195 
1196     priv->create = FALSE;
1197 
1198     save_encoding_metadata (doc);
1199 
1200     /* Async operation finished. */
1201     g_object_unref (doc);
1202 }
1203 
1204 static void
xed_document_saved_real(XedDocument * doc)1205 xed_document_saved_real (XedDocument  *doc)
1206 {
1207     XedDocumentPrivate *priv;
1208     GFile *location;
1209 
1210     priv = xed_document_get_instance_private (doc);
1211 
1212     location = gtk_source_file_get_location (priv->file);
1213 
1214     /* Keep the doc alive during the async operation. */
1215     g_object_ref (doc);
1216 
1217     g_file_query_info_async (location,
1218                              G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1219                              G_FILE_QUERY_INFO_NONE,
1220                              G_PRIORITY_DEFAULT,
1221                              NULL,
1222                              (GAsyncReadyCallback) saved_query_info_cb,
1223                              doc);
1224 }
1225 
1226 gboolean
xed_document_is_untouched(XedDocument * doc)1227 xed_document_is_untouched (XedDocument *doc)
1228 {
1229     XedDocumentPrivate *priv;
1230     GFile *location;
1231 
1232     priv = xed_document_get_instance_private (doc);
1233 
1234     g_return_val_if_fail (XED_IS_DOCUMENT (doc), TRUE);
1235 
1236     location = gtk_source_file_get_location (priv->file);
1237 
1238     return location == NULL && !gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc));
1239 }
1240 
1241 gboolean
xed_document_is_untitled(XedDocument * doc)1242 xed_document_is_untitled (XedDocument *doc)
1243 {
1244     XedDocumentPrivate *priv;
1245 
1246     g_return_val_if_fail (XED_IS_DOCUMENT (doc), TRUE);
1247 
1248     priv = xed_document_get_instance_private (doc);
1249 
1250     return gtk_source_file_get_location (priv->file) == NULL;
1251 }
1252 
1253 gboolean
xed_document_is_local(XedDocument * doc)1254 xed_document_is_local (XedDocument *doc)
1255 {
1256     XedDocumentPrivate *priv;
1257 
1258     g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
1259 
1260     priv = xed_document_get_instance_private (doc);
1261 
1262     return gtk_source_file_is_local (priv->file);
1263 }
1264 
1265 gboolean
xed_document_get_deleted(XedDocument * doc)1266 xed_document_get_deleted (XedDocument *doc)
1267 {
1268     XedDocumentPrivate *priv;
1269 
1270     g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
1271 
1272     priv = xed_document_get_instance_private (doc);
1273 
1274     return gtk_source_file_is_deleted (priv->file);
1275 }
1276 
1277 /*
1278  * Deletion and external modification is only checked for local files.
1279  */
1280 gboolean
_xed_document_needs_saving(XedDocument * doc)1281 _xed_document_needs_saving (XedDocument *doc)
1282 {
1283     XedDocumentPrivate *priv;
1284     gboolean externally_modified = FALSE;
1285     gboolean deleted = FALSE;
1286 
1287     g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
1288 
1289     priv = xed_document_get_instance_private (doc);
1290 
1291     if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
1292     {
1293         return TRUE;
1294     }
1295 
1296     if (gtk_source_file_is_local (priv->file))
1297     {
1298         gtk_source_file_check_file_on_disk (priv->file);
1299         externally_modified = gtk_source_file_is_externally_modified (priv->file);
1300         deleted = gtk_source_file_is_deleted (priv->file);
1301     }
1302 
1303     return (externally_modified || deleted) && !priv->create;
1304 }
1305 
1306 /*
1307  * If @line is bigger than the lines of the document, the cursor is moved
1308  * to the last line and FALSE is returned.
1309  */
1310 gboolean
xed_document_goto_line(XedDocument * doc,gint line)1311 xed_document_goto_line (XedDocument *doc,
1312                         gint         line)
1313 {
1314     GtkTextIter iter;
1315 
1316     xed_debug (DEBUG_DOCUMENT);
1317 
1318     g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
1319     g_return_val_if_fail (line >= -1, FALSE);
1320 
1321     gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc), &iter, line);
1322 
1323     gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
1324 
1325     return gtk_text_iter_get_line (&iter) == line;
1326 }
1327 
1328 gboolean
xed_document_goto_line_offset(XedDocument * doc,gint line,gint line_offset)1329 xed_document_goto_line_offset (XedDocument *doc,
1330                                gint         line,
1331                                gint         line_offset)
1332 {
1333     GtkTextIter iter;
1334 
1335     g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
1336     g_return_val_if_fail (line >= -1, FALSE);
1337     g_return_val_if_fail (line_offset >= -1, FALSE);
1338 
1339     gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (doc), &iter, line, line_offset);
1340 
1341     gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
1342 
1343     return (gtk_text_iter_get_line (&iter) == line && gtk_text_iter_get_line_offset (&iter) == line_offset);
1344 }
1345 
1346 /**
1347  * xed_document_set_language:
1348  * @doc:
1349  * @lang: (allow-none):
1350  **/
1351 void
xed_document_set_language(XedDocument * doc,GtkSourceLanguage * lang)1352 xed_document_set_language (XedDocument       *doc,
1353                            GtkSourceLanguage *lang)
1354 {
1355     g_return_if_fail (XED_IS_DOCUMENT (doc));
1356 
1357     set_language (doc, lang, TRUE);
1358 }
1359 
1360 /**
1361  * xed_document_get_language:
1362  * @doc:
1363  *
1364  * Return value: (transfer none):
1365  */
1366 GtkSourceLanguage *
xed_document_get_language(XedDocument * doc)1367 xed_document_get_language (XedDocument *doc)
1368 {
1369     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1370 
1371     return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc));
1372 }
1373 
1374 const GtkSourceEncoding *
xed_document_get_encoding(XedDocument * doc)1375 xed_document_get_encoding (XedDocument *doc)
1376 {
1377     XedDocumentPrivate *priv;
1378 
1379     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1380 
1381     priv = xed_document_get_instance_private (doc);
1382 
1383     return gtk_source_file_get_encoding (priv->file);
1384 }
1385 
1386 glong
_xed_document_get_seconds_since_last_save_or_load(XedDocument * doc)1387 _xed_document_get_seconds_since_last_save_or_load (XedDocument *doc)
1388 {
1389     XedDocumentPrivate *priv;
1390     GTimeVal current_time;
1391 
1392     xed_debug (DEBUG_DOCUMENT);
1393 
1394     g_return_val_if_fail (XED_IS_DOCUMENT (doc), -1);
1395 
1396     priv = xed_document_get_instance_private (doc);
1397 
1398     g_get_current_time (&current_time);
1399 
1400     return (current_time.tv_sec - priv->time_of_last_save_or_load.tv_sec);
1401 }
1402 
1403 GtkSourceNewlineType
xed_document_get_newline_type(XedDocument * doc)1404 xed_document_get_newline_type (XedDocument *doc)
1405 {
1406     XedDocumentPrivate *priv;
1407 
1408     g_return_val_if_fail (XED_IS_DOCUMENT (doc), 0);
1409 
1410     priv = xed_document_get_instance_private (doc);
1411 
1412     return gtk_source_file_get_newline_type (priv->file);
1413 }
1414 
1415 static gchar *
get_metadata_from_metadata_manager(XedDocument * doc,const gchar * key)1416 get_metadata_from_metadata_manager (XedDocument *doc,
1417                                     const gchar *key)
1418 {
1419     XedDocumentPrivate *priv;
1420     GFile *location;
1421 
1422     priv = xed_document_get_instance_private (doc);
1423 
1424     location = gtk_source_file_get_location (priv->file);
1425 
1426     if (location != NULL)
1427     {
1428         return xed_metadata_manager_get (location, key);
1429     }
1430 
1431     return NULL;
1432 }
1433 
1434 static gchar *
get_metadata_from_gvfs(XedDocument * doc,const gchar * key)1435 get_metadata_from_gvfs (XedDocument *doc,
1436                         const gchar *key)
1437 {
1438     XedDocumentPrivate *priv;
1439 
1440     priv = xed_document_get_instance_private (doc);
1441 
1442     if (priv->metadata_info != NULL &&
1443         g_file_info_has_attribute (priv->metadata_info, key) &&
1444         g_file_info_get_attribute_type (priv->metadata_info, key) == G_FILE_ATTRIBUTE_TYPE_STRING)
1445     {
1446         return g_strdup (g_file_info_get_attribute_string (priv->metadata_info, key));
1447     }
1448 
1449     return NULL;
1450 }
1451 
1452 static void
set_gvfs_metadata(GFileInfo * info,const gchar * key,const gchar * value)1453 set_gvfs_metadata (GFileInfo   *info,
1454                    const gchar *key,
1455                    const gchar *value)
1456 {
1457     g_return_if_fail (G_IS_FILE_INFO (info));
1458 
1459     if (value != NULL)
1460     {
1461         g_file_info_set_attribute_string (info, key, value);
1462     }
1463     else
1464     {
1465         /* Unset the key */
1466         g_file_info_set_attribute (info, key, G_FILE_ATTRIBUTE_TYPE_INVALID, NULL);
1467     }
1468 }
1469 
1470 /**
1471  * xed_document_get_metadata:
1472  * @doc: a #XedDocument
1473  * @key: name of the key
1474  *
1475  * Gets the metadata assigned to @key.
1476  *
1477  * Returns: the value assigned to @key. Free with g_free().
1478  */
1479 gchar *
xed_document_get_metadata(XedDocument * doc,const gchar * key)1480 xed_document_get_metadata (XedDocument *doc,
1481                            const gchar *key)
1482 {
1483     XedDocumentPrivate *priv;
1484 
1485     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1486     g_return_val_if_fail (key != NULL, NULL);
1487 
1488     priv = xed_document_get_instance_private (doc);
1489 
1490     if (priv->use_gvfs_metadata)
1491     {
1492         return get_metadata_from_gvfs (doc, key);
1493     }
1494 
1495     return get_metadata_from_metadata_manager (doc, key);
1496 }
1497 
1498 static void
set_attributes_cb(GFile * location,GAsyncResult * result)1499 set_attributes_cb (GFile        *location,
1500                    GAsyncResult *result)
1501 {
1502     GError *error = NULL;
1503 
1504     g_file_set_attributes_finish (location, result, NULL, &error);
1505 
1506     if (error != NULL)
1507     {
1508         g_warning ("Set document metadata failed: %s", error->message);
1509         g_error_free (error);
1510     }
1511 }
1512 
1513 /**
1514  * xed_document_set_metadata:
1515  * @doc: a #XedDocument
1516  * @first_key: name of the first key to set
1517  * @...: value for the first key, followed optionally by more key/value pairs,
1518  * followed by %NULL.
1519  *
1520  * Sets metadata on a document.
1521  */
1522 void
xed_document_set_metadata(XedDocument * doc,const gchar * first_key,...)1523 xed_document_set_metadata (XedDocument *doc,
1524                            const gchar   *first_key,
1525                            ...)
1526 {
1527     XedDocumentPrivate *priv;
1528     GFile *location;
1529     const gchar *key;
1530     va_list var_args;
1531     GFileInfo *info = NULL;
1532 
1533     g_return_if_fail (XED_IS_DOCUMENT (doc));
1534     g_return_if_fail (first_key != NULL);
1535 
1536     priv = xed_document_get_instance_private (doc);
1537 
1538     location = gtk_source_file_get_location (priv->file);
1539 
1540     /* With the metadata manager, can't set metadata for untitled documents.
1541      * With GVFS metadata, if the location is NULL the metadata is stored in
1542      * priv->metadata_info, so that it can be saved later if the document is
1543      * saved.
1544      */
1545 
1546     if (!priv->use_gvfs_metadata && location == NULL)
1547     {
1548         return;
1549     }
1550 
1551     if (priv->use_gvfs_metadata)
1552     {
1553         info = g_file_info_new ();
1554     }
1555 
1556     va_start (var_args, first_key);
1557 
1558     for (key = first_key; key; key = va_arg (var_args, const gchar *))
1559     {
1560         const gchar *value = va_arg (var_args, const gchar *);
1561 
1562         if (priv->use_gvfs_metadata)
1563         {
1564             /* Collect the metadata into @info. */
1565             set_gvfs_metadata (info, key, value);
1566             set_gvfs_metadata (priv->metadata_info, key, value);
1567         }
1568         else
1569         {
1570             /* Unset the key */
1571             xed_metadata_manager_set (location, key, value);
1572         }
1573     }
1574 
1575     va_end (var_args);
1576 
1577     if (priv->use_gvfs_metadata && location != NULL)
1578     {
1579         g_file_set_attributes_async (location,
1580                                      info,
1581                                      G_FILE_QUERY_INFO_NONE,
1582                                      G_PRIORITY_DEFAULT,
1583                                      NULL,
1584                                      (GAsyncReadyCallback) set_attributes_cb,
1585                                      NULL);
1586     }
1587 
1588     g_clear_object (&info);
1589 }
1590 
1591 /**
1592  * xed_document_set_search_context:
1593  * @doc: a #XedDocument
1594  * @search_context: (allow-none): the new #GtkSourceSearchContext
1595  *
1596  * Sets the new search context for the document.
1597  */
1598 void
xed_document_set_search_context(XedDocument * doc,GtkSourceSearchContext * search_context)1599 xed_document_set_search_context (XedDocument            *doc,
1600                                  GtkSourceSearchContext *search_context)
1601 {
1602     XedDocumentPrivate *priv;
1603 
1604     g_return_if_fail (XED_IS_DOCUMENT (doc));
1605 
1606     priv = xed_document_get_instance_private (doc);
1607 
1608     g_clear_object (&priv->search_context);
1609     priv->search_context = search_context;
1610 
1611     if (search_context != NULL)
1612     {
1613         gboolean highlight = g_settings_get_boolean (priv->editor_settings, XED_SETTINGS_SEARCH_HIGHLIGHTING);
1614 
1615         gtk_source_search_context_set_highlight (search_context, highlight);
1616 
1617         g_object_ref (search_context);
1618     }
1619 }
1620 
1621 /**
1622  * xed_document_get_search_context:
1623  * @doc: a #XedDocument
1624  *
1625  * Returns: (transfer full): the current search context of the document,
1626  * or NULL if there is no search context
1627  */
1628 GtkSourceSearchContext *
xed_document_get_search_context(XedDocument * doc)1629 xed_document_get_search_context (XedDocument *doc)
1630 {
1631     XedDocumentPrivate *priv;
1632 
1633     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1634 
1635     priv = xed_document_get_instance_private (doc);
1636 
1637     return priv->search_context;
1638 }
1639 
1640 /**
1641  * xed_document_get_file:
1642  * @doc: a #XedDocument.
1643  *
1644  * Gets the associated #GtkSourceFile. You should use it only for reading
1645  * purposes, not for creating a #GtkSourceFileLoader or #GtkSourceFileSaver,
1646  * because xed does some extra work when loading or saving a file and
1647  * maintains an internal state. If you use in a plugin a file loader or saver on
1648  * the returned #GtkSourceFile, the internal state of xed won't be updated.
1649  *
1650  * If you want to save the #XedDocument to a secondary file, you can create a
1651  * new #GtkSourceFile and use a #GtkSourceFileSaver.
1652  *
1653  * Returns: (transfer none): the associated #GtkSourceFile.
1654  */
1655 GtkSourceFile *
xed_document_get_file(XedDocument * doc)1656 xed_document_get_file (XedDocument *doc)
1657 {
1658     XedDocumentPrivate *priv;
1659 
1660     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1661 
1662     priv = xed_document_get_instance_private (doc);
1663 
1664     return priv->file;
1665 }
1666 
1667 void
_xed_document_set_create(XedDocument * doc,gboolean create)1668 _xed_document_set_create (XedDocument *doc,
1669                           gboolean     create)
1670 {
1671     XedDocumentPrivate *priv;
1672 
1673     g_return_if_fail (XED_IS_DOCUMENT (doc));
1674 
1675     priv = xed_document_get_instance_private (doc);
1676 
1677     priv->create = create != FALSE;
1678 }
1679 
1680 gboolean
_xed_document_get_create(XedDocument * doc)1681 _xed_document_get_create (XedDocument *doc)
1682 {
1683     XedDocumentPrivate *priv;
1684 
1685     g_return_val_if_fail (XED_IS_DOCUMENT (doc), FALSE);
1686 
1687     priv = xed_document_get_instance_private (doc);
1688 
1689     return priv->create;
1690 }
1691