xed/xedit/xedit-document.c

2902 lines
69 KiB
C
Raw Permalink Normal View History

2011-11-07 13:46:58 -06:00
/*
2016-01-25 08:13:49 -06:00
* xedit-document.c
* This file is part of xedit
2011-11-07 13:46:58 -06:00
*
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
* Copyright (C) 2002-2005 Paolo Maggi
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2012-11-18 19:54:49 -06:00
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
2011-11-07 13:46:58 -06:00
*/
/*
2016-01-25 08:13:49 -06:00
* Modified by the xedit Team, 1998-2005. See the AUTHORS file for a
* list of people on the xedit Team.
2011-11-07 13:46:58 -06:00
* See the ChangeLog files for a list of changes.
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <glib/gi18n.h>
2013-10-29 18:56:56 -05:00
#include <gtk/gtk.h>
2013-11-04 05:46:45 -06:00
#if GTK_CHECK_VERSION (3, 0, 0)
#include <gtksourceview/gtksource.h>
#else
2011-11-07 13:46:58 -06:00
#include <gtksourceview/gtksourceiter.h>
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
#include "xedit-prefs-manager-app.h"
#include "xedit-document.h"
#include "xedit-debug.h"
#include "xedit-utils.h"
#include "xedit-language-manager.h"
#include "xedit-style-scheme-manager.h"
#include "xedit-document-loader.h"
#include "xedit-document-saver.h"
#include "xedit-marshal.h"
#include "xedit-enum-types.h"
#include "xedittextregion.h"
2011-11-07 13:46:58 -06:00
#ifndef ENABLE_GVFS_METADATA
2016-01-25 08:13:49 -06:00
#include "xedit-metadata-manager.h"
2011-11-07 13:46:58 -06:00
#else
#define METADATA_QUERY "metadata::*"
#endif
#undef ENABLE_PROFILE
#ifdef ENABLE_PROFILE
#define PROFILE(x) x
#else
#define PROFILE(x)
#endif
PROFILE (static GTimer *timer = NULL)
#ifdef MAXPATHLEN
2016-01-25 08:13:49 -06:00
#define XEDIT_MAX_PATH_LEN MAXPATHLEN
2011-11-07 13:46:58 -06:00
#elif defined (PATH_MAX)
2016-01-25 08:13:49 -06:00
#define XEDIT_MAX_PATH_LEN PATH_MAX
2011-11-07 13:46:58 -06:00
#else
2016-01-25 08:13:49 -06:00
#define XEDIT_MAX_PATH_LEN 2048
2011-11-07 13:46:58 -06:00
#endif
2016-01-25 08:13:49 -06:00
#define XEDIT_DOCUMENT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XEDIT_TYPE_DOCUMENT, XeditDocumentPrivate))
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
static void xedit_document_load_real (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding,
2011-11-07 13:46:58 -06:00
gint line_pos,
gboolean create);
2016-01-25 08:13:49 -06:00
static void xedit_document_save_real (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding,
XeditDocumentSaveFlags flags);
static void to_search_region_range (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *start,
GtkTextIter *end);
2016-01-25 08:13:49 -06:00
static void insert_text_cb (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *pos,
const gchar *text,
gint length);
2016-01-25 08:13:49 -06:00
static void delete_range_cb (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *start,
GtkTextIter *end);
2016-01-25 08:13:49 -06:00
struct _XeditDocumentPrivate
2011-11-07 13:46:58 -06:00
{
gchar *uri;
gint untitled_number;
gchar *short_name;
GFileInfo *metadata_info;
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding;
2011-11-07 13:46:58 -06:00
gchar *content_type;
GTimeVal mtime;
GTimeVal time_of_last_save_or_load;
guint search_flags;
gchar *search_text;
gint num_of_lines_search_text;
2016-01-25 08:13:49 -06:00
XeditDocumentNewlineType newline_type;
2011-11-07 13:46:58 -06:00
/* Temp data while loading */
2016-01-25 08:13:49 -06:00
XeditDocumentLoader *loader;
2011-11-07 13:46:58 -06:00
gboolean create; /* Create file if uri points
* to a non existing file */
2016-01-25 08:13:49 -06:00
const XeditEncoding *requested_encoding;
2011-11-07 13:46:58 -06:00
gint requested_line_pos;
/* Saving stuff */
2016-01-25 08:13:49 -06:00
XeditDocumentSaver *saver;
2011-11-07 13:46:58 -06:00
/* Search highlighting support variables */
2016-01-25 08:13:49 -06:00
XeditTextRegion *to_search_region;
2011-11-07 13:46:58 -06:00
GtkTextTag *found_tag;
/* Mount operation factory */
2016-01-25 08:13:49 -06:00
XeditMountOperationFactory mount_operation_factory;
2011-11-07 13:46:58 -06:00
gpointer mount_operation_userdata;
gint readonly : 1;
gint last_save_was_manually : 1;
gint language_set_by_user : 1;
gint stop_cursor_moved_emission : 1;
gint dispose_has_run : 1;
};
enum {
PROP_0,
PROP_URI,
PROP_SHORTNAME,
PROP_CONTENT_TYPE,
PROP_MIME_TYPE,
PROP_READ_ONLY,
PROP_ENCODING,
PROP_CAN_SEARCH_AGAIN,
PROP_ENABLE_SEARCH_HIGHLIGHTING,
PROP_NEWLINE_TYPE
};
enum {
CURSOR_MOVED,
LOAD,
LOADING,
LOADED,
SAVE,
SAVING,
SAVED,
SEARCH_HIGHLIGHT_UPDATED,
LAST_SIGNAL
};
static guint document_signals[LAST_SIGNAL] = { 0 };
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
2016-01-25 08:13:49 -06:00
G_DEFINE_TYPE(XeditDocument, xedit_document, GTK_SOURCE_TYPE_BUFFER)
2013-10-29 18:56:56 -05:00
#else
2016-01-25 08:13:49 -06:00
G_DEFINE_TYPE(XeditDocument, xedit_document, GTK_TYPE_SOURCE_BUFFER)
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
GQuark
2016-01-25 08:13:49 -06:00
xedit_document_error_quark (void)
2011-11-07 13:46:58 -06:00
{
static GQuark quark = 0;
if (G_UNLIKELY (quark == 0))
2016-01-25 08:13:49 -06:00
quark = g_quark_from_static_string ("xedit_io_load_error");
2011-11-07 13:46:58 -06:00
return quark;
}
static GHashTable *allocated_untitled_numbers = NULL;
static gint
get_untitled_number (void)
{
gint i = 1;
if (allocated_untitled_numbers == NULL)
allocated_untitled_numbers = g_hash_table_new (NULL, NULL);
g_return_val_if_fail (allocated_untitled_numbers != NULL, -1);
while (TRUE)
{
if (g_hash_table_lookup (allocated_untitled_numbers, GINT_TO_POINTER (i)) == NULL)
{
g_hash_table_insert (allocated_untitled_numbers,
GINT_TO_POINTER (i),
GINT_TO_POINTER (i));
return i;
}
++i;
}
}
static void
release_untitled_number (gint n)
{
g_return_if_fail (allocated_untitled_numbers != NULL);
g_hash_table_remove (allocated_untitled_numbers, GINT_TO_POINTER (n));
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_dispose (GObject *object)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
XeditDocument *doc = XEDIT_DOCUMENT (object);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
/* Metadata must be saved here and not in finalize
* because the language is gone by the time finalize runs.
* beside if some plugin prevents proper finalization by
* holding a ref to the doc, we still save the metadata */
if ((!doc->priv->dispose_has_run) && (doc->priv->uri != NULL))
{
GtkTextIter iter;
gchar *position;
const gchar *language = NULL;
if (doc->priv->language_set_by_user)
{
GtkSourceLanguage *lang;
2016-01-25 08:13:49 -06:00
lang = xedit_document_get_language (doc);
2011-11-07 13:46:58 -06:00
if (lang == NULL)
language = "_NORMAL_";
else
language = gtk_source_language_get_id (lang);
}
gtk_text_buffer_get_iter_at_mark (
GTK_TEXT_BUFFER (doc),
&iter,
gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (doc)));
position = g_strdup_printf ("%d",
gtk_text_iter_get_offset (&iter));
if (language == NULL)
2016-01-25 08:13:49 -06:00
xedit_document_set_metadata (doc, XEDIT_METADATA_ATTRIBUTE_POSITION,
2011-11-07 13:46:58 -06:00
position, NULL);
else
2016-01-25 08:13:49 -06:00
xedit_document_set_metadata (doc, XEDIT_METADATA_ATTRIBUTE_POSITION,
position, XEDIT_METADATA_ATTRIBUTE_LANGUAGE,
2011-11-07 13:46:58 -06:00
language, NULL);
g_free (position);
}
if (doc->priv->loader)
{
g_object_unref (doc->priv->loader);
doc->priv->loader = NULL;
}
if (doc->priv->metadata_info != NULL)
{
g_object_unref (doc->priv->metadata_info);
doc->priv->metadata_info = NULL;
}
doc->priv->dispose_has_run = TRUE;
2016-01-25 08:13:49 -06:00
G_OBJECT_CLASS (xedit_document_parent_class)->dispose (object);
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_finalize (GObject *object)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
XeditDocument *doc = XEDIT_DOCUMENT (object);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
if (doc->priv->untitled_number > 0)
{
g_return_if_fail (doc->priv->uri == NULL);
release_untitled_number (doc->priv->untitled_number);
}
g_free (doc->priv->uri);
g_free (doc->priv->content_type);
g_free (doc->priv->search_text);
if (doc->priv->to_search_region != NULL)
{
/* we can't delete marks if we're finalizing the buffer */
2016-01-25 08:13:49 -06:00
xedit_text_region_destroy (doc->priv->to_search_region, FALSE);
2011-11-07 13:46:58 -06:00
}
2016-01-25 08:13:49 -06:00
G_OBJECT_CLASS (xedit_document_parent_class)->finalize (object);
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_get_property (GObject *object,
2011-11-07 13:46:58 -06:00
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
2016-01-25 08:13:49 -06:00
XeditDocument *doc = XEDIT_DOCUMENT (object);
2011-11-07 13:46:58 -06:00
switch (prop_id)
{
case PROP_URI:
g_value_set_string (value, doc->priv->uri);
break;
case PROP_SHORTNAME:
2016-01-25 08:13:49 -06:00
g_value_take_string (value, xedit_document_get_short_name_for_display (doc));
2011-11-07 13:46:58 -06:00
break;
case PROP_CONTENT_TYPE:
2016-01-25 08:13:49 -06:00
g_value_take_string (value, xedit_document_get_content_type (doc));
2011-11-07 13:46:58 -06:00
break;
case PROP_MIME_TYPE:
2016-01-25 08:13:49 -06:00
g_value_take_string (value, xedit_document_get_mime_type (doc));
2011-11-07 13:46:58 -06:00
break;
case PROP_READ_ONLY:
g_value_set_boolean (value, doc->priv->readonly);
break;
case PROP_ENCODING:
g_value_set_boxed (value, doc->priv->encoding);
break;
case PROP_CAN_SEARCH_AGAIN:
2016-01-25 08:13:49 -06:00
g_value_set_boolean (value, xedit_document_get_can_search_again (doc));
2011-11-07 13:46:58 -06:00
break;
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
2016-01-25 08:13:49 -06:00
g_value_set_boolean (value, xedit_document_get_enable_search_highlighting (doc));
2011-11-07 13:46:58 -06:00
break;
case PROP_NEWLINE_TYPE:
g_value_set_enum (value, doc->priv->newline_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_set_property (GObject *object,
2011-11-07 13:46:58 -06:00
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
2016-01-25 08:13:49 -06:00
XeditDocument *doc = XEDIT_DOCUMENT (object);
2011-11-07 13:46:58 -06:00
switch (prop_id)
{
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
2016-01-25 08:13:49 -06:00
xedit_document_set_enable_search_highlighting (doc,
2011-11-07 13:46:58 -06:00
g_value_get_boolean (value));
break;
case PROP_NEWLINE_TYPE:
2016-01-25 08:13:49 -06:00
xedit_document_set_newline_type (doc,
2011-11-07 13:46:58 -06:00
g_value_get_enum (value));
break;
case PROP_SHORTNAME:
2016-01-25 08:13:49 -06:00
xedit_document_set_short_name_for_display (doc,
2011-11-07 13:46:58 -06:00
g_value_get_string (value));
break;
case PROP_CONTENT_TYPE:
2016-01-25 08:13:49 -06:00
xedit_document_set_content_type (doc,
2011-11-07 13:46:58 -06:00
g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
2016-01-25 08:13:49 -06:00
emit_cursor_moved (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
if (!doc->priv->stop_cursor_moved_emission)
{
g_signal_emit (doc,
document_signals[CURSOR_MOVED],
0);
}
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_mark_set (GtkTextBuffer *buffer,
2011-11-07 13:46:58 -06:00
const GtkTextIter *iter,
GtkTextMark *mark)
{
2016-01-25 08:13:49 -06:00
XeditDocument *doc = XEDIT_DOCUMENT (buffer);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
if (GTK_TEXT_BUFFER_CLASS (xedit_document_parent_class)->mark_set)
GTK_TEXT_BUFFER_CLASS (xedit_document_parent_class)->mark_set (buffer,
2011-11-07 13:46:58 -06:00
iter,
mark);
if (mark == gtk_text_buffer_get_insert (buffer))
{
emit_cursor_moved (doc);
}
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_changed (GtkTextBuffer *buffer)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
emit_cursor_moved (XEDIT_DOCUMENT (buffer));
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
GTK_TEXT_BUFFER_CLASS (xedit_document_parent_class)->changed (buffer);
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_class_init (XeditDocumentClass *klass)
2011-11-07 13:46:58 -06:00
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkTextBufferClass *buf_class = GTK_TEXT_BUFFER_CLASS (klass);
2016-01-25 08:13:49 -06:00
object_class->dispose = xedit_document_dispose;
object_class->finalize = xedit_document_finalize;
object_class->get_property = xedit_document_get_property;
object_class->set_property = xedit_document_set_property;
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
buf_class->mark_set = xedit_document_mark_set;
buf_class->changed = xedit_document_changed;
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
klass->load = xedit_document_load_real;
klass->save = xedit_document_save_real;
2011-11-07 13:46:58 -06:00
g_object_class_install_property (object_class, PROP_URI,
g_param_spec_string ("uri",
"URI",
"The document's URI",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_SHORTNAME,
g_param_spec_string ("shortname",
"Short Name",
"The document's short name",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CONTENT_TYPE,
g_param_spec_string ("content-type",
"Content Type",
"The document's Content Type",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_MIME_TYPE,
g_param_spec_string ("mime-type",
"MIME Type",
"The document's MIME Type",
"text/plain",
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_READ_ONLY,
g_param_spec_boolean ("read-only",
"Read Only",
"Whether the document is read only or not",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_ENCODING,
g_param_spec_boxed ("encoding",
"Encoding",
2016-01-25 08:13:49 -06:00
"The XeditEncoding used for the document",
XEDIT_TYPE_ENCODING,
2011-11-07 13:46:58 -06:00
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CAN_SEARCH_AGAIN,
g_param_spec_boolean ("can-search-again",
"Can search again",
2014-02-21 05:25:58 -06:00
"Whether it's possible to search again in the document",
2011-11-07 13:46:58 -06:00
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_ENABLE_SEARCH_HIGHLIGHTING,
g_param_spec_boolean ("enable-search-highlighting",
"Enable Search Highlighting",
"Whether all the occurrences of the searched string must be highlighted",
2011-11-07 13:46:58 -06:00
FALSE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
2016-01-25 08:13:49 -06:00
* XeditDocument:newline-type:
2011-11-07 13:46:58 -06:00
*
* The :newline-type property determines what is considered
* as a line ending when saving the document
*/
g_object_class_install_property (object_class, PROP_NEWLINE_TYPE,
g_param_spec_enum ("newline-type",
"Newline type",
"The accepted types of line ending",
2016-01-25 08:13:49 -06:00
XEDIT_TYPE_DOCUMENT_NEWLINE_TYPE,
XEDIT_DOCUMENT_NEWLINE_TYPE_LF,
2011-11-07 13:46:58 -06:00
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB));
/* This signal is used to update the cursor position is the statusbar,
* it's emitted either when the insert mark is moved explicitely or
* when the buffer changes (insert/delete).
* We prevent the emission of the signal during replace_all to
* improve performance.
*/
document_signals[CURSOR_MOVED] =
g_signal_new ("cursor-moved",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, cursor_moved),
2011-11-07 13:46:58 -06:00
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
2016-01-25 08:13:49 -06:00
* XeditDocument::load:
* @document: the #XeditDocument.
2011-11-07 13:46:58 -06:00
* @uri: the uri where to load the document from.
2016-01-25 08:13:49 -06:00
* @encoding: the #XeditEncoding to encode the document.
2011-11-07 13:46:58 -06:00
* @line_pos: the line to show.
* @create: whether the document should be created if it doesn't exist.
*
* The "load" signal is emitted when a document is loaded.
*
* Since: 2.22
*/
document_signals[LOAD] =
g_signal_new ("load",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, load),
2011-11-07 13:46:58 -06:00
NULL, NULL,
2016-01-25 08:13:49 -06:00
xedit_marshal_VOID__STRING_BOXED_INT_BOOLEAN,
2011-11-07 13:46:58 -06:00
G_TYPE_NONE,
4,
G_TYPE_STRING,
2016-01-25 08:13:49 -06:00
/* we rely on the fact that the XeditEncoding pointer stays
2011-11-07 13:46:58 -06:00
* the same forever */
2016-01-25 08:13:49 -06:00
XEDIT_TYPE_ENCODING | G_SIGNAL_TYPE_STATIC_SCOPE,
2011-11-07 13:46:58 -06:00
G_TYPE_INT,
G_TYPE_BOOLEAN);
document_signals[LOADING] =
g_signal_new ("loading",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, loading),
2011-11-07 13:46:58 -06:00
NULL, NULL,
2016-01-25 08:13:49 -06:00
xedit_marshal_VOID__UINT64_UINT64,
2011-11-07 13:46:58 -06:00
G_TYPE_NONE,
2,
G_TYPE_UINT64,
G_TYPE_UINT64);
document_signals[LOADED] =
g_signal_new ("loaded",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, loaded),
2011-11-07 13:46:58 -06:00
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
/**
2016-01-25 08:13:49 -06:00
* XeditDocument::save:
* @document: the #XeditDocument.
2011-11-07 13:46:58 -06:00
* @uri: the uri where the document is about to be saved.
2016-01-25 08:13:49 -06:00
* @encoding: the #XeditEncoding used to save the document.
* @flags: the #XeditDocumentSaveFlags for the save operation.
2011-11-07 13:46:58 -06:00
*
* The "save" signal is emitted when the document is saved.
*
* Since: 2.20
*/
document_signals[SAVE] =
g_signal_new ("save",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, save),
2011-11-07 13:46:58 -06:00
NULL, NULL,
2016-01-25 08:13:49 -06:00
xedit_marshal_VOID__STRING_BOXED_FLAGS,
2011-11-07 13:46:58 -06:00
G_TYPE_NONE,
3,
G_TYPE_STRING,
2016-01-25 08:13:49 -06:00
/* we rely on the fact that the XeditEncoding pointer stays
2011-11-07 13:46:58 -06:00
* the same forever */
2016-01-25 08:13:49 -06:00
XEDIT_TYPE_ENCODING | G_SIGNAL_TYPE_STATIC_SCOPE,
XEDIT_TYPE_DOCUMENT_SAVE_FLAGS);
2011-11-07 13:46:58 -06:00
document_signals[SAVING] =
g_signal_new ("saving",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, saving),
2011-11-07 13:46:58 -06:00
NULL, NULL,
2016-01-25 08:13:49 -06:00
xedit_marshal_VOID__UINT64_UINT64,
2011-11-07 13:46:58 -06:00
G_TYPE_NONE,
2,
G_TYPE_UINT64,
G_TYPE_UINT64);
document_signals[SAVED] =
g_signal_new ("saved",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, saved),
2011-11-07 13:46:58 -06:00
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
document_signals[SEARCH_HIGHLIGHT_UPDATED] =
g_signal_new ("search_highlight_updated",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
2016-01-25 08:13:49 -06:00
G_STRUCT_OFFSET (XeditDocumentClass, search_highlight_updated),
2011-11-07 13:46:58 -06:00
NULL, NULL,
2016-01-25 08:13:49 -06:00
xedit_marshal_VOID__BOXED_BOXED,
2011-11-07 13:46:58 -06:00
G_TYPE_NONE,
2,
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
2016-01-25 08:13:49 -06:00
g_type_class_add_private (object_class, sizeof(XeditDocumentPrivate));
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
set_language (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkSourceLanguage *lang,
gboolean set_by_user)
{
GtkSourceLanguage *old_lang;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
old_lang = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc));
if (old_lang == lang)
return;
gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (doc), lang);
if (lang != NULL)
gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (doc),
2016-01-25 08:13:49 -06:00
xedit_prefs_manager_get_enable_syntax_highlighting ());
2011-11-07 13:46:58 -06:00
else
gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (doc),
FALSE);
if (set_by_user && (doc->priv->uri != NULL))
{
2016-01-25 08:13:49 -06:00
xedit_document_set_metadata (doc, XEDIT_METADATA_ATTRIBUTE_LANGUAGE,
2011-11-07 13:46:58 -06:00
(lang == NULL) ? "_NORMAL_" : gtk_source_language_get_id (lang),
NULL);
}
doc->priv->language_set_by_user = set_by_user;
}
static void
2016-01-25 08:13:49 -06:00
set_encoding (XeditDocument *doc,
const XeditEncoding *encoding,
2011-11-07 13:46:58 -06:00
gboolean set_by_user)
{
g_return_if_fail (encoding != NULL);
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
if (doc->priv->encoding == encoding)
return;
doc->priv->encoding = encoding;
if (set_by_user)
{
const gchar *charset;
2016-01-25 08:13:49 -06:00
charset = xedit_encoding_get_charset (encoding);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_document_set_metadata (doc, XEDIT_METADATA_ATTRIBUTE_ENCODING,
2011-11-07 13:46:58 -06:00
charset, NULL);
}
g_object_notify (G_OBJECT (doc), "encoding");
}
static GtkSourceStyleScheme *
get_default_style_scheme (void)
{
gchar *scheme_id;
GtkSourceStyleScheme *def_style;
GtkSourceStyleSchemeManager *manager;
2016-01-25 08:13:49 -06:00
manager = xedit_get_style_scheme_manager ();
scheme_id = xedit_prefs_manager_get_source_style_scheme ();
2011-11-07 13:46:58 -06:00
def_style = gtk_source_style_scheme_manager_get_scheme (manager,
scheme_id);
if (def_style == NULL)
{
g_warning ("Default style scheme '%s' cannot be found, falling back to 'classic' style scheme ", scheme_id);
def_style = gtk_source_style_scheme_manager_get_scheme (manager, "classic");
if (def_style == NULL)
{
g_warning ("Style scheme 'classic' cannot be found, check your GtkSourceView installation.");
}
}
g_free (scheme_id);
return def_style;
}
static void
2016-01-25 08:13:49 -06:00
on_uri_changed (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GParamSpec *pspec,
gpointer useless)
{
#ifdef ENABLE_GVFS_METADATA
GFile *location;
2016-01-25 08:13:49 -06:00
location = xedit_document_get_location (doc);
2011-11-07 13:46:58 -06:00
/* load metadata for this uri: we load sync since metadata is
* always local so it should be fast and we need the information
* right after the uri was set.
*/
if (location != NULL)
{
GError *error = NULL;
if (doc->priv->metadata_info != NULL)
g_object_unref (doc->priv->metadata_info);
doc->priv->metadata_info = g_file_query_info (location,
METADATA_QUERY,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
if (error != NULL)
{
if (error->code != G_FILE_ERROR_ISDIR &&
error->code != G_FILE_ERROR_NOTDIR &&
error->code != G_FILE_ERROR_NOENT)
{
g_warning ("%s", error->message);
}
g_error_free (error);
}
g_object_unref (location);
}
#endif
}
static GtkSourceLanguage *
2016-01-25 08:13:49 -06:00
guess_language (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *content_type)
{
gchar *data;
GtkSourceLanguage *language = NULL;
2016-01-25 08:13:49 -06:00
data = xedit_document_get_metadata (doc, XEDIT_METADATA_ATTRIBUTE_LANGUAGE);
2011-11-07 13:46:58 -06:00
if (data != NULL)
{
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "Language from metadata: %s", data);
2011-11-07 13:46:58 -06:00
if (strcmp (data, "_NORMAL_") != 0)
{
language = gtk_source_language_manager_get_language (
2016-01-25 08:13:49 -06:00
xedit_get_language_manager (),
2011-11-07 13:46:58 -06:00
data);
}
g_free (data);
}
else
{
GFile *file;
gchar *basename = NULL;
2016-01-25 08:13:49 -06:00
file = xedit_document_get_location (doc);
xedit_debug_message (DEBUG_DOCUMENT, "Sniffing Language");
2011-11-07 13:46:58 -06:00
if (file)
{
basename = g_file_get_basename (file);
}
else if (doc->priv->short_name != NULL)
{
basename = g_strdup (doc->priv->short_name);
}
language = gtk_source_language_manager_guess_language (
2016-01-25 08:13:49 -06:00
xedit_get_language_manager (),
2011-11-07 13:46:58 -06:00
basename,
content_type);
g_free (basename);
if (file != NULL)
{
g_object_unref (file);
}
}
return language;
}
static void
2016-01-25 08:13:49 -06:00
on_content_type_changed (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GParamSpec *pspec,
gpointer useless)
{
if (!doc->priv->language_set_by_user)
{
GtkSourceLanguage *language;
language = guess_language (doc, doc->priv->content_type);
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "Language: %s",
2011-11-07 13:46:58 -06:00
language != NULL ? gtk_source_language_get_name (language) : "None");
set_language (doc, language, FALSE);
}
}
static gchar *
get_default_content_type (void)
{
return g_content_type_from_mime_type ("text/plain");
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_init (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
GtkSourceStyleScheme *style_scheme;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
doc->priv = XEDIT_DOCUMENT_GET_PRIVATE (doc);
2011-11-07 13:46:58 -06:00
doc->priv->uri = NULL;
doc->priv->untitled_number = get_untitled_number ();
doc->priv->metadata_info = NULL;
doc->priv->content_type = get_default_content_type ();
doc->priv->readonly = FALSE;
doc->priv->stop_cursor_moved_emission = FALSE;
doc->priv->last_save_was_manually = TRUE;
doc->priv->language_set_by_user = FALSE;
doc->priv->dispose_has_run = FALSE;
doc->priv->mtime.tv_sec = 0;
doc->priv->mtime.tv_usec = 0;
g_get_current_time (&doc->priv->time_of_last_save_or_load);
2016-01-25 08:13:49 -06:00
doc->priv->encoding = xedit_encoding_get_utf8 ();
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
doc->priv->newline_type = XEDIT_DOCUMENT_NEWLINE_TYPE_DEFAULT;
2011-11-07 13:46:58 -06:00
gtk_source_buffer_set_max_undo_levels (GTK_SOURCE_BUFFER (doc),
2016-01-25 08:13:49 -06:00
xedit_prefs_manager_get_undo_actions_limit ());
2011-11-07 13:46:58 -06:00
gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (doc),
2016-01-25 08:13:49 -06:00
xedit_prefs_manager_get_bracket_matching ());
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_document_set_enable_search_highlighting (doc,
xedit_prefs_manager_get_enable_search_highlighting ());
2011-11-07 13:46:58 -06:00
style_scheme = get_default_style_scheme ();
if (style_scheme != NULL)
gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (doc),
style_scheme);
g_signal_connect_after (doc,
"insert-text",
G_CALLBACK (insert_text_cb),
NULL);
g_signal_connect_after (doc,
"delete-range",
G_CALLBACK (delete_range_cb),
NULL);
g_signal_connect (doc,
"notify::content-type",
G_CALLBACK (on_content_type_changed),
NULL);
g_signal_connect (doc,
"notify::uri",
G_CALLBACK (on_uri_changed),
NULL);
}
2016-01-25 08:13:49 -06:00
XeditDocument *
xedit_document_new (void)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
return XEDIT_DOCUMENT (g_object_new (XEDIT_TYPE_DOCUMENT, NULL));
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
set_content_type_no_guess (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *content_type)
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
if (doc->priv->content_type != NULL && content_type != NULL &&
(0 == strcmp (doc->priv->content_type, content_type)))
return;
g_free (doc->priv->content_type);
if (content_type == NULL || g_content_type_is_unknown (content_type))
doc->priv->content_type = get_default_content_type ();
else
doc->priv->content_type = g_strdup (content_type);
g_object_notify (G_OBJECT (doc), "content-type");
}
static void
2016-01-25 08:13:49 -06:00
set_content_type (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *content_type)
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
if (content_type == NULL)
{
GFile *file;
gchar *guessed_type = NULL;
/* If content type is null, we guess from the filename */
2016-01-25 08:13:49 -06:00
file = xedit_document_get_location (doc);
2011-11-07 13:46:58 -06:00
if (file != NULL)
{
gchar *basename;
basename = g_file_get_basename (file);
guessed_type = g_content_type_guess (basename, NULL, 0, NULL);
g_free (basename);
g_object_unref (file);
}
set_content_type_no_guess (doc, guessed_type);
g_free (guessed_type);
}
else
{
set_content_type_no_guess (doc, content_type);
}
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_set_content_type:
* @doc:
* @content_type: (allow-none):
*/
2011-11-07 13:46:58 -06:00
void
2016-01-25 08:13:49 -06:00
xedit_document_set_content_type (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *content_type)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
set_content_type (doc, content_type);
}
static void
2016-01-25 08:13:49 -06:00
set_uri (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri)
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
g_return_if_fail ((uri == NULL) || xedit_utils_is_valid_uri (uri));
2011-11-07 13:46:58 -06:00
if (uri != NULL)
{
if (doc->priv->uri == uri)
return;
g_free (doc->priv->uri);
doc->priv->uri = g_strdup (uri);
if (doc->priv->untitled_number > 0)
{
release_untitled_number (doc->priv->untitled_number);
doc->priv->untitled_number = 0;
}
}
g_object_notify (G_OBJECT (doc), "uri");
if (doc->priv->short_name == NULL)
{
g_object_notify (G_OBJECT (doc), "shortname");
}
}
GFile *
2016-01-25 08:13:49 -06:00
xedit_document_get_location (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
return doc->priv->uri == NULL ? NULL : g_file_new_for_uri (doc->priv->uri);
}
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_uri (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
return g_strdup (doc->priv->uri);
}
void
2016-01-25 08:13:49 -06:00
xedit_document_set_uri (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (uri != NULL);
set_uri (doc, uri);
set_content_type (doc, NULL);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_get_uri_for_display:
* @doc:
*
* Note: this never returns %NULL.
**/
2011-11-07 13:46:58 -06:00
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_uri_for_display (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), g_strdup (""));
2011-11-07 13:46:58 -06:00
if (doc->priv->uri == NULL)
return g_strdup_printf (_("Unsaved Document %d"),
doc->priv->untitled_number);
else
2016-01-25 08:13:49 -06:00
return xedit_utils_uri_for_display (doc->priv->uri);
2011-11-07 13:46:58 -06:00
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_get_short_name_for_display:
* @doc:
*
* Note: this never returns %NULL.
**/
2011-11-07 13:46:58 -06:00
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_short_name_for_display (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), g_strdup (""));
2011-11-07 13:46:58 -06:00
if (doc->priv->short_name != NULL)
return g_strdup (doc->priv->short_name);
else if (doc->priv->uri == NULL)
return g_strdup_printf (_("Unsaved Document %d"),
doc->priv->untitled_number);
else
2016-01-25 08:13:49 -06:00
return xedit_utils_basename_for_display (doc->priv->uri);
2011-11-07 13:46:58 -06:00
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_set_short_name_for_display:
* @doc:
* @short_name: (allow-none):
*/
2011-11-07 13:46:58 -06:00
void
2016-01-25 08:13:49 -06:00
xedit_document_set_short_name_for_display (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *short_name)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_free (doc->priv->short_name);
doc->priv->short_name = g_strdup (short_name);
g_object_notify (G_OBJECT (doc), "shortname");
}
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_content_type (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
return g_strdup (doc->priv->content_type);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_get_mime_type:
* @doc:
*
* Note: this never returns %NULL.
**/
2011-11-07 13:46:58 -06:00
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_mime_type (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
gchar *mime_type = NULL;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), g_strdup ("text/plain"));
2011-11-07 13:46:58 -06:00
if ((doc->priv->content_type != NULL) &&
(!g_content_type_is_unknown (doc->priv->content_type)))
{
mime_type = g_content_type_get_mime_type (doc->priv->content_type);
}
return mime_type != NULL ? mime_type : g_strdup ("text/plain");
}
/* Note: do not emit the notify::read-only signal */
static gboolean
2016-01-25 08:13:49 -06:00
set_readonly (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
gboolean readonly)
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
readonly = (readonly != FALSE);
if (doc->priv->readonly == readonly)
return FALSE;
doc->priv->readonly = readonly;
return TRUE;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_set_readonly:
* @doc: a #XeditDocument
2011-11-07 13:46:58 -06:00
* @readonly: %TRUE to se the document as read-only
*
* If @readonly is %TRUE sets @doc as read-only.
*/
void
2016-01-25 08:13:49 -06:00
_xedit_document_set_readonly (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
gboolean readonly)
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
if (set_readonly (doc, readonly))
{
g_object_notify (G_OBJECT (doc), "read-only");
}
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_get_readonly (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), TRUE);
2011-11-07 13:46:58 -06:00
return doc->priv->readonly;
}
gboolean
2016-01-25 08:13:49 -06:00
_xedit_document_check_externally_modified (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
GFile *gfile;
GFileInfo *info;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
if (doc->priv->uri == NULL)
{
return FALSE;
}
gfile = g_file_new_for_uri (doc->priv->uri);
info = g_file_query_info (gfile,
G_FILE_ATTRIBUTE_TIME_MODIFIED "," \
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
g_object_unref (gfile);
if (info != NULL)
{
/* While at it also check if permissions changed */
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
{
gboolean read_only;
read_only = !g_file_info_get_attribute_boolean (info,
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
2016-01-25 08:13:49 -06:00
_xedit_document_set_readonly (doc, read_only);
2011-11-07 13:46:58 -06:00
}
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
{
GTimeVal timeval;
g_file_info_get_modification_time (info, &timeval);
g_object_unref (info);
return (timeval.tv_sec > doc->priv->mtime.tv_sec) ||
(timeval.tv_sec == doc->priv->mtime.tv_sec &&
timeval.tv_usec > doc->priv->mtime.tv_usec);
}
}
return FALSE;
}
static void
2016-01-25 08:13:49 -06:00
reset_temp_loading_data (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
/* the loader has been used, throw it away */
g_object_unref (doc->priv->loader);
doc->priv->loader = NULL;
doc->priv->requested_encoding = NULL;
doc->priv->requested_line_pos = 0;
}
static void
2016-01-25 08:13:49 -06:00
document_loader_loaded (XeditDocumentLoader *loader,
2011-11-07 13:46:58 -06:00
const GError *error,
2016-01-25 08:13:49 -06:00
XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
/* load was successful */
if (error == NULL ||
2016-01-25 08:13:49 -06:00
(error->domain == XEDIT_DOCUMENT_ERROR &&
error->code == XEDIT_DOCUMENT_ERROR_CONVERSION_FALLBACK))
2011-11-07 13:46:58 -06:00
{
GtkTextIter iter;
GFileInfo *info;
const gchar *content_type = NULL;
gboolean read_only = FALSE;
GTimeVal mtime = {0, 0};
2016-01-25 08:13:49 -06:00
info = xedit_document_loader_get_info (loader);
2011-11-07 13:46:58 -06:00
if (info)
{
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
content_type = g_file_info_get_attribute_string (info,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
g_file_info_get_modification_time (info, &mtime);
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
read_only = !g_file_info_get_attribute_boolean (info,
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
}
doc->priv->mtime = mtime;
set_readonly (doc, read_only);
g_get_current_time (&doc->priv->time_of_last_save_or_load);
set_encoding (doc,
2016-01-25 08:13:49 -06:00
xedit_document_loader_get_encoding (loader),
2011-11-07 13:46:58 -06:00
(doc->priv->requested_encoding != NULL));
set_content_type (doc, content_type);
2016-01-25 08:13:49 -06:00
xedit_document_set_newline_type (doc,
xedit_document_loader_get_newline_type (loader));
2011-11-07 13:46:58 -06:00
/* move the cursor at the requested line if any */
if (doc->priv->requested_line_pos > 0)
{
/* line_pos - 1 because get_iter_at_line counts from 0 */
gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc),
&iter,
doc->priv->requested_line_pos - 1);
}
/* else, if enabled, to the position stored in the metadata */
2016-01-25 08:13:49 -06:00
else if (xedit_prefs_manager_get_restore_cursor_position ())
2011-11-07 13:46:58 -06:00
{
gchar *pos;
gint offset;
2016-01-25 08:13:49 -06:00
pos = xedit_document_get_metadata (doc, XEDIT_METADATA_ATTRIBUTE_POSITION);
2011-11-07 13:46:58 -06:00
offset = pos ? atoi (pos) : 0;
g_free (pos);
gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc),
&iter,
MAX (offset, 0));
/* make sure it's a valid position, if the file
* changed we may have ended up in the middle of
* a utf8 character cluster */
if (!gtk_text_iter_is_cursor_position (&iter))
{
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (doc),
&iter);
}
}
/* otherwise to the top */
else
{
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (doc),
&iter);
}
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
}
/* special case creating a named new doc */
else if (doc->priv->create &&
(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND) &&
2016-01-25 08:13:49 -06:00
(xedit_utils_uri_has_file_scheme (doc->priv->uri)))
2011-11-07 13:46:58 -06:00
{
reset_temp_loading_data (doc);
g_signal_emit (doc,
document_signals[LOADED],
0,
NULL);
return;
}
g_signal_emit (doc,
document_signals[LOADED],
0,
error);
reset_temp_loading_data (doc);
}
static void
2016-01-25 08:13:49 -06:00
document_loader_loading (XeditDocumentLoader *loader,
2011-11-07 13:46:58 -06:00
gboolean completed,
const GError *error,
2016-01-25 08:13:49 -06:00
XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
if (completed)
{
document_loader_loaded (loader, error, doc);
}
else
{
goffset size = 0;
goffset read;
GFileInfo *info;
2016-01-25 08:13:49 -06:00
info = xedit_document_loader_get_info (loader);
2011-11-07 13:46:58 -06:00
if (info && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
size = g_file_info_get_attribute_uint64 (info,
G_FILE_ATTRIBUTE_STANDARD_SIZE);
2016-01-25 08:13:49 -06:00
read = xedit_document_loader_get_bytes_read (loader);
2011-11-07 13:46:58 -06:00
g_signal_emit (doc,
document_signals[LOADING],
0,
read,
size);
}
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_load_real (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding,
2011-11-07 13:46:58 -06:00
gint line_pos,
gboolean create)
{
g_return_if_fail (doc->priv->loader == NULL);
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "load_real: uri = %s", uri);
2011-11-07 13:46:58 -06:00
/* create a loader. It will be destroyed when loading is completed */
2016-01-25 08:13:49 -06:00
doc->priv->loader = xedit_document_loader_new (doc, uri, encoding);
2011-11-07 13:46:58 -06:00
g_signal_connect (doc->priv->loader,
"loading",
G_CALLBACK (document_loader_loading),
doc);
doc->priv->create = create;
doc->priv->requested_encoding = encoding;
doc->priv->requested_line_pos = line_pos;
set_uri (doc, uri);
set_content_type (doc, NULL);
2016-01-25 08:13:49 -06:00
xedit_document_loader_load (doc->priv->loader);
2011-11-07 13:46:58 -06:00
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_load:
* @doc: the #XeditDocument.
2011-11-07 13:46:58 -06:00
* @uri: the uri where to load the document from.
2016-01-25 08:13:49 -06:00
* @encoding: the #XeditEncoding to encode the document.
2011-11-07 13:46:58 -06:00
* @line_pos: the line to show.
* @create: whether the document should be created if it doesn't exist.
*
* Load a document. This results in the "load" signal to be emitted.
*/
void
2016-01-25 08:13:49 -06:00
xedit_document_load (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding,
2011-11-07 13:46:58 -06:00
gint line_pos,
gboolean create)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (uri != NULL);
2016-01-25 08:13:49 -06:00
g_return_if_fail (xedit_utils_is_valid_uri (uri));
2011-11-07 13:46:58 -06:00
g_signal_emit (doc, document_signals[LOAD], 0, uri, encoding, line_pos, create);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_load_cancel:
* @doc: the #XeditDocument.
2011-11-07 13:46:58 -06:00
*
* Cancel load of a document.
*/
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_load_cancel (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
if (doc->priv->loader == NULL)
return FALSE;
2016-01-25 08:13:49 -06:00
return xedit_document_loader_cancel (doc->priv->loader);
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
document_saver_saving (XeditDocumentSaver *saver,
2011-11-07 13:46:58 -06:00
gboolean completed,
const GError *error,
2016-01-25 08:13:49 -06:00
XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
if (completed)
{
/* save was successful */
if (error == NULL)
{
const gchar *uri;
const gchar *content_type = NULL;
GTimeVal mtime = {0, 0};
GFileInfo *info;
2016-01-25 08:13:49 -06:00
uri = xedit_document_saver_get_uri (saver);
2011-11-07 13:46:58 -06:00
set_uri (doc, uri);
2016-01-25 08:13:49 -06:00
info = xedit_document_saver_get_info (saver);
2011-11-07 13:46:58 -06:00
if (info != NULL)
{
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
content_type = g_file_info_get_attribute_string (info,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
g_file_info_get_modification_time (info, &mtime);
}
set_content_type (doc, content_type);
doc->priv->mtime = mtime;
g_get_current_time (&doc->priv->time_of_last_save_or_load);
2016-01-25 08:13:49 -06:00
_xedit_document_set_readonly (doc, FALSE);
2011-11-07 13:46:58 -06:00
gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc),
FALSE);
set_encoding (doc,
doc->priv->requested_encoding,
TRUE);
}
g_signal_emit (doc,
document_signals[SAVED],
0,
error);
/* the saver has been used, throw it away */
g_object_unref (doc->priv->saver);
doc->priv->saver = NULL;
}
else
{
goffset size = 0;
goffset written = 0;
2016-01-25 08:13:49 -06:00
size = xedit_document_saver_get_file_size (saver);
written = xedit_document_saver_get_bytes_written (saver);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "save progress: %" G_GINT64_FORMAT " of %" G_GINT64_FORMAT, written, size);
2011-11-07 13:46:58 -06:00
g_signal_emit (doc,
document_signals[SAVING],
0,
written,
size);
}
}
static void
2016-01-25 08:13:49 -06:00
xedit_document_save_real (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding,
XeditDocumentSaveFlags flags)
2011-11-07 13:46:58 -06:00
{
g_return_if_fail (doc->priv->saver == NULL);
/* create a saver, it will be destroyed once saving is complete */
2016-01-25 08:13:49 -06:00
doc->priv->saver = xedit_document_saver_new (doc, uri, encoding,
2011-11-07 13:46:58 -06:00
doc->priv->newline_type,
flags);
g_signal_connect (doc->priv->saver,
"saving",
G_CALLBACK (document_saver_saving),
doc);
doc->priv->requested_encoding = encoding;
2016-01-25 08:13:49 -06:00
xedit_document_saver_save (doc->priv->saver,
2011-11-07 13:46:58 -06:00
&doc->priv->mtime);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_save:
* @doc: the #XeditDocument.
* @flags: optionnal #XeditDocumentSaveFlags.
2011-11-07 13:46:58 -06:00
*
* Save the document to its previous location. This results in the "save"
* signal to be emitted.
*/
void
2016-01-25 08:13:49 -06:00
xedit_document_save (XeditDocument *doc,
XeditDocumentSaveFlags flags)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (doc->priv->uri != NULL);
g_signal_emit (doc,
document_signals[SAVE],
0,
doc->priv->uri,
doc->priv->encoding,
flags);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_save_as:
* @doc: the #XeditDocument.
2011-11-07 13:46:58 -06:00
* @uri: the uri where to save the document.
2016-01-25 08:13:49 -06:00
* @encoding: the #XeditEncoding to encode the document.
* @flags: optionnal #XeditDocumentSaveFlags.
2011-11-07 13:46:58 -06:00
*
* Save the document to a new location. This results in the "save" signal
* to be emitted.
*/
void
2016-01-25 08:13:49 -06:00
xedit_document_save_as (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding,
XeditDocumentSaveFlags flags)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (uri != NULL);
g_return_if_fail (encoding != NULL);
/* priv->mtime refers to the the old uri (if any). Thus, it should be
* ignored when saving as. */
g_signal_emit (doc,
document_signals[SAVE],
0,
uri,
encoding,
2016-01-25 08:13:49 -06:00
flags | XEDIT_DOCUMENT_SAVE_IGNORE_MTIME);
2011-11-07 13:46:58 -06:00
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_insert_file (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *iter,
const gchar *uri,
2016-01-25 08:13:49 -06:00
const XeditEncoding *encoding)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (iter != NULL, FALSE);
g_return_val_if_fail (gtk_text_iter_get_buffer (iter) ==
GTK_TEXT_BUFFER (doc), FALSE);
/* TODO */
return FALSE;
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_is_untouched (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), TRUE);
2011-11-07 13:46:58 -06:00
return (doc->priv->uri == NULL) &&
(!gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)));
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_is_untitled (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), TRUE);
2011-11-07 13:46:58 -06:00
return (doc->priv->uri == NULL);
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_is_local (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
if (doc->priv->uri == NULL)
{
return FALSE;
}
2016-01-25 08:13:49 -06:00
return xedit_utils_uri_has_file_scheme (doc->priv->uri);
2011-11-07 13:46:58 -06:00
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_get_deleted (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
return doc->priv->uri && !xedit_utils_uri_exists (doc->priv->uri);
2011-11-07 13:46:58 -06:00
}
/*
* If @line is bigger than the lines of the document, the cursor is moved
* to the last line and FALSE is returned.
*/
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_goto_line (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
gint line)
{
gboolean ret = TRUE;
guint line_count;
GtkTextIter iter;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (line >= -1, FALSE);
line_count = gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (doc));
if (line >= line_count)
{
ret = FALSE;
gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc),
&iter);
}
else
{
gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc),
&iter,
line);
}
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
return ret;
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_goto_line_offset (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
gint line,
gint line_offset)
{
gboolean ret = TRUE;
guint offset_count;
GtkTextIter iter;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (line >= -1, FALSE);
g_return_val_if_fail (line_offset >= -1, FALSE);
gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc),
&iter,
line);
offset_count = gtk_text_iter_get_chars_in_line (&iter);
if (line_offset > offset_count)
{
ret = FALSE;
}
else
{
gtk_text_iter_set_line_offset (&iter, line_offset);
}
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
return ret;
}
static gint
compute_num_of_lines (const gchar *text)
{
const gchar *p;
gint len;
gint n = 1;
g_return_val_if_fail (text != NULL, 0);
len = strlen (text);
p = text;
while (len > 0)
{
gint del, par;
pango_find_paragraph_boundary (p, len, &del, &par);
if (del == par) /* not found */
break;
p += par;
len -= par;
++n;
}
return n;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_set_search_text"
* @doc:
* @text: (allow-none):
* @flags:
**/
2011-11-07 13:46:58 -06:00
void
2016-01-25 08:13:49 -06:00
xedit_document_set_search_text (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *text,
guint flags)
{
gchar *converted_text;
gboolean notify = FALSE;
gboolean update_to_search_region = FALSE;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail ((text == NULL) || (doc->priv->search_text != text));
g_return_if_fail ((text == NULL) || g_utf8_validate (text, -1, NULL));
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "text = %s", text);
2011-11-07 13:46:58 -06:00
if (text != NULL)
{
if (*text != '\0')
{
2016-01-25 08:13:49 -06:00
converted_text = xedit_utils_unescape_search_text (text);
notify = !xedit_document_get_can_search_again (doc);
2011-11-07 13:46:58 -06:00
}
else
{
converted_text = g_strdup("");
2016-01-25 08:13:49 -06:00
notify = xedit_document_get_can_search_again (doc);
2011-11-07 13:46:58 -06:00
}
g_free (doc->priv->search_text);
doc->priv->search_text = converted_text;
doc->priv->num_of_lines_search_text = compute_num_of_lines (doc->priv->search_text);
update_to_search_region = TRUE;
}
2016-01-25 08:13:49 -06:00
if (!XEDIT_SEARCH_IS_DONT_SET_FLAGS (flags))
2011-11-07 13:46:58 -06:00
{
if (doc->priv->search_flags != flags)
update_to_search_region = TRUE;
doc->priv->search_flags = flags;
}
if (update_to_search_region)
{
GtkTextIter begin;
GtkTextIter end;
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc),
&begin,
&end);
to_search_region_range (doc,
&begin,
&end);
}
if (notify)
g_object_notify (G_OBJECT (doc), "can-search-again");
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_get_search_text:
* @doc:
* @flags: (allow-none):
*/
2011-11-07 13:46:58 -06:00
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_search_text (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
guint *flags)
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
if (flags != NULL)
*flags = doc->priv->search_flags;
2016-01-25 08:13:49 -06:00
return xedit_utils_escape_search_text (doc->priv->search_text);
2011-11-07 13:46:58 -06:00
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_get_can_search_again (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
return ((doc->priv->search_text != NULL) &&
(*doc->priv->search_text != '\0'));
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_search_forward:
* @doc:
* @start: (allow-none):
* @end: (allow-none):
* @match_start: (allow-none):
* @match_end: (allow=none):
**/
2011-11-07 13:46:58 -06:00
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_search_forward (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const GtkTextIter *start,
const GtkTextIter *end,
GtkTextIter *match_start,
GtkTextIter *match_end)
{
GtkTextIter iter;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
GtkTextSearchFlags search_flags;
#else
2011-11-07 13:46:58 -06:00
GtkSourceSearchFlags search_flags;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
gboolean found = FALSE;
GtkTextIter m_start;
GtkTextIter m_end;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail ((start == NULL) ||
(gtk_text_iter_get_buffer (start) == GTK_TEXT_BUFFER (doc)), FALSE);
g_return_val_if_fail ((end == NULL) ||
(gtk_text_iter_get_buffer (end) == GTK_TEXT_BUFFER (doc)), FALSE);
if (doc->priv->search_text == NULL)
{
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == NULL\n");
2011-11-07 13:46:58 -06:00
return FALSE;
}
else
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text);
2011-11-07 13:46:58 -06:00
if (start == NULL)
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (doc), &iter);
else
iter = *start;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
#else
2011-11-07 13:46:58 -06:00
search_flags = GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_TEXT_ONLY;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
if (!XEDIT_SEARCH_IS_CASE_SENSITIVE (doc->priv->search_flags))
2011-11-07 13:46:58 -06:00
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
#else
2011-11-07 13:46:58 -06:00
search_flags = search_flags | GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
}
while (!found)
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
found = gtk_text_iter_forward_search (&iter,
#else
2011-11-07 13:46:58 -06:00
found = gtk_source_iter_forward_search (&iter,
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
doc->priv->search_text,
search_flags,
&m_start,
&m_end,
end);
2016-01-25 08:13:49 -06:00
if (found && XEDIT_SEARCH_IS_ENTIRE_WORD (doc->priv->search_flags))
2011-11-07 13:46:58 -06:00
{
found = gtk_text_iter_starts_word (&m_start) &&
gtk_text_iter_ends_word (&m_end);
if (!found)
iter = m_end;
}
else
break;
}
if (found && (match_start != NULL))
*match_start = m_start;
if (found && (match_end != NULL))
*match_end = m_end;
return found;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_search_backward:
* @doc:
* @start: (allow-none):
* @end: (allow-none):
* @match_start: (allow-none):
* @match_end: (allow=none):
**/
2011-11-07 13:46:58 -06:00
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_search_backward (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const GtkTextIter *start,
const GtkTextIter *end,
GtkTextIter *match_start,
GtkTextIter *match_end)
{
GtkTextIter iter;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
GtkTextSearchFlags search_flags;
#else
2011-11-07 13:46:58 -06:00
GtkSourceSearchFlags search_flags;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
gboolean found = FALSE;
GtkTextIter m_start;
GtkTextIter m_end;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail ((start == NULL) ||
(gtk_text_iter_get_buffer (start) == GTK_TEXT_BUFFER (doc)), FALSE);
g_return_val_if_fail ((end == NULL) ||
(gtk_text_iter_get_buffer (end) == GTK_TEXT_BUFFER (doc)), FALSE);
if (doc->priv->search_text == NULL)
{
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == NULL\n");
2011-11-07 13:46:58 -06:00
return FALSE;
}
else
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text);
2011-11-07 13:46:58 -06:00
if (end == NULL)
gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter);
else
iter = *end;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
#else
2011-11-07 13:46:58 -06:00
search_flags = GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_TEXT_ONLY;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
if (!XEDIT_SEARCH_IS_CASE_SENSITIVE (doc->priv->search_flags))
2011-11-07 13:46:58 -06:00
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
#else
2011-11-07 13:46:58 -06:00
search_flags = search_flags | GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
}
while (!found)
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
found = gtk_text_iter_backward_search (&iter,
#else
2011-11-07 13:46:58 -06:00
found = gtk_source_iter_backward_search (&iter,
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
doc->priv->search_text,
search_flags,
&m_start,
&m_end,
start);
2016-01-25 08:13:49 -06:00
if (found && XEDIT_SEARCH_IS_ENTIRE_WORD (doc->priv->search_flags))
2011-11-07 13:46:58 -06:00
{
found = gtk_text_iter_starts_word (&m_start) &&
gtk_text_iter_ends_word (&m_end);
if (!found)
iter = m_start;
}
else
break;
}
if (found && (match_start != NULL))
*match_start = m_start;
if (found && (match_end != NULL))
*match_end = m_end;
return found;
}
/* FIXME this is an issue for introspection regardning @find */
2011-11-07 13:46:58 -06:00
gint
2016-01-25 08:13:49 -06:00
xedit_document_replace_all (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *find,
const gchar *replace,
guint flags)
{
GtkTextIter iter;
GtkTextIter m_start;
GtkTextIter m_end;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
GtkTextSearchFlags search_flags = 0;
#else
2011-11-07 13:46:58 -06:00
GtkSourceSearchFlags search_flags = 0;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
gboolean found = TRUE;
gint cont = 0;
gchar *search_text;
gchar *replace_text;
gint replace_text_len;
GtkTextBuffer *buffer;
gboolean brackets_highlighting;
gboolean search_highliting;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), 0);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (replace != NULL, 0);
g_return_val_if_fail ((find != NULL) || (doc->priv->search_text != NULL), 0);
buffer = GTK_TEXT_BUFFER (doc);
if (find == NULL)
search_text = g_strdup (doc->priv->search_text);
else
2016-01-25 08:13:49 -06:00
search_text = xedit_utils_unescape_search_text (find);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
replace_text = xedit_utils_unescape_search_text (replace);
2011-11-07 13:46:58 -06:00
gtk_text_buffer_get_start_iter (buffer, &iter);
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
#else
2011-11-07 13:46:58 -06:00
search_flags = GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_TEXT_ONLY;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
if (!XEDIT_SEARCH_IS_CASE_SENSITIVE (flags))
2011-11-07 13:46:58 -06:00
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
#else
2011-11-07 13:46:58 -06:00
search_flags = search_flags | GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
}
replace_text_len = strlen (replace_text);
/* disable cursor_moved emission until the end of the
* replace_all so that we don't spend all the time
* updating the position in the statusbar
*/
doc->priv->stop_cursor_moved_emission = TRUE;
/* also avoid spending time matching brackets */
brackets_highlighting = gtk_source_buffer_get_highlight_matching_brackets (GTK_SOURCE_BUFFER (buffer));
gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (buffer), FALSE);
/* and do search highliting later */
2016-01-25 08:13:49 -06:00
search_highliting = xedit_document_get_enable_search_highlighting (doc);
xedit_document_set_enable_search_highlighting (doc, FALSE);
2011-11-07 13:46:58 -06:00
gtk_text_buffer_begin_user_action (buffer);
do
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
found = gtk_text_iter_forward_search (&iter,
#else
2011-11-07 13:46:58 -06:00
found = gtk_source_iter_forward_search (&iter,
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
search_text,
search_flags,
&m_start,
&m_end,
NULL);
2016-01-25 08:13:49 -06:00
if (found && XEDIT_SEARCH_IS_ENTIRE_WORD (flags))
2011-11-07 13:46:58 -06:00
{
gboolean word;
word = gtk_text_iter_starts_word (&m_start) &&
gtk_text_iter_ends_word (&m_end);
if (!word)
{
iter = m_end;
continue;
}
}
if (found)
{
++cont;
gtk_text_buffer_delete (buffer,
&m_start,
&m_end);
gtk_text_buffer_insert (buffer,
&m_start,
replace_text,
replace_text_len);
iter = m_start;
}
} while (found);
gtk_text_buffer_end_user_action (buffer);
/* re-enable cursor_moved emission and notify
* the current position
*/
doc->priv->stop_cursor_moved_emission = FALSE;
emit_cursor_moved (doc);
gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (buffer),
brackets_highlighting);
2016-01-25 08:13:49 -06:00
xedit_document_set_enable_search_highlighting (doc, search_highliting);
2011-11-07 13:46:58 -06:00
g_free (search_text);
g_free (replace_text);
return cont;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_set_language:
* @doc:
* @lang: (allow-none):
**/
2011-11-07 13:46:58 -06:00
void
2016-01-25 08:13:49 -06:00
xedit_document_set_language (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkSourceLanguage *lang)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
set_language (doc, lang, TRUE);
}
GtkSourceLanguage *
2016-01-25 08:13:49 -06:00
xedit_document_get_language (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc));
}
2016-01-25 08:13:49 -06:00
const XeditEncoding *
xedit_document_get_encoding (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
return doc->priv->encoding;
}
glong
2016-01-25 08:13:49 -06:00
_xedit_document_get_seconds_since_last_save_or_load (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
GTimeVal current_time;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), -1);
2011-11-07 13:46:58 -06:00
g_get_current_time (&current_time);
return (current_time.tv_sec - doc->priv->time_of_last_save_or_load.tv_sec);
}
static void
2016-01-25 08:13:49 -06:00
get_search_match_colors (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
gboolean *foreground_set,
#if GTK_CHECK_VERSION (3, 14, 0)
GdkRGBA *foreground,
gboolean *background_set,
GdkRGBA *background)
#else
2011-11-07 13:46:58 -06:00
GdkColor *foreground,
gboolean *background_set,
GdkColor *background)
#endif
2011-11-07 13:46:58 -06:00
{
GtkSourceStyleScheme *style_scheme;
GtkSourceStyle *style;
gchar *bg;
gchar *fg;
style_scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (doc));
if (style_scheme == NULL)
goto fallback;
style = gtk_source_style_scheme_get_style (style_scheme,
"search-match");
if (style == NULL)
goto fallback;
g_object_get (style,
"foreground-set", foreground_set,
"foreground", &fg,
"background-set", background_set,
"background", &bg,
NULL);
if (*foreground_set)
{
#if GTK_CHECK_VERSION (3, 14, 0)
if (fg == NULL ||
!gdk_rgba_parse (foreground, fg))
{
*foreground_set = FALSE;
}
}
if (*background_set)
{
if (bg == NULL ||
!gdk_rgba_parse (background, bg))
{
*background_set = FALSE;
#else
2011-11-07 13:46:58 -06:00
if (fg == NULL ||
!gdk_color_parse (fg, foreground))
{
*foreground_set = FALSE;
}
}
if (*background_set)
{
if (bg == NULL ||
!gdk_color_parse (bg, background))
{
*background_set = FALSE;
#endif
2011-11-07 13:46:58 -06:00
}
}
g_free (fg);
g_free (bg);
return;
fallback:
2016-01-25 08:13:49 -06:00
xedit_debug_message (DEBUG_DOCUMENT,
2011-11-07 13:46:58 -06:00
"Falling back to hard-coded colors "
"for the \"found\" text tag.");
#if GTK_CHECK_VERSION (3, 14, 0)
gdk_rgba_parse (background, "#FFFF78");
#else
2011-11-07 13:46:58 -06:00
gdk_color_parse ("#FFFF78", background);
#endif
2011-11-07 13:46:58 -06:00
*background_set = TRUE;
*foreground_set = FALSE;
return;
}
static void
2016-01-25 08:13:49 -06:00
sync_found_tag (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GParamSpec *pspec,
gpointer data)
{
#if GTK_CHECK_VERSION (3, 14, 0)
GdkRGBA fg;
GdkRGBA bg;
#else
2011-11-07 13:46:58 -06:00
GdkColor fg;
GdkColor bg;
#endif
2011-11-07 13:46:58 -06:00
gboolean fg_set;
gboolean bg_set;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
g_return_if_fail (GTK_TEXT_TAG (doc->priv->found_tag));
get_search_match_colors (doc,
&fg_set, &fg,
&bg_set, &bg);
g_object_set (doc->priv->found_tag,
#if GTK_CHECK_VERSION (3, 14, 0)
"foreground-rgba", fg_set ? &fg : NULL,
NULL);
g_object_set (doc->priv->found_tag,
"background-rgba", bg_set ? &bg : NULL,
#else
2011-11-07 13:46:58 -06:00
"foreground-gdk", fg_set ? &fg : NULL,
NULL);
g_object_set (doc->priv->found_tag,
"background-gdk", bg_set ? &bg : NULL,
#endif
2011-11-07 13:46:58 -06:00
NULL);
}
static void
text_tag_set_highest_priority (GtkTextTag *tag,
GtkTextBuffer *buffer)
{
GtkTextTagTable *table;
gint n;
table = gtk_text_buffer_get_tag_table (buffer);
n = gtk_text_tag_table_get_size (table);
gtk_text_tag_set_priority (tag, n - 1);
}
static void
2016-01-25 08:13:49 -06:00
search_region (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *start,
GtkTextIter *end)
{
GtkTextIter iter;
GtkTextIter m_start;
2013-10-29 18:56:56 -05:00
GtkTextIter m_end;
#if GTK_CHECK_VERSION (3, 0, 0)
GtkTextSearchFlags search_flags = 0;
#else
2011-11-07 13:46:58 -06:00
GtkSourceSearchFlags search_flags = 0;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
gboolean found = TRUE;
GtkTextBuffer *buffer;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
buffer = GTK_TEXT_BUFFER (doc);
if (doc->priv->found_tag == NULL)
{
doc->priv->found_tag = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (doc),
"found",
NULL);
sync_found_tag (doc, NULL, NULL);
g_signal_connect (doc,
"notify::style-scheme",
G_CALLBACK (sync_found_tag),
NULL);
}
/* make sure the 'found' tag has the priority over
* syntax highlighting tags */
text_tag_set_highest_priority (doc->priv->found_tag,
GTK_TEXT_BUFFER (doc));
if (doc->priv->search_text == NULL)
return;
g_return_if_fail (doc->priv->num_of_lines_search_text > 0);
gtk_text_iter_backward_lines (start, doc->priv->num_of_lines_search_text);
gtk_text_iter_forward_lines (end, doc->priv->num_of_lines_search_text);
if (gtk_text_iter_has_tag (start, doc->priv->found_tag) &&
!gtk_text_iter_begins_tag (start, doc->priv->found_tag))
gtk_text_iter_backward_to_tag_toggle (start, doc->priv->found_tag);
if (gtk_text_iter_has_tag (end, doc->priv->found_tag) &&
!gtk_text_iter_ends_tag (end, doc->priv->found_tag))
gtk_text_iter_forward_to_tag_toggle (end, doc->priv->found_tag);
/*
g_print ("[%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
*/
gtk_text_buffer_remove_tag (buffer,
doc->priv->found_tag,
start,
end);
if (*doc->priv->search_text == '\0')
return;
iter = *start;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
#else
2011-11-07 13:46:58 -06:00
search_flags = GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_TEXT_ONLY;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
if (!XEDIT_SEARCH_IS_CASE_SENSITIVE (doc->priv->search_flags))
2011-11-07 13:46:58 -06:00
{
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
#else
2011-11-07 13:46:58 -06:00
search_flags = search_flags | GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
}
do
{
if ((end != NULL) && gtk_text_iter_is_end (end))
end = NULL;
2013-10-29 18:56:56 -05:00
#if GTK_CHECK_VERSION (3, 0, 0)
found = gtk_text_iter_forward_search (&iter,
#else
2011-11-07 13:46:58 -06:00
found = gtk_source_iter_forward_search (&iter,
2013-10-29 18:56:56 -05:00
#endif
2011-11-07 13:46:58 -06:00
doc->priv->search_text,
search_flags,
&m_start,
&m_end,
end);
iter = m_end;
2016-01-25 08:13:49 -06:00
if (found && XEDIT_SEARCH_IS_ENTIRE_WORD (doc->priv->search_flags))
2011-11-07 13:46:58 -06:00
{
gboolean word;
word = gtk_text_iter_starts_word (&m_start) &&
gtk_text_iter_ends_word (&m_end);
if (!word)
continue;
}
if (found)
{
gtk_text_buffer_apply_tag (buffer,
doc->priv->found_tag,
&m_start,
&m_end);
}
} while (found);
}
static void
2016-01-25 08:13:49 -06:00
to_search_region_range (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *start,
GtkTextIter *end)
{
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
if (doc->priv->to_search_region == NULL)
return;
gtk_text_iter_set_line_offset (start, 0);
gtk_text_iter_forward_to_line_end (end);
/*
g_print ("+ [%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
*/
/* Add the region to the refresh region */
2016-01-25 08:13:49 -06:00
xedit_text_region_add (doc->priv->to_search_region, start, end);
2011-11-07 13:46:58 -06:00
/* Notify views of the updated highlight region */
gtk_text_iter_backward_lines (start, doc->priv->num_of_lines_search_text);
gtk_text_iter_forward_lines (end, doc->priv->num_of_lines_search_text);
g_signal_emit (doc, document_signals [SEARCH_HIGHLIGHT_UPDATED], 0, start, end);
}
void
2016-01-25 08:13:49 -06:00
_xedit_document_search_region (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const GtkTextIter *start,
const GtkTextIter *end)
{
2016-01-25 08:13:49 -06:00
XeditTextRegion *region;
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (start != NULL);
g_return_if_fail (end != NULL);
if (doc->priv->to_search_region == NULL)
return;
/*
g_print ("U [%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
*/
/* get the subregions not yet highlighted */
2016-01-25 08:13:49 -06:00
region = xedit_text_region_intersect (doc->priv->to_search_region,
2011-11-07 13:46:58 -06:00
start,
end);
if (region)
{
gint i;
GtkTextIter start_search;
GtkTextIter end_search;
2016-01-25 08:13:49 -06:00
i = xedit_text_region_subregions (region);
xedit_text_region_nth_subregion (region,
2011-11-07 13:46:58 -06:00
0,
&start_search,
NULL);
2016-01-25 08:13:49 -06:00
xedit_text_region_nth_subregion (region,
2011-11-07 13:46:58 -06:00
i - 1,
NULL,
&end_search);
2016-01-25 08:13:49 -06:00
xedit_text_region_destroy (region, TRUE);
2011-11-07 13:46:58 -06:00
gtk_text_iter_order (&start_search, &end_search);
search_region (doc, &start_search, &end_search);
/* remove the just highlighted region */
2016-01-25 08:13:49 -06:00
xedit_text_region_subtract (doc->priv->to_search_region,
2011-11-07 13:46:58 -06:00
start,
end);
}
}
static void
2016-01-25 08:13:49 -06:00
insert_text_cb (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *pos,
const gchar *text,
gint length)
{
GtkTextIter start;
GtkTextIter end;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
start = end = *pos;
/*
* pos is invalidated when
* insertion occurs (because the buffer contents change), but the
* default signal handler revalidates it to point to the end of the
* inserted text
*/
gtk_text_iter_backward_chars (&start,
g_utf8_strlen (text, length));
to_search_region_range (doc, &start, &end);
}
static void
2016-01-25 08:13:49 -06:00
delete_range_cb (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
GtkTextIter *start,
GtkTextIter *end)
{
GtkTextIter d_start;
GtkTextIter d_end;
2016-01-25 08:13:49 -06:00
xedit_debug (DEBUG_DOCUMENT);
2011-11-07 13:46:58 -06:00
d_start = *start;
d_end = *end;
to_search_region_range (doc, &d_start, &d_end);
}
void
2016-01-25 08:13:49 -06:00
xedit_document_set_enable_search_highlighting (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
gboolean enable)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
enable = enable != FALSE;
if ((doc->priv->to_search_region != NULL) == enable)
return;
if (doc->priv->to_search_region != NULL)
{
/* Disable search highlighting */
if (doc->priv->found_tag != NULL)
{
/* If needed remove the found_tag */
GtkTextIter begin;
GtkTextIter end;
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc),
&begin,
&end);
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (doc),
doc->priv->found_tag,
&begin,
&end);
}
2016-01-25 08:13:49 -06:00
xedit_text_region_destroy (doc->priv->to_search_region,
2011-11-07 13:46:58 -06:00
TRUE);
doc->priv->to_search_region = NULL;
}
else
{
2016-01-25 08:13:49 -06:00
doc->priv->to_search_region = xedit_text_region_new (GTK_TEXT_BUFFER (doc));
if (xedit_document_get_can_search_again (doc))
2011-11-07 13:46:58 -06:00
{
/* If search_text is not empty, highligth all its occurrences */
GtkTextIter begin;
GtkTextIter end;
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc),
&begin,
&end);
to_search_region_range (doc,
&begin,
&end);
}
}
}
gboolean
2016-01-25 08:13:49 -06:00
xedit_document_get_enable_search_highlighting (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), FALSE);
2011-11-07 13:46:58 -06:00
return (doc->priv->to_search_region != NULL);
}
void
2016-01-25 08:13:49 -06:00
xedit_document_set_newline_type (XeditDocument *doc,
XeditDocumentNewlineType newline_type)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
if (doc->priv->newline_type != newline_type)
{
doc->priv->newline_type = newline_type;
g_object_notify (G_OBJECT (doc), "newline-type");
}
}
2016-01-25 08:13:49 -06:00
XeditDocumentNewlineType
xedit_document_get_newline_type (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), 0);
2011-11-07 13:46:58 -06:00
return doc->priv->newline_type;
}
void
2016-01-25 08:13:49 -06:00
_xedit_document_set_mount_operation_factory (XeditDocument *doc,
XeditMountOperationFactory callback,
2011-11-07 13:46:58 -06:00
gpointer userdata)
{
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
doc->priv->mount_operation_factory = callback;
doc->priv->mount_operation_userdata = userdata;
}
GMountOperation *
2016-01-25 08:13:49 -06:00
_xedit_document_create_mount_operation (XeditDocument *doc)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
if (doc->priv->mount_operation_factory == NULL)
return g_mount_operation_new ();
else
return doc->priv->mount_operation_factory (doc,
doc->priv->mount_operation_userdata);
}
#ifndef ENABLE_GVFS_METADATA
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_metadata (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *key)
{
gchar *value = NULL;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (key != NULL, NULL);
2016-01-25 08:13:49 -06:00
if (!xedit_document_is_untitled (doc))
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
value = xedit_metadata_manager_get (doc->priv->uri, key);
2011-11-07 13:46:58 -06:00
}
return value;
}
void
2016-01-25 08:13:49 -06:00
xedit_document_set_metadata (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *first_key,
...)
{
const gchar *key;
const gchar *value;
va_list var_args;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (first_key != NULL);
2016-01-25 08:13:49 -06:00
if (xedit_document_is_untitled (doc))
2011-11-07 13:46:58 -06:00
{
/* Can't set metadata for untitled documents */
return;
}
va_start (var_args, first_key);
for (key = first_key; key; key = va_arg (var_args, const gchar *))
{
value = va_arg (var_args, const gchar *);
2016-01-25 08:13:49 -06:00
xedit_metadata_manager_set (doc->priv->uri,
2011-11-07 13:46:58 -06:00
key,
value);
}
va_end (var_args);
}
#else
/**
2016-01-25 08:13:49 -06:00
* xedit_document_get_metadata:
* @doc: a #XeditDocument
2011-11-07 13:46:58 -06:00
* @key: name of the key
*
* Gets the metadata assigned to @key.
*
* Returns: the value assigned to @key.
*/
gchar *
2016-01-25 08:13:49 -06:00
xedit_document_get_metadata (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *key)
{
gchar *value = NULL;
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_DOCUMENT (doc), NULL);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (key != NULL, NULL);
if (doc->priv->metadata_info && g_file_info_has_attribute (doc->priv->metadata_info,
key))
{
value = g_strdup (g_file_info_get_attribute_string (doc->priv->metadata_info,
key));
}
return value;
}
static void
set_attributes_cb (GObject *source,
GAsyncResult *res,
gpointer useless)
{
g_file_set_attributes_finish (G_FILE (source),
res,
NULL,
NULL);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_document_set_metadata:
* @doc: a #XeditDocument
2011-11-07 13:46:58 -06:00
* @first_key: name of the first key to set
* @...: value for the first key, followed optionally by more key/value pairs,
* followed by %NULL.
*
* Sets metadata on a document.
*/
void
2016-01-25 08:13:49 -06:00
xedit_document_set_metadata (XeditDocument *doc,
2011-11-07 13:46:58 -06:00
const gchar *first_key,
...)
{
const gchar *key;
const gchar *value;
va_list var_args;
GFileInfo *info;
GFile *location;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_DOCUMENT (doc));
2011-11-07 13:46:58 -06:00
g_return_if_fail (first_key != NULL);
info = g_file_info_new ();
va_start (var_args, first_key);
for (key = first_key; key; key = va_arg (var_args, const gchar *))
{
value = va_arg (var_args, const gchar *);
if (value != NULL)
{
g_file_info_set_attribute_string (info,
key, value);
}
else
{
/* Unset the key */
g_file_info_set_attribute (info, key,
G_FILE_ATTRIBUTE_TYPE_INVALID,
NULL);
}
}
va_end (var_args);
if (doc->priv->metadata_info != NULL)
g_file_info_copy_into (info, doc->priv->metadata_info);
2016-01-25 08:13:49 -06:00
location = xedit_document_get_location (doc);
2011-11-07 13:46:58 -06:00
if (location != NULL)
{
g_file_set_attributes_async (location,
info,
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
NULL,
set_attributes_cb,
NULL);
g_object_unref (location);
}
g_object_unref (info);
}
#endif