/* dia-undo_manager.c * Copyright (C) 2003 Arjan Molenaar * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "dia-undo-manager.h" #include "diamarshal.h" #include "../config.h" /** * dia_undo_action_new: * @sizeof_undo_action: Size of the real undo entry * @undo: function called on an undo operation * @redo: function called in a redo operation * @destroy: function called to free the resources held by this undo entry * * Create a new DiaUndoAction. DiaUndoAction is the object that is passed to * the UndoManager. This "class" is normally subclassed, so specific attributes * can be stored (this struct is an "abstract class"). * * Return value: **/ DiaUndoAction* dia_undo_action_new (gsize sizeof_undo_action, DiaUndoFunc undo, DiaUndoFunc redo, GDestroyNotify destroy) { DiaUndoAction *entry; g_return_val_if_fail (sizeof_undo_action >= sizeof(DiaUndoAction), NULL); entry = g_malloc0 (sizeof_undo_action); entry->undo = undo; entry->redo = redo; entry->destroy = destroy; return entry; } void dia_undo_action_undo (DiaUndoAction *entry) { g_return_if_fail (entry != NULL); if (entry->undo) entry->undo (entry); } void dia_undo_action_redo (DiaUndoAction *entry) { g_return_if_fail (entry != NULL); if (entry->redo) entry->redo (entry); } void dia_undo_action_destroy (DiaUndoAction *entry) { g_return_if_fail (entry != NULL); if (entry->destroy) entry->destroy (entry); g_free (entry); } enum { BEGIN_TRANSACTION, COMMIT_TRANSACTION, DISCARD_TRANSACTION, ADD_UNDO_ACTION, UNDO_TRANSACTION, REDO_TRANSACTION, CLEAR_UNDO_STACK, CLEAR_REDO_STACK, LAST_SIGNAL }; static void dia_undo_manager_base_init (gpointer klass); static guint undo_manager_signals[LAST_SIGNAL] = { 0 }; GType dia_undo_manager_get_type (void) { static GType undo_manager_type = 0; if (!undo_manager_type) { static const GTypeInfo undo_manager_info = { sizeof (DiaUndoManagerIface), /* class_size */ dia_undo_manager_base_init, /* base_init */ NULL, /* base_finalize */ NULL, NULL, /* class_finalize */ NULL, /* class_data */ 0, 0, /* n_preallocs */ NULL }; undo_manager_type = g_type_register_static (G_TYPE_INTERFACE, "DiaUndoManager", &undo_manager_info, 0); g_type_interface_add_prerequisite (undo_manager_type, G_TYPE_OBJECT); } return undo_manager_type; } static void dia_undo_manager_base_init (gpointer iface) { static gboolean initialized = FALSE; if (!initialized) { undo_manager_signals[BEGIN_TRANSACTION] = g_signal_new ("begin_transaction", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DiaUndoManagerIface, begin_transaction), NULL, NULL, dia_marshal_VOID__VOID, G_TYPE_NONE, 0); undo_manager_signals[COMMIT_TRANSACTION] = g_signal_new ("commit_transaction", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DiaUndoManagerIface, commit_transaction), NULL, NULL, dia_marshal_VOID__VOID, G_TYPE_NONE, 0); undo_manager_signals[DISCARD_TRANSACTION] = g_signal_new ("discard_transaction", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DiaUndoManagerIface, discard_transaction), NULL, NULL, dia_marshal_VOID__VOID, G_TYPE_NONE, 0); undo_manager_signals[ADD_UNDO_ACTION] = g_signal_new ("add_undo_action", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DiaUndoManagerIface, add_undo_action), NULL, NULL, dia_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); undo_manager_signals[UNDO_TRANSACTION] = g_signal_new ("undo_transaction", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DiaUndoManagerIface, undo_transaction), NULL, NULL, dia_marshal_VOID__VOID, G_TYPE_NONE, 0); undo_manager_signals[REDO_TRANSACTION] = g_signal_new ("redo_transaction", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (DiaUndoManagerIface, redo_transaction), NULL, NULL, dia_marshal_VOID__VOID, G_TYPE_NONE, 0); initialized = TRUE; } } /** * dia_undo_manager_in_transaction: * @undo_manager: * * This function returns TRUE if there is an open transaction. * * Return value: **/ gboolean dia_undo_manager_in_transaction (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); if (!DIA_UNDO_MANAGER_GET_IFACE (undo_manager)->in_transaction) return FALSE; return DIA_UNDO_MANAGER_GET_IFACE (undo_manager)->in_transaction (undo_manager); } /** * dia_undo_manager_can_undo: * @undo_manager: * * * * Return value: TRUE if there are transactions that can be undone. **/ gboolean dia_undo_manager_can_undo (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); if (!DIA_UNDO_MANAGER_GET_IFACE (undo_manager)->can_undo) return FALSE; return DIA_UNDO_MANAGER_GET_IFACE (undo_manager)->can_undo (undo_manager); } /** * dia_undo_manager_can_redo: * @undo_manager: * * * * Return value: TRUE if there are transactions that can be redone. **/ gboolean dia_undo_manager_can_redo (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); if (!DIA_UNDO_MANAGER_GET_IFACE (undo_manager)->can_redo) return FALSE; return DIA_UNDO_MANAGER_GET_IFACE (undo_manager)->can_redo (undo_manager); } /** * dia_undo_manager_begin_transaction: * @undo_manager: * * Begin a new transaction. **/ void dia_undo_manager_begin_transaction (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); g_signal_emit (undo_manager, undo_manager_signals[BEGIN_TRANSACTION], 0); } /** * dia_undo_manager_commit_transaction: * @undo_manager: * * Store the transaction on the undo stack. If there are no actions to be * undone, a specific implementation may consider no storing it. **/ void dia_undo_manager_commit_transaction (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); g_signal_emit (undo_manager, undo_manager_signals[COMMIT_TRANSACTION], 0); } /** * dia_undo_manager_discard_transaction: * @undo_manager: * * Discard the current transaction. It is not stored on the undo stack. **/ void dia_undo_manager_discard_transaction (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); g_signal_emit (undo_manager, undo_manager_signals[DISCARD_TRANSACTION], 0); } /** * dia_undo_manager_add_undo_action: * @undo_manager: * @entry: * * Add an entry to the current transaction. A transaction should have been * started by calling dia_undo_manager_begin_transaction(). **/ void dia_undo_manager_add_undo_action (DiaUndoManager *undo_manager, DiaUndoAction *entry) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); g_signal_emit (undo_manager, undo_manager_signals[ADD_UNDO_ACTION], 0, entry); } /** * dia_undo_manager_undo_transaction: * @undo_manager: * * Undo the actions in the last commited transaction. **/ void dia_undo_manager_undo_transaction (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); g_signal_emit (undo_manager, undo_manager_signals[UNDO_TRANSACTION], 0); } void dia_undo_manager_redo_transaction (DiaUndoManager *undo_manager) { g_return_if_fail (DIA_IS_UNDO_MANAGER (undo_manager)); g_signal_emit (undo_manager, undo_manager_signals[REDO_TRANSACTION], 0); }