/* * Copyright (C) 2007 OpenedHand Ltd * * 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 Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "koto-undo-action.h" /* this is defined in glib 2.14 */ #ifndef G_PARAM_STATIC_STRINGS #define G_PARAM_STATIC_STRINGS (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB) #endif G_DEFINE_TYPE (KotoUndoAction, koto_undo_action, GTK_TYPE_ACTION); #define GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ KOTO_TYPE_UNDO_ACTION, \ KotoUndoActionPrivate)) typedef void (*ChangedHandler) (KotoUndoManager *manager, gpointer user_data); typedef struct { gboolean undo; /* TRUE for undo, FALSE for redo */ ChangedHandler handler; /* Handler to invoke on manager state change */ KotoUndoManager *manager; guint changed_id; } KotoUndoActionPrivate; enum { PROP_0, PROP_UNDO, PROP_MANAGER, }; static void on_manager_changed_undo (KotoUndoManager *manager, gpointer user_data) { GtkAction *action = GTK_ACTION (user_data); char *label; if (koto_undo_manager_can_undo (manager)) { label = g_strdup_printf (_("Undo %s"), koto_undo_manager_get_undo_name (manager)); g_object_set (action, "sensitive", TRUE, "label", label, NULL); g_free (label); } else { g_object_set (action, "sensitive", FALSE, "label", _("Undo"), NULL); } } static void on_manager_changed_redo (KotoUndoManager *manager, gpointer user_data) { GtkAction *action = GTK_ACTION (user_data); char *label; if (koto_undo_manager_can_redo (manager)) { label = g_strdup_printf (_("Redo %s"), koto_undo_manager_get_redo_name (manager)); g_object_set (action, "sensitive", TRUE, "label", label, NULL); g_free (label); } else { g_object_set (action, "sensitive", FALSE, "label", _("Redo"), NULL); } } static void koto_undo_action_activate (GtkAction *action) { KotoUndoActionPrivate *priv = GET_PRIVATE (action); if (priv->undo) { koto_undo_manager_undo (priv->manager); } else { koto_undo_manager_redo (priv->manager); } } static void koto_undo_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { KotoUndoActionPrivate *priv = GET_PRIVATE (gobject); switch (prop_id) { case PROP_UNDO: priv->undo = g_value_get_boolean (value); priv->handler = priv->undo ? on_manager_changed_undo : on_manager_changed_redo; break; case PROP_MANAGER: if (priv->manager) { g_signal_handler_disconnect (priv->manager, priv->changed_id); g_object_unref (priv->manager); } priv->manager = g_value_dup_object (value); priv->changed_id = g_signal_connect (priv->manager, "changed", G_CALLBACK (priv->handler), gobject); /* Update the state */ priv->handler (priv->manager, gobject); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); return; } } static void koto_undo_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { KotoUndoActionPrivate *priv = GET_PRIVATE (gobject); switch (prop_id) { case PROP_UNDO: g_value_set_boolean (value, priv->undo); break; case PROP_MANAGER: g_value_set_object (value, priv->manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); return; } } static void koto_undo_action_dispose (GObject *gobject) { KotoUndoActionPrivate *priv = GET_PRIVATE (gobject); if (priv->manager) { g_signal_handler_disconnect (priv->manager, priv->changed_id); g_object_unref (priv->manager); priv->manager = NULL; } G_OBJECT_CLASS (koto_undo_action_parent_class)->dispose (gobject); } static void koto_undo_action_class_init (KotoUndoActionClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkActionClass *action_class = GTK_ACTION_CLASS (klass); g_type_class_add_private (klass, sizeof (KotoUndoActionPrivate)); gobject_class->dispose = koto_undo_action_dispose; gobject_class->set_property = koto_undo_action_set_property; gobject_class->get_property = koto_undo_action_get_property; action_class->activate = koto_undo_action_activate; g_object_class_install_property (gobject_class, PROP_UNDO, g_param_spec_boolean ("undo", "undo", "TRUE for undo, FALSE for redo", TRUE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MANAGER, g_param_spec_object ("manager", "manager", "Undo manager", KOTO_TYPE_UNDO_MANAGER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void koto_undo_action_init (KotoUndoAction *action) { /* TODO: set stock-id in a constructor */ } GtkAction * koto_undo_action_new (const char *name, KotoUndoManager *undo_manager) { g_return_val_if_fail (KOTO_IS_UNDO_MANAGER (undo_manager), NULL); return g_object_new (KOTO_TYPE_UNDO_ACTION, "name", name, "manager", undo_manager, "undo", TRUE, "stock-id", GTK_STOCK_UNDO, NULL); } GtkAction * koto_undo_action_new_redo (const char *name, KotoUndoManager *undo_manager) { g_return_val_if_fail (KOTO_IS_UNDO_MANAGER (undo_manager), NULL); return g_object_new (KOTO_TYPE_UNDO_ACTION, "name", name, "manager", undo_manager, "undo", FALSE, "stock-id", GTK_STOCK_REDO, NULL); }