sourceview: Move preferences in plugins/sourceview
[anjuta.git] / plugins / sourceview / sourceview-io.c
blob3c749f14a6ab1cfbc9ab9750331aad5e9341ecdc
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-trunk
4 * Copyright (C) Johannes Schmid 2008 <jhs@gnome.org>
6 * anjuta-trunk is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta-trunk is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "sourceview-io.h"
21 #include "sourceview-private.h"
22 #include <libanjuta/interfaces/ianjuta-editor.h>
23 #include <libanjuta/anjuta-convert.h>
24 #include <libanjuta/anjuta-encodings.h>
26 #define READ_SIZE 4096
27 #define RATE_LIMIT 5000 /* Use a big rate limit to avoid duplicates */
28 #define TIMEOUT 5
30 enum
32 SAVE_STATUS,
33 SAVE_FINISHED,
34 OPEN_STATUS,
35 OPEN_FINISHED,
36 OPEN_FAILED,
37 SAVE_FAILED,
38 FILE_DELETED,
40 LAST_SIGNAL
43 #define IO_ERROR_QUARK g_quark_from_string ("SourceviewIO-Error")
45 static guint io_signals[LAST_SIGNAL] = { 0 };
47 G_DEFINE_TYPE (SourceviewIO, sourceview_io, G_TYPE_OBJECT);
49 static void
50 sourceview_io_init (SourceviewIO *object)
52 object->file = NULL;
53 object->filename = NULL;
54 object->read_buffer = NULL;
55 object->write_buffer = NULL;
56 object->cancel = g_cancellable_new();
57 object->monitor = NULL;
58 object->last_encoding = NULL;
59 object->bytes_read = 0;
62 static void
63 sourceview_io_finalize (GObject *object)
65 SourceviewIO* sio = SOURCEVIEW_IO(object);
66 if (sio->file)
67 g_object_unref (sio->file);
68 g_free(sio->filename);
69 g_free(sio->read_buffer);
70 g_free(sio->write_buffer);
71 g_object_unref (sio->cancel);
72 if (sio->monitor_idle > 0)
73 g_source_remove (sio->monitor_idle);
74 if (sio->monitor)
75 g_object_unref (sio->monitor);
77 G_OBJECT_CLASS (sourceview_io_parent_class)->finalize (object);
80 static void
81 sourceview_io_class_init (SourceviewIOClass *klass)
83 GObjectClass* object_class = G_OBJECT_CLASS (klass);
85 object_class->finalize = sourceview_io_finalize;
87 klass->changed = NULL;
88 klass->deleted = NULL;
89 klass->save_finished = NULL;
90 klass->open_finished = NULL;
91 klass->open_failed = NULL;
92 klass->save_failed = NULL;
94 io_signals[SAVE_STATUS] =
95 g_signal_new ("changed",
96 G_OBJECT_CLASS_TYPE (klass),
98 G_STRUCT_OFFSET (SourceviewIOClass, changed),
99 NULL, NULL,
100 g_cclosure_marshal_VOID__VOID,
101 G_TYPE_NONE, 0,
102 NULL);
104 io_signals[SAVE_FINISHED] =
105 g_signal_new ("save-finished",
106 G_OBJECT_CLASS_TYPE (klass),
108 G_STRUCT_OFFSET (SourceviewIOClass, save_finished),
109 NULL, NULL,
110 g_cclosure_marshal_VOID__VOID,
111 G_TYPE_NONE, 0,
112 NULL);
114 io_signals[OPEN_FINISHED] =
115 g_signal_new ("open-finished",
116 G_OBJECT_CLASS_TYPE (klass),
118 G_STRUCT_OFFSET (SourceviewIOClass, open_finished),
119 NULL, NULL,
120 g_cclosure_marshal_VOID__VOID,
121 G_TYPE_NONE, 0,
122 NULL);
124 io_signals[OPEN_FAILED] =
125 g_signal_new ("open-failed",
126 G_OBJECT_CLASS_TYPE (klass),
128 G_STRUCT_OFFSET (SourceviewIOClass, open_failed),
129 NULL, NULL,
130 g_cclosure_marshal_VOID__POINTER,
131 G_TYPE_NONE, 1,
132 G_TYPE_POINTER);
134 io_signals[SAVE_FAILED] =
135 g_signal_new ("save-failed",
136 G_OBJECT_CLASS_TYPE (klass),
138 G_STRUCT_OFFSET (SourceviewIOClass, save_failed),
139 NULL, NULL,
140 g_cclosure_marshal_VOID__POINTER,
141 G_TYPE_NONE, 1,
142 G_TYPE_POINTER);
144 io_signals[FILE_DELETED] =
145 g_signal_new ("deleted",
146 G_OBJECT_CLASS_TYPE (klass),
148 G_STRUCT_OFFSET (SourceviewIOClass, deleted),
149 NULL, NULL,
150 g_cclosure_marshal_VOID__VOID,
151 G_TYPE_NONE, 0,
152 NULL);
155 static void on_file_changed (GFileMonitor* monitor,
156 GFile* file,
157 GFile* other_file,
158 GFileMonitorEvent event_type,
159 gpointer data)
161 SourceviewIO* sio = SOURCEVIEW_IO(data);
163 switch (event_type)
165 case G_FILE_MONITOR_EVENT_CREATED:
166 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
167 g_signal_emit_by_name (sio, "changed");
168 break;
169 case G_FILE_MONITOR_EVENT_DELETED:
170 g_signal_emit_by_name (sio, "deleted");
171 break;
172 default:
173 break;
177 static gboolean
178 setup_monitor_idle(gpointer data)
180 SourceviewIO* sio = SOURCEVIEW_IO(data);
181 sio->monitor_idle = 0;
182 if (sio->monitor != NULL)
183 g_object_unref (sio->monitor);
184 sio->monitor = g_file_monitor_file (sio->file,
185 G_FILE_MONITOR_NONE,
186 NULL,
187 NULL);
188 if (sio->monitor)
190 g_signal_connect (sio->monitor, "changed",
191 G_CALLBACK(on_file_changed), sio);
192 g_file_monitor_set_rate_limit (sio->monitor, RATE_LIMIT);
194 return FALSE;
197 static void
198 setup_monitor(SourceviewIO* sio)
200 if (sio->monitor_idle > 0)
201 g_source_remove (sio->monitor_idle);
203 sio->monitor_idle = g_timeout_add_seconds (TIMEOUT,
204 setup_monitor_idle,
205 sio);
208 static void
209 cancel_monitor (SourceviewIO* sio)
211 if (sio->monitor != NULL)
212 g_object_unref (sio->monitor);
213 sio->monitor = NULL;
216 static void
217 set_display_name (SourceviewIO* sio)
219 GFileInfo* file_info = g_file_query_info (sio->file,
220 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
221 G_FILE_QUERY_INFO_NONE,
222 NULL,
223 NULL);
224 if (file_info)
226 g_free (sio->filename);
227 sio->filename = g_strdup(g_file_info_get_display_name (file_info));
229 else
231 g_free (sio->filename);
232 sio->filename = NULL;
234 g_object_unref (file_info);
237 static void
238 on_save_finished (GObject* file, GAsyncResult* result, gpointer data)
240 SourceviewIO* sio = SOURCEVIEW_IO(data);
241 AnjutaShell* shell = ANJUTA_PLUGIN (sio->sv->priv->plugin)->shell;
242 GError* err = NULL;
243 g_file_replace_contents_finish (G_FILE (file),
244 result,
245 NULL,
246 &err);
247 g_free (sio->write_buffer);
248 sio->write_buffer = NULL;
249 if (err)
251 g_signal_emit_by_name (sio, "save-failed", err);
252 g_error_free (err);
254 else
256 set_display_name (sio);
257 setup_monitor (sio);
258 g_signal_emit_by_name (sio, "save-finished");
260 g_object_unref (sio);
261 anjuta_shell_saving_pop (shell);
264 void
265 sourceview_io_save (SourceviewIO* sio)
267 if (!sio->file)
269 GError* error = NULL;
270 g_set_error (&error, IO_ERROR_QUARK, 0,
271 _("Could not save file because filename not yet specified"));
272 g_signal_emit_by_name (sio, "save-failed", error);
273 g_error_free(error);
275 else
276 sourceview_io_save_as (sio, sio->file);
279 void
280 sourceview_io_save_as (SourceviewIO* sio, GFile* file)
282 AnjutaShell* shell = ANJUTA_PLUGIN (sio->sv->priv->plugin)->shell;
283 gboolean backup = TRUE;
284 gsize len;
286 g_return_if_fail (file != NULL);
288 cancel_monitor (sio);
290 backup = g_settings_get_boolean (sio->sv->priv->settings,
291 "backup");
293 if (sio->last_encoding == NULL)
295 sio->write_buffer = ianjuta_editor_get_text_all (IANJUTA_EDITOR(sio->sv),
296 NULL);
297 len = strlen (sio->write_buffer);
299 else
301 GError* err = NULL;
302 gchar* buffer_text = ianjuta_editor_get_text_all (IANJUTA_EDITOR(sio->sv),
303 NULL);
304 sio->write_buffer = anjuta_convert_from_utf8 (buffer_text,
306 sio->last_encoding,
307 &len,
308 &err);
309 g_free (buffer_text);
310 if (err != NULL)
312 g_signal_emit_by_name (sio, "save-failed", err);
313 g_error_free(err);
314 return;
317 g_cancellable_reset (sio->cancel);
318 g_file_replace_contents_async (file,
319 sio->write_buffer,
320 len,
321 NULL,
322 backup,
323 G_FILE_CREATE_NONE,
324 sio->cancel,
325 on_save_finished,
326 sio);
327 anjuta_shell_saving_push (shell);
329 if (sio->file != file)
331 if (sio->file)
332 g_object_unref (sio->file);
333 sio->file = file;
334 g_object_ref (file);
336 g_object_ref (sio);
339 static void insert_text_in_document(SourceviewIO* sio, const gchar* text, gsize len)
341 GtkSourceBuffer* document = GTK_SOURCE_BUFFER (sio->sv->priv->document);
342 gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (sio->sv->priv->document));
344 /* Insert text in the buffer */
345 gtk_text_buffer_set_text (GTK_TEXT_BUFFER (document),
346 text,
347 len);
349 gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (document),
350 FALSE);
352 gtk_source_buffer_end_not_undoable_action (document);
355 static gboolean
356 append_buffer (SourceviewIO* sio, gsize size)
358 /* Text is utf-8 - good */
359 if (g_utf8_validate (sio->read_buffer, size, NULL))
361 insert_text_in_document (sio, sio->read_buffer, size);
363 else
365 /* Text is not utf-8 */
366 GError *conv_error = NULL;
367 gchar *converted_text = NULL;
368 gsize new_len = size;
369 const AnjutaEncoding* enc = NULL;
371 converted_text = anjuta_convert_to_utf8 (sio->read_buffer,
372 size,
373 &enc,
374 &new_len,
375 &conv_error);
376 if (converted_text == NULL)
378 /* Last chance, let's try 8859-15 */
379 enc = anjuta_encoding_get_from_charset( "ISO-8859-15");
380 conv_error = NULL;
381 converted_text = anjuta_convert_to_utf8 (sio->read_buffer,
382 size,
383 &enc,
384 &new_len,
385 &conv_error);
387 if (converted_text == NULL)
389 g_return_val_if_fail (conv_error != NULL, FALSE);
391 g_signal_emit_by_name (sio, "open-failed", conv_error);
392 g_error_free (conv_error);
393 g_cancellable_cancel (sio->cancel);
394 return FALSE;
396 sio->last_encoding = enc;
397 insert_text_in_document (sio, converted_text, new_len);
398 g_free (converted_text);
400 return TRUE;
403 static void
404 on_read_finished (GObject* input, GAsyncResult* result, gpointer data)
406 SourceviewIO* sio = SOURCEVIEW_IO(data);
407 GInputStream* input_stream = G_INPUT_STREAM(input);
408 gsize current_bytes = 0;
409 GError* err = NULL;
411 current_bytes = g_input_stream_read_finish (input_stream, result, &err);
412 if (err)
414 g_signal_emit_by_name (sio, "open-failed", err);
415 g_error_free (err);
416 g_object_unref (input_stream);
417 g_free (sio->read_buffer);
418 sio->read_buffer = NULL;
419 sio->bytes_read = 0;
420 return;
423 sio->bytes_read += current_bytes;
424 if (current_bytes != 0)
426 sio->read_buffer = g_realloc (sio->read_buffer, sio->bytes_read + READ_SIZE);
427 g_input_stream_read_async (G_INPUT_STREAM (input_stream),
428 sio->read_buffer + sio->bytes_read,
429 READ_SIZE,
430 G_PRIORITY_LOW,
431 sio->cancel,
432 on_read_finished,
433 sio);
434 return;
436 else
438 if (append_buffer (sio, sio->bytes_read))
439 g_signal_emit_by_name (sio, "open-finished");
440 sio->bytes_read = 0;
441 g_object_unref (input_stream);
442 setup_monitor (sio);
443 g_free (sio->read_buffer);
444 sio->read_buffer = NULL;
448 void
449 sourceview_io_open (SourceviewIO* sio, GFile* file)
451 GFileInputStream* input_stream;
452 GError* err = NULL;
454 g_return_if_fail (file != NULL);
456 if (sio->file)
457 g_object_unref (sio->file);
458 sio->file = file;
459 g_object_ref (sio->file);
460 set_display_name(sio);
462 input_stream = g_file_read (file, NULL, &err);
463 if (!input_stream)
465 g_signal_emit_by_name (sio, "open-failed", err);
466 g_error_free (err);
467 return;
469 sio->read_buffer = g_realloc (sio->read_buffer, READ_SIZE);
470 g_input_stream_read_async (G_INPUT_STREAM (input_stream),
471 sio->read_buffer,
472 READ_SIZE,
473 G_PRIORITY_LOW,
474 sio->cancel,
475 on_read_finished,
476 sio);
479 GFile*
480 sourceview_io_get_file (SourceviewIO* sio)
482 if (sio->file)
483 g_object_ref (sio->file);
484 return sio->file;
487 void
488 sourceview_io_cancel (SourceviewIO* sio)
490 g_cancellable_cancel (sio->cancel);
493 const gchar*
494 sourceview_io_get_filename (SourceviewIO* sio)
496 static gint new_file_count = 1;
497 if (sio->filename == NULL) /* new file */
499 sio->filename = g_strdup_printf (_("New file %d"), new_file_count++);
501 return sio->filename;
504 void
505 sourceview_io_set_filename (SourceviewIO* sio, const gchar* filename)
507 g_free (sio->filename);
508 sio->filename = g_strdup(filename);
511 gchar*
512 sourceview_io_get_mime_type (SourceviewIO* sio)
514 GFileInfo* file_info;
516 if (!sio->file)
517 return NULL;
519 file_info = g_file_query_info (sio->file,
520 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
521 G_FILE_QUERY_INFO_NONE,
522 NULL,
523 NULL);
524 if (file_info)
526 gchar* mime_type = g_strdup (g_file_info_get_content_type (file_info));
527 g_object_unref (file_info);
528 return mime_type;
530 else
531 return NULL;
535 gboolean
536 sourceview_io_get_read_only (SourceviewIO* sio)
538 GFileInfo* file_info;
539 gboolean retval;
541 if (!sio->file)
542 return FALSE;
544 file_info = g_file_query_info (sio->file,
545 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
546 G_FILE_QUERY_INFO_NONE,
547 NULL,
548 NULL);
549 if (!file_info)
550 return FALSE;
552 retval = !g_file_info_get_attribute_boolean (file_info,
553 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
554 g_object_unref (file_info);
555 return retval;
558 SourceviewIO*
559 sourceview_io_new (Sourceview* sv)
561 SourceviewIO* sio = SOURCEVIEW_IO(g_object_new (SOURCEVIEW_TYPE_IO, NULL));
562 sio->sv = sv;
563 return sio;