medit/moo/mooedit/moousertools.c

573 lines
15 KiB
C
Raw Normal View History

/*
* moousertools.c
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#include "mooedit/moousertools.h"
2006-08-15 22:18:16 -07:00
#include "mooedit/moocommand.h"
#include "mooedit/mooeditwindow.h"
2006-04-20 01:57:05 -07:00
#include "mooedit/mooedit-actions.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooaccel.h"
2006-08-15 22:18:16 -07:00
#include "mooutils/mooi18n.h"
#include "mooutils/mooaction-private.h"
#include <string.h>
2006-08-15 22:18:16 -07:00
#define TOOLS_FILE "tools.xml"
#define MENU_FILE "menu.xml"
enum {
2006-04-20 01:57:05 -07:00
FILE_TOOLS,
2006-08-15 22:18:16 -07:00
FILE_MENU,
N_FILES
};
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
enum {
PROP_0,
PROP_COMMAND
};
typedef struct {
2006-08-15 22:18:16 -07:00
GSList *tools;
} ToolStore;
2006-08-15 22:18:16 -07:00
typedef struct {
char *id;
MooUIXML *xml;
guint merge_id;
2006-08-15 22:18:16 -07:00
} ToolInfo;
2006-08-15 22:18:16 -07:00
typedef struct {
MooEditAction parent;
MooCommand *cmd;
} MooToolAction;
2006-08-15 22:18:16 -07:00
typedef MooEditActionClass MooToolActionClass;
2006-08-15 22:18:16 -07:00
GType _moo_tool_action_get_type (void) G_GNUC_CONST;
G_DEFINE_TYPE (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))
2006-08-15 22:18:16 -07:00
static ToolStore *tools_stores[N_FILES];
2006-08-15 22:18:16 -07:00
static void parse_user_tools (MooMarkupDoc *doc,
MooUIXML *xml,
int type);
static MooCommandContext *create_command_context (gpointer window,
gpointer doc);
static void
unload_user_tools (int type)
{
ToolStore *store = tools_stores[type];
GSList *list;
gpointer klass;
if (!store)
return;
2006-08-15 22:18:16 -07:00
list = store->tools;
store->tools = NULL;
2006-08-15 22:18:16 -07:00
if (type == FILE_MENU)
klass = g_type_class_peek (MOO_TYPE_EDIT_WINDOW);
else
klass = g_type_class_peek (MOO_TYPE_EDIT);
2006-08-15 22:18:16 -07:00
while (list)
{
2006-08-15 22:18:16 -07:00
gpointer klass;
ToolInfo *info = list->data;
list = g_slist_delete_link (list, list);
2006-08-15 22:18:16 -07:00
if (info->xml)
{
moo_ui_xml_remove_ui (info->xml, info->merge_id);
g_object_unref (info->xml);
}
if (type == FILE_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);
}
2006-08-15 22:18:16 -07:00
g_free (store);
tools_stores[type] = NULL;
}
2006-08-15 22:18:16 -07:00
static char *
find_user_tools_file (int type)
2006-04-20 01:57:05 -07:00
{
2006-08-15 22:18:16 -07:00
char **files;
guint n_files;
char *filename = NULL;
int i;
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
files = moo_get_data_files (type == FILE_TOOLS ? TOOLS_FILE : MENU_FILE,
MOO_DATA_SHARE, &n_files);
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
if (!n_files)
return NULL;
for (i = n_files - 1; i >= 0; --i)
{
if (g_file_test (files[i], G_FILE_TEST_EXISTS))
{
filename = g_strdup (files[i]);
break;
}
}
g_strfreev (files);
return filename;
2006-04-20 01:57:05 -07:00
}
static void
2006-08-15 22:18:16 -07:00
load_user_tools (const char *file,
MooUIXML *xml,
int type)
{
2006-08-15 22:18:16 -07:00
MooMarkupDoc *doc;
GError *error = NULL;
char *freeme = NULL;
2006-08-15 22:18:16 -07:00
g_return_if_fail (!xml || MOO_IS_UI_XML (xml));
g_return_if_fail (type < N_FILES);
unload_user_tools (type);
_moo_command_init ();
if (!file)
{
2006-08-15 22:18:16 -07:00
freeme = find_user_tools_file (type);
file = freeme;
}
2006-08-15 22:18:16 -07:00
if (!file)
return;
2006-08-15 22:18:16 -07:00
doc = moo_markup_parse_file (file, &error);
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
if (doc)
{
parse_user_tools (doc, xml, type);
moo_markup_doc_unref (doc);
}
else
{
g_warning ("could not load file '%s': %s", file, error->message);
g_error_free (error);
}
2006-08-15 22:18:16 -07:00
g_free (freeme);
}
void
2006-08-15 22:18:16 -07:00
moo_edit_load_user_tools (const char *file,
MooUIXML *xml)
{
2006-08-15 22:18:16 -07:00
return load_user_tools (file, xml, FILE_TOOLS);
}
void
2006-08-15 22:18:16 -07:00
moo_edit_load_user_menu (const char *file,
MooUIXML *xml)
{
2006-08-15 22:18:16 -07:00
return load_user_tools (file, xml, FILE_MENU);
}
2006-08-15 22:18:16 -07:00
static gboolean
check_sensitive_func (GtkAction *gtkaction,
MooEditWindow *window,
MooEdit *doc,
G_GNUC_UNUSED gpointer data)
{
2006-08-15 22:18:16 -07:00
MooToolAction *action;
2006-08-15 22:18:16 -07:00
g_return_val_if_fail (MOO_IS_TOOL_ACTION (gtkaction), FALSE);
action = MOO_TOOL_ACTION (gtkaction);
2006-08-15 22:18:16 -07:00
return moo_command_check_sensitive (action->cmd, doc, window);
}
2006-08-15 22:18:16 -07:00
static void
parse_element (MooMarkupNode *node,
MooUIXML *xml,
int type,
const char *file)
{
2006-08-15 22:18:16 -07:00
const char *os, *id;
const char *position = NULL, *name = NULL, *label = NULL;
const char *accel = NULL, *menu = NULL, *langs = NULL;
MooMarkupNode *cmd_node, *child;
MooCommand *cmd;
2006-08-15 22:18:16 -07:00
gboolean enabled;
ToolStore **store;
ToolInfo *tool_info;
gpointer klass = NULL;
2006-08-15 22:18:16 -07:00
if (strcmp (node->name, "tool"))
{
2006-08-15 22:18:16 -07:00
g_warning ("invalid element %s in file %s", node->name, file);
return;
}
2006-08-15 22:18:16 -07:00
id = moo_markup_get_prop (node, "id");
2006-08-15 22:18:16 -07:00
if (!id || !id[0])
{
g_warning ("tool id attribute missing in file %s", file);
return;
}
2006-08-15 22:18:16 -07:00
enabled = moo_markup_get_bool_prop (node, "enabled", TRUE);
os = moo_markup_get_prop (node, "os");
position = moo_markup_get_prop (node, "position");
2006-04-20 12:13:42 -07:00
2006-05-01 01:35:41 -07:00
if (!enabled)
return;
2006-04-20 12:13:42 -07:00
if (os)
{
#ifdef __WIN32__
2006-08-15 22:18:16 -07:00
if (g_ascii_strncasecmp (os, "win", 3);
2006-04-20 12:13:42 -07:00
return;
#else
2006-08-15 22:18:16 -07:00
if (g_ascii_strcasecmp (os, "unix"))
2006-04-20 12:13:42 -07:00
return;
#endif
2006-08-15 22:18:16 -07:00
}
for (child = node->children; child != NULL; child = child->next)
{
if (!MOO_MARKUP_IS_ELEMENT (child) || !strcmp (child->name, "command"))
continue;
if (!strcmp (child->name, "name"))
name = moo_markup_get_content (child);
else if (!strcmp (child->name, "_name"))
name = _(moo_markup_get_content (child));
else if (!strcmp (child->name, "label"))
label = moo_markup_get_content (child);
else if (!strcmp (child->name, "_label"))
label = _(moo_markup_get_content (child));
else if (!strcmp (child->name, "accel"))
accel = moo_markup_get_content (child);
else if (!strcmp (child->name, "position"))
position = moo_markup_get_content (child);
else if (!strcmp (child->name, "menu"))
menu = moo_markup_get_content (child);
else if (!strcmp (child->name, "langs"))
langs = moo_markup_get_content (child);
else
g_warning ("unknown element %s in tool %s in file %s",
child->name, id, file);
}
2006-04-20 12:13:42 -07:00
2006-08-15 22:18:16 -07:00
if (!name)
{
g_warning ("name missing for tool '%s' in file %s", id, file);
return;
2006-04-20 12:13:42 -07:00
}
2006-08-15 22:18:16 -07:00
if (!label)
label = name;
cmd_node = moo_markup_get_element (node, "command");
2006-08-15 22:18:16 -07:00
if (!cmd_node)
{
g_warning ("command missing for tool '%s' in file %s", id, file);
return;
}
2006-08-15 22:18:16 -07:00
cmd = _moo_command_parse_markup (cmd_node);
2006-08-15 22:18:16 -07:00
if (!cmd)
{
g_warning ("could not get command for tool '%s' in file %s", id, file);
return;
}
2006-04-20 01:57:05 -07:00
switch (type)
{
case FILE_TOOLS:
klass = g_type_class_peek (MOO_TYPE_EDIT_WINDOW);
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
if (!moo_window_class_find_group (klass, "Tools"))
moo_window_class_new_group (klass, "Tools", _("Tools"));
moo_window_class_new_action (klass, id, "Tools",
"action-type::", MOO_TYPE_TOOL_ACTION,
"display-name", name,
"label", label,
"accel", accel,
"command", cmd,
NULL);
moo_edit_window_set_action_check (id, MOO_ACTION_CHECK_SENSITIVE,
check_sensitive_func,
NULL, NULL);
if (langs)
moo_edit_window_set_action_langs (id, MOO_ACTION_CHECK_ACTIVE, langs);
2006-04-20 01:57:05 -07:00
break;
case FILE_MENU:
klass = g_type_class_peek (MOO_TYPE_EDIT);
2006-08-15 22:18:16 -07:00
moo_edit_class_new_action (klass, id,
"action-type::", MOO_TYPE_TOOL_ACTION,
"display-name", name,
"label", label,
"accel", accel,
"command", cmd,
"langs", langs,
NULL);
2006-04-20 01:57:05 -07:00
break;
}
2006-08-15 22:18:16 -07:00
tool_info = g_new0 (ToolInfo, 1);
tool_info->id = g_strdup (id);
store = &tools_stores[type];
if (!*store)
*store = g_new (ToolStore, 1);
(*store)->tools = g_slist_prepend ((*store)->tools, tool_info);
if (xml)
{
const char *ui_path;
char *freeme = NULL;
char *markup;
2006-08-15 22:18:16 -07:00
markup = g_markup_printf_escaped ("<item action=\"%s\"/>", id);
tool_info->xml = g_object_ref (xml);
tool_info->merge_id = moo_ui_xml_new_merge_id (xml);
2006-04-20 01:57:05 -07:00
if (type == FILE_MENU)
{
ui_path = "Editor/Popup/PopupEnd";
2006-08-15 22:18:16 -07:00
if (position)
2006-04-20 01:57:05 -07:00
{
2006-08-15 22:18:16 -07:00
if (!g_ascii_strcasecmp (position, "end"))
ui_path = "Editor/Popup/PopupEnd";
2006-08-15 22:18:16 -07:00
else if (!g_ascii_strcasecmp (position, "start"))
ui_path = "Editor/Popup/PopupStart";
2006-04-20 15:58:25 -07:00
else
2006-08-15 22:18:16 -07:00
g_warning ("unknown position type '%s' for tool %s in file %s",
position, id, file);
2006-04-20 01:57:05 -07:00
}
}
else
{
freeme = g_strdup_printf ("Editor/Menubar/%s/UserMenu",
menu ? menu : "Tools");
ui_path = freeme;
2006-04-20 01:57:05 -07:00
}
2006-08-15 22:18:16 -07:00
moo_ui_xml_insert_markup (xml, tool_info->merge_id, ui_path, -1, markup);
g_free (markup);
g_free (freeme);
}
2006-08-15 22:18:16 -07:00
g_object_unref (cmd);
}
2006-08-15 22:18:16 -07:00
static void
parse_user_tools (MooMarkupDoc *doc,
MooUIXML *xml,
int type)
{
2006-08-15 22:18:16 -07:00
MooMarkupNode *root, *child;
2006-08-15 22:18:16 -07:00
root = moo_markup_get_root_element (doc, "tools");
2006-08-15 22:18:16 -07:00
if (!root)
2006-04-20 01:57:05 -07:00
{
2006-08-15 22:18:16 -07:00
g_warning ("no 'tools' element in file '%s'", doc->name);
return;
2006-04-20 01:57:05 -07:00
}
2006-08-15 22:18:16 -07:00
for (child = root->children; child != NULL; child = child->next)
{
2006-08-15 22:18:16 -07:00
if (MOO_MARKUP_IS_ELEMENT (child))
parse_element (child, xml, type, doc->name);
}
}
static void
2006-08-15 22:18:16 -07:00
moo_tool_action_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
2006-08-15 22:18:16 -07:00
MooToolAction *action = MOO_TOOL_ACTION (object);
2006-08-15 22:18:16 -07:00
switch (property_id)
{
2006-08-15 22:18:16 -07:00
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;
2006-08-15 22:18:16 -07:00
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
2006-04-20 01:57:05 -07:00
static void
2006-08-15 22:18:16 -07:00
moo_tool_action_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
2006-04-20 01:57:05 -07:00
{
2006-08-15 22:18:16 -07:00
MooToolAction *action = MOO_TOOL_ACTION (object);
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
switch (property_id)
2006-04-20 01:57:05 -07:00
{
2006-08-15 22:18:16 -07:00
case PROP_COMMAND:
g_value_set_object (value, action->cmd);
break;
2006-04-20 01:57:05 -07:00
2006-08-15 22:18:16 -07:00
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
2006-04-20 01:57:05 -07:00
}
2006-08-15 22:18:16 -07:00
static void
moo_tool_action_finalize (GObject *object)
2006-04-16 20:06:13 -07:00
{
2006-08-15 22:18:16 -07:00
MooToolAction *action = MOO_TOOL_ACTION (object);
2006-04-16 20:06:13 -07:00
2006-08-15 22:18:16 -07:00
if (action->cmd)
g_object_unref (action->cmd);
2006-08-15 22:18:16 -07:00
G_OBJECT_CLASS (_moo_tool_action_parent_class)->finalize (object);
2006-04-16 20:06:13 -07:00
}
static void
2006-08-15 22:18:16 -07:00
moo_tool_action_activate (GtkAction *gtkaction)
{
2006-08-15 22:18:16 -07:00
MooEditWindow *window;
MooCommandContext *ctx = NULL;
MooEdit *doc;
2006-08-15 22:18:16 -07:00
MooToolAction *action = MOO_TOOL_ACTION (gtkaction);
MooEditAction *edit_action = MOO_EDIT_ACTION (gtkaction);
2006-08-15 22:18:16 -07:00
g_return_if_fail (action->cmd != NULL);
2006-04-16 20:06:13 -07:00
2006-08-15 22:18:16 -07:00
if (edit_action->doc)
{
doc = edit_action->doc;
window = moo_edit_get_window (doc);
}
else
{
2006-08-15 22:18:16 -07:00
window = _moo_action_get_window (action);
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
doc = moo_edit_window_get_active_doc (window);
}
2006-08-15 22:18:16 -07:00
ctx = create_command_context (window, doc);
2006-04-16 20:06:13 -07:00
2006-08-15 22:18:16 -07:00
moo_command_run (action->cmd, ctx);
2006-08-15 22:18:16 -07:00
g_object_unref (ctx);
}
2006-08-15 22:18:16 -07:00
static void
2006-08-15 22:18:16 -07:00
moo_tool_action_check_state (MooEditAction *edit_action)
{
2006-08-15 22:18:16 -07:00
gboolean sensitive;
MooToolAction *action = MOO_TOOL_ACTION (edit_action);
2006-08-15 22:18:16 -07:00
g_return_if_fail (action->cmd != NULL);
2006-08-15 22:18:16 -07:00
MOO_EDIT_ACTION_CLASS (_moo_tool_action_parent_class)->check_state (edit_action);
2006-08-15 22:18:16 -07:00
if (!gtk_action_is_visible (GTK_ACTION (action)))
return;
2006-08-15 22:18:16 -07:00
sensitive = moo_command_check_sensitive (action->cmd,
edit_action->doc,
moo_edit_get_window (edit_action->doc));
2006-08-15 22:18:16 -07:00
g_object_set (action, "sensitive", sensitive, NULL);
}
2006-08-15 22:18:16 -07:00
static void
_moo_tool_action_init (G_GNUC_UNUSED MooToolAction *action)
2006-04-20 01:57:05 -07:00
{
}
static void
2006-08-15 22:18:16 -07:00
_moo_tool_action_class_init (MooToolActionClass *klass)
{
2006-08-15 22:18:16 -07:00
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));
}
2006-08-15 22:18:16 -07:00
static MooCommandContext *
create_command_context (gpointer window,
gpointer doc)
{
2006-08-15 22:18:16 -07:00
MooCommandContext *ctx;
2006-08-15 22:18:16 -07:00
ctx = moo_command_context_new (doc, window);
2006-08-15 22:18:16 -07:00
return ctx;
}