Commit 3ada85db authored by Gene Z. Ragan's avatar Gene Z. Ragan Committed by Gene Ragan

libnautilus-extensions/nautilus-undoable.c

2000-04-27  Gene Z. Ragan  <gzr@eazel.com>

	* libnautilus-extensions/nautilus-undoable.c
	* libnautilus-extensions/nautilus-undoable.h
	* libnautilus-extensions/nautilus-undo-manager.c
	* libnautilus-extensions/nautilus-undo-manager.h
	* libnautilus-extensions/nautilus-undo-transaction.c
	* libnautilus-extensions/nautilus-undo-transaction.h
	* libnautilus-extensions/nautilus-undo-manager-private.h
	Added architecture for undo mechanism.
	NautilusUndoManager maintains undo and redo queues of NautilusUndoTransactions
	as well as maintaining various state information pertinant to the user interface.
	NautilusUndoTransaction contains a transaction name and a list of NautilusUndoables.
	NautilusUndoable is a object that contains a pointer to an object and a GData object.
	The GData object contains named data that can be added and retrieved during an undo/
	redo operation.  The NautilusUndoable also emits signals to the object that enables it
	to perform the undo and redo operations.  I will write up more complete documents when the
	code has matured.

	* libnautilus-extensions/nautilus-icon-container.c
	* libnautilus-extensions/nautilus-icon-container.h
	* src/file-manager/fm-icon-view.c
	Removed obsolete undo functions and callbacks.  These were invalidated
	by the new undo mechanism.

	* src/ntl-main.c
	Added call to nautilus_undo_manager_initialize_global_manager() in main.
	This call initializes a Nautilus global undo manager.
	Also fixed some minor coding style issues.

	* nautilus-window-menus.c
	edit_menu_undo_callback():
	Added callback to handle selection of Undo item form edit menu.  Callback
	checks with Undo Manager for a current undo transaction and asks manager to
	perform an undo if there is one.
