445 lines
12 KiB
C
445 lines
12 KiB
C
/*
|
|
* mooeditaction.c
|
|
*
|
|
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1 as published by the Free Software Foundation.
|
|
*
|
|
* See COPYING file that comes with this distribution.
|
|
*/
|
|
|
|
#define MOOEDIT_COMPILATION
|
|
#include "mooedit/mooeditaction.h"
|
|
#include "mooedit/mooeditaction-factory.h"
|
|
#include "mooedit/mooedit-private.h"
|
|
#include "mooedit/mooeditfiltersettings.h"
|
|
#include <glib/gregex.h>
|
|
#include <string.h>
|
|
|
|
|
|
typedef enum {
|
|
FILTER_SENSITIVE,
|
|
FILTER_VISIBLE
|
|
} FilterType;
|
|
|
|
#define N_FILTERS 2
|
|
|
|
struct _MooEditActionPrivate {
|
|
MooEdit *doc;
|
|
MooEditFilter *file_filter;
|
|
GRegex *filters[N_FILTERS];
|
|
};
|
|
|
|
typedef struct {
|
|
GRegex *regex;
|
|
guint use_count;
|
|
} RegexRef;
|
|
|
|
typedef struct {
|
|
GHashTable *hash;
|
|
} FilterStore;
|
|
|
|
static FilterStore filter_store;
|
|
|
|
G_DEFINE_TYPE (MooEditAction, moo_edit_action, MOO_TYPE_ACTION)
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_DOC,
|
|
PROP_FILE_FILTER,
|
|
PROP_FILTER_SENSITIVE,
|
|
PROP_FILTER_VISIBLE
|
|
};
|
|
|
|
|
|
static GRegex *get_filter_regex (const char *pattern);
|
|
static void unuse_filter_regex (GRegex *regex);
|
|
|
|
static gboolean moo_edit_action_check_visible (MooEditAction *action);
|
|
static gboolean moo_edit_action_check_sensitive (MooEditAction *action);
|
|
static void moo_edit_action_check_state (MooEditAction *action);
|
|
|
|
|
|
static void
|
|
moo_edit_action_finalize (GObject *object)
|
|
{
|
|
guint i;
|
|
MooEditAction *action = MOO_EDIT_ACTION (object);
|
|
|
|
for (i = 0; i < N_FILTERS; ++i)
|
|
if (action->priv->filters[i])
|
|
unuse_filter_regex (action->priv->filters[i]);
|
|
|
|
_moo_edit_filter_free (action->priv->file_filter);
|
|
|
|
G_OBJECT_CLASS(moo_edit_action_parent_class)->finalize (object);
|
|
}
|
|
|
|
|
|
static const char *
|
|
moo_edit_action_get_filter (MooEditAction *action,
|
|
FilterType type)
|
|
{
|
|
g_assert (type < N_FILTERS);
|
|
return action->priv->filters[type] ?
|
|
g_regex_get_pattern (action->priv->filters[type]) : NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
MooEditAction *action = MOO_EDIT_ACTION (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_DOC:
|
|
g_value_set_object (value, action->priv->doc);
|
|
break;
|
|
|
|
case PROP_FILTER_VISIBLE:
|
|
g_value_set_string (value, moo_edit_action_get_filter (action, FILTER_VISIBLE));
|
|
break;
|
|
|
|
case PROP_FILTER_SENSITIVE:
|
|
g_value_set_string (value, moo_edit_action_get_filter (action, FILTER_SENSITIVE));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_set_file_filter (MooEditAction *action,
|
|
const char *string)
|
|
{
|
|
_moo_edit_filter_free (action->priv->file_filter);
|
|
action->priv->file_filter = _moo_edit_filter_new (string);
|
|
g_object_notify (G_OBJECT (action), "file-filter");
|
|
}
|
|
|
|
|
|
MooEdit *
|
|
moo_edit_action_get_doc (MooEditAction *action)
|
|
{
|
|
g_return_val_if_fail (MOO_IS_EDIT_ACTION (action), NULL);
|
|
return action->priv->doc;
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_set_filter (MooEditAction *action,
|
|
const char *filter,
|
|
FilterType type)
|
|
{
|
|
GRegex *tmp;
|
|
|
|
g_assert (type < N_FILTERS);
|
|
|
|
tmp = action->priv->filters[type];
|
|
action->priv->filters[type] = filter ? get_filter_regex (filter) : NULL;
|
|
unuse_filter_regex (tmp);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
MooEditAction *action = MOO_EDIT_ACTION (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_DOC:
|
|
action->priv->doc = g_value_get_object (value);
|
|
g_object_notify (object, "doc");
|
|
break;
|
|
|
|
case PROP_FILE_FILTER:
|
|
moo_edit_action_set_file_filter (action, g_value_get_string (value));
|
|
break;
|
|
|
|
case PROP_FILTER_SENSITIVE:
|
|
moo_edit_action_set_filter (action,
|
|
g_value_get_string (value),
|
|
FILTER_SENSITIVE);
|
|
break;
|
|
|
|
case PROP_FILTER_VISIBLE:
|
|
moo_edit_action_set_filter (action,
|
|
g_value_get_string (value),
|
|
FILTER_VISIBLE);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_init (MooEditAction *action)
|
|
{
|
|
action->priv = G_TYPE_INSTANCE_GET_PRIVATE (action, MOO_TYPE_EDIT_ACTION, MooEditActionPrivate);
|
|
}
|
|
|
|
|
|
static const char *
|
|
get_current_line (MooEdit *doc)
|
|
{
|
|
char *line;
|
|
|
|
line = g_object_get_data (G_OBJECT (doc), "moo-edit-current-line");
|
|
|
|
if (!line)
|
|
{
|
|
GtkTextIter line_start, line_end;
|
|
GtkTextBuffer *buffer;
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (doc));
|
|
gtk_text_buffer_get_iter_at_mark (buffer, &line_start,
|
|
gtk_text_buffer_get_insert (buffer));
|
|
line_end = line_start;
|
|
gtk_text_iter_set_line_offset (&line_start, 0);
|
|
if (!gtk_text_iter_ends_line (&line_end))
|
|
gtk_text_iter_forward_to_line_end (&line_end);
|
|
|
|
line = gtk_text_buffer_get_slice (buffer, &line_start, &line_end, TRUE);
|
|
|
|
g_object_set_data_full (G_OBJECT (doc), "moo-edit-current-line", line, g_free);
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_edit_action_check_visible_real (MooEditAction *action)
|
|
{
|
|
gboolean visible = TRUE;
|
|
GRegex *filter = action->priv->filters[FILTER_VISIBLE];
|
|
|
|
if (!action->priv->doc)
|
|
return gtk_action_get_visible (GTK_ACTION (action));
|
|
|
|
if (!action->priv->file_filter && !filter)
|
|
return gtk_action_get_visible (GTK_ACTION (action));
|
|
|
|
if (visible && action->priv->file_filter)
|
|
if (!_moo_edit_filter_match (action->priv->file_filter, action->priv->doc))
|
|
visible = FALSE;
|
|
|
|
if (visible && filter)
|
|
{
|
|
const char *line = get_current_line (action->priv->doc);
|
|
if (!g_regex_match (filter, line, 0, NULL))
|
|
visible = FALSE;
|
|
}
|
|
|
|
return visible;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_edit_action_check_sensitive_real (MooEditAction *action)
|
|
{
|
|
const char *line;
|
|
GRegex *filter = action->priv->filters[FILTER_SENSITIVE];
|
|
|
|
if (!action->priv->doc || !filter)
|
|
return gtk_action_get_sensitive (GTK_ACTION (action));
|
|
|
|
line = get_current_line (action->priv->doc);
|
|
return g_regex_match (filter, line, 0, NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_check_state_real (MooEditAction *action)
|
|
{
|
|
gboolean visible, sensitive;
|
|
|
|
visible = moo_edit_action_check_visible (action);
|
|
sensitive = moo_edit_action_check_sensitive (action);
|
|
|
|
g_object_set (action, "sensitive", sensitive, "visible", visible, NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_edit_action_class_init (MooEditActionClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->finalize = moo_edit_action_finalize;
|
|
gobject_class->set_property = moo_edit_action_set_property;
|
|
gobject_class->get_property = moo_edit_action_get_property;
|
|
|
|
klass->check_state = moo_edit_action_check_state_real;
|
|
klass->check_visible = moo_edit_action_check_visible_real;
|
|
klass->check_sensitive = moo_edit_action_check_sensitive_real;
|
|
|
|
g_type_class_add_private (klass, sizeof (MooEditActionPrivate));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_DOC,
|
|
g_param_spec_object ("doc",
|
|
"doc",
|
|
"doc",
|
|
MOO_TYPE_EDIT,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_FILE_FILTER,
|
|
g_param_spec_string ("file-filter",
|
|
"file-filter",
|
|
"file-filter",
|
|
NULL,
|
|
G_PARAM_WRITABLE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_FILTER_SENSITIVE,
|
|
g_param_spec_string ("filter-sensitive",
|
|
"filter-sensitive",
|
|
"filter-sensitive",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_FILTER_VISIBLE,
|
|
g_param_spec_string ("filter-visible",
|
|
"filter-visible",
|
|
"filter-visible",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_edit_action_check_visible (MooEditAction *action)
|
|
{
|
|
g_return_val_if_fail (MOO_IS_EDIT_ACTION (action), TRUE);
|
|
|
|
if (MOO_EDIT_ACTION_GET_CLASS (action)->check_visible)
|
|
return MOO_EDIT_ACTION_GET_CLASS (action)->check_visible (action);
|
|
else
|
|
return gtk_action_get_visible (GTK_ACTION (action));
|
|
}
|
|
|
|
static gboolean
|
|
moo_edit_action_check_sensitive (MooEditAction *action)
|
|
{
|
|
g_return_val_if_fail (MOO_IS_EDIT_ACTION (action), TRUE);
|
|
|
|
if (MOO_EDIT_ACTION_GET_CLASS (action)->check_sensitive)
|
|
return MOO_EDIT_ACTION_GET_CLASS (action)->check_sensitive (action);
|
|
else
|
|
return gtk_action_get_sensitive (GTK_ACTION (action));
|
|
}
|
|
|
|
static void
|
|
moo_edit_action_check_state (MooEditAction *action)
|
|
{
|
|
g_return_if_fail (MOO_IS_EDIT_ACTION (action));
|
|
g_return_if_fail (MOO_EDIT_ACTION_GET_CLASS (action)->check_state != NULL);
|
|
MOO_EDIT_ACTION_GET_CLASS (action)->check_state (action);
|
|
}
|
|
|
|
|
|
void
|
|
_moo_edit_check_actions (MooEdit *edit)
|
|
{
|
|
GtkActionGroup *group = moo_edit_get_actions (edit);
|
|
GList *actions = gtk_action_group_list_actions (group);
|
|
|
|
while (actions)
|
|
{
|
|
if (MOO_IS_EDIT_ACTION (actions->data))
|
|
moo_edit_action_check_state (actions->data);
|
|
actions = g_list_delete_link (actions, actions);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
regex_ref_free (RegexRef *ref)
|
|
{
|
|
if (ref)
|
|
{
|
|
g_regex_unref (ref->regex);
|
|
g_free (ref);
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_filter_store (void)
|
|
{
|
|
if (!filter_store.hash)
|
|
filter_store.hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
|
|
(GDestroyNotify) regex_ref_free);
|
|
}
|
|
|
|
|
|
static GRegex *
|
|
get_filter_regex (const char *pattern)
|
|
{
|
|
RegexRef *ref;
|
|
|
|
g_return_val_if_fail (pattern != NULL, NULL);
|
|
|
|
init_filter_store ();
|
|
|
|
ref = g_hash_table_lookup (filter_store.hash, pattern);
|
|
|
|
if (!ref)
|
|
{
|
|
GRegex *regex;
|
|
GError *error = NULL;
|
|
|
|
regex = g_regex_new (pattern, G_REGEX_OPTIMIZE, 0, &error);
|
|
|
|
if (!regex)
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, error->message);
|
|
g_error_free (error);
|
|
return NULL;
|
|
}
|
|
|
|
ref = g_new0 (RegexRef, 1);
|
|
ref->regex = regex;
|
|
|
|
g_hash_table_insert (filter_store.hash, g_strdup (pattern), ref);
|
|
}
|
|
|
|
ref->use_count++;
|
|
return ref->regex;
|
|
}
|
|
|
|
|
|
static void
|
|
unuse_filter_regex (GRegex *regex)
|
|
{
|
|
RegexRef *ref;
|
|
const char *pattern;
|
|
|
|
g_return_if_fail (regex != NULL);
|
|
|
|
init_filter_store ();
|
|
|
|
pattern = g_regex_get_pattern (regex);
|
|
ref = g_hash_table_lookup (filter_store.hash, pattern);
|
|
g_return_if_fail (ref != NULL);
|
|
|
|
if (!--ref->use_count)
|
|
g_hash_table_remove (filter_store.hash, pattern);
|
|
}
|