Logo Search packages:      
Sourcecode: tasks version File versions  Download package

koto-entry.c

/*
 * 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
 */

/* TODO: add undo/redo context menu items */

#include <config.h>

#include <string.h>
#include <glib/gi18n.h>

#include "koto-undo-manager.h"
#include "koto-entry.h"

static void koto_entry_editable_init (GtkEditableClass *iface);

G_DEFINE_TYPE_WITH_CODE (KotoEntry, koto_entry,
                         GTK_TYPE_ENTRY,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, koto_entry_editable_init));

static GtkEditableClass *parent_editable_interface = NULL;

#define ENTRY_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), KOTO_TYPE_ENTRY, KotoEntryPrivate))

typedef struct {
  KotoUndoManager *manager;
  gboolean user_edit;
} KotoEntryPrivate;

typedef struct {
  GtkEditable *editable;
  char *text;
  int length;
  int position;
} InsertState;

static void
insert_undo (gpointer closure)
{
  InsertState *state = closure;
  KotoEntryPrivate *priv = ENTRY_PRIVATE (state->editable);

  priv->user_edit = FALSE;
  gtk_editable_delete_text (state->editable,
                            state->position,
                            state->position + state->length);
  priv->user_edit = TRUE;
}

static void
insert_redo (gpointer closure)
{
  InsertState *state = closure;
  KotoEntryPrivate *priv = ENTRY_PRIVATE (state->editable);
  int pos = state->position;

  priv->user_edit = FALSE;
  gtk_editable_insert_text (state->editable,
                            state->text,
                            state->length,
                            &pos);
  priv->user_edit = TRUE;
}

static void
insert_destroy (gpointer closure)
{
  InsertState *state = closure;
  g_free (state->text);
  g_slice_free (InsertState, state);
}

static void
koto_entry_insert_text (GtkEditable *editable, const gchar *text, int length, int *position)
{
  KotoEntry *entry = KOTO_ENTRY (editable);
  KotoEntryPrivate *priv = ENTRY_PRIVATE (entry);

  if (priv->user_edit) {
    KotoUndoContext *context;
    InsertState *state;
    
    context = koto_undo_manager_context_begin (priv->manager, _("Insert"));
    
    state = g_slice_new0 (InsertState);
    state->editable = editable;
    state->text = g_strdup (text);
    state->length = strlen (text);
    state->position = *position;
    
    koto_undo_context_add
      (context, koto_undoable_new (insert_undo, insert_redo, insert_destroy, state));

    koto_undo_manager_context_end (priv->manager, context);
  }

  parent_editable_interface->insert_text (editable, text, length, position);
}

static void 
koto_entry_delete_text (GtkEditable *editable, int start_pos, int end_pos)
{
  KotoEntry *entry = KOTO_ENTRY (editable);
  KotoEntryPrivate *priv = ENTRY_PRIVATE (entry);

  if (priv->user_edit) {
    KotoUndoContext *context;
    InsertState *state;
    
    context = koto_undo_manager_context_begin (priv->manager, _("Delete"));
    
    state = g_slice_new0 (InsertState);
    state->editable = editable;
    state->text = gtk_editable_get_chars (editable, start_pos, end_pos);
    state->length = strlen (state->text);
    state->position = start_pos;
    
    koto_undo_context_add
      (context, koto_undoable_new (insert_redo, insert_undo, insert_destroy, state));

    koto_undo_manager_context_end (priv->manager, context);
  }
  
  parent_editable_interface->delete_text (editable, start_pos, end_pos);
}

static void
koto_entry_dispose (GObject *object)
{
  KotoEntryPrivate *priv = ENTRY_PRIVATE (object);
  
  if (priv->manager) {
    g_object_unref (priv->manager);
    priv->manager = NULL;
  }
  
  G_OBJECT_CLASS (koto_entry_parent_class)->dispose (object);
}


static void
koto_entry_editable_init (GtkEditableClass *iface)
{
  parent_editable_interface = g_type_interface_peek_parent (iface);
  
  iface->insert_text = koto_entry_insert_text;
  iface->delete_text = koto_entry_delete_text;
}

static void
koto_entry_class_init (KotoEntryClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  g_type_class_add_private (klass, sizeof (KotoEntryPrivate));

  object_class->dispose = koto_entry_dispose;
}

static gboolean
on_key_press_event (GtkWidget *widget, GdkEventKey *event)
{
  gboolean control;
  
  control = event->state & GDK_CONTROL_MASK;
  
  if (control && event->keyval == 'z') {
    KotoEntryPrivate *priv = ENTRY_PRIVATE (widget); 
    koto_undo_manager_undo (priv->manager);
    return TRUE;
  } else if (control && event->keyval == 'Z') {
    KotoEntryPrivate *priv = ENTRY_PRIVATE (widget); 
    koto_undo_manager_redo (priv->manager);
    return TRUE;
  }
  return FALSE;
}

static void
koto_entry_init (KotoEntry *self)
{
  KotoEntryPrivate *priv = ENTRY_PRIVATE (self);

  priv->manager = koto_undo_manager_new ();
  priv->user_edit = TRUE;

  g_signal_connect (self, "key-press-event", G_CALLBACK (on_key_press_event), NULL);
}

GtkWidget *
koto_entry_new (void)
{
  return g_object_new (KOTO_TYPE_ENTRY, NULL);
}

void
koto_entry_set_text (KotoEntry *entry, const char *text)
{
  KotoEntryPrivate *priv;
  
  g_return_if_fail (KOTO_IS_ENTRY (entry));
  
  priv = ENTRY_PRIVATE (entry);

  priv->user_edit = FALSE;
  gtk_entry_set_text (GTK_ENTRY (entry), text);
  priv->user_edit = TRUE;
}

Generated by  Doxygen 1.6.0   Back to index