parent 6397f17c
2000-04-27 Gene Z. Ragan <gzr@eazel.com>
* libnautilus-extensions/nautilus-undoable.c
* libnautilus-extensions/nautilus-undoable.h
* libnautilus-extensions/nautilus-undo-manager.c
* libnautilus-extensions/nautilus-undo-manager.h
* libnautilus-extensions/nautilus-undo-transaction.c
* libnautilus-extensions/nautilus-undo-transaction.h
* libnautilus-extensions/nautilus-undo-manager-private.h
Added architecture for undo mechanism.
NautilusUndoManager maintains undo and redo queues of NautilusUndoTransactions
as well as maintaining various state information pertinant to the user interface.
NautilusUndoTransaction contains a transaction name and a list of NautilusUndoables.
NautilusUndoable is a object that contains a pointer to an object and a GData object.
The GData object contains named data that can be added and retrieved during an undo/
redo operation. The NautilusUndoable also emits signals to the object that enables it
to perform the undo and redo operations. I will write up more complete documents when the
code has matured.
* libnautilus-extensions/nautilus-icon-container.c
* libnautilus-extensions/nautilus-icon-container.h
* src/file-manager/fm-icon-view.c
Removed obsolete undo functions and callbacks. These were invalidated
by the new undo mechanism.
* src/ntl-main.c
Added call to nautilus_undo_manager_initialize_global_manager() in main.
This call initializes a Nautilus global undo manager.
Also fixed some minor coding style issues.
* nautilus-window-menus.c
edit_menu_undo_callback():
Added callback to handle selection of Undo item form edit menu. Callback
checks with Undo Manager for a current undo transaction and asks manager to
perform an undo if there is one.
2000-04-27 Darin Adler <darin@eazel.com>
* MAINTAINERS: Changed to the new Nautilus list instead of the
......
......@@ -64,6 +64,9 @@ libnautilus_extensionsinclude_HEADERS= \
nautilus-self-checks.h \
nautilus-string-list.h \
nautilus-string.h \
nautilus-undo-manager.h \
nautilus-undo-transaction.h \
nautilus-undoable.c \
nautilus-xml-extensions.h \
$(NULL)
......@@ -110,6 +113,9 @@ libnautilus_extensions_la_SOURCES = \
nautilus-self-checks.c \
nautilus-string-list.c \
nautilus-string.c \
nautilus-undo-manager.c \
nautilus-undo-transaction.c \
nautilus-undoable.c \
nautilus-xml-extensions.c \
$(fsextension_idl_sources) \
$(NULL)
......
......@@ -3087,52 +3087,6 @@ nautilus_self_check_compute_stretch (int icon_x, int icon_y, int icon_size,
current.icon_size);
}
/**
* rename_text_dirty
* @container: An icon container widget.
*
* Check and see if a rename edit has modified the icon tect item text
**/
static gboolean
rename_text_dirty(NautilusIconContainer *container)
{
char *edit_text;
if (!container->details->renaming)
return FALSE;
if (container->details->original_text == NULL)
return FALSE;
edit_text = nautilus_icon_text_item_get_text (container->details->rename_widget);
if (g_strcasecmp(container->details->original_text, edit_text) == 0)
return FALSE;
return TRUE;
}
/**
* text_edited_callback
* @container: An icon container widget.
*
* Signal callback connected to icon text widget. Callback is called
* on any edit event. This may be just the movement of the i-beam
* or an actual change of the text. If the text has changed, we need
* to fire the signal to allow the undo menu to be enabled.
**/
static void
text_edited_callback(NautilusIconTextItem *item, NautilusIconContainer *container)
{
/* Check and see if we need to update our dirty flag */
if (rename_text_dirty(container) && !container->details->renaming_is_dirty) {
container->details->renaming_is_dirty = TRUE;
gtk_signal_emit (GTK_OBJECT (container), signals[ICON_TEXT_EDIT_OCCURRED]);
}
}
/**
* nautilus_icon_container_is_renaming
* @container: An icon container widget.
......@@ -3146,23 +3100,6 @@ nautilus_icon_container_is_renaming (NautilusIconContainer *container)
return container->details->renaming;
}
/**
* nautilus_icon_container_is_renaming_is_dirty
* @container: An icon container widget.
*
* Returns true if container is in renaming mode
**/
gboolean
nautilus_icon_container_is_renaming_is_dirty (NautilusIconContainer *container)
{
if (!container->details->renaming)
return FALSE;
return container->details->renaming_is_dirty;
}
/**
* nautilus_icon_container_start_renaming_selected_item
* @container: An icon container widget.
......@@ -3230,9 +3167,6 @@ nautilus_icon_container_start_renaming_selected_item (NautilusIconContainer *con
1); /* allocate local copy */
/* Set up the signals */
gtk_signal_connect (GTK_OBJECT (details->rename_widget), "text_edited",
GTK_SIGNAL_FUNC (text_edited_callback),
container);
gtk_signal_connect (GTK_OBJECT (details->rename_widget), "editing_started",
GTK_SIGNAL_FUNC (editing_started),
container);
......@@ -3246,28 +3180,10 @@ nautilus_icon_container_start_renaming_selected_item (NautilusIconContainer *con
/* We are in renaming mode */
details->renaming = TRUE;
/* The text is not dirty yet */
details->renaming_is_dirty = FALSE;
nautilus_icon_canvas_item_set_renaming (icon->item, details->renaming);
}
/**
* nautilus_icon_container_undo_renaming_selected_item
* @container: An icon container widget.
*
* Undo renaming operation on item being renamed
**/
void
nautilus_icon_container_undo_renaming_selected_item (NautilusIconContainer *container)
{
nautilus_icon_text_item_set_text (container->details->rename_widget,
container->details->original_text);
}
static void
end_renaming_mode (NautilusIconContainer *container, gboolean commit)
{
......@@ -3311,7 +3227,6 @@ hide_rename_widget (NautilusIconContainer *container, NautilusIcon *icon)
/* We are not in renaming mode */
container->details->renaming = FALSE;
container->details->renaming_is_dirty = FALSE;
nautilus_icon_canvas_item_set_renaming (icon->item, container->details->renaming);
}
......
......@@ -145,8 +145,6 @@ void nautilus_icon_container_show_stretch_handles (NautilusIconContaine
void nautilus_icon_container_unstretch (NautilusIconContainer *container);
void nautilus_icon_container_start_renaming_selected_item (NautilusIconContainer *container);
gboolean nautilus_icon_container_is_renaming (NautilusIconContainer *container);
gboolean nautilus_icon_container_is_renaming_is_dirty (NautilusIconContainer *container);
void nautilus_icon_container_undo_renaming_selected_item (NautilusIconContainer *container);
/* options */
int nautilus_icon_container_get_zoom_level (NautilusIconContainer *view);
......
......@@ -134,7 +134,6 @@ struct NautilusIconContainerDetails {
/* Renaming Details */
gboolean renaming;
gboolean renaming_is_dirty;
NautilusIconTextItem *rename_widget; /* Editable text item */
gchar *original_text; /* Copy of editable text for later compare */
......
......@@ -11,7 +11,9 @@
#include <config.h>
#include "nautilus-icon-text-item.h"
#include "nautilus-entry.h"
#include "nautilus-undo-manager.h"
#include <math.h>
#include <stdio.h>
......@@ -38,6 +40,11 @@
typedef NautilusIconTextItem Iti;
/* Signal callbacks */
static void save_undo_snapshot_callback (NautilusUndoable *object);
static void restore_from_undo_snapshot_callback(NautilusUndoable *object);
/* Private part of the NautilusIconTextItem structure */
typedef struct {
/* Font */
......@@ -725,6 +732,88 @@ iti_selection_motion (Iti *iti, int idx)
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti));
}
/* Position insertion point based on arrow key event */
static void
iti_handle_arrow_key_event (NautilusIconTextItem *iti, GdkEvent *event)
{
ItiPrivate *priv;
GnomeIconTextInfoRow *row;
GList *list;
GtkEditable *editable;
int index, lines, line;
int position, pos_count, new_position;
int cur_count, prev_count, next_count;
float scale;
/* Get number of lines. Do nothing if we have only one line */
lines = g_list_length (iti->ti->rows);
if (lines <= 1) {
return;
}
/* Figure out which line the current insertion point is on */
priv = iti->priv;
editable = GTK_EDITABLE (priv->entry);
pos_count = position = gtk_editable_get_position (editable);
for (list = iti->ti->rows, line = -1, index = 1; index <= lines; index++) {
if (list != NULL) {
row = list->data;
if (pos_count > row->text_length) {
list = list->next;
pos_count -= row->text_length;
}
else {
line = index;
break;
}
}
}
/* Calculate new position of insertion point */
switch (event->key.keyval) {
case GDK_Up:
/* Try to set insertion point to previous line */
if (line > 1) {
list = g_list_nth(iti->ti->rows, line - 1);
row = list->data;
cur_count = row->text_length;
list = g_list_nth(iti->ti->rows, line - 2);
row = list->data;
prev_count = row->text_length;
scale = (float)prev_count / (float)cur_count;
new_position = pos_count * scale;
position -= prev_count + pos_count;
position += new_position;
gtk_editable_set_position (editable, position);
}
break;
case GDK_Down:
/* Try to set insertion point to next line */
if (line < lines) {
int new_position;
list = g_list_nth(iti->ti->rows, line - 1);
row = list->data;
cur_count = row->text_length;
list = g_list_nth(iti->ti->rows, line);
row = list->data;
next_count = row->text_length;
scale = (float)next_count / (float)cur_count;
new_position = pos_count * scale;
new_position += (position + (cur_count - pos_count));
gtk_editable_set_position (editable, new_position);
}
break;
default:
break;
}
}
/* Event handler for icon text items */
static gint
iti_event (GnomeCanvasItem *item, GdkEvent *event)
......@@ -750,18 +839,26 @@ iti_event (GnomeCanvasItem *item, GdkEvent *event)
case GDK_Return:
case GDK_KP_Enter:
return FALSE;
/* Handle up and down arrow keys. GdkEntry does not know
* how to handle multi line items */
case GDK_Up:
case GDK_Down:
iti_handle_arrow_key_event(iti, event);
break;
default:
/* Check for control key operations */
if (event->key.state & GDK_CONTROL_MASK) {
return FALSE;
}
/* Handle any events that reach us */
gtk_widget_event (GTK_WIDGET (priv->entry), event);
break;
}
/* Handle any events that reach us */
gtk_widget_event (GTK_WIDGET (priv->entry), event);
/* Update text item to reflect changes */
layout_text (iti);
priv->need_text_update = TRUE;
gnome_canvas_item_request_update (item);
......@@ -942,6 +1039,9 @@ iti_init (NautilusIconTextItem *iti)
iti->priv = priv;
}
/**
* nautilus_icon_text_item_configure:
* @iti: An icon text item.
......@@ -1159,6 +1259,8 @@ nautilus_icon_text_item_get_text (NautilusIconTextItem *iti)
void
nautilus_icon_text_item_start_editing (NautilusIconTextItem *iti)
{
NautilusUndoable *undoable;
g_return_if_fail (iti != NULL);
g_return_if_fail (IS_ITI (iti));
......@@ -1168,6 +1270,11 @@ nautilus_icon_text_item_start_editing (NautilusIconTextItem *iti)
iti->selected = TRUE; /* Ensure that we are selected */
gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (iti));
iti_start_editing (iti);
nautilus_undo_manager_begin_transaction ("Text Edit");
nautilus_undoable_save_undo_snapshot (undoable, GTK_OBJECT(iti), save_undo_snapshot_callback,
restore_from_undo_snapshot_callback);
nautilus_undo_manager_end_transaction ();
}
/**
......@@ -1182,17 +1289,18 @@ nautilus_icon_text_item_start_editing (NautilusIconTextItem *iti)
void
nautilus_icon_text_item_stop_editing (NautilusIconTextItem *iti,
gboolean accept)
{
{
g_return_if_fail (iti != NULL);
g_return_if_fail (IS_ITI (iti));
if (!iti->editing)
return;
if (accept)
if (accept) {
iti_edition_accept (iti);
else
} else {
iti_stop_editing (iti);
}
}
......@@ -1242,3 +1350,44 @@ nautilus_icon_text_item_get_margins (int *x, int *y)
*y = MARGIN_Y;
}
/* save_undo_snapshot_callback
*
* Get text at start of edit operation and store in undo data as
* string with a key of "undo_text".
*/
static void
save_undo_snapshot_callback(NautilusUndoable *undoable)
{
char *undo_text;
NautilusIconTextItem *iti;
iti = NAUTILUS_ICON_TEXT_ITEM(undoable->undo_target_class);
/* Add some data to the data list */
undo_text = g_strdup(iti->text);
g_datalist_set_data(&undoable->undo_data, "undo_text", undo_text);
}
/* restore_from_undo_snapshot_callback
*
* Restore edited text to data stored in undoable. Data is stored as
* a string with a key of "undo_text".
*/
static void
restore_from_undo_snapshot_callback(NautilusUndoable *undoable)
{
char *undo_text;
NautilusIconTextItem *iti;
iti = NAUTILUS_ICON_TEXT_ITEM(undoable->undo_target_class);
undo_text = g_datalist_get_data(&undoable->undo_data, "undo_text");
if (undo_text != NULL) {
printf("undo_text: %s\n", undo_text);
nautilus_icon_text_item_set_text (iti, undo_text);
}
}
......@@ -58,14 +58,14 @@ typedef struct {
GnomeCanvasItemClass parent_class;
/* Signals we emit */
int (* text_changed) (NautilusIconTextItem *item);
void (* text_edited) (NautilusIconTextItem *item);
void (* height_changed) (NautilusIconTextItem *item);
void (* width_changed) (NautilusIconTextItem *item);
void (* editing_started) (NautilusIconTextItem *item);
void (* editing_stopped) (NautilusIconTextItem *item);
void (* selection_started) (NautilusIconTextItem *item);
void (* selection_stopped) (NautilusIconTextItem *item);
int (* text_changed) (NautilusIconTextItem *item);
void (* text_edited) (NautilusIconTextItem *item);
void (* height_changed) (NautilusIconTextItem *item);
void (* width_changed) (NautilusIconTextItem *item);
void (* editing_started) (NautilusIconTextItem *item);
void (* editing_stopped) (NautilusIconTextItem *item);
void (* selection_started) (NautilusIconTextItem *item);
void (* selection_stopped) (NautilusIconTextItem *item);
} NautilusIconTextItemClass;
GtkType nautilus_icon_text_item_get_type (void);
......
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* nautulus-undo-manager-private.h
*
* Copyright (C) 2000 Eazel, Inc.
*
* Author: Gene Z. Ragan <gzr@eazel.com>
*
* 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.
*/
#ifndef NAUTILUS_UNDO_MANAGER_PRIVATE_H
#define NAUTILUS_UNDO_MANAGER_PRIVATE_H
#include <glib.h>
#include "nautilus-undo-transaction.h"
/* Private data */
NautilusUndoManager *global_undo_manager;
struct NautilusUndoManagerDetails {
NautilusUndoTransaction *transaction; /* Current active and unique transaction */
GList *undo_list;
GList *redo_list;
gboolean transaction_in_progress;
};
#endif /* NAUTILUS_UNDO_MANAGER_PRIVATE_H */
\ No newline at end of file
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* NautilusUndoTransaction - An object for an undoable transcation.
*
* Copyright (C) 2000 Eazel, Inc.
*
* Author: Gene Z. Ragan <gzr@eazel.com>
*
* 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 "nautilus-undo-transaction.h"
/* nautilus_undo_transaction_new */
NautilusUndoTransaction *nautilus_undo_transaction_new (const gchar *name)
{
NautilusUndoTransaction *transaction;
transaction = g_new(NautilusUndoTransaction, 1);
transaction->transaction_list = NULL;
transaction->name = g_strdup(name);
return transaction;
}
/* nautilus_undo_transaction_add_undoable */
gboolean nautilus_undo_transaction_add_undoable (NautilusUndoTransaction *transaction,
NautilusUndoable *undoable)
{
if (transaction == NULL) {
g_warning("Cannot add undoable to a NULL transaction");
return FALSE;
}
if (undoable == NULL) {
g_warning("Cannot add a NULL undoable to a transaction");
return FALSE;
}
transaction->transaction_list = g_list_append(transaction->transaction_list, undoable);
return TRUE;
}
/* nautilus_undo_transaction_undo
* Parse transaction and send undo signals to undoable objects stored in transaction
*/
gboolean
nautilus_undo_transaction_undo (NautilusUndoTransaction *transaction)
{
NautilusUndoable *undoable;
guint index;
g_return_val_if_fail(transaction != NULL, FALSE);
for ( index = 0; index < g_list_length(transaction->transaction_list); index++) {
/* Get pointer to undoable */
undoable = g_list_nth_data(transaction->transaction_list, index);
/* Send object restore from undo signal */
if (undoable != NULL)
nautilus_undoable_restore_from_undo_snapshot (undoable);
}
return TRUE;
}
const gchar *nautilus_undo_transaction_get_name (NautilusUndoTransaction *transaction)
{
g_return_val_if_fail(transaction != NULL, NULL);
return transaction->name;
}
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* NautilusUndoTransaction - An object for an undoable transcation.
*
* Copyright (C) 2000 Eazel, Inc.
*
* Author: Gene Z. Ragan <gzr@eazel.com>
*
* 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.
*/
#ifndef NAUTILUS_UNDO_TRANSACTION_H
#define NAUTILUS_UNDO_TRANSACTION_H
#include <glib.h>
#include "nautilus-undoable.h"