2005-09-06 09:21:05 -07:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
|
2005-09-09 02:54:58 -07:00
|
|
|
*
|
2005-09-02 16:27:25 -07:00
|
|
|
* mooeditfileops.c
|
2005-06-22 11:20:32 -07:00
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* See COPYING file that comes with this distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MOOEDIT_COMPILATION
|
|
|
|
#include "mooedit/mooedit-private.h"
|
2005-09-02 16:27:25 -07:00
|
|
|
#include "mooedit/mooeditfileops.h"
|
2005-06-22 11:20:32 -07:00
|
|
|
#include "mooedit/mooeditdialogs.h"
|
|
|
|
#include "mooutils/moofileutils.h"
|
2005-09-05 22:36:44 -07:00
|
|
|
#include "mooutils/moocompat.h"
|
2005-06-22 11:20:32 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
static MooEditLoader *default_loader = NULL;
|
|
|
|
static MooEditSaver *default_saver = NULL;
|
2005-09-03 15:48:05 -07:00
|
|
|
static GSList *UNTITLED = NULL;
|
|
|
|
static GHashTable *UNTITLED_NO = NULL;
|
2005-09-02 16:27:25 -07:00
|
|
|
|
|
|
|
|
|
|
|
static gboolean moo_edit_load_default (MooEditLoader *loader,
|
|
|
|
MooEdit *edit,
|
|
|
|
const char *file,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error);
|
|
|
|
static gboolean moo_edit_reload_default (MooEditLoader *loader,
|
|
|
|
MooEdit *edit,
|
|
|
|
GError **error);
|
|
|
|
static gboolean moo_edit_save_default (MooEditSaver *saver,
|
|
|
|
MooEdit *edit,
|
|
|
|
const char *file,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error);
|
|
|
|
|
2005-06-22 11:20:32 -07:00
|
|
|
static void block_buffer_signals (MooEdit *edit);
|
|
|
|
static void unblock_buffer_signals (MooEdit *edit);
|
|
|
|
static void start_file_watch (MooEdit *edit);
|
|
|
|
static void stop_file_watch (MooEdit *edit);
|
|
|
|
static gboolean file_watch_timeout_func (MooEdit *edit);
|
|
|
|
static gboolean focus_in_cb (MooEdit *edit);
|
|
|
|
static gboolean check_file_status (MooEdit *edit,
|
|
|
|
gboolean in_focus_only);
|
|
|
|
static void file_modified_on_disk (MooEdit *edit);
|
|
|
|
static void file_deleted (MooEdit *edit);
|
|
|
|
static void file_watch_error (MooEdit *edit);
|
|
|
|
static void file_watch_access_denied (MooEdit *edit);
|
2005-09-02 16:27:25 -07:00
|
|
|
static void add_status (MooEdit *edit,
|
|
|
|
MooEditStatus s);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
MooEditLoader *moo_edit_loader_get_default (void)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
if (!default_loader)
|
|
|
|
{
|
|
|
|
default_loader = g_new0 (MooEditLoader, 1);
|
|
|
|
default_loader->ref_count = 1;
|
|
|
|
default_loader->load = moo_edit_load_default;
|
|
|
|
default_loader->reload = moo_edit_reload_default;
|
|
|
|
}
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
return default_loader;
|
|
|
|
}
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-07-28 12:25:10 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
MooEditSaver *moo_edit_saver_get_default (void)
|
|
|
|
{
|
|
|
|
if (!default_saver)
|
|
|
|
{
|
|
|
|
default_saver = g_new0 (MooEditSaver, 1);
|
|
|
|
default_saver->ref_count = 1;
|
|
|
|
default_saver->save = moo_edit_save_default;
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
return default_saver;
|
|
|
|
}
|
2005-07-28 12:25:10 -07:00
|
|
|
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
MooEditLoader *moo_edit_loader_ref (MooEditLoader *loader)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (loader != NULL, NULL);
|
|
|
|
loader->ref_count++;
|
|
|
|
return loader;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MooEditSaver *moo_edit_saver_ref (MooEditSaver *saver)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (saver != NULL, NULL);
|
|
|
|
saver->ref_count++;
|
|
|
|
return saver;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void moo_edit_loader_unref (MooEditLoader *loader)
|
|
|
|
{
|
|
|
|
if (!loader || --loader->ref_count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free (loader);
|
|
|
|
|
|
|
|
if (loader == default_loader)
|
|
|
|
default_loader = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void moo_edit_saver_unref (MooEditSaver *saver)
|
|
|
|
{
|
|
|
|
if (!saver || --saver->ref_count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free (saver);
|
|
|
|
|
|
|
|
if (saver == default_saver)
|
|
|
|
default_saver = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gboolean moo_edit_load (MooEditLoader *loader,
|
|
|
|
MooEdit *edit,
|
2005-09-03 15:48:05 -07:00
|
|
|
const char *filename,
|
2005-09-02 16:27:25 -07:00
|
|
|
const char *encoding,
|
|
|
|
GError **error)
|
|
|
|
{
|
2005-09-03 15:48:05 -07:00
|
|
|
char *filename_copy, *encoding_copy;
|
|
|
|
gboolean result;
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_return_val_if_fail (loader != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
|
2005-09-03 15:48:05 -07:00
|
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
|
|
|
|
|
|
|
filename_copy = g_strdup (filename);
|
|
|
|
encoding_copy = g_strdup (encoding);
|
2005-09-02 16:27:25 -07:00
|
|
|
|
2005-09-03 15:48:05 -07:00
|
|
|
result = loader->load (loader, edit, filename_copy, encoding_copy, error);
|
|
|
|
|
|
|
|
g_free (filename_copy);
|
|
|
|
g_free (encoding_copy);
|
|
|
|
return result;
|
2005-09-02 16:27:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gboolean moo_edit_reload (MooEditLoader *loader,
|
|
|
|
MooEdit *edit,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (loader != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
|
|
|
|
|
|
|
|
return loader->reload (loader, edit, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gboolean moo_edit_save (MooEditSaver *saver,
|
|
|
|
MooEdit *edit,
|
2005-09-03 15:48:05 -07:00
|
|
|
const char *filename,
|
2005-09-02 16:27:25 -07:00
|
|
|
const char *encoding,
|
|
|
|
GError **error)
|
|
|
|
{
|
2005-09-03 15:48:05 -07:00
|
|
|
char *filename_copy, *encoding_copy;
|
|
|
|
gboolean result;
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_return_val_if_fail (saver != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
|
2005-09-03 15:48:05 -07:00
|
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
|
|
|
|
|
|
|
filename_copy = g_strdup (filename);
|
|
|
|
encoding_copy = g_strdup (encoding);
|
2005-09-02 16:27:25 -07:00
|
|
|
|
2005-09-03 15:48:05 -07:00
|
|
|
result = saver->save (saver, edit, filename_copy, encoding_copy, error);
|
|
|
|
|
|
|
|
g_free (filename_copy);
|
|
|
|
g_free (encoding_copy);
|
|
|
|
return result;
|
2005-09-02 16:27:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/* File loading
|
|
|
|
*/
|
|
|
|
|
|
|
|
static gboolean do_load (MooEdit *edit,
|
|
|
|
const char *file,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error);
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean moo_edit_load_default (G_GNUC_UNUSED MooEditLoader *loader,
|
|
|
|
MooEdit *edit,
|
|
|
|
const char *file,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GtkTextIter start, end;
|
2005-09-06 09:21:05 -07:00
|
|
|
GtkTextBuffer *buffer;
|
2005-09-02 16:27:25 -07:00
|
|
|
MooEditFileInfo *info = NULL;
|
|
|
|
gboolean undo;
|
|
|
|
|
|
|
|
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
|
|
|
|
g_return_val_if_fail (file && file[0], FALSE);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
|
|
|
block_buffer_signals (edit);
|
|
|
|
|
|
|
|
if (moo_edit_is_empty (edit))
|
|
|
|
undo = FALSE;
|
|
|
|
else
|
|
|
|
undo = TRUE;
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
|
|
|
|
|
2005-06-22 11:20:32 -07:00
|
|
|
if (undo)
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_begin_user_action (buffer);
|
2005-06-22 11:20:32 -07:00
|
|
|
else
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (buffer));
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
|
|
|
gtk_text_buffer_delete (buffer, &start, &end);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (!do_load (edit, file, encoding, error))
|
2005-07-28 12:25:10 -07:00
|
|
|
{
|
2005-06-22 11:20:32 -07:00
|
|
|
moo_edit_file_info_free (info);
|
|
|
|
edit->priv->status = 0;
|
|
|
|
stop_file_watch (edit);
|
|
|
|
unblock_buffer_signals (edit);
|
2005-07-28 12:25:10 -07:00
|
|
|
|
|
|
|
if (undo)
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_end_user_action (buffer);
|
2005-07-28 12:25:10 -07:00
|
|
|
else
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (buffer));
|
2005-07-28 12:25:10 -07:00
|
|
|
|
2005-06-22 11:20:32 -07:00
|
|
|
moo_edit_set_modified (edit, FALSE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_get_start_iter (buffer, &start);
|
|
|
|
gtk_text_buffer_place_cursor (buffer, &start);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
|
|
|
unblock_buffer_signals (edit);
|
|
|
|
edit->priv->status = 0;
|
|
|
|
_moo_edit_set_filename (edit, file, encoding);
|
|
|
|
moo_edit_set_modified (edit, FALSE);
|
|
|
|
start_file_watch (edit);
|
|
|
|
|
|
|
|
moo_edit_file_info_free (info);
|
|
|
|
|
|
|
|
if (undo)
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_end_user_action (buffer);
|
2005-06-22 11:20:32 -07:00
|
|
|
else
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (buffer));
|
2005-06-22 11:20:32 -07:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
static gboolean do_load (MooEdit *edit,
|
|
|
|
const char *filename,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
GIOChannel *file = NULL;
|
|
|
|
GIOStatus status;
|
2005-09-06 09:21:05 -07:00
|
|
|
GtkTextBuffer *buffer;
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 23:25:43 -07:00
|
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
|
|
|
|
|
|
|
|
if (!encoding || !strcmp (encoding, "UTF-8") || !strcmp (encoding, "UTF8"))
|
2005-09-05 22:36:44 -07:00
|
|
|
{
|
|
|
|
char *contents;
|
|
|
|
gsize len;
|
|
|
|
GMappedFile *mapped_file = g_mapped_file_new (filename, FALSE, error);
|
|
|
|
|
|
|
|
if (mapped_file)
|
|
|
|
{
|
|
|
|
contents = g_mapped_file_get_contents (mapped_file);
|
|
|
|
len = g_mapped_file_get_length (mapped_file);
|
|
|
|
|
|
|
|
if (!g_utf8_validate (contents, len, NULL))
|
|
|
|
{
|
|
|
|
g_mapped_file_free (mapped_file);
|
|
|
|
g_set_error (error, G_CONVERT_ERROR,
|
|
|
|
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
|
|
|
|
"Invalid UTF8 data read from file");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_insert_at_cursor (buffer, contents, len);
|
2005-09-05 22:36:44 -07:00
|
|
|
g_free (edit->priv->encoding);
|
|
|
|
edit->priv->encoding = NULL;
|
|
|
|
|
|
|
|
g_mapped_file_free (mapped_file);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("%s: could not create mapped file", G_STRLOC);
|
|
|
|
g_warning ("%s: %s", G_STRLOC, (*error)->message);
|
|
|
|
g_clear_error (error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
file = g_io_channel_new_file (filename, "r", error);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (!file)
|
|
|
|
return FALSE;
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
if (!encoding)
|
|
|
|
encoding = "UTF8";
|
|
|
|
|
|
|
|
if (g_io_channel_set_encoding (file, encoding, error) != G_IO_STATUS_NORMAL)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
2005-06-22 11:20:32 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
char *line = NULL;
|
|
|
|
gsize len;
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
status = g_io_channel_read_line (file, &line, &len, NULL, error);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (line)
|
2005-07-29 04:51:36 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
if (!g_utf8_validate (line, len, NULL))
|
|
|
|
{
|
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
g_set_error (error, G_CONVERT_ERROR,
|
|
|
|
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
|
|
|
|
"Invalid UTF8 data read from file");
|
|
|
|
g_free (line);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_insert_at_cursor (buffer, line, len);
|
2005-09-02 16:27:25 -07:00
|
|
|
g_free (line);
|
2005-07-29 04:51:36 -07:00
|
|
|
}
|
2005-09-02 16:27:25 -07:00
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
if (status != G_IO_STATUS_NORMAL)
|
2005-07-29 04:51:36 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
if (status != G_IO_STATUS_EOF)
|
|
|
|
{
|
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
break;
|
|
|
|
}
|
2005-07-29 04:51:36 -07:00
|
|
|
}
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_free (edit->priv->encoding);
|
|
|
|
edit->priv->encoding = g_strdup (encoding);
|
|
|
|
g_clear_error (error);
|
2005-06-22 11:20:32 -07:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
static gboolean moo_edit_reload_default (MooEditLoader *loader,
|
|
|
|
MooEdit *edit,
|
|
|
|
GError **error)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
|
|
|
GtkTextIter start, end;
|
2005-09-06 09:21:05 -07:00
|
|
|
GtkTextBuffer *buffer;
|
2005-06-22 11:20:32 -07:00
|
|
|
|
|
|
|
g_return_val_if_fail (edit->priv->filename != NULL, FALSE);
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
|
|
|
|
|
2005-06-22 11:20:32 -07:00
|
|
|
block_buffer_signals (edit);
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_begin_user_action (buffer);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
|
|
|
gtk_text_buffer_delete (buffer, &start, &end);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-03 15:48:05 -07:00
|
|
|
if (!moo_edit_load (loader, edit, edit->priv->filename,
|
|
|
|
edit->priv->encoding, error))
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_end_user_action (buffer);
|
2005-06-22 11:20:32 -07:00
|
|
|
unblock_buffer_signals (edit);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-09-02 16:27:25 -07:00
|
|
|
else
|
|
|
|
{
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_end_user_action (buffer);
|
2005-06-22 11:20:32 -07:00
|
|
|
edit->priv->status = 0;
|
|
|
|
unblock_buffer_signals (edit);
|
|
|
|
moo_edit_set_modified (edit, FALSE);
|
|
|
|
start_file_watch (edit);
|
2005-09-02 16:27:25 -07:00
|
|
|
g_clear_error (error);
|
2005-06-22 11:20:32 -07:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
/***************************************************************************/
|
|
|
|
/* File saving
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
static const char *line_end[3] = {"\n", "\r\n", "\r"};
|
|
|
|
static guint line_end_len[3] = {1, 2, 1};
|
|
|
|
|
|
|
|
static gboolean do_write (MooEdit *edit,
|
|
|
|
const char *file,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error);
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean moo_edit_save_default (G_GNUC_UNUSED MooEditSaver *saver,
|
|
|
|
MooEdit *edit,
|
|
|
|
const char *filename,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
|
|
|
|
g_return_val_if_fail (filename && filename[0], FALSE);
|
|
|
|
|
|
|
|
if (!do_write (edit, filename, encoding, error))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
edit->priv->status = 0;
|
|
|
|
_moo_edit_set_filename (edit, filename, encoding);
|
|
|
|
moo_edit_set_modified (edit, FALSE);
|
|
|
|
start_file_watch (edit);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean do_write (MooEdit *edit,
|
|
|
|
const char *filename,
|
|
|
|
const char *encoding,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GIOChannel *file;
|
|
|
|
GIOStatus status;
|
|
|
|
GtkTextIter line_start;
|
|
|
|
const char *le = line_end[edit->priv->line_end_type];
|
|
|
|
gssize le_len = line_end_len[edit->priv->line_end_type];
|
2005-09-06 09:21:05 -07:00
|
|
|
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
|
2005-09-02 16:27:25 -07:00
|
|
|
|
|
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
if (encoding && (!strcmp (encoding, "UTF-8") || !strcmp (encoding, "UTF8")))
|
2005-09-02 16:27:25 -07:00
|
|
|
encoding = NULL;
|
|
|
|
|
|
|
|
file = g_io_channel_new_file (filename, "w", error);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
|
|
|
if (!file)
|
2005-09-02 16:27:25 -07:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (encoding && g_io_channel_set_encoding (file, encoding, error) != G_IO_STATUS_NORMAL)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
return FALSE;
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
gtk_text_buffer_get_start_iter (buffer, &line_start);
|
2005-09-02 16:27:25 -07:00
|
|
|
|
|
|
|
do
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
gsize written;
|
|
|
|
GtkTextIter line_end = line_start;
|
|
|
|
gboolean write_line_end = FALSE;
|
|
|
|
|
|
|
|
if (!gtk_text_iter_ends_line (&line_start))
|
|
|
|
{
|
|
|
|
char *line;
|
|
|
|
gssize len = -1;
|
|
|
|
|
|
|
|
gtk_text_iter_forward_to_line_end (&line_end);
|
2005-09-06 09:21:05 -07:00
|
|
|
line = gtk_text_buffer_get_text (buffer, &line_start, &line_end, FALSE);
|
2005-09-02 16:27:25 -07:00
|
|
|
|
|
|
|
status = g_io_channel_write_chars (file, line, len, &written, error);
|
|
|
|
g_free (line);
|
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
if (status != G_IO_STATUS_NORMAL)
|
|
|
|
{
|
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gtk_text_iter_ends_line (&line_start))
|
|
|
|
write_line_end = !gtk_text_iter_is_end (&line_start);
|
2005-06-22 11:20:32 -07:00
|
|
|
else
|
2005-09-02 16:27:25 -07:00
|
|
|
write_line_end = !gtk_text_iter_is_end (&line_end);
|
|
|
|
|
|
|
|
if (write_line_end)
|
|
|
|
{
|
|
|
|
status = g_io_channel_write_chars (file, le, le_len, &written, error);
|
|
|
|
|
|
|
|
if (written < (gsize)le_len || status != G_IO_STATUS_NORMAL)
|
|
|
|
{
|
|
|
|
g_io_channel_shutdown (file, TRUE, NULL);
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
2005-09-02 16:27:25 -07:00
|
|
|
while (gtk_text_iter_forward_line (&line_start));
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
status = g_io_channel_shutdown (file, TRUE, error);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (status != G_IO_STATUS_NORMAL)
|
|
|
|
{
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_io_channel_unref (file);
|
|
|
|
g_clear_error (error);
|
|
|
|
return TRUE;
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
/***************************************************************************/
|
|
|
|
/* Aux stuff
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void block_buffer_signals (MooEdit *edit)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-09 02:40:10 -07:00
|
|
|
MooTextView *view = MOO_TEXT_VIEW (edit);
|
2005-09-06 09:21:05 -07:00
|
|
|
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
|
2005-09-09 02:40:10 -07:00
|
|
|
g_signal_handler_block (buffer, view->priv->can_undo_handler_id);
|
|
|
|
g_signal_handler_block (buffer, view->priv->can_redo_handler_id);
|
2005-09-06 09:21:05 -07:00
|
|
|
g_signal_handler_block (buffer, edit->priv->modified_changed_handler_id);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
static void unblock_buffer_signals (MooEdit *edit)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-09 02:40:10 -07:00
|
|
|
MooTextView *view = MOO_TEXT_VIEW (edit);
|
2005-09-06 09:21:05 -07:00
|
|
|
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
|
2005-09-09 02:40:10 -07:00
|
|
|
g_signal_handler_unblock (buffer, view->priv->can_undo_handler_id);
|
|
|
|
g_signal_handler_unblock (buffer, view->priv->can_redo_handler_id);
|
2005-09-06 09:21:05 -07:00
|
|
|
g_signal_handler_unblock (buffer, edit->priv->modified_changed_handler_id);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
/* XXX use MooFileWatch */
|
|
|
|
static void start_file_watch (MooEdit *edit)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
|
|
|
GTime timestamp;
|
|
|
|
|
|
|
|
if (edit->priv->file_watch_id)
|
|
|
|
g_source_remove (edit->priv->file_watch_id);
|
|
|
|
edit->priv->file_watch_id = 0;
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_return_if_fail ((edit->priv->status & MOO_EDIT_CHANGED_ON_DISK) == 0);
|
2005-06-22 11:20:32 -07:00
|
|
|
g_return_if_fail (edit->priv->filename != NULL);
|
|
|
|
|
|
|
|
timestamp = moo_get_file_mtime (edit->priv->filename);
|
|
|
|
g_return_if_fail (timestamp > 0); /* TODO TODO */
|
|
|
|
edit->priv->timestamp = timestamp;
|
|
|
|
|
|
|
|
if (edit->priv->file_watch_timeout)
|
|
|
|
edit->priv->file_watch_id =
|
|
|
|
g_timeout_add (edit->priv->file_watch_timeout,
|
|
|
|
(GSourceFunc) file_watch_timeout_func,
|
|
|
|
edit);
|
|
|
|
if (!edit->priv->focus_in_handler_id)
|
|
|
|
edit->priv->focus_in_handler_id =
|
|
|
|
g_signal_connect (edit, "focus-in-event",
|
|
|
|
G_CALLBACK (focus_in_cb),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
static void stop_file_watch (MooEdit *edit)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
|
|
|
if (edit->priv->file_watch_id)
|
|
|
|
g_source_remove (edit->priv->file_watch_id);
|
2005-09-02 16:27:25 -07:00
|
|
|
|
2005-06-22 11:20:32 -07:00
|
|
|
edit->priv->file_watch_id = 0;
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (edit->priv->focus_in_handler_id)
|
|
|
|
{
|
2005-06-22 11:20:32 -07:00
|
|
|
g_signal_handler_disconnect (edit, edit->priv->focus_in_handler_id);
|
|
|
|
edit->priv->focus_in_handler_id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean file_watch_timeout_func (MooEdit *edit)
|
|
|
|
{
|
|
|
|
return check_file_status (edit, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean focus_in_cb (MooEdit *edit)
|
|
|
|
{
|
|
|
|
check_file_status (edit, TRUE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean check_file_status (MooEdit *edit,
|
|
|
|
gboolean in_focus_only)
|
|
|
|
{
|
|
|
|
GTime stamp;
|
|
|
|
|
|
|
|
if (in_focus_only && !GTK_WIDGET_HAS_FOCUS (edit))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
g_return_val_if_fail (edit->priv->filename != NULL, FALSE);
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_return_val_if_fail (!(edit->priv->status & MOO_EDIT_CHANGED_ON_DISK), FALSE);
|
2005-06-22 11:20:32 -07:00
|
|
|
g_return_val_if_fail (edit->priv->timestamp > 0, FALSE);
|
|
|
|
g_return_val_if_fail (edit->priv->filename != NULL, FALSE);
|
|
|
|
|
|
|
|
stamp = moo_get_file_mtime (edit->priv->filename);
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (stamp < 0)
|
|
|
|
{
|
|
|
|
switch (stamp)
|
|
|
|
{
|
2005-06-22 11:20:32 -07:00
|
|
|
case MOO_EACCESS:
|
|
|
|
file_watch_access_denied (edit);
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case MOO_ENOENT:
|
|
|
|
file_deleted (edit);
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case MOO_EIO:
|
|
|
|
default:
|
|
|
|
g_critical ("%s: error in moo_get_file_mtime", G_STRLOC);
|
|
|
|
file_watch_error (edit);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stamp == edit->priv->timestamp)
|
|
|
|
return TRUE;
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (stamp < edit->priv->timestamp)
|
|
|
|
{
|
2005-06-22 11:20:32 -07:00
|
|
|
g_warning ("%s: mtime of file on disk is less than timestamp", G_STRLOC);
|
|
|
|
file_watch_error (edit);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_modified_on_disk (edit);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void file_modified_on_disk (MooEdit *edit)
|
|
|
|
{
|
|
|
|
g_return_if_fail (edit->priv->filename != NULL);
|
2005-09-02 16:27:25 -07:00
|
|
|
stop_file_watch (edit);
|
|
|
|
add_status (edit, MOO_EDIT_MODIFIED_ON_DISK);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void file_deleted (MooEdit *edit)
|
|
|
|
{
|
|
|
|
g_return_if_fail (edit->priv->filename != NULL);
|
2005-09-02 16:27:25 -07:00
|
|
|
stop_file_watch (edit);
|
|
|
|
add_status (edit, MOO_EDIT_DELETED);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void file_watch_error (MooEdit *edit)
|
|
|
|
{
|
|
|
|
g_critical ("%s", G_STRLOC);
|
|
|
|
stop_file_watch (edit);
|
2005-09-02 16:27:25 -07:00
|
|
|
add_status (edit, MOO_EDIT_DELETED);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void file_watch_access_denied (MooEdit *edit)
|
|
|
|
{
|
|
|
|
g_critical ("%s", G_STRLOC);
|
|
|
|
stop_file_watch (edit);
|
2005-09-02 16:27:25 -07:00
|
|
|
/* XXX */
|
|
|
|
add_status (edit, MOO_EDIT_DELETED);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
static void add_status (MooEdit *edit,
|
|
|
|
MooEditStatus s)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
edit->priv->status |= s;
|
|
|
|
g_signal_emit_by_name (edit, "doc-status-changed", NULL);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-03 15:48:05 -07:00
|
|
|
static void remove_untitled (gpointer destroyed,
|
|
|
|
MooEdit *edit)
|
|
|
|
{
|
|
|
|
gpointer n = g_hash_table_lookup (UNTITLED_NO, edit);
|
|
|
|
|
|
|
|
if (n)
|
|
|
|
{
|
|
|
|
UNTITLED = g_slist_remove (UNTITLED, n);
|
|
|
|
g_hash_table_remove (UNTITLED_NO, edit);
|
|
|
|
if (!destroyed)
|
|
|
|
g_object_weak_unref (G_OBJECT (edit),
|
|
|
|
(GWeakNotify) remove_untitled,
|
|
|
|
GINT_TO_POINTER (TRUE));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int add_untitled (MooEdit *edit)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (!(n = GPOINTER_TO_INT (g_hash_table_lookup (UNTITLED_NO, edit))))
|
|
|
|
{
|
|
|
|
for (n = 1; ; ++n)
|
|
|
|
{
|
|
|
|
if (!g_slist_find (UNTITLED, GINT_TO_POINTER (n)))
|
|
|
|
{
|
|
|
|
UNTITLED = g_slist_prepend (UNTITLED, GINT_TO_POINTER (n));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_hash_table_insert (UNTITLED_NO, edit, GINT_TO_POINTER (n));
|
|
|
|
g_object_weak_ref (G_OBJECT (edit),
|
|
|
|
(GWeakNotify) remove_untitled,
|
|
|
|
GINT_TO_POINTER (TRUE));
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
void _moo_edit_set_filename (MooEdit *edit,
|
|
|
|
const char *file,
|
|
|
|
const char *encoding)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-02 16:27:25 -07:00
|
|
|
MooEditLang *lang;
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_free (edit->priv->filename);
|
|
|
|
g_free (edit->priv->basename);
|
|
|
|
g_free (edit->priv->display_filename);
|
|
|
|
g_free (edit->priv->display_basename);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-03 15:48:05 -07:00
|
|
|
if (!UNTITLED_NO)
|
|
|
|
UNTITLED_NO = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (!file)
|
2005-06-22 11:20:32 -07:00
|
|
|
{
|
2005-09-03 15:48:05 -07:00
|
|
|
int n = add_untitled (edit);
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
edit->priv->filename = NULL;
|
|
|
|
edit->priv->basename = NULL;
|
2005-09-03 15:48:05 -07:00
|
|
|
|
|
|
|
if (n == 1)
|
|
|
|
edit->priv->display_filename = g_strdup ("Untitled");
|
|
|
|
else
|
|
|
|
edit->priv->display_filename = g_strdup_printf ("Untitled %d", n);
|
|
|
|
|
|
|
|
edit->priv->display_basename = g_strdup (edit->priv->display_filename);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
2005-09-02 16:27:25 -07:00
|
|
|
else
|
|
|
|
{
|
2005-09-03 15:48:05 -07:00
|
|
|
remove_untitled (NULL, edit);
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
edit->priv->filename = g_strdup (file);
|
|
|
|
edit->priv->basename = g_path_get_basename (file);
|
2005-09-03 15:48:05 -07:00
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
edit->priv->display_filename =
|
|
|
|
_moo_edit_filename_to_utf8 (file);
|
|
|
|
edit->priv->display_basename =
|
|
|
|
_moo_edit_filename_to_utf8 (edit->priv->basename);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
if (!edit->priv->lang_custom)
|
|
|
|
{
|
|
|
|
if (file)
|
|
|
|
lang = moo_edit_lang_mgr_get_language_for_file (_moo_edit_get_lang_mgr (edit), file);
|
2005-06-22 11:20:32 -07:00
|
|
|
else
|
2005-09-02 16:27:25 -07:00
|
|
|
lang = moo_edit_lang_mgr_get_default_language (_moo_edit_get_lang_mgr (edit));
|
|
|
|
moo_edit_set_lang (edit, lang);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_free (edit->priv->encoding);
|
|
|
|
edit->priv->encoding = g_strdup (encoding);
|
2005-06-22 11:20:32 -07:00
|
|
|
|
2005-09-06 09:21:05 -07:00
|
|
|
_moo_edit_choose_indenter (edit);
|
|
|
|
|
2005-09-02 16:27:25 -07:00
|
|
|
g_signal_emit_by_name (edit, "filename-changed", edit->priv->filename, NULL);
|
|
|
|
g_signal_emit_by_name (edit, "doc-status-changed", NULL);
|
2005-06-22 11:20:32 -07:00
|
|
|
}
|
2005-07-30 21:28:41 -07:00
|
|
|
|
|
|
|
|
|
|
|
char *_moo_edit_filename_to_utf8 (const char *filename)
|
|
|
|
{
|
|
|
|
GError *err = NULL;
|
|
|
|
char *utf_filename;
|
|
|
|
|
|
|
|
g_return_val_if_fail (filename != NULL, NULL);
|
|
|
|
|
|
|
|
utf_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, &err);
|
|
|
|
|
|
|
|
if (!utf_filename)
|
|
|
|
{
|
|
|
|
g_critical ("%s: could not convert filename to utf8", G_STRLOC);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
g_critical ("%s: %s", G_STRLOC, err->message);
|
|
|
|
g_error_free (err);
|
|
|
|
err = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
utf_filename = g_strdup ("<Unknown>");
|
|
|
|
}
|
|
|
|
|
|
|
|
return utf_filename;
|
|
|
|
}
|