medit/moo/mooedit/moousertools.c

1176 lines
30 KiB
C

/*
* moousertools.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 as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#define MOOEDIT_COMPILATION
#include "mooedit/moousertools.h"
#include "mooedit/moocommand-private.h"
#include "mooedit/mooeditor.h"
#include "mooedit/mooeditaction.h"
#include "mooedit/mooeditaction-factory.h"
#include "mooedit/mookeyfile.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooaccel.h"
#include "mooutils/mooi18n.h"
#include "mooutils/mooaction-private.h"
#include "mooutils/mootype-macros.h"
#include <string.h>
#define N_TOOLS 2
#define ITEM_TOOL "tool"
#define KEY_ACCEL "accel"
#define KEY_MENU "menu"
#define KEY_LANGS "langs"
#define KEY_POSITION "position"
#define KEY_COMMAND "command"
#define KEY_NAME "name"
#define KEY_ENABLED "enabled"
#define KEY_OS "os"
#define KEY_ID "id"
#define KEY_DELETED "deleted"
#define KEY_BUILTIN "builtin"
enum {
PROP_0,
PROP_COMMAND
};
typedef struct {
GSList *tools;
} ToolStore;
typedef struct {
char *id;
MooUIXML *xml;
guint merge_id;
} ToolInfo;
typedef struct {
MooEditAction parent;
MooCommand *cmd;
} MooToolAction;
typedef MooEditActionClass MooToolActionClass;
MOO_DEFINE_TYPE_STATIC (MooToolAction, _moo_tool_action, MOO_TYPE_EDIT_ACTION)
#define MOO_TYPE_TOOL_ACTION (_moo_tool_action_get_type())
#define MOO_IS_TOOL_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, MOO_TYPE_TOOL_ACTION))
#define MOO_TOOL_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, MOO_TYPE_TOOL_ACTION, MooToolAction))
static const char *FILENAMES[N_TOOLS] = {"menu.cfg", "context.cfg"};
static ToolStore *tools_stores[N_TOOLS];
static MooCommandContext *create_command_context (gpointer window,
gpointer doc);
static MooUserToolInfo *_moo_user_tool_info_ref (MooUserToolInfo *info);
static void
unload_user_tools (int type)
{
ToolStore *store = tools_stores[type];
GSList *list;
gpointer klass;
g_assert (type < N_TOOLS);
if (!store)
return;
list = store->tools;
store->tools = NULL;
if (type == MOO_USER_TOOL_MENU)
klass = g_type_class_peek (MOO_TYPE_EDIT_WINDOW);
else
klass = g_type_class_peek (MOO_TYPE_EDIT);
while (list)
{
ToolInfo *info = list->data;
if (info->xml)
{
moo_ui_xml_remove_ui (info->xml, info->merge_id);
g_object_unref (info->xml);
}
if (type == MOO_USER_TOOL_MENU)
moo_window_class_remove_action (klass, info->id);
else
moo_edit_class_remove_action (klass, info->id);
g_free (info->id);
g_free (info);
list = g_slist_delete_link (list, list);
}
g_free (store);
tools_stores[type] = NULL;
}
static ToolInfo *
tools_store_add (MooUserToolType type,
char *id)
{
ToolInfo *info;
g_assert (type < N_TOOLS);
info = g_new0 (ToolInfo, 1);
info->id = g_strdup (id);
switch (type)
{
case MOO_USER_TOOL_MENU:
info->xml = moo_editor_get_ui_xml (moo_editor_instance ());
break;
case MOO_USER_TOOL_CONTEXT:
info->xml = moo_editor_get_doc_ui_xml (moo_editor_instance ());
break;
}
if (info->xml)
{
g_object_ref (info->xml);
info->merge_id = moo_ui_xml_new_merge_id (info->xml);
}
if (!tools_stores[type])
tools_stores[type] = g_new0 (ToolStore, 1);
tools_stores[type]->tools = g_slist_prepend (tools_stores[type]->tools, info);
return info;
}
static void
find_user_tools_file (int type,
char ***sys_files_p,
char **user_file_p)
{
char **files;
guint n_files;
int i;
GPtrArray *sys_files = NULL;
*sys_files_p = NULL;
*user_file_p = NULL;
files = _moo_strv_reverse (moo_get_data_files (FILENAMES[type], MOO_DATA_SHARE, &n_files));
if (!n_files)
return;
if (g_file_test (files[n_files - 1], G_FILE_TEST_EXISTS))
*user_file_p = g_strdup (files[n_files - 1]);
for (i = 0; i < (int) n_files - 1; ++i)
{
if (g_file_test (files[i], G_FILE_TEST_EXISTS))
{
if (!sys_files)
sys_files = g_ptr_array_new ();
g_ptr_array_add (sys_files, g_strdup (files[i]));
}
}
if (sys_files)
{
g_ptr_array_add (sys_files, NULL);
*sys_files_p = (char**) g_ptr_array_free (sys_files, FALSE);
}
g_strfreev (files);
}
static gboolean
check_sensitive_func (GtkAction *gtkaction,
MooEditWindow *window,
MooEdit *doc,
G_GNUC_UNUSED gpointer data)
{
MooToolAction *action;
g_return_val_if_fail (MOO_IS_TOOL_ACTION (gtkaction), FALSE);
action = MOO_TOOL_ACTION (gtkaction);
return moo_command_check_sensitive (action->cmd, doc, window);
}
static char *
get_name (const char *label)
{
char *underscore, *name;
name = g_strdup (label);
underscore = strchr (name, '_');
if (underscore)
memmove (underscore, underscore + 1, strlen (underscore + 1) + 1);
return name;
}
static gboolean
check_info (MooUserToolInfo *info,
MooUserToolType type)
{
if (!info->id || !info->id[0])
{
g_warning ("tool id missing in file %s", info->file);
return FALSE;
}
if (!info->name || !info->name[0])
{
g_warning ("tool name missing in file %s", info->file);
return FALSE;
}
if (info->position != MOO_USER_TOOL_POS_END &&
type != MOO_USER_TOOL_CONTEXT)
{
g_warning ("position specified in tool %s in file %s",
info->name, info->file);
}
if (info->menu != NULL && type != MOO_USER_TOOL_MENU)
g_warning ("menu specified in tool %s in file %s",
info->name, info->file);
if (!info->cmd_factory)
{
g_warning ("command type missing in tool '%s' in file %s",
info->name, info->file);
return FALSE;
}
if (!info->cmd_data)
info->cmd_data = moo_command_data_new (info->cmd_factory->n_keys);
return TRUE;
}
static void
load_tool (MooUserToolInfo *info)
{
ToolInfo *tool_info;
gpointer klass = NULL;
MooCommand *cmd;
char *name;
g_return_if_fail (info != NULL);
g_return_if_fail (info->file != NULL);
if (!check_info (info, info->type))
return;
if (!info->enabled)
return;
#ifdef __WIN32__
if (info->os_type != MOO_USER_TOOL_WIN32)
return;
#else
if (info->os_type != MOO_USER_TOOL_UNIX)
return;
#endif
g_return_if_fail (MOO_IS_COMMAND_FACTORY (info->cmd_factory));
cmd = moo_command_create (info->cmd_factory->name,
info->options,
info->cmd_data);
if (!cmd)
{
g_warning ("could not get command for tool '%s' in file %s",
info->name, info->file);
return;
}
name = get_name (info->name);
switch (info->type)
{
case MOO_USER_TOOL_MENU:
klass = g_type_class_peek (MOO_TYPE_EDIT_WINDOW);
if (!moo_window_class_find_group (klass, "Tools"))
moo_window_class_new_group (klass, "Tools", _("Tools"));
moo_window_class_new_action (klass, info->id, "Tools",
"action-type::", MOO_TYPE_TOOL_ACTION,
"display-name", name,
"label", info->name,
"accel", info->accel,
"command", cmd,
NULL);
moo_edit_window_set_action_check (info->id, MOO_ACTION_CHECK_SENSITIVE,
check_sensitive_func,
NULL, NULL);
if (info->langs)
moo_edit_window_set_action_langs (info->id, MOO_ACTION_CHECK_ACTIVE, info->langs);
break;
case MOO_USER_TOOL_CONTEXT:
klass = g_type_class_peek (MOO_TYPE_EDIT);
moo_edit_class_new_action (klass, info->id,
"action-type::", MOO_TYPE_TOOL_ACTION,
"display-name", name,
"label", info->name,
"accel", info->accel,
"command", cmd,
"langs", info->langs,
NULL);
break;
}
tool_info = tools_store_add (info->type, info->id);
if (tool_info->xml)
{
const char *ui_path;
char *freeme = NULL;
char *markup;
markup = g_markup_printf_escaped ("<item action=\"%s\"/>", info->id);
if (info->type == MOO_USER_TOOL_CONTEXT)
{
if (info->position == MOO_USER_TOOL_POS_START)
ui_path = "Editor/Popup/PopupStart";
else
ui_path = "Editor/Popup/PopupEnd";
}
else
{
freeme = g_strdup_printf ("Editor/Menubar/%s/UserMenu",
info->menu ? info->menu : "Tools");
ui_path = freeme;
}
moo_ui_xml_insert_markup (tool_info->xml,
tool_info->merge_id,
ui_path, -1, markup);
g_free (markup);
g_free (freeme);
}
g_free (name);
g_object_unref (cmd);
}
static void
init_tools_environment (void)
{
static gboolean done;
if (!done)
{
char **script_dirs;
guint n_script_dirs;
const char *old_path;
char *new_path, *my_path;
done = TRUE;
script_dirs = moo_get_data_subdirs ("scripts", MOO_DATA_LIB, &n_script_dirs);
g_return_if_fail (n_script_dirs != 0);
old_path = g_getenv ("PATH");
g_return_if_fail (old_path != NULL);
my_path = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, script_dirs);
new_path = g_strdup_printf ("%s%s%s", my_path, G_SEARCHPATH_SEPARATOR_S, old_path);
g_setenv ("PATH", new_path, TRUE);
g_free (my_path);
g_free (new_path);
g_strfreev (script_dirs);
}
}
void
_moo_edit_load_user_tools (MooUserToolType type)
{
GSList *list;
init_tools_environment ();
unload_user_tools (type);
list = _moo_edit_parse_user_tools (type);
while (list)
{
load_tool (list->data);
_moo_user_tool_info_unref (list->data);
list = g_slist_delete_link (list, list);
}
}
static MooUserToolInfo *
parse_item (MooKeyFileItem *item,
MooUserToolType type,
const char *file)
{
char *os;
char *position = NULL;
MooUserToolInfo *info;
if (strcmp (moo_key_file_item_name (item), ITEM_TOOL))
{
g_warning ("invalid group %s in file %s", moo_key_file_item_name (item), file);
return NULL;
}
info = _moo_user_tool_info_new ();
info->type = type;
info->file = g_strdup (file);
info->position = MOO_USER_TOOL_POS_END;
info->id = moo_key_file_item_steal (item, KEY_ID);
info->name = moo_key_file_item_steal (item, KEY_NAME);
info->enabled = moo_key_file_item_steal_bool (item, KEY_ENABLED, TRUE);
info->deleted = moo_key_file_item_steal_bool (item, KEY_DELETED, FALSE);
info->builtin = moo_key_file_item_steal_bool (item, KEY_BUILTIN, FALSE);
if (!info->id)
{
g_warning ("tool id missing in file %s", file);
_moo_user_tool_info_unref (info);
return NULL;
}
if (info->deleted || info->builtin)
return info;
os = moo_key_file_item_steal (item, KEY_OS);
if (!os || !os[0])
info->os_type = MOO_USER_TOOL_THIS_OS;
else if (!g_ascii_strncasecmp (os, "win", 3))
info->os_type = MOO_USER_TOOL_WIN32;
else
info->os_type = MOO_USER_TOOL_UNIX;
g_free (os);
info->accel = moo_key_file_item_steal (item, KEY_ACCEL);
info->menu = moo_key_file_item_steal (item, KEY_MENU);
info->langs = moo_key_file_item_steal (item, KEY_LANGS);
position = moo_key_file_item_steal (item, KEY_POSITION);
if (position)
{
if (!g_ascii_strcasecmp (position, "end"))
info->position = MOO_USER_TOOL_POS_END;
else if (!g_ascii_strcasecmp (position, "start"))
info->position = MOO_USER_TOOL_POS_START;
else
g_warning ("unknown position type '%s' for tool %s in file %s",
position, info->name, file);
g_free (position);
}
info->cmd_data = _moo_command_parse_item (item, info->name, file,
&info->cmd_factory,
&info->options);
if (!info->cmd_data)
{
g_warning ("could not get command data for tool '%s' in file %s", info->name, file);
_moo_user_tool_info_unref (info);
return NULL;
}
return info;
}
static GSList *
parse_key_file (MooKeyFile *key_file,
MooUserToolType type,
const char *filename)
{
guint n_items, i;
GSList *list = NULL;
n_items = moo_key_file_n_items (key_file);
for (i = 0; i < n_items; ++i)
{
MooKeyFileItem *item = moo_key_file_nth_item (key_file, i);
MooUserToolInfo *info = parse_item (item, type, filename);
if (info)
list = g_slist_prepend (list, info);
}
return g_slist_reverse (list);
}
static GSList *
parse_file_simple (const char *filename,
MooUserToolType type)
{
MooKeyFile *key_file;
GError *error = NULL;
GSList *list = NULL;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (type < N_TOOLS, NULL);
key_file = moo_key_file_new_from_file (filename, &error);
if (key_file)
{
list = parse_key_file (key_file, type, filename);
moo_key_file_unref (key_file);
}
else
{
g_warning ("could not load file '%s': %s", filename, error->message);
g_error_free (error);
}
return list;
}
static void
parse_file (const char *filename,
MooUserToolType type,
GSList **list,
GHashTable *ids)
{
GSList *new_list;
new_list = parse_file_simple (filename, type);
if (!new_list)
return;
while (new_list)
{
MooUserToolInfo *info, *old_info;
GSList *old_link;
info = new_list->data;
g_return_if_fail (info->id != NULL);
old_link = g_hash_table_lookup (ids, info->id);
old_info = old_link ? old_link->data : NULL;
if (old_link)
{
*list = g_slist_delete_link (*list, old_link);
g_hash_table_remove (ids, info->id);
}
if (info->deleted)
{
_moo_user_tool_info_unref (info);
info = NULL;
}
else if (info->builtin)
{
_moo_user_tool_info_unref (info);
info = old_info ? _moo_user_tool_info_ref (old_info) : NULL;
}
if (info)
{
*list = g_slist_prepend (*list, info);
g_hash_table_insert (ids, g_strdup (info->id), *list);
}
if (old_info)
_moo_user_tool_info_unref (old_info);
new_list = g_slist_delete_link (new_list, new_list);
}
}
static GSList *
parse_user_tools (MooUserToolType type,
GHashTable **ids_p,
gboolean sys_only)
{
char **sys_files, *user_file;
GSList *list = NULL;
GHashTable *ids = NULL;
char **p;
g_return_val_if_fail (type < N_TOOLS, NULL);
_moo_command_init ();
find_user_tools_file (type, &sys_files, &user_file);
ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (p = sys_files; p && *p; ++p)
parse_file (*p, type, &list, ids);
if (!sys_only && user_file)
parse_file (user_file, type, &list, ids);
if (ids_p)
*ids_p = ids;
else
g_hash_table_destroy (ids);
g_strfreev (sys_files);
g_free (user_file);
return g_slist_reverse (list);
}
GSList *
_moo_edit_parse_user_tools (MooUserToolType type)
{
g_return_val_if_fail (type < N_TOOLS, NULL);
return parse_user_tools (type, NULL, FALSE);
}
static void
generate_id (MooUserToolInfo *info,
GHashTable *ids)
{
char *base, *name;
g_return_if_fail (info->id == NULL);
if (info->name)
name = get_name (info->name);
else
name = NULL;
base = g_strdup_printf ("MooUserTool_%s", name ? name : "");
g_strcanon (base, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "_", '_');
if (!g_hash_table_lookup (ids, base))
{
info->id = base;
base = NULL;
}
else
{
guint i = 0;
while (TRUE)
{
char *tmp = g_strdup_printf ("%s_%u", base, i);
if (!g_hash_table_lookup (ids, tmp))
{
info->id = tmp;
break;
}
g_free (tmp);
i += 1;
}
}
g_free (name);
g_free (base);
}
static void
assign_missing_ids (GSList *list)
{
GSList *l;
GHashTable *ids;
ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (l = list; l != NULL; l = l->next)
{
MooUserToolInfo *info = l->data;
if (info->id)
g_hash_table_insert (ids, g_strdup (info->id), l);
}
for (l = list; l != NULL; l = l->next)
{
MooUserToolInfo *info = l->data;
if (!info->id)
{
generate_id (info, ids);
g_hash_table_insert (ids, g_strdup (info->id), l);
}
}
g_hash_table_destroy (ids);
}
static void
add_deleted (const char *id,
GSList *link,
GSList **list)
{
MooUserToolInfo *info;
g_assert (!strcmp (((MooUserToolInfo*)link->data)->id, id));
info = _moo_user_tool_info_new ();
info->id = g_strdup (id);
info->deleted = TRUE;
*list = g_slist_prepend (*list, info);
}
static gboolean
info_equal (MooUserToolInfo *info1,
MooUserToolInfo *info2)
{
if (info1 == info2)
return TRUE;
if (info1->deleted)
return info2->deleted != 0;
if (info1->builtin)
return info2->builtin != 0;
if (!info1->enabled != !info2->enabled)
return FALSE;
return info1->position == info2->position &&
info1->os_type == info2->os_type &&
info1->position == info2->position &&
info1->position == info2->position &&
info1->cmd_factory == info2->cmd_factory &&
_moo_str_equal (info1->name, info2->name) &&
_moo_str_equal (info1->accel, info2->accel) &&
_moo_str_equal (info1->menu, info2->menu) &&
_moo_str_equal (info1->langs, info2->langs) &&
_moo_str_equal (info1->options, info2->options) &&
_moo_command_factory_data_equal (info1->cmd_factory, info1->cmd_data, info2->cmd_data);
}
static GSList *
generate_real_list (MooUserToolType type,
GSList *list)
{
GSList *real_list = NULL;
GSList *sys_list;
GHashTable *sys_ids;
sys_list = parse_user_tools (type, &sys_ids, TRUE);
assign_missing_ids (list);
while (list)
{
MooUserToolInfo *new_info = NULL;
MooUserToolInfo *info = list->data;
GSList *sys_link;
sys_link = g_hash_table_lookup (sys_ids, info->id);
if (sys_link)
{
MooUserToolInfo *sys_info = sys_link->data;
if (info_equal (sys_info, info))
{
new_info = _moo_user_tool_info_new ();
new_info->id = g_strdup (sys_info->id);
new_info->builtin = TRUE;
}
else
{
new_info = _moo_user_tool_info_ref (info);
}
g_hash_table_remove (sys_ids, info->id);
}
else
{
new_info = _moo_user_tool_info_ref (info);
}
real_list = g_slist_prepend (real_list, new_info);
list = list->next;
}
g_hash_table_foreach (sys_ids, (GHFunc) add_deleted, &real_list);
g_hash_table_destroy (sys_ids);
g_slist_foreach (sys_list, (GFunc) _moo_user_tool_info_unref, NULL);
g_slist_free (sys_list);
return g_slist_reverse (real_list);
}
void
_moo_edit_save_user_tools (MooUserToolType type,
GSList *user_list)
{
MooKeyFile *key_file;
GError *error = NULL;
char *string;
GSList *list;
g_return_if_fail (type < N_TOOLS);
key_file = moo_key_file_new ();
list = generate_real_list (type, user_list);
while (list)
{
MooKeyFileItem *item;
MooUserToolInfo *info = list->data;
item = moo_key_file_new_item (key_file, ITEM_TOOL);
moo_key_file_item_set (item, KEY_ID, info->id);
if (info->deleted)
{
moo_key_file_item_set_bool (item, KEY_DELETED, TRUE);
}
else if (info->builtin)
{
moo_key_file_item_set_bool (item, KEY_BUILTIN, TRUE);
}
else
{
if (info->name && info->name[0])
moo_key_file_item_set (item, KEY_NAME, info->name);
if (info->accel && info->accel[0])
moo_key_file_item_set (item, KEY_ACCEL, info->accel);
if (info->menu && info->menu[0])
moo_key_file_item_set (item, KEY_MENU, info->menu);
if (info->langs && info->langs[0])
moo_key_file_item_set (item, KEY_LANGS, info->langs);
if (!info->enabled)
moo_key_file_item_set_bool (item, KEY_ENABLED, info->enabled);
if (info->position != MOO_USER_TOOL_POS_END)
moo_key_file_item_set (item, KEY_POSITION, "start");
_moo_command_format_item (item,
info->cmd_data,
info->cmd_factory,
info->options);
}
_moo_user_tool_info_unref (info);
list = g_slist_delete_link (list, list);
}
string = moo_key_file_format (key_file, "This file is autogenerated, do not edit", 2);
_moo_message ("saving file %s", FILENAMES[type]);
if (!moo_save_user_data_file (FILENAMES[type], string, -1, &error))
{
g_critical ("could not save tools file: %s", error->message);
g_error_free (error);
}
_moo_message ("done");
g_free (string);
moo_key_file_unref (key_file);
}
MooUserToolInfo *
_moo_user_tool_info_new (void)
{
MooUserToolInfo *info = g_new0 (MooUserToolInfo, 1);
info->ref_count = 1;
return info;
}
static MooUserToolInfo *
_moo_user_tool_info_ref (MooUserToolInfo *info)
{
g_return_val_if_fail (info != NULL, NULL);
info->ref_count++;
return info;
}
void
_moo_user_tool_info_unref (MooUserToolInfo *info)
{
g_return_if_fail (info != NULL);
if (--info->ref_count)
return;
g_free (info->id);
g_free (info->name);
g_free (info->accel);
g_free (info->menu);
g_free (info->langs);
g_free (info->options);
g_free (info->file);
if (info->cmd_data)
moo_command_data_unref (info->cmd_data);
g_free (info);
}
GType
_moo_user_tool_info_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (!type))
type = g_boxed_type_register_static ("MooUserToolInfo",
(GBoxedCopyFunc) _moo_user_tool_info_ref,
(GBoxedFreeFunc) _moo_user_tool_info_unref);
return type;
}
static void
moo_tool_action_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
MooToolAction *action = MOO_TOOL_ACTION (object);
switch (property_id)
{
case PROP_COMMAND:
if (action->cmd)
g_object_unref (action->cmd);
action->cmd = g_value_get_object (value);
if (action->cmd)
g_object_ref (action->cmd);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
moo_tool_action_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
MooToolAction *action = MOO_TOOL_ACTION (object);
switch (property_id)
{
case PROP_COMMAND:
g_value_set_object (value, action->cmd);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
moo_tool_action_finalize (GObject *object)
{
MooToolAction *action = MOO_TOOL_ACTION (object);
if (action->cmd)
g_object_unref (action->cmd);
G_OBJECT_CLASS (_moo_tool_action_parent_class)->finalize (object);
}
static void
moo_tool_action_activate (GtkAction *gtkaction)
{
MooEditWindow *window;
MooCommandContext *ctx = NULL;
MooEdit *doc;
MooToolAction *action = MOO_TOOL_ACTION (gtkaction);
MooEditAction *edit_action = MOO_EDIT_ACTION (gtkaction);
g_return_if_fail (action->cmd != NULL);
doc = moo_edit_action_get_doc (edit_action);
if (doc)
{
window = moo_edit_get_window (doc);
}
else
{
window = _moo_action_get_window (action);
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
doc = moo_edit_window_get_active_doc (window);
}
ctx = create_command_context (window, doc);
moo_command_run (action->cmd, ctx);
g_object_unref (ctx);
}
static void
moo_tool_action_check_state (MooEditAction *edit_action)
{
gboolean sensitive;
MooToolAction *action = MOO_TOOL_ACTION (edit_action);
MooEdit *doc;
g_return_if_fail (action->cmd != NULL);
MOO_EDIT_ACTION_CLASS (_moo_tool_action_parent_class)->check_state (edit_action);
if (!gtk_action_is_visible (GTK_ACTION (action)))
return;
doc = moo_edit_action_get_doc (edit_action);
sensitive = moo_command_check_sensitive (action->cmd, doc, moo_edit_get_window (doc));
g_object_set (action, "sensitive", sensitive, NULL);
}
static void
_moo_tool_action_init (G_GNUC_UNUSED MooToolAction *action)
{
}
static void
_moo_tool_action_class_init (MooToolActionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkActionClass *gtkaction_class = GTK_ACTION_CLASS (klass);
MooEditActionClass *action_class = MOO_EDIT_ACTION_CLASS (klass);
object_class->set_property = moo_tool_action_set_property;
object_class->get_property = moo_tool_action_get_property;
object_class->finalize = moo_tool_action_finalize;
gtkaction_class->activate = moo_tool_action_activate;
action_class->check_state = moo_tool_action_check_state;
g_object_class_install_property (object_class, PROP_COMMAND,
g_param_spec_object ("command", "command", "command",
MOO_TYPE_COMMAND,
G_PARAM_READWRITE));
}
static void
get_extension (const char *string,
char **base,
char **ext)
{
char *dot;
g_return_if_fail (string != NULL);
dot = strrchr (string, '.');
if (dot)
{
*base = g_strndup (string, dot - string);
*ext = g_strdup (dot);
}
else
{
*base = g_strdup (string);
*ext = g_strdup ("");
}
}
static MooCommandContext *
create_command_context (gpointer window,
gpointer doc)
{
MooCommandContext *ctx;
char *user_dir;
ctx = moo_command_context_new (doc, window);
if (MOO_IS_EDIT (doc) && !moo_edit_is_untitled (doc))
{
char *filename, *basename;
char *dirname, *base = NULL, *extension = NULL;
filename = moo_edit_get_filename (doc);
basename = filename ? g_path_get_basename (filename) : NULL;
dirname = g_path_get_dirname (filename);
get_extension (basename, &base, &extension);
moo_command_context_set_string (ctx, "DOC", basename);
moo_command_context_set_string (ctx, "DOC_DIR", dirname);
moo_command_context_set_string (ctx, "DOC_BASE", base);
moo_command_context_set_string (ctx, "DOC_EXT", extension);
g_free (dirname);
g_free (base);
g_free (extension);
g_free (basename);
g_free (filename);
}
if (MOO_IS_EDIT (doc))
{
GValue val;
val.g_type = 0;
g_value_init (&val, G_TYPE_INT);
g_value_set_int (&val, moo_text_view_get_cursor_line (doc));
moo_command_context_set (ctx, "LINE0", &val);
g_value_set_int (&val, moo_text_view_get_cursor_line (doc) + 1);
moo_command_context_set (ctx, "LINE", &val);
g_value_unset (&val);
}
user_dir = moo_get_user_data_dir ();
moo_command_context_set_string (ctx, "DATA_DIR", user_dir);
moo_command_context_set_string (ctx, "APP_PID", _moo_get_pid_string ());
/* XXX */
moo_command_context_set_string (ctx, "MEDIT_PID", _moo_get_pid_string ());
g_free (user_dir);
return ctx;
}