[libgda] Improved data entry widgets for constrained typing
- From: Vivien Malerba <vivien src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libgda] Improved data entry widgets for constrained typing
- Date: Tue, 29 Sep 2009 19:27:37 +0000 (UTC)
commit 79fdb04b80d9c253bab6bb70d4ffada0aac49136
Author: Vivien Malerba <malerba gnome-db org>
Date: Mon Sep 28 20:34:58 2009 +0200
Improved data entry widgets for constrained typing
as the old implementation was not really maintainable because
too complicated.
configure.in | 2 +-
libgda-ui/data-entries/.gitignore | 4 +-
libgda-ui/data-entries/Makefile.am | 14 +-
.../gdaui-data-cell-renderer-textual.c | 3 +
libgda-ui/data-entries/gdaui-entry-common-time.c | 74 +-
libgda-ui/data-entries/gdaui-entry-number.c | 503 ++++++
libgda-ui/data-entries/gdaui-entry-number.h | 61 +
...ing-number.xml.in => gdaui-entry-number.xml.in} | 4 +-
libgda-ui/data-entries/gdaui-entry-string.c | 188 +--
...ing-string.xml.in => gdaui-entry-string.xml.in} | 0
libgda-ui/data-entries/gdaui-entry.c | 619 +++++++
libgda-ui/data-entries/gdaui-entry.h | 101 ++
libgda-ui/data-entries/gdaui-format-entry.c | 1783 --------------------
libgda-ui/data-entries/gdaui-format-entry.h | 70 -
libgda-ui/data-entries/gdaui-formatted-entry.c | 489 ++++++
libgda-ui/data-entries/gdaui-formatted-entry.h | 57 +
libgda-ui/data-entries/gdaui-numeric-entry.c | 695 ++++++++
libgda-ui/data-entries/gdaui-numeric-entry.h | 57 +
libgda-ui/data-entries/plugins/gdaui-entry-cidr.c | 15 +-
libgda-ui/gdaui-init.c | 21 +-
libgda-ui/libgda-ui.symbols | 27 +-
libgda/handlers/gda-handler-time.c | 35 +-
po/POTFILES.in | 4 +-
testing/.gitignore | 1 +
testing/Makefile.am | 11 +-
testing/gdaui-test-widget-entry.c | 409 +++++
26 files changed, 3184 insertions(+), 2063 deletions(-)
---
diff --git a/configure.in b/configure.in
index 2138e3f..6837d40 100644
--- a/configure.in
+++ b/configure.in
@@ -30,7 +30,7 @@ m4_undefine([minor])
m4_undefine([micro])
dnl required versions of other tools.
-m4_define([req_ver_glib], [2.12.0])
+m4_define([req_ver_glib], [2.12.11])
#
# Making releases:
diff --git a/libgda-ui/data-entries/.gitignore b/libgda-ui/data-entries/.gitignore
index 9e4e717..a0680bc 100644
--- a/libgda-ui/data-entries/.gitignore
+++ b/libgda-ui/data-entries/.gitignore
@@ -1,2 +1,2 @@
-gdaui-entry-string-number.xml
-gdaui-entry-string-string.xml
+gdaui-entry-number.xml
+gdaui-entry-string.xml
diff --git a/libgda-ui/data-entries/Makefile.am b/libgda-ui/data-entries/Makefile.am
index 2a004ae..be69277 100644
--- a/libgda-ui/data-entries/Makefile.am
+++ b/libgda-ui/data-entries/Makefile.am
@@ -25,12 +25,15 @@ libgda_ui_data_entries_headers = \
gdaui-entry-none.h \
gdaui-entry-shell.h \
gdaui-entry-string.h \
+ gdaui-entry-number.h \
gdaui-entry-common-time.h \
gdaui-entry-time.h \
gdaui-entry-timestamp.h \
gdaui-entry-date.h \
gdaui-entry-wrapper.h \
- gdaui-format-entry.h
+ gdaui-entry.h \
+ gdaui-formatted-entry.h \
+ gdaui-numeric-entry.h
libgda_ui_data_entries_la_SOURCES = \
$(libgda_ui_data_entries_headers) \
@@ -47,17 +50,20 @@ libgda_ui_data_entries_la_SOURCES = \
gdaui-entry-none.c \
gdaui-entry-shell.c \
gdaui-entry-string.c \
+ gdaui-entry-number.c \
gdaui-entry-common-time.c \
gdaui-entry-time.c \
gdaui-entry-timestamp.c \
gdaui-entry-date.c \
gdaui-entry-wrapper.c \
- gdaui-format-entry.c
+ gdaui-entry.c \
+ gdaui-formatted-entry.c \
+ gdaui-numeric-entry.c
xmldir = $(datadir)/libgda-4.0/ui
xml_in_files = \
- gdaui-entry-string-string.xml.in \
- gdaui-entry-string-number.xml.in
+ gdaui-entry-string.xml.in \
+ gdaui-entry-number.xml.in
@INTLTOOL_XML_RULE@
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
index a7058d1..06dcc53 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
@@ -29,6 +29,7 @@
#include "gdaui-data-cell-renderer-textual.h"
#include "gdaui-data-entry.h"
#include "gdaui-entry-string.h"
+#include "gdaui-entry-number.h"
#include "gdaui-entry-date.h"
#include "gdaui-entry-time.h"
#include "gdaui-entry-timestamp.h"
@@ -683,6 +684,8 @@ gdaui_data_cell_renderer_textual_start_editing (GtkCellRenderer *cell,
entry = gdaui_entry_time_new (datacell->priv->dh);
else if (datacell->priv->type == GDA_TYPE_TIMESTAMP)
entry = gdaui_entry_timestamp_new (datacell->priv->dh);
+ else if (gdaui_entry_number_is_type_numeric (datacell->priv->type))
+ entry = gdaui_entry_number_new (datacell->priv->dh, datacell->priv->type, datacell->priv->options);
else
entry = gdaui_entry_string_new (datacell->priv->dh, datacell->priv->type, datacell->priv->options);
diff --git a/libgda-ui/data-entries/gdaui-entry-common-time.c b/libgda-ui/data-entries/gdaui-entry-common-time.c
index 2c4361e..1cabe04 100644
--- a/libgda-ui/data-entries/gdaui-entry-common-time.c
+++ b/libgda-ui/data-entries/gdaui-entry-common-time.c
@@ -23,7 +23,7 @@
#include <libgda/gda-data-handler.h>
#include <gdk/gdkkeysyms.h>
#include <string.h>
-#include "gdaui-format-entry.h"
+#include "gdaui-formatted-entry.h"
/*
* Main static functions
@@ -328,51 +328,51 @@ real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
if (type == G_TYPE_DATE) {
if (value) {
if (gda_value_is_null ((GValue *) value))
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
else {
gchar *str;
str = gda_data_handler_get_str_from_value (dh, value);
- gtk_entry_set_text (GTK_ENTRY (mgtim->priv->entry_date), str);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), str);
g_free (str);
}
}
else
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
}
else if (type == GDA_TYPE_TIME) {
if (value) {
if (gda_value_is_null ((GValue *) value))
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
else {
gchar *str;
str = gda_data_handler_get_str_from_value (dh, value);
- gtk_entry_set_text (GTK_ENTRY (mgtim->priv->entry_time), str);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), str);
g_free (str);
}
}
else
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
}
else if (type == GDA_TYPE_TIMESTAMP) {
if (value) {
if (gda_value_is_null ((GValue *) value))
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
else {
gchar *str, *ptr;
str = gda_data_handler_get_str_from_value (dh, value);
ptr = strtok (str, " ");
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date), ptr);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), ptr);
ptr = strtok (NULL, " ");
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time), ptr);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), ptr);
g_free (str);
}
}
else {
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date), NULL);
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
}
}
else
@@ -404,12 +404,12 @@ real_get_value (GdauiEntryWrapper *mgwrap)
dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
if (type == G_TYPE_DATE) {
- str2 = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date));
+ str2 = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_date));
value = gda_data_handler_get_value_from_str (dh, str2, type); /* FIXME: not SQL but STR */
g_free (str2);
}
else if (type == GDA_TYPE_TIME) {
- str2 = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time));
+ str2 = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_time));
value = gda_data_handler_get_value_from_str (dh, str2, type);
if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL) &&
mgtim->priv->last_value_set &&
@@ -427,8 +427,8 @@ real_get_value (GdauiEntryWrapper *mgwrap)
else if (type == GDA_TYPE_TIMESTAMP) {
gchar *tmpstr, *tmpstr2;
- tmpstr = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time));
- tmpstr2 = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date));
+ tmpstr = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_time));
+ tmpstr2 = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_date));
str2 = g_strdup_printf ("%s %s", tmpstr2, tmpstr);
g_free (tmpstr);
g_free (tmpstr2);
@@ -567,14 +567,20 @@ create_entry_date (GdauiEntryCommonTime *mgtim)
/* text entry */
dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgtim));
- wid = gdaui_format_entry_new ();
if (GDA_IS_HANDLER_TIME (dh)) {
- gchar *str;
+ gchar *str, *mask, *ptr;
str = gda_handler_time_get_format (GDA_HANDLER_TIME (dh), G_TYPE_DATE);
- gdaui_format_entry_set_format (GDAUI_FORMAT_ENTRY (wid), str, NULL, NULL);
- gtk_entry_set_width_chars (GTK_ENTRY (wid), g_utf8_strlen (str, -1));
+ mask = g_strdup (str);
+ for (ptr = mask; *ptr; ptr++) {
+ if (*ptr == '0')
+ *ptr = '-';
+ }
+ wid = gdaui_formatted_entry_new (str, mask);
g_free (str);
+ g_free (mask);
}
+ else
+ wid = gdaui_entry_new (NULL, NULL);
gtk_box_pack_start (GTK_BOX (hb), wid, FALSE, FALSE, 0);
gtk_widget_show (wid);
mgtim->priv->entry_date = wid;
@@ -633,17 +639,19 @@ internal_set_time (GtkWidget *widget, GdauiEntryCommonTime *mgtim)
type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgtim));
if (type == GDA_TYPE_TIMESTAMP) {
GdaDataHandler *dh;
- gchar *str;
+ gchar *str, *str2;
GValue *value;
dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgtim));
- str = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time));
- value = gda_data_handler_get_value_from_str (dh, str, type);
+ str = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_time));
+ str2 = g_strdup_printf ("01.01.2000 %s", str);
+ g_free (str);
+ value = gda_data_handler_get_value_from_str (dh, str2, type);
if (!value || gda_value_is_null (value))
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_time), "00:00:00");
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), "00:00:00");
if (value)
gda_value_free (value);
- g_free (str);
+ g_free (str2);
}
}
@@ -722,7 +730,7 @@ date_day_selected (GtkCalendar *calendar, GdauiEntryCommonTime *mgtim)
buffer[sizeof(buffer)-1] = '\0';
str_utf8 = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgtim->priv->entry_date), str_utf8);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), str_utf8);
g_free (str_utf8);
}
@@ -902,14 +910,20 @@ create_entry_time (GdauiEntryCommonTime *mgtim)
/* text entry */
dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgtim));
- wid = gdaui_format_entry_new ();
if (GDA_IS_HANDLER_TIME (dh)) {
- gchar *str;
+ gchar *str, *mask, *ptr;
str = gda_handler_time_get_format (GDA_HANDLER_TIME (dh), GDA_TYPE_TIME);
- gdaui_format_entry_set_format (GDAUI_FORMAT_ENTRY (wid), str, NULL, NULL);
- gtk_entry_set_width_chars (GTK_ENTRY (wid), g_utf8_strlen (str, -1));
+ mask = g_strdup (str);
+ for (ptr = mask; *ptr; ptr++) {
+ if (*ptr == '0')
+ *ptr = '-';
+ }
+ wid = gdaui_formatted_entry_new (str, mask);
g_free (str);
+ g_free (mask);
}
+ else
+ wid = gdaui_entry_new (NULL, NULL);
mgtim->priv->entry_time = wid;
/* format tooltip */
diff --git a/libgda-ui/data-entries/gdaui-entry-number.c b/libgda-ui/data-entries/gdaui-entry-number.c
new file mode 100644
index 0000000..bdd1367
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-entry-number.c
@@ -0,0 +1,503 @@
+/* gdaui-entry-number.c
+ *
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <glib/gi18n-lib.h>
+#include "gdaui-entry-number.h"
+#include "gdaui-numeric-entry.h"
+#include <libgda/gda-data-handler.h>
+#include "gdk/gdkkeysyms.h"
+
+/*
+ * Main static functions
+ */
+static void gdaui_entry_number_class_init (GdauiEntryNumberClass *klass);
+static void gdaui_entry_number_init (GdauiEntryNumber *srv);
+static void gdaui_entry_number_dispose (GObject *object);
+static void gdaui_entry_number_finalize (GObject *object);
+
+static void gdaui_entry_number_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdaui_entry_number_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_EDITING_CANCELLED,
+ PROP_OPTIONS
+};
+
+/* GtkCellEditable interface */
+static void gdaui_entry_number_cell_editable_init (GtkCellEditableIface *iface);
+static void gdaui_entry_number_start_editing (GtkCellEditable *iface, GdkEvent *event);
+static void sync_entry_options (GdauiEntryNumber *mgstr);
+
+/* virtual functions */
+static GtkWidget *create_entry (GdauiEntryWrapper *mgwrap);
+static void real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value);
+static GValue *real_get_value (GdauiEntryWrapper *mgwrap);
+static void connect_signals(GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb);
+static gboolean expand_in_layout (GdauiEntryWrapper *mgwrap);
+static void set_editable (GdauiEntryWrapper *mgwrap, gboolean editable);
+static void grab_focus (GdauiEntryWrapper *mgwrap);
+
+/* options */
+static void set_entry_options (GdauiEntryNumber *mgstr, const gchar *options);
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+/* private structure */
+struct _GdauiEntryNumberPrivate
+{
+ GtkWidget *entry;
+
+ guchar thousand_sep;
+ guint16 nb_decimals;
+ gchar *currency;
+
+ gulong entry_change_sig;
+};
+
+static void
+gdaui_entry_number_cell_editable_init (GtkCellEditableIface *iface)
+{
+ iface->start_editing = gdaui_entry_number_start_editing;
+}
+
+GType
+gdaui_entry_number_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GdauiEntryNumberClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdaui_entry_number_class_init,
+ NULL,
+ NULL,
+ sizeof (GdauiEntryNumber),
+ 0,
+ (GInstanceInitFunc) gdaui_entry_number_init
+ };
+
+ static const GInterfaceInfo cell_editable_info = {
+ (GInterfaceInitFunc) gdaui_entry_number_cell_editable_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (GDAUI_TYPE_ENTRY_WRAPPER, "GdauiEntryNumber", &info, 0);
+ g_type_add_interface_static (type, GTK_TYPE_CELL_EDITABLE, &cell_editable_info);
+ }
+ return type;
+}
+
+static void
+gdaui_entry_number_class_init (GdauiEntryNumberClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = gdaui_entry_number_dispose;
+ object_class->finalize = gdaui_entry_number_finalize;
+
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->create_entry = create_entry;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->real_set_value = real_set_value;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->real_get_value = real_get_value;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->connect_signals = connect_signals;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->expand_in_layout = expand_in_layout;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->set_editable = set_editable;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->grab_focus = grab_focus;
+
+ /* Properties */
+ object_class->set_property = gdaui_entry_number_set_property;
+ object_class->get_property = gdaui_entry_number_get_property;
+
+ g_object_class_install_property (object_class, PROP_EDITING_CANCELLED,
+ g_param_spec_boolean ("editing_cancelled", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (object_class, PROP_OPTIONS,
+ g_param_spec_string ("options", NULL, NULL, NULL, G_PARAM_WRITABLE));
+}
+
+static void
+gdaui_entry_number_init (GdauiEntryNumber * mgstr)
+{
+ mgstr->priv = g_new0 (GdauiEntryNumberPrivate, 1);
+ mgstr->priv->entry = NULL;
+
+ mgstr->priv->thousand_sep = 0;
+ mgstr->priv->nb_decimals = G_MAXUINT16; /* unlimited number of decimals */
+ mgstr->priv->currency = NULL;
+
+ mgstr->priv->entry_change_sig = 0;
+}
+
+gboolean
+gdaui_entry_number_is_type_numeric (GType type)
+{
+ if ((type == G_TYPE_INT64) || (type == G_TYPE_UINT64) || (type == G_TYPE_DOUBLE) ||
+ (type == G_TYPE_INT) || (type == GDA_TYPE_NUMERIC) || (type == G_TYPE_FLOAT) ||
+ (type == GDA_TYPE_SHORT) || (type == GDA_TYPE_USHORT) || (type == G_TYPE_CHAR) ||
+ (type == G_TYPE_UCHAR) || (type == G_TYPE_LONG) || (type == G_TYPE_ULONG) || (type == G_TYPE_UINT))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/**
+ * gdaui_entry_number_new
+ * @dh: the data handler to be used by the new widget
+ * @type: the requested data type (compatible with @dh)
+ *
+ * Creates a new widget which is mainly a GtkEntry
+ *
+ * Returns: the new widget
+ */
+GtkWidget *
+gdaui_entry_number_new (GdaDataHandler *dh, GType type, const gchar *options)
+{
+ GObject *obj;
+ GdauiEntryNumber *mgstr;
+
+ g_return_val_if_fail (GDA_IS_DATA_HANDLER (dh), NULL);
+ g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
+ g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL);
+ g_return_val_if_fail (gdaui_entry_number_is_type_numeric (type), NULL);
+
+ obj = g_object_new (GDAUI_TYPE_ENTRY_NUMBER, "handler", dh, NULL);
+ mgstr = GDAUI_ENTRY_NUMBER (obj);
+ gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (mgstr), type);
+
+ g_object_set (obj, "options", options, NULL);
+
+ return GTK_WIDGET (obj);
+}
+
+static gboolean focus_out_cb (GtkWidget *widget, GdkEventFocus *event, GdauiEntryNumber *mgstr);
+static void
+gdaui_entry_number_dispose (GObject * object)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDAUI_IS_ENTRY_NUMBER (object));
+
+ mgstr = GDAUI_ENTRY_NUMBER (object);
+ if (mgstr->priv) {
+ if (mgstr->priv->entry) {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (mgstr->priv->entry),
+ G_CALLBACK (focus_out_cb), mgstr);
+ mgstr->priv->entry = NULL;
+ }
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+static void
+gdaui_entry_number_finalize (GObject * object)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDAUI_IS_ENTRY_NUMBER (object));
+
+ mgstr = GDAUI_ENTRY_NUMBER (object);
+ if (mgstr->priv) {
+ g_free (mgstr->priv->currency);
+ g_free (mgstr->priv);
+ mgstr->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->finalize (object);
+}
+
+static void
+gdaui_entry_number_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiEntryNumber *mgstr;
+
+ mgstr = GDAUI_ENTRY_NUMBER (object);
+ if (mgstr->priv) {
+ switch (param_id) {
+ case PROP_OPTIONS:
+ set_entry_options (mgstr, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+static void
+gdaui_entry_number_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiEntryNumber *mgstr;
+
+ mgstr = GDAUI_ENTRY_NUMBER (object);
+ if (mgstr->priv) {
+ switch (param_id) {
+ case PROP_EDITING_CANCELLED:
+ g_value_set_boolean (value, GTK_ENTRY (mgstr->priv->entry)->editing_canceled);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+static GtkWidget *
+create_entry (GdauiEntryWrapper *mgwrap)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_val_if_fail (GDAUI_IS_ENTRY_NUMBER (mgwrap), NULL);
+ mgstr = GDAUI_ENTRY_NUMBER (mgwrap);
+
+ mgstr->priv->entry = gdaui_numeric_entry_new (gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgwrap)));
+ sync_entry_options (mgstr);
+
+ return mgstr->priv->entry;
+}
+
+static void
+real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
+{
+ GdauiEntryNumber *mgstr;
+ GdaDataHandler *dh;
+ gchar *text;
+
+ g_return_if_fail (GDAUI_IS_ENTRY_NUMBER (mgwrap));
+ mgstr = GDAUI_ENTRY_NUMBER (mgwrap);
+
+ dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
+
+ text = gda_data_handler_get_str_from_value (dh, value);
+ if (value) {
+ if (gda_value_is_null ((GValue *) value))
+ gdaui_entry_set_text (GDAUI_ENTRY (mgstr->priv->entry), NULL);
+ else
+ gdaui_entry_set_text (GDAUI_ENTRY (mgstr->priv->entry), text);
+ }
+ else
+ gdaui_entry_set_text (GDAUI_ENTRY (mgstr->priv->entry), NULL);
+
+ g_free (text);
+}
+
+static GValue *
+real_get_value (GdauiEntryWrapper *mgwrap)
+{
+ GValue *value;
+ GdauiEntryNumber *mgstr;
+
+ g_return_val_if_fail (GDAUI_IS_ENTRY_NUMBER (mgwrap), NULL);
+ mgstr = GDAUI_ENTRY_NUMBER (mgwrap);
+ g_return_val_if_fail (mgstr->priv, NULL);
+
+ value = gdaui_numeric_entry_get_value (GDAUI_NUMERIC_ENTRY (mgstr->priv->entry));
+
+ if (!value) {
+ /* in case the contents of the GtkEntry cannot be interpreted as a GValue */
+ value = gda_value_new_null ();
+ }
+
+ return value;
+}
+
+typedef void (*Callback2) (gpointer, gpointer);
+static gboolean
+focus_out_cb (GtkWidget *widget, GdkEventFocus *event, GdauiEntryNumber *mgstr)
+{
+ GCallback activate_cb;
+ activate_cb = g_object_get_data (G_OBJECT (widget), "_activate_cb");
+ g_assert (activate_cb);
+ ((Callback2)activate_cb) (widget, mgstr);
+
+ return FALSE;
+}
+
+static void
+connect_signals (GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_if_fail (GDAUI_IS_ENTRY_NUMBER (mgwrap));
+ mgstr = GDAUI_ENTRY_NUMBER (mgwrap);
+ g_return_if_fail (mgstr->priv);
+ g_object_set_data (G_OBJECT (mgstr->priv->entry), "_activate_cb", activate_cb);
+
+ mgstr->priv->entry_change_sig = g_signal_connect (G_OBJECT (mgstr->priv->entry), "changed",
+ modify_cb, mgwrap);
+ g_signal_connect (G_OBJECT (mgstr->priv->entry), "activate",
+ activate_cb, mgwrap);
+ g_signal_connect (G_OBJECT (mgstr->priv->entry), "focus-out-event",
+ G_CALLBACK (focus_out_cb), mgstr);
+}
+
+static gboolean
+expand_in_layout (GdauiEntryWrapper *mgwrap)
+{
+ return FALSE;
+}
+
+static void
+set_editable (GdauiEntryWrapper *mgwrap, gboolean editable)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_if_fail (GDAUI_IS_ENTRY_NUMBER (mgwrap));
+ mgstr = GDAUI_ENTRY_NUMBER (mgwrap);
+
+ gtk_entry_set_editable (GTK_ENTRY (mgstr->priv->entry), editable);
+}
+
+static void
+grab_focus (GdauiEntryWrapper *mgwrap)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_if_fail (GDAUI_IS_ENTRY_NUMBER (mgwrap));
+ mgstr = GDAUI_ENTRY_NUMBER (mgwrap);
+
+ gtk_widget_grab_focus (mgstr->priv->entry);
+}
+
+/*
+ * GtkCellEditable interface
+ */
+static void
+gtk_cell_editable_entry_editing_done_cb (GtkEntry *entry, GdauiEntryNumber *mgstr)
+{
+ gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (mgstr));
+}
+
+static void
+gtk_cell_editable_entry_remove_widget_cb (GtkEntry *entry, GdauiEntryNumber *mgstr)
+{
+ gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (mgstr));
+}
+
+static void
+gdaui_entry_number_start_editing (GtkCellEditable *iface, GdkEvent *event)
+{
+ GdauiEntryNumber *mgstr;
+
+ g_return_if_fail (iface && GDAUI_IS_ENTRY_NUMBER (iface));
+ mgstr = GDAUI_ENTRY_NUMBER (iface);
+
+ g_object_set (G_OBJECT (mgstr->priv->entry), "has_frame", FALSE, "xalign", 0., NULL);
+
+ gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (mgstr->priv->entry), event);
+ g_signal_connect (G_OBJECT (mgstr->priv->entry), "editing_done",
+ G_CALLBACK (gtk_cell_editable_entry_editing_done_cb), mgstr);
+ g_signal_connect (G_OBJECT (mgstr->priv->entry), "remove_widget",
+ G_CALLBACK (gtk_cell_editable_entry_remove_widget_cb), mgstr);
+ gdaui_entry_shell_refresh (GDAUI_ENTRY_SHELL (mgstr));
+
+ gtk_widget_grab_focus (mgstr->priv->entry);
+ gtk_widget_queue_draw (GTK_WIDGET (mgstr));
+}
+
+/*
+ * Options handling
+ */
+
+static guchar
+get_default_thousands_sep ()
+{
+ static guchar value = 255;
+
+ if (value == 255) {
+ gchar text[20];
+ sprintf (text, "%'f", 1234.);
+ if (text[1] == '2')
+ value = ' ';
+ else
+ value = text[1];
+ }
+ return value;
+}
+
+static void
+set_entry_options (GdauiEntryNumber *mgstr, const gchar *options)
+{
+ g_assert (mgstr->priv);
+
+ if (options && *options) {
+ GdaQuarkList *params;
+ const gchar *str;
+
+ params = gda_quark_list_new_from_string (options);
+
+ str = gda_quark_list_find (params, "THOUSAND_SEP");
+ if (str) {
+ if ((*str == 't') || (*str == 'T'))
+ mgstr->priv->thousand_sep = get_default_thousands_sep ();
+ else
+ mgstr->priv->thousand_sep = 0;
+ }
+ str = gda_quark_list_find (params, "NB_DECIMALS");
+ if (str)
+ mgstr->priv->nb_decimals = atoi (str);
+ str = gda_quark_list_find (params, "CURRENCY");
+ if (str) {
+ g_free (mgstr->priv->currency);
+ mgstr->priv->currency = g_strdup_printf ("%s ", str);
+ }
+ gda_quark_list_free (params);
+ sync_entry_options (mgstr);
+ }
+}
+
+/* sets the correct options for mgstr->priv->entry if it exists */
+static void
+sync_entry_options (GdauiEntryNumber *mgstr)
+{
+ if (!mgstr->priv->entry)
+ return;
+
+ g_object_set (G_OBJECT (mgstr->priv->entry),
+ "type", gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgstr)),
+ "n_decimals", mgstr->priv->nb_decimals,
+ "thousands-sep", mgstr->priv->thousand_sep,
+ "prefix", mgstr->priv->currency,
+ NULL);
+ g_signal_emit_by_name (mgstr->priv->entry, "changed");
+}
diff --git a/libgda-ui/data-entries/gdaui-entry-number.h b/libgda-ui/data-entries/gdaui-entry-number.h
new file mode 100644
index 0000000..8d7110b
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-entry-number.h
@@ -0,0 +1,61 @@
+/* gdaui-entry-number.h
+ *
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifndef __GDAUI_ENTRY_NUMBER_H_
+#define __GDAUI_ENTRY_NUMBER_H_
+
+#include "gdaui-entry-wrapper.h"
+
+G_BEGIN_DECLS
+
+#define GDAUI_TYPE_ENTRY_NUMBER (gdaui_entry_number_get_type())
+#define GDAUI_ENTRY_NUMBER(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, gdaui_entry_number_get_type(), GdauiEntryNumber)
+#define GDAUI_ENTRY_NUMBER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, gdaui_entry_number_get_type (), GdauiEntryNumberClass)
+#define GDAUI_IS_ENTRY_NUMBER(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, gdaui_entry_number_get_type ())
+
+
+typedef struct _GdauiEntryNumber GdauiEntryNumber;
+typedef struct _GdauiEntryNumberClass GdauiEntryNumberClass;
+typedef struct _GdauiEntryNumberPrivate GdauiEntryNumberPrivate;
+
+
+/* struct for the object's data */
+struct _GdauiEntryNumber
+{
+ GdauiEntryWrapper object;
+ GdauiEntryNumberPrivate *priv;
+};
+
+/* struct for the object's class */
+struct _GdauiEntryNumberClass
+{
+ GdauiEntryWrapperClass parent_class;
+};
+
+GType gdaui_entry_number_get_type (void) G_GNUC_CONST;
+GtkWidget *gdaui_entry_number_new (GdaDataHandler *dh, GType type, const gchar *options);
+
+
+gboolean gdaui_entry_number_is_type_numeric (GType type);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda-ui/data-entries/gdaui-entry-string-number.xml.in b/libgda-ui/data-entries/gdaui-entry-number.xml.in
similarity index 88%
rename from libgda-ui/data-entries/gdaui-entry-string-number.xml.in
rename to libgda-ui/data-entries/gdaui-entry-number.xml.in
index 2b644cb..4dcdeba 100644
--- a/libgda-ui/data-entries/gdaui-entry-string-number.xml.in
+++ b/libgda-ui/data-entries/gdaui-entry-number.xml.in
@@ -3,11 +3,9 @@
<parameters>
<parameter id="THOUSAND_SEP" _name="Use 1000s separators" _descr="Use thousands separator as specified by current locale" gdatype="gboolean">
<gda_value>FALSE</gda_value>
- <gda_value>FALSE</gda_value>
</parameter>
<parameter id="NB_DECIMALS" _name="Decimals" _descr="Number of decimals" gdatype="guint">
- <gda_value>4</gda_value>
- <gda_value>4</gda_value>
+ <gda_value>2</gda_value>
</parameter>
<parameter id="CURRENCY" _name="Currency symbol" _descr="A currency symbol" source="currencies:0" gdatype="gchararray"/>
</parameters>
diff --git a/libgda-ui/data-entries/gdaui-entry-string.c b/libgda-ui/data-entries/gdaui-entry-string.c
index 3a36471..173754b 100644
--- a/libgda-ui/data-entries/gdaui-entry-string.c
+++ b/libgda-ui/data-entries/gdaui-entry-string.c
@@ -21,20 +21,19 @@
#include <glib/gi18n-lib.h>
#include <string.h>
#include "gdaui-entry-string.h"
-#include "gdaui-format-entry.h"
+#include "gdaui-entry.h"
#include <libgda/gda-data-handler.h>
#include "gdk/gdkkeysyms.h"
-#include <pango/pango.h>
#define MAX_ACCEPTED_STRING_LENGTH 500
/*
* Main static functions
*/
-static void gdaui_entry_string_class_init (GdauiEntryStringClass * class);
-static void gdaui_entry_string_init (GdauiEntryString * srv);
-static void gdaui_entry_string_dispose (GObject * object);
-static void gdaui_entry_string_finalize (GObject * object);
+static void gdaui_entry_string_class_init (GdauiEntryStringClass *klass);
+static void gdaui_entry_string_init (GdauiEntryString *srv);
+static void gdaui_entry_string_dispose (GObject *object);
+static void gdaui_entry_string_finalize (GObject *object);
static void gdaui_entry_string_set_property (GObject *object,
guint param_id,
@@ -74,18 +73,11 @@ static void set_entry_options (GdauiEntryString *mgstr, const gchar *options);
/* get a pointer to the parents to be able to call their destructor */
static GObjectClass *parent_class = NULL;
-typedef enum {
- TYPE_UNKNOWN, /* when value is undefined */
- TYPE_NUMERIC,
- TYPE_NOT_NUMERIC
-} InternalType;
-
/* private structure */
struct _GdauiEntryStringPrivate
{
gboolean multiline;
gboolean hidden;
- InternalType internal_type;
GtkWidget *vbox;
GtkWidget *entry;
@@ -95,9 +87,6 @@ struct _GdauiEntryStringPrivate
GtkWidget *view;
gint maxsize;
- guchar thousand_sep;
- gint nb_decimals;
- gchar *currency;
gulong entry_change_sig;
};
@@ -139,22 +128,22 @@ gdaui_entry_string_get_type (void)
}
static void
-gdaui_entry_string_class_init (GdauiEntryStringClass * class)
+gdaui_entry_string_class_init (GdauiEntryStringClass * klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- parent_class = g_type_class_peek_parent (class);
+ parent_class = g_type_class_peek_parent (klass);
object_class->dispose = gdaui_entry_string_dispose;
object_class->finalize = gdaui_entry_string_finalize;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->create_entry = create_entry;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->real_set_value = real_set_value;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->real_get_value = real_get_value;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->connect_signals = connect_signals;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->expand_in_layout = expand_in_layout;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->set_editable = set_editable;
- GDAUI_ENTRY_WRAPPER_CLASS (class)->grab_focus = grab_focus;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->create_entry = create_entry;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->real_set_value = real_set_value;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->real_get_value = real_get_value;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->connect_signals = connect_signals;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->expand_in_layout = expand_in_layout;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->set_editable = set_editable;
+ GDAUI_ENTRY_WRAPPER_CLASS (klass)->grab_focus = grab_focus;
/* Properties */
object_class->set_property = gdaui_entry_string_set_property;
@@ -181,27 +170,11 @@ gdaui_entry_string_init (GdauiEntryString * mgstr)
mgstr->priv->view = NULL;
mgstr->priv->sw = NULL;
- mgstr->priv->internal_type = TYPE_UNKNOWN;
- mgstr->priv->maxsize = 0; /* unlimited */
- mgstr->priv->thousand_sep = 0;
- mgstr->priv->nb_decimals = -1; /* unlimited number of decimals */
- mgstr->priv->currency = NULL;
+ mgstr->priv->maxsize = 65535; /* eg. unlimited for GtkEntry */
mgstr->priv->entry_change_sig = 0;
}
-static InternalType
-determine_internal_type (GType type)
-{
- if ((type == G_TYPE_INT64) || (type == G_TYPE_UINT64) || (type == G_TYPE_DOUBLE) ||
- (type == G_TYPE_INT) || (type == GDA_TYPE_NUMERIC) || (type == G_TYPE_FLOAT) ||
- (type == GDA_TYPE_SHORT) || (type == GDA_TYPE_USHORT) || (type == G_TYPE_CHAR) ||
- (type == G_TYPE_UCHAR) || (type == G_TYPE_LONG) || (type == G_TYPE_ULONG) || (type == G_TYPE_UINT))
- return TYPE_NUMERIC;
- else
- return TYPE_NOT_NUMERIC;
-}
-
/**
* gdaui_entry_string_new
* @dh: the data handler to be used by the new widget
@@ -220,12 +193,12 @@ gdaui_entry_string_new (GdaDataHandler *dh, GType type, const gchar *options)
g_return_val_if_fail (GDA_IS_DATA_HANDLER (dh), NULL);
g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL);
+ g_return_val_if_fail (type == G_TYPE_STRING, NULL);
obj = g_object_new (GDAUI_TYPE_ENTRY_STRING, "handler", dh, NULL);
mgstr = GDAUI_ENTRY_STRING (obj);
gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (mgstr), type);
- mgstr->priv->internal_type = determine_internal_type (type);
g_object_set (obj, "options", options, NULL);
return GTK_WIDGET (obj);
@@ -269,7 +242,6 @@ gdaui_entry_string_finalize (GObject * object)
mgstr = GDAUI_ENTRY_STRING (object);
if (mgstr->priv) {
- g_free (mgstr->priv->currency);
g_free (mgstr->priv);
mgstr->priv = NULL;
}
@@ -290,14 +262,6 @@ gdaui_entry_string_set_property (GObject *object,
if (mgstr->priv) {
switch (param_id) {
case PROP_MULTILINE:
- if (mgstr->priv->internal_type == TYPE_UNKNOWN)
- mgstr->priv->internal_type =
- determine_internal_type (gdaui_data_entry_get_value_type
- (GDAUI_DATA_ENTRY (mgstr)));
-
- if (mgstr->priv->internal_type == TYPE_NUMERIC)
- return;
-
if (g_value_get_boolean (value) != mgstr->priv->multiline) {
mgstr->priv->multiline = g_value_get_boolean (value);
if (mgstr->priv->multiline) {
@@ -360,7 +324,7 @@ create_entry (GdauiEntryWrapper *mgwrap)
mgstr->priv->vbox = vbox;
/* one line entry */
- mgstr->priv->entry = gdaui_format_entry_new ();
+ mgstr->priv->entry = gdaui_entry_new (NULL, NULL);
sync_entry_options (mgstr);
gtk_box_pack_start (GTK_BOX (vbox), mgstr->priv->entry, FALSE, TRUE, 0);
g_signal_connect_after (G_OBJECT (mgstr->priv->entry), "show",
@@ -436,12 +400,12 @@ real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
/* fill the single line widget */
if (value) {
if (gda_value_is_null ((GValue *) value))
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgstr->priv->entry), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgstr->priv->entry), NULL);
else
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgstr->priv->entry), text);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgstr->priv->entry), text);
}
else
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgstr->priv->entry), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgstr->priv->entry), NULL);
/* fill the multiline widget */
if (value) {
@@ -470,7 +434,7 @@ real_get_value (GdauiEntryWrapper *mgwrap)
dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
if (! mgstr->priv->multiline) {
gchar *cstr;
- cstr = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgstr->priv->entry));
+ cstr = gdaui_entry_get_text (GDAUI_ENTRY (mgstr->priv->entry));
value = gda_data_handler_get_value_from_str (dh, cstr, gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgwrap)));
g_free (cstr);
}
@@ -616,23 +580,6 @@ gdaui_entry_string_start_editing (GtkCellEditable *iface, GdkEvent *event)
/*
* Options handling
*/
-
-static guchar
-get_default_thousands_sep ()
-{
- static guchar value = 255;
-
- if (value == 255) {
- gchar text[20];
- sprintf (text, "%f", 1234.);
- if (text[1] == '2')
- value = 0;
- else
- value = text[1];
- }
- return value;
-}
-
static void
set_entry_options (GdauiEntryString *mgstr, const gchar *options)
{
@@ -642,64 +589,39 @@ set_entry_options (GdauiEntryString *mgstr, const gchar *options)
GdaQuarkList *params;
const gchar *str;
- if (mgstr->priv->internal_type == TYPE_UNKNOWN)
- mgstr->priv->internal_type =
- determine_internal_type (gdaui_data_entry_get_value_type
- (GDAUI_DATA_ENTRY (mgstr)));
-
params = gda_quark_list_new_from_string (options);
- if (mgstr->priv->internal_type == TYPE_NOT_NUMERIC) {
- /* STRING specific options */
- str = gda_quark_list_find (params, "MAX_SIZE");
- if (str)
- mgstr->priv->maxsize = atoi (str);
-
- str = gda_quark_list_find (params, "MULTILINE");
- if (str) {
- if ((*str == 't') || (*str == 'T'))
- mgstr->priv->multiline = TRUE;
- else
- mgstr->priv->multiline = FALSE;
-
- }
-
- str = gda_quark_list_find (params, "HIDDEN");
- if (str) {
- if ((*str == 't') || (*str == 'T'))
- mgstr->priv->hidden = TRUE;
- else
- mgstr->priv->hidden = FALSE;
- }
- if (mgstr->priv->entry) {
- if (mgstr->priv->multiline) {
- gtk_widget_hide (mgstr->priv->entry);
- gtk_widget_show (mgstr->priv->sw);
- }
- else {
- gtk_widget_show (mgstr->priv->entry);
- gtk_widget_hide (mgstr->priv->sw);
- gtk_entry_set_visibility (GTK_ENTRY (mgstr->priv->entry),
- !mgstr->priv->hidden);
- }
- }
- }
- else {
- /* NUMERIC specific options */
- str = gda_quark_list_find (params, "THOUSAND_SEP");
- if (str) {
- if ((*str == 't') || (*str == 'T'))
- mgstr->priv->thousand_sep = get_default_thousands_sep ();
- else
- mgstr->priv->thousand_sep = 0;
+ str = gda_quark_list_find (params, "MAX_SIZE");
+ if (str)
+ mgstr->priv->maxsize = atoi (str);
+
+ str = gda_quark_list_find (params, "MULTILINE");
+ if (str) {
+ if ((*str == 't') || (*str == 'T'))
+ mgstr->priv->multiline = TRUE;
+ else
+ mgstr->priv->multiline = FALSE;
+
+ }
+
+ str = gda_quark_list_find (params, "HIDDEN");
+ if (str) {
+ if ((*str == 't') || (*str == 'T'))
+ mgstr->priv->hidden = TRUE;
+ else
+ mgstr->priv->hidden = FALSE;
+ }
+
+ if (mgstr->priv->entry) {
+ if (mgstr->priv->multiline) {
+ gtk_widget_hide (mgstr->priv->entry);
+ gtk_widget_show (mgstr->priv->sw);
}
- str = gda_quark_list_find (params, "NB_DECIMALS");
- if (str)
- mgstr->priv->nb_decimals = atoi (str);
- str = gda_quark_list_find (params, "CURRENCY");
- if (str) {
- g_free (mgstr->priv->currency);
- mgstr->priv->currency = g_strdup_printf ("%s ", str);
+ else {
+ gtk_widget_show (mgstr->priv->entry);
+ gtk_widget_hide (mgstr->priv->sw);
+ gtk_entry_set_visibility (GTK_ENTRY (mgstr->priv->entry),
+ !mgstr->priv->hidden);
}
}
gda_quark_list_free (params);
@@ -715,11 +637,7 @@ sync_entry_options (GdauiEntryString *mgstr)
return;
g_object_set (G_OBJECT (mgstr->priv->entry),
- "edited_type", gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgstr)),
- "n_decimals", mgstr->priv->nb_decimals,
- "thousands_sep", mgstr->priv->thousand_sep,
- "prefix", mgstr->priv->currency,
- "max_length", mgstr->priv->maxsize,
+ "max-length", mgstr->priv->maxsize,
NULL);
g_signal_emit_by_name (mgstr->priv->entry, "changed");
}
diff --git a/libgda-ui/data-entries/gdaui-entry-string-string.xml.in b/libgda-ui/data-entries/gdaui-entry-string.xml.in
similarity index 100%
rename from libgda-ui/data-entries/gdaui-entry-string-string.xml.in
rename to libgda-ui/data-entries/gdaui-entry-string.xml.in
diff --git a/libgda-ui/data-entries/gdaui-entry.c b/libgda-ui/data-entries/gdaui-entry.c
new file mode 100644
index 0000000..cf54df0
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-entry.c
@@ -0,0 +1,619 @@
+/* gdaui-entry.c
+ *
+ * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <string.h>
+
+#include "gdaui-entry.h"
+
+struct _GdauiEntryPrivate {
+ gchar *prefix;
+ gint prefix_len;
+ gint prefix_clen; /* UTF8 len */
+ gchar *suffix;
+ gint suffix_len;
+ gint suffix_clen; /* UTF8 len */
+ gint maxlen; /* UTF8 len */
+ gboolean isnull;
+ guchar internal_changes;
+};
+
+#define ENTER_INTERNAL_CHANGES(entry) (entry)->priv->internal_changes ++
+#define LEAVE_INTERNAL_CHANGES(entry) (entry)->priv->internal_changes --
+
+static void gdaui_entry_class_init (GdauiEntryClass *klass);
+static void gdaui_entry_init (GdauiEntry *entry);
+static void gdaui_entry_finalize (GObject *object);
+static void gdaui_entry_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdaui_entry_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+void
+_gdaui_entry_block_changes (GdauiEntry *entry)
+{
+ ENTER_INTERNAL_CHANGES(entry);
+}
+
+void
+_gdaui_entry_unblock_changes (GdauiEntry *entry)
+{
+ LEAVE_INTERNAL_CHANGES(entry);
+}
+
+
+static gchar *truncate_utf8_string (gchar *text, gint pos);
+static void adjust_display (GdauiEntry *entry, gchar *existing_text);
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_PREFIX,
+ PROP_SUFFIX,
+ PROP_MAXLEN
+};
+
+static void signal_handlers_block (GdauiEntry *entry);
+static void signal_handlers_unblock (GdauiEntry *entry);
+
+static void changed_cb (GtkEditable *editable, gpointer data);
+static void delete_text_cb (GtkEditable *editable, gint start_pos, gint end_pos, gpointer data);
+static void insert_text_cb (GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer data);
+
+
+static GObjectClass *parent_class = NULL;
+
+GType
+gdaui_entry_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (GdauiEntryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gdaui_entry_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdauiEntry),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gdaui_entry_init,
+ };
+
+ type = g_type_register_static (GTK_TYPE_ENTRY, "GdauiEntry", &type_info, 0);
+ }
+
+ return type;
+}
+
+static void
+gdaui_entry_class_init (GdauiEntryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdaui_entry_finalize;
+ klass->assume_insert = NULL;
+ klass->assume_delete = NULL;
+ klass->get_empty_text = NULL;
+
+ /* Properties */
+ object_class->set_property = gdaui_entry_set_property;
+ object_class->get_property = gdaui_entry_get_property;
+
+ g_object_class_install_property (object_class, PROP_PREFIX,
+ g_param_spec_string ("prefix", NULL, NULL, NULL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class, PROP_SUFFIX,
+ g_param_spec_string ("suffix", NULL, NULL, NULL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_override_property (object_class, PROP_MAXLEN, "max-length");
+}
+
+static void
+gdaui_entry_init (GdauiEntry *entry)
+{
+ entry->priv = g_new0 (GdauiEntryPrivate, 1);
+ entry->priv->prefix = NULL;
+ entry->priv->suffix = NULL;
+ entry->priv->maxlen = 65535; /* eg. unlimited for GtkEntry */
+ entry->priv->isnull = TRUE;
+ entry->priv->internal_changes = 0;
+
+ g_signal_connect (G_OBJECT (entry), "delete-text",
+ G_CALLBACK (delete_text_cb), NULL);
+
+ g_signal_connect (G_OBJECT (entry), "insert-text",
+ G_CALLBACK (insert_text_cb), NULL);
+
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (changed_cb), NULL);
+}
+
+static void
+gdaui_entry_finalize (GObject *object)
+{
+ GdauiEntry *entry;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDAUI_IS_ENTRY (object));
+
+ entry = GDAUI_ENTRY (object);
+ if (entry->priv) {
+ g_free (entry->priv->prefix);
+ g_free (entry->priv->suffix);
+ g_free (entry->priv);
+ entry->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->finalize (object);
+}
+
+static void
+gdaui_entry_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiEntry *entry;
+ const gchar *str;
+ gchar *otext;
+
+ entry = GDAUI_ENTRY (object);
+ if (entry->priv) {
+ switch (param_id) {
+ case PROP_PREFIX:
+ otext = gdaui_entry_get_text (entry);
+ g_free (entry->priv->prefix);
+ entry->priv->prefix = NULL;
+ entry->priv->prefix_len = 0;
+
+ str = g_value_get_string (value);
+ if (str) {
+ if (! g_utf8_validate (str, -1, NULL))
+ g_warning (_("Invalid UTF-8 format!"));
+ else {
+ entry->priv->prefix = g_strdup (str);
+ entry->priv->prefix_len = strlen (str);
+ entry->priv->prefix_clen = g_utf8_strlen (str, -1);
+ }
+ }
+ adjust_display (entry, otext);
+ g_free (otext);
+ break;
+ case PROP_SUFFIX:
+ otext = gdaui_entry_get_text (entry);
+ g_free (entry->priv->suffix);
+ entry->priv->suffix = NULL;
+ entry->priv->suffix_len = 0;
+
+ str = g_value_get_string (value);
+ if (str) {
+ if (! g_utf8_validate (str, -1, NULL))
+ g_warning (_("Invalid UTF-8 format!"));
+ else {
+ entry->priv->suffix = g_strdup (str);
+ entry->priv->suffix_len = strlen (str);
+ entry->priv->suffix_clen = g_utf8_strlen (str, -1);
+ }
+ }
+ adjust_display (entry, otext);
+ g_free (otext);
+ break;
+ case PROP_MAXLEN:
+ entry->priv->maxlen = g_value_get_int (value);
+ otext = gdaui_entry_get_text (entry);
+ adjust_display (entry, otext);
+ g_free (otext);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+static void
+gdaui_entry_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiEntry *entry;
+
+ entry = GDAUI_ENTRY (object);
+ if (entry->priv) {
+ switch (param_id) {
+ case PROP_PREFIX:
+ g_value_set_string (value, entry->priv->prefix);
+ break;
+ case PROP_SUFFIX:
+ g_value_set_string (value, entry->priv->suffix);
+ break;
+ case PROP_MAXLEN:
+ g_value_set_int (value, entry->priv->maxlen);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+static void
+signal_handlers_block (GdauiEntry *entry)
+{
+ ENTER_INTERNAL_CHANGES (entry);
+ g_signal_handlers_block_by_func (entry, G_CALLBACK (insert_text_cb), NULL);
+ g_signal_handlers_block_by_func (entry, G_CALLBACK (delete_text_cb), NULL);
+}
+
+static void
+signal_handlers_unblock (GdauiEntry *entry)
+{
+ g_signal_handlers_unblock_by_func (entry, G_CALLBACK (insert_text_cb), NULL);
+ g_signal_handlers_unblock_by_func (entry, G_CALLBACK (delete_text_cb), NULL);
+ LEAVE_INTERNAL_CHANGES (entry);
+}
+
+/*
+ * truncate_utf8_string
+ * @text: a string, not %NULL
+ * @pos: the position where the string wil be truncated <=> text[pos]=0 for ASCII
+ *
+ * Returns: @text
+ */
+static gchar *
+truncate_utf8_string (gchar *text, gint pos)
+{
+ gchar *ptr;
+ gint i;
+ for (ptr = text, i = 0; (i < pos) && ptr && *ptr; ptr = g_utf8_next_char (ptr), i++);
+ if (i == pos)
+ *ptr = 0;
+ return text;
+}
+
+/*
+ * Computes new new display
+ *
+ * WARNING: @existing_text may be modified!!!
+ */
+static void
+adjust_display (GdauiEntry *entry, gchar *existing_text)
+{
+ gchar *tmp;
+
+ if (!entry->priv->isnull) {
+ signal_handlers_block (entry);
+ if (g_utf8_strlen (existing_text, -1) > entry->priv->maxlen)
+ truncate_utf8_string (existing_text, entry->priv->maxlen);
+ tmp = g_strdup_printf ("%s%s%s",
+ entry->priv->prefix ? entry->priv->prefix : "",
+ existing_text ? existing_text : "",
+ entry->priv->suffix ? entry->priv->suffix : "");
+
+ gtk_entry_set_text (GTK_ENTRY (entry), tmp); /* emits a "changed" signal */
+ g_free (tmp);
+ signal_handlers_unblock (entry);
+ }
+}
+
+/**
+ * gdaui_entry_new:
+ * @prefix: a prefix (not modifiable) string, or %NULL
+ * @suffix: a suffix (not modifiable) string, or %NULL
+ *
+ * Creates a new #GdauiEntry widget.
+ *
+ * Returns: the newly created #GdauiEntry widget.
+ */
+GtkWidget*
+gdaui_entry_new (const gchar *prefix, const gchar *suffix)
+{
+ GObject *obj;
+
+ obj = g_object_new (GDAUI_TYPE_ENTRY, "prefix", prefix, "suffix", suffix, NULL);
+ return GTK_WIDGET (obj);
+}
+
+/**
+ * gdaui_entry_set_max_length
+ * @entry: a #GdauiEntry.
+ * @max: the maximum length of the entry, or 0 for no maximum.
+ *
+ * Sets the maximum allowed length of the contents of the widget.
+ * If the current contents are longer than the given length, then they will be truncated to fit.
+ *
+ * The difference with gtk_entry_set_max_length() is that the max length does not take into account
+ * the prefix and/or suffix parts which may have been set.
+ */
+void
+gdaui_entry_set_max_length (GdauiEntry *entry, gint max)
+{
+ g_return_if_fail (GDAUI_IS_ENTRY (entry));
+
+ g_object_set (G_OBJECT (entry), "max-length", max, NULL);
+}
+
+/**
+ * gdaui_entry_get_text:
+ * @entry: a #GdauiEntry.
+ *
+ * Get a new string containing the contents of the widget as a string without the
+ * prefix and/or suffix and/or format if they have been specified. This method differs
+ * from calling gtk_entry_get_text() since the latest will return the complete text
+ * in @entry including prefix and/or suffix and/or format.
+ *
+ * Note: %NULL may be returned if this method is called while the widget is working on some
+ * internal modifications, or if gdaui_entry_set_text() was called with a %NULL
+ * as its @text argument.
+ *
+ * Returns: a new string, or %NULL
+ */
+gchar *
+gdaui_entry_get_text (GdauiEntry *entry)
+{
+ gchar *text;
+
+ g_return_val_if_fail (GDAUI_IS_ENTRY (entry), NULL);
+ g_return_val_if_fail (entry->priv, NULL);
+
+ if (entry->priv->isnull)
+ text = NULL;
+ else {
+ const gchar *ctext;
+ gint len;
+ ctext = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (ctext) {
+ len = strlen (ctext);
+ text = g_strdup (ctext);
+ if (entry->priv->prefix) {
+ len -= entry->priv->prefix_len;
+ g_memmove (text, text + entry->priv->prefix_len, len+1);
+ }
+ if (entry->priv->suffix) {
+ len -= entry->priv->suffix_len;
+ text [len] = 0;
+ }
+ }
+ else
+ text = g_strdup ("");
+ }
+
+ return text;
+}
+
+/**
+ * gdaui_entry_set_text
+ * @entry: a #GdauiEntry widget
+ * @text: the text to set into @entry, or %NULL
+ *
+ * Sets @text into @entry.
+ *
+ * As a side effect, if @text is %NULL, then the entry will
+ * be completely empty, whereas if @text is the empty string (""), then
+ * @entry will display the prefix and/or suffix and/or format string if they have
+ * been set. Except this case, calling this method is similar to calling
+ * gtk_entry_set_text()
+ */
+void
+gdaui_entry_set_text (GdauiEntry *entry, const gchar *text)
+{
+ g_return_if_fail (GDAUI_IS_ENTRY (entry));
+ g_return_if_fail (entry->priv);
+
+ if (text) {
+ entry->priv->isnull = TRUE;
+ signal_handlers_block (entry);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ signal_handlers_unblock (entry);
+ ENTER_INTERNAL_CHANGES(entry);
+ gtk_entry_set_text (GTK_ENTRY (entry), text); /* emits the "insert-text" signal which is treated */
+ LEAVE_INTERNAL_CHANGES(entry);
+ g_signal_emit_by_name (entry, "changed");
+ }
+ else {
+ entry->priv->isnull = TRUE;
+ signal_handlers_block (entry);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ signal_handlers_unblock (entry);
+ g_signal_emit_by_name (entry, "changed");
+ }
+}
+
+/**
+ * gdaui_entry_set_prefix
+ * @entry: a #GdauiEntry widget
+ * @prefix: a prefix string
+ *
+ * Sets @prefix as a prefix string of @entry: that string will always be displayed in the
+ * text entry, will not be modifiable, and won't be part of the returned text
+ */
+void
+gdaui_entry_set_prefix (GdauiEntry *entry, const gchar *prefix)
+{
+ g_return_if_fail (GDAUI_IS_ENTRY (entry));
+ g_return_if_fail (entry->priv);
+
+ g_object_set (G_OBJECT (entry), "prefix", prefix, NULL);
+}
+
+/**
+ * gdaui_entry_set_suffix
+ * @entry: a #GdauiEntry widget
+ * @suffix: a suffix string
+ *
+ * Sets @suffix as a suffix string of @entry: that string will always be displayed in the
+ * text entry, will not be modifiable, and won't be part of the returned text
+ */
+void
+gdaui_entry_set_suffix (GdauiEntry *entry, const gchar *suffix)
+{
+ g_return_if_fail (GDAUI_IS_ENTRY (entry));
+ g_return_if_fail (entry->priv);
+
+ g_object_set (G_OBJECT (entry), "suffix", suffix, NULL);
+}
+
+
+/*
+ * callbacks
+ */
+
+static void
+changed_cb (GtkEditable *editable, gpointer data)
+{
+ GdauiEntry *entry = (GdauiEntry*) editable;
+ if (entry->priv->internal_changes > 0)
+ g_signal_stop_emission_by_name (editable, "changed");
+}
+
+static void
+delete_text_cb (GtkEditable *editable, gint start_pos, gint end_pos, gpointer data)
+{
+ const gchar *otext = NULL;
+ gint len;
+ gint nstart = start_pos, nend = end_pos;
+ GdauiEntry *entry = GDAUI_ENTRY (editable);
+
+ signal_handlers_block (entry);
+ if (entry->priv->prefix) {
+ if (nstart < entry->priv->prefix_clen)
+ nstart = entry->priv->prefix_clen;
+ }
+ if (nend < 0) {
+ otext = gtk_entry_get_text ((GtkEntry*) entry);
+ len = g_utf8_strlen (otext, -1);
+ nend = len;
+ }
+
+ if (nend - nstart < 1) {
+ g_signal_stop_emission_by_name (editable, "delete-text");
+ signal_handlers_unblock (entry);
+ return;
+ }
+
+ if (entry->priv->suffix) {
+ if (!otext) {
+ otext = gtk_entry_get_text ((GtkEntry*) entry);
+ len = g_utf8_strlen (otext, -1);
+ }
+ if (nend - nstart == 1) {
+ if ((nstart >= len - entry->priv->suffix_clen)) {
+ nstart = len - entry->priv->suffix_clen - 1;
+ nend = nstart + 1;
+ g_signal_stop_emission_by_name (editable, "delete-text");
+ signal_handlers_unblock (entry);
+ gtk_editable_set_position (editable, nend);
+ gtk_editable_delete_text (editable, nstart, nend);
+ return;
+ }
+ }
+ if (nend > len - entry->priv->suffix_clen)
+ nend = len - entry->priv->suffix_clen;
+ }
+
+ if (GDAUI_ENTRY_GET_CLASS (editable)->assume_delete) {
+ g_signal_stop_emission_by_name (editable, "delete-text");
+ GDAUI_ENTRY_GET_CLASS (editable)->assume_delete (entry, nstart - entry->priv->prefix_clen,
+ nend - entry->priv->prefix_clen,
+ entry->priv->prefix_clen);
+ //g_print ("Subclass assumes text delete\n");
+ }
+ else if ((nstart != start_pos) || (nend != end_pos)) {
+ g_signal_stop_emission_by_name (editable, "delete-text");
+ if (nstart != nend)
+ gtk_editable_delete_text (editable, nstart, nend);
+ }
+
+ signal_handlers_unblock (entry);
+ g_signal_emit_by_name (entry, "changed");
+}
+
+
+static void
+insert_text_cb (GtkEditable *editable, const gchar *text, gint text_length, gint *position, gpointer data)
+{
+ const gchar *otext;
+ gint clen;
+ GdauiEntry *entry = GDAUI_ENTRY (editable);
+ gint text_clen;
+
+ signal_handlers_block (entry);
+
+ if (entry->priv->isnull) {
+ gchar *etext = NULL;
+ entry->priv->isnull = FALSE;
+ if (GDAUI_ENTRY_GET_CLASS (editable)->get_empty_text)
+ etext = GDAUI_ENTRY_GET_CLASS (editable)->get_empty_text (entry);
+ adjust_display (entry, etext ? etext : "");
+ g_free (etext);
+ }
+
+ otext = gtk_entry_get_text ((GtkEntry*) entry);
+ clen = g_utf8_strlen (otext, -1);
+
+ /* adjust insert position */
+ if (entry->priv->prefix) {
+ if (*position < entry->priv->prefix_clen)
+ *position = entry->priv->prefix_clen;
+ }
+ if (entry->priv->suffix) {
+ if (*position > clen - entry->priv->suffix_clen)
+ *position = clen - entry->priv->suffix_clen;
+ }
+
+ /* test if the whole insertion is Ok */
+ text_clen = g_utf8_strlen (text, text_length);
+ if (clen - entry->priv->prefix_clen - entry->priv->suffix_clen + text_clen > entry->priv->maxlen) {
+ gchar *itext;
+ gint nallowed;
+ nallowed = entry->priv->maxlen - (clen - entry->priv->prefix_clen - entry->priv->suffix_clen);
+ g_signal_stop_emission_by_name (editable, "insert-text");
+ itext = g_strdup (text);
+ itext [nallowed] = 0; /* FIXME: convert nallowed to gchar */
+ /*g_print ("Corrected by length insert text: [%s]\n", itext);*/
+ if (*itext)
+ gtk_editable_insert_text (editable, itext, nallowed, position);
+ g_free (itext);
+ }
+ else if (GDAUI_ENTRY_GET_CLASS (editable)->assume_insert) {
+ g_signal_stop_emission_by_name (editable, "insert-text");
+ //g_print ("Subclass assumes text insert\n");
+ gint pos = *position - entry->priv->prefix_clen;
+ GDAUI_ENTRY_GET_CLASS (editable)->assume_insert (entry, text, text_length,
+ &pos, entry->priv->prefix_clen);
+ *position = pos + entry->priv->prefix_clen;
+ }
+
+ signal_handlers_unblock (entry);
+ g_signal_emit_by_name (entry, "changed");
+}
diff --git a/libgda-ui/data-entries/gdaui-entry.h b/libgda-ui/data-entries/gdaui-entry.h
new file mode 100644
index 0000000..a5f3875
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-entry.h
@@ -0,0 +1,101 @@
+/* gdaui-entry.h
+ *
+ * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 __GDAUI_ENTRY_H__
+#define __GDAUI_ENTRY_H__
+
+#include <gtk/gtkentry.h>
+
+G_BEGIN_DECLS
+
+#define GDAUI_TYPE_ENTRY (gdaui_entry_get_type ())
+#define GDAUI_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDAUI_TYPE_ENTRY, GdauiEntry))
+#define GDAUI_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDAUI_TYPE_ENTRY, GdauiEntryClass))
+#define GDAUI_IS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDAUI_TYPE_ENTRY))
+#define GDAUI_IS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDAUI_TYPE_ENTRY))
+#define GDAUI_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDAUI_TYPE_ENTRY, GdauiEntryClass))
+
+typedef struct _GdauiEntry GdauiEntry;
+typedef struct _GdauiEntryClass GdauiEntryClass;
+typedef struct _GdauiEntryPrivate GdauiEntryPrivate;
+
+struct _GdauiEntry
+{
+ GtkEntry entry;
+ GdauiEntryPrivate *priv;
+};
+
+struct _GdauiEntryClass
+{
+ GtkEntryClass parent_class;
+
+ /* virtual methods */
+ /**
+ * GdauiEntryClass::get_empty_text
+ *
+ * If defined, sould return a text suitable to display EMPTY value, it will be called when
+ * entry was set to NULL and is becomming not NULL
+ *
+ * Returs: a newt string, or %NULL
+ */
+ gchar *(*get_empty_text) (GdauiEntry *entry);
+
+ /**
+ * GdauiEntryClass::assume_insert
+ * @entry:
+ * @text: the text to be inserted
+ * @text_length: @text's length in bytes (not characters)
+ * @virt_pos: the position where @text is to be inserted
+ * @offset: an offset to add to positions using @virt_pos as reference to call gtk_editable_*()
+ *
+ * To be defined by children classes to handle insert themselves
+ */
+ void (*assume_insert) (GdauiEntry *entry, const gchar *text, gint text_length,
+ gint *virt_pos, gint offset);
+ /**
+ * GdauiEntryClass::assume_delete
+ * @entry:
+ * @virt_start_pos: the starting position.
+ * @virt_end_pos: the end position (not included in deletion), always > @start_pos
+ * @offset: an offset to add to positions using @virt_start_pos or @virt_end_pos as reference
+ * to call gtk_editable_*()
+ *
+ * To be defined by children classes to handle delete themselves
+ */
+ void (*assume_delete) (GdauiEntry *entry, gint virt_start_pos, gint virt_end_pos, gint offset);
+};
+
+GType gdaui_entry_get_type (void) G_GNUC_CONST;
+GtkWidget *gdaui_entry_new (const gchar *prefix, const gchar *suffix);
+
+void gdaui_entry_set_max_length (GdauiEntry *entry, gint max);
+void gdaui_entry_set_prefix (GdauiEntry *entry, const gchar *prefix);
+void gdaui_entry_set_suffix (GdauiEntry *entry, const gchar *suffix);
+
+void gdaui_entry_set_text (GdauiEntry *entry, const gchar *text);
+gchar *gdaui_entry_get_text (GdauiEntry *entry);
+
+/* for sub classes */
+void _gdaui_entry_block_changes (GdauiEntry *entry);
+void _gdaui_entry_unblock_changes (GdauiEntry *entry);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda-ui/data-entries/gdaui-formatted-entry.c b/libgda-ui/data-entries/gdaui-formatted-entry.c
new file mode 100644
index 0000000..f0640c3
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-formatted-entry.c
@@ -0,0 +1,489 @@
+/* gdaui-formatted-entry.c
+ *
+ * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <string.h>
+
+#include "gdaui-formatted-entry.h"
+
+struct _GdauiFormattedEntryPrivate {
+ gchar *format; /* UTF-8! */
+ gint format_clen; /* in characters, not gchar */
+ gchar *mask; /* ASCII! */
+ gint mask_len; /* in gchar */
+};
+
+static void gdaui_formatted_entry_class_init (GdauiFormattedEntryClass *klass);
+static void gdaui_formatted_entry_init (GdauiFormattedEntry *entry);
+static void gdaui_formatted_entry_finalize (GObject *object);
+static void gdaui_formatted_entry_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdaui_formatted_entry_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static gchar *gdaui_formatted_entry_get_empty_text (GdauiEntry *entry);
+static void gdaui_formatted_entry_assume_insert (GdauiEntry *entry, const gchar *text, gint text_length, gint *virt_pos, gint offset);
+static void gdaui_formatted_entry_assume_delete (GdauiEntry *entry, gint virt_start_pos, gint virt_end_pos, gint offset);
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_FORMAT,
+ PROP_MASK
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+gdaui_formatted_entry_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (GdauiFormattedEntryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gdaui_formatted_entry_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdauiFormattedEntry),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gdaui_formatted_entry_init,
+ };
+
+ type = g_type_register_static (GDAUI_TYPE_ENTRY, "GdauiFormattedEntry", &type_info, 0);
+ }
+
+ return type;
+}
+
+static void
+gdaui_formatted_entry_class_init (GdauiFormattedEntryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdaui_formatted_entry_finalize;
+ GDAUI_ENTRY_CLASS (klass)->assume_insert = gdaui_formatted_entry_assume_insert;
+ GDAUI_ENTRY_CLASS (klass)->assume_delete = gdaui_formatted_entry_assume_delete;
+ GDAUI_ENTRY_CLASS (klass)->get_empty_text = gdaui_formatted_entry_get_empty_text;
+
+ /* Properties */
+ object_class->set_property = gdaui_formatted_entry_set_property;
+ object_class->get_property = gdaui_formatted_entry_get_property;
+
+ g_object_class_install_property (object_class, PROP_FORMAT,
+ g_param_spec_string ("format", NULL, NULL, NULL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class, PROP_MASK,
+ g_param_spec_string ("mask", NULL, NULL, NULL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+static void
+gdaui_formatted_entry_init (GdauiFormattedEntry *entry)
+{
+ entry->priv = g_new0 (GdauiFormattedEntryPrivate, 1);
+ entry->priv->format = NULL;
+ entry->priv->mask = NULL;
+}
+
+static void
+gdaui_formatted_entry_finalize (GObject *object)
+{
+ GdauiFormattedEntry *entry;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDAUI_IS_ENTRY (object));
+
+ entry = GDAUI_FORMATTED_ENTRY (object);
+ if (entry->priv) {
+ g_free (entry->priv->format);
+ g_free (entry->priv->mask);
+ g_free (entry->priv);
+ entry->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->finalize (object);
+}
+
+static void
+gdaui_formatted_entry_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiFormattedEntry *entry;
+ const gchar *str;
+ gchar *otext;
+
+ entry = GDAUI_FORMATTED_ENTRY (object);
+ otext = gdaui_entry_get_text (GDAUI_ENTRY (entry));
+ if (entry->priv) {
+ switch (param_id) {
+ case PROP_FORMAT:
+ g_free (entry->priv->format);
+ entry->priv->format = NULL;
+ entry->priv->format_clen = 0;
+
+ str = g_value_get_string (value);
+ if (str) {
+ if (! g_utf8_validate (str, -1, NULL))
+ g_warning (_("Invalid UTF-8 format!"));
+ else {
+ entry->priv->format = g_strdup (str);
+ entry->priv->format_clen = g_utf8_strlen (str, -1);
+ gtk_entry_set_max_length (GTK_ENTRY (entry), entry->priv->format_clen);
+ }
+ }
+ break;
+ case PROP_MASK:
+ g_free (entry->priv->mask);
+ entry->priv->mask = NULL;
+ entry->priv->mask_len = 0;
+
+ str = g_value_get_string (value);
+ if (str) {
+ entry->priv->mask = g_strdup (str);
+ entry->priv->mask_len = strlen (str);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+ gdaui_entry_set_text (GDAUI_ENTRY (entry), otext);
+ g_free (otext);
+}
+
+static void
+gdaui_formatted_entry_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiFormattedEntry *entry;
+
+ entry = GDAUI_FORMATTED_ENTRY (object);
+ if (entry->priv) {
+ switch (param_id) {
+ case PROP_FORMAT:
+ g_value_set_string (value, entry->priv->format);
+ break;
+ case PROP_MASK:
+ g_value_set_string (value, entry->priv->mask);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+/*
+ * is_writable
+ * @fentry:
+ * @pos: the position (in characters) in @fentry->priv->format
+ * @ptr: the character (in @fentry->priv->format)
+ *
+ * Returns: %TRUE if it is a writable loaction
+ */
+static gboolean
+is_writable (GdauiFormattedEntry *fentry, gint pos, const gchar *ptr)
+{
+ if (((*ptr == '0') ||
+ (*ptr == '9') ||
+ (*ptr == '@') ||
+ (*ptr == '^') ||
+ (*ptr == '#') ||
+ (*ptr == '*')) &&
+ (!fentry->priv->mask ||
+ (fentry->priv->mask &&
+ (pos < fentry->priv->mask_len) &&
+ (fentry->priv->mask [pos] != ' '))))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*
+ * is_allowed
+ * @fentry:
+ * @ptr: the character (in @fentry->priv->format)
+ * @wc: the character to be inserted
+ *
+ * Returns: %TRUE if @wc can be used to replace @ptr
+ */
+static gboolean
+is_allowed (GdauiFormattedEntry *fentry, const gchar *ptr, const gunichar wc, gunichar *out_wc)
+{
+ gunichar fwc;
+
+ fwc = g_utf8_get_char (ptr);
+ *out_wc = wc;
+ if (*ptr == '0')
+ return g_unichar_isdigit (wc);
+ else if (*ptr == '9')
+ return g_unichar_isdigit (wc) && (wc != g_utf8_get_char ("0"));
+ else if (*ptr == '@')
+ return g_unichar_isalpha (wc);
+ else if (*ptr == '^') {
+ gboolean isa = g_unichar_isalpha (wc);
+ if (isa)
+ *out_wc = g_unichar_toupper (wc);
+ return isa;
+ }
+ else if (*ptr == '#')
+ return g_unichar_isalnum (wc);
+ else if (*ptr == '*')
+ return g_unichar_isprint (wc);
+ else {
+ g_warning (_("Unknown format character starting at %s"), ptr);
+ return FALSE;
+ }
+}
+
+static gchar *
+gdaui_formatted_entry_get_empty_text (GdauiEntry *entry)
+{
+ GdauiFormattedEntry *fentry;
+
+ fentry = (GdauiFormattedEntry*) entry;
+ if (fentry->priv->format) {
+ GString *string;
+
+ string = g_string_new ("");
+ gchar *ptr;
+ gint i;
+ for (ptr = fentry->priv->format, i = 0;
+ ptr && *ptr;
+ ptr = g_utf8_next_char (ptr), i++) {
+ if (is_writable (fentry, i, ptr))
+ g_string_append_c (string, '_');
+ else {
+ gunichar wc;
+ wc = g_utf8_get_char (ptr);
+ g_string_append_unichar (string, wc);
+ }
+ }
+ return g_string_free (string, FALSE);
+ }
+ else
+ return NULL;
+}
+
+static void
+gdaui_formatted_entry_assume_insert (GdauiEntry *entry, const gchar *text, gint text_length,
+ gint *virt_pos, gint offset)
+{
+ GdauiFormattedEntry *fentry;
+ gint i, pos;
+
+ fentry = (GdauiFormattedEntry*) entry;
+
+ const gchar *ptr, *fptr;
+ pos = *virt_pos;
+ for (fptr = fentry->priv->format, i = 0;
+ (i < pos) && fptr && *fptr;
+ fptr = g_utf8_next_char (fptr), i++);
+
+ if (i != pos)
+ return;
+
+ _gdaui_entry_block_changes (entry);
+ for (ptr = text, i = 0; ptr && *ptr && *fptr; ptr = g_utf8_next_char (ptr)) {
+ while ((pos < fentry->priv->format_clen) &&
+ !is_writable (fentry, pos, fptr)) {
+ fptr = g_utf8_next_char (fptr);
+ if (!fptr || !*fptr)
+ return;
+ pos++;
+ }
+
+ gunichar wc;
+ wc = g_utf8_get_char (ptr);
+ if ((pos < fentry->priv->format_clen) &&
+ is_allowed (fentry, fptr, wc, &wc)){
+ /* Ok, insert *ptr (<=> text[i] if it was ASCII) */
+ gint rpos = pos + offset;
+ gint usize;
+ gchar buf [6];
+
+ usize = g_unichar_to_utf8 (wc, buf);
+ gtk_editable_delete_text ((GtkEditable*) entry, rpos, rpos + 1);
+ gtk_editable_insert_text ((GtkEditable*) entry, buf, usize, &rpos);
+ pos++;
+ fptr = g_utf8_next_char (fptr);
+ }
+ }
+ _gdaui_entry_unblock_changes (entry);
+ *virt_pos = pos;
+}
+
+static void
+gdaui_formatted_entry_assume_delete (GdauiEntry *entry, gint virt_start_pos, gint virt_end_pos, gint offset)
+{
+ GdauiFormattedEntry *fentry;
+ gchar *fptr;
+ gint i;
+
+ fentry = (GdauiFormattedEntry*) entry;
+
+#ifdef GDA_DEBUG
+ gint clen;
+ gchar *otext;
+ otext = gdaui_entry_get_text (entry);
+ if (otext) {
+ clen = g_utf8_strlen (otext, -1);
+ g_assert (clen == fentry->priv->format_clen);
+ g_free (otext);
+ }
+#endif
+
+ g_assert (virt_end_pos <= fentry->priv->format_clen);
+
+ /* move fptr to the @virt_start_pos in fentry->priv->format */
+ for (fptr = fentry->priv->format, i = 0;
+ (i < virt_start_pos) && *fptr;
+ fptr = g_utf8_next_char (fptr), i++);
+ if (i != virt_start_pos)
+ return;
+
+ _gdaui_entry_block_changes (entry);
+ for (;
+ (i < virt_end_pos) && fptr && *fptr;
+ fptr = g_utf8_next_char (fptr), i++) {
+ if (!is_writable (fentry, i, fptr)) {
+ if (virt_end_pos - virt_start_pos == 1) {
+ gint npos;
+ npos = gtk_editable_get_position ((GtkEditable*) entry);
+ while ((i >= 0) && !is_writable (fentry, i, fptr)) {
+ virt_start_pos --;
+ virt_end_pos --;
+ i--;
+ fptr = g_utf8_find_prev_char (fentry->priv->format, fptr);
+ npos --;
+ }
+ if (i < 0)
+ return;
+ else
+ gtk_editable_set_position ((GtkEditable*) entry, npos);
+ }
+ else
+ continue;
+ }
+ gint rpos = i + offset;
+ gtk_editable_delete_text ((GtkEditable*) entry, rpos, rpos + 1);
+ gtk_editable_insert_text ((GtkEditable*) entry, "_", 1, &rpos);
+ }
+ _gdaui_entry_unblock_changes (entry);
+}
+
+/**
+ * gdaui_formatted_entry_new:
+ * @format: a format string
+ * @mask: a mask string, or %NULL
+ *
+ * Creates a new #GdauiFormattedEntry widget.
+ *
+ * Characters in @format are of two types:
+ * writeable: writeable characters which will be replaced with and underscore and where text will be entered
+ * fixed: every other characters are fixed characters, where text cant' be edited, and will be displayed AS IS
+ *
+ * Possible values for writeable characters are:
+ * <itemizedlist>
+ * <listitem><para>'0': digits</para></listitem>
+ * <listitem><para>'9': digits excluded 0</para></listitem>
+ * <listitem><para>'@': alpha</para></listitem>
+ * <listitem><para>'^': alpha converted to upper case</para></listitem>
+ * <listitem><para>'#': alphanumeric</para></listitem>
+ * <listitem><para>'*': any char</para></listitem>
+ * </itemizedlist>
+ *
+ * if @mask is not %NULL, then it should only contains the follogin characters, which are used side by side with
+ * @format's characters:
+ * <itemizedlist>
+ * <listitem><para>'_': the corresponding character in @format is actually used as a writable character</para></listitem>
+ * <listitem><para>'-': the corresponding character in @format is actually used as a writable character, but
+ * the character will be removed from gdaui_formatted_entry_get_text()'s result if it was not
+ * filled by the user</para></listitem>
+ * <listitem><para>' ': the corresponding character in @format will not be considered as a writable character
+ * but as a non writable character</para></listitem>
+ * </itemizedlist>
+ * it is then interpreted in the following way: for a character C in @format, if the character at the same
+ * position in @mask is the space character (' '), then C will not interpreted as a writable format
+ * character as defined above. @mask does not be to have the same length as @format.
+ *
+ * Returns: the newly created #GdauiFormattedEntry widget.
+ */
+GtkWidget*
+gdaui_formatted_entry_new (const gchar *format, const gchar *mask)
+{
+ GObject *obj;
+
+ obj = g_object_new (GDAUI_TYPE_FORMATTED_ENTRY, "format", format, "mask", mask, NULL);
+ return GTK_WIDGET (obj);
+}
+
+/**
+ * gdaui_formatted_entry_get_text
+ * @entry: a #GdauiFormattedEntry widget
+ *
+ * Get @entry's contents. This function is similar to gdaui_get_text() except
+ * that it optionnally uses the information contained in @mask when gdaui_formatted_entry_new()
+ * was called to format the output differently.
+ *
+ * Returns: a new string, or %NULL
+ */
+gchar *
+gdaui_formatted_entry_get_text (GdauiFormattedEntry *entry)
+{
+ gchar *text;
+ g_return_val_if_fail (GDAUI_IS_FORMATTED_ENTRY (entry), NULL);
+
+ text = gdaui_entry_get_text ((GdauiEntry*) entry);
+ if (text && entry->priv->mask) {
+ gchar *tptr, *mptr;
+ gint len;
+ len = strlen (text);
+ for (tptr = text, mptr = entry->priv->mask;
+ *tptr && *mptr;
+ mptr++) {
+ if ((*mptr == '-') && (*tptr == '_')) {
+ /* remove that char */
+ g_memmove (tptr, tptr+1, len - (tptr - text));
+ }
+ else
+ tptr = g_utf8_next_char (tptr);
+ }
+ }
+
+ return text;
+}
diff --git a/libgda-ui/data-entries/gdaui-formatted-entry.h b/libgda-ui/data-entries/gdaui-formatted-entry.h
new file mode 100644
index 0000000..9c869d1
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-formatted-entry.h
@@ -0,0 +1,57 @@
+/* gdaui-formatted-entry.h
+ *
+ * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 __GDAUI_FORMATTED_ENTRY_H__
+#define __GDAUI_FORMATTED_ENTRY_H__
+
+#include "gdaui-entry.h"
+
+G_BEGIN_DECLS
+
+#define GDAUI_TYPE_FORMATTED_ENTRY (gdaui_formatted_entry_get_type ())
+#define GDAUI_FORMATTED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDAUI_TYPE_FORMATTED_ENTRY, GdauiFormattedEntry))
+#define GDAUI_FORMATTED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDAUI_TYPE_FORMATTED_ENTRY, GdauiFormattedEntry))
+#define GDAUI_IS_FORMATTED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDAUI_TYPE_FORMATTED_ENTRY))
+#define GDAUI_IS_FORMATTED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDAUI_TYPE_FORMATTED_ENTRY))
+#define GDAUI_FORMATTED_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDAUI_TYPE_FORMATTED_ENTRY, GdauiFormattedEntry))
+
+
+typedef struct _GdauiFormattedEntry GdauiFormattedEntry;
+typedef struct _GdauiFormattedEntryClass GdauiFormattedEntryClass;
+typedef struct _GdauiFormattedEntryPrivate GdauiFormattedEntryPrivate;
+
+struct _GdauiFormattedEntry
+{
+ GdauiEntry entry;
+ GdauiFormattedEntryPrivate *priv;
+};
+
+struct _GdauiFormattedEntryClass
+{
+ GdauiEntryClass parent_class;
+};
+
+GType gdaui_formatted_entry_get_type (void) G_GNUC_CONST;
+GtkWidget *gdaui_formatted_entry_new (const gchar *format, const gchar *mask);
+gchar *gdaui_formatted_entry_get_text (GdauiFormattedEntry *entry);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda-ui/data-entries/gdaui-numeric-entry.c b/libgda-ui/data-entries/gdaui-numeric-entry.c
new file mode 100644
index 0000000..29bbd6b
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-numeric-entry.c
@@ -0,0 +1,695 @@
+/* gdaui-numeric-entry.c
+ *
+ * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <string.h>
+#include <libgda/gda-value.h>
+#include <errno.h>
+
+#include <math.h>
+
+#include "gdaui-numeric-entry.h"
+
+typedef struct {
+ gboolean is_numerical;
+ gint64 imin;
+ gint64 imax;
+ guint64 uimax;
+ gdouble fmax;
+ gboolean is_int;
+ gboolean is_signed;
+} NumAttr;
+
+struct _GdauiNumericEntryPrivate {
+ GType type;
+ gchar decimal_sep; /* default obtained automatically */
+ gchar thousands_sep; /* 0 for no separator */
+ guint16 nb_decimals; /* G_MAXUINT16 for no limit */
+
+ NumAttr num_attr;
+};
+
+static void gdaui_numeric_entry_class_init (GdauiNumericEntryClass *klass);
+static void gdaui_numeric_entry_init (GdauiNumericEntry *entry);
+static void gdaui_numeric_entry_finalize (GObject *object);
+static void gdaui_numeric_entry_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdaui_numeric_entry_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gdaui_numeric_entry_assume_insert (GdauiEntry *entry, const gchar *text, gint text_length, gint *virt_pos, gint offset);
+static void gdaui_numeric_entry_assume_delete (GdauiEntry *entry, gint virt_start_pos, gint virt_end_pos, gint offset);
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_TYPE,
+ PROP_N_DECIMALS,
+ PROP_DECIMAL_SEP,
+ PROP_THOUSANDS_SEP
+};
+
+static GObjectClass *parent_class = NULL;
+
+GType
+gdaui_numeric_entry_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (GdauiNumericEntryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gdaui_numeric_entry_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdauiNumericEntry),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gdaui_numeric_entry_init,
+ };
+
+ type = g_type_register_static (GDAUI_TYPE_ENTRY, "GdauiNumericEntry", &type_info, 0);
+ }
+
+ return type;
+}
+
+static void
+gdaui_numeric_entry_class_init (GdauiNumericEntryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdaui_numeric_entry_finalize;
+ GDAUI_ENTRY_CLASS (klass)->assume_insert = gdaui_numeric_entry_assume_insert;
+ GDAUI_ENTRY_CLASS (klass)->assume_delete = gdaui_numeric_entry_assume_delete;
+ GDAUI_ENTRY_CLASS (klass)->get_empty_text = NULL;
+
+ /* Properties */
+ object_class->set_property = gdaui_numeric_entry_set_property;
+ object_class->get_property = gdaui_numeric_entry_get_property;
+
+ g_object_class_install_property (object_class, PROP_TYPE,
+ g_param_spec_gtype ("type", NULL, NULL, G_TYPE_NONE,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class, PROP_N_DECIMALS,
+ g_param_spec_uint ("n-decimals", NULL, NULL,
+ 0, G_MAXUINT16, G_MAXUINT16,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class, PROP_DECIMAL_SEP,
+ g_param_spec_char ("decimal-sep", NULL, NULL,
+ 0, 127, '.',
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class, PROP_THOUSANDS_SEP,
+ g_param_spec_char ("thousands_sep", NULL, NULL,
+ 0, 127, ',',
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+static void
+compute_numeric_attributes (GType type, NumAttr *attr)
+{
+ attr->imin = 0;
+ attr->imax = 0;
+ attr->uimax = 0;
+ attr->fmax = 0.;
+ attr->is_int = FALSE;
+ attr->is_signed = TRUE;
+ attr->is_numerical = TRUE;
+
+ if (type == G_TYPE_INT64) {
+ attr->imax = G_MAXINT64;
+ attr->imin = G_MININT64;
+ attr->is_int = TRUE;
+ }
+ else if (type == G_TYPE_UINT64) {
+ attr->uimax = G_MAXUINT64;
+ attr->is_int = TRUE;
+ attr->is_signed = FALSE;
+ }
+ else if (type == G_TYPE_LONG) {
+ attr->imax = G_MAXLONG;
+ attr->imin = G_MINLONG;
+ attr->is_int = TRUE;
+ }
+ else if (type == G_TYPE_ULONG) {
+ attr->uimax = G_MAXULONG;
+ attr->is_int = TRUE;
+ attr->is_signed = FALSE;
+ }
+ else if (type == G_TYPE_INT) {
+ attr->imax = G_MAXINT;
+ attr->imin = G_MININT;
+ attr->is_int = TRUE;
+ }
+ else if (type == G_TYPE_UINT) {
+ attr->uimax = G_MAXUINT;
+ attr->is_int = TRUE;
+ attr->is_signed = FALSE;
+ }
+ else if (type == G_TYPE_CHAR) {
+ attr->imax = 127;
+ attr->imin = -128;
+ attr->is_int = TRUE;
+ }
+ else if (type == G_TYPE_UCHAR) {
+ attr->uimax = 255;
+ attr->is_int = TRUE;
+ attr->is_signed = FALSE;}
+ else if (type == G_TYPE_FLOAT) {
+ attr->fmax = G_MAXFLOAT;
+ }
+ else if (type == G_TYPE_DOUBLE) {
+ attr->fmax = G_MAXDOUBLE;
+ }
+ else if (type == GDA_TYPE_NUMERIC) {
+ }
+ else if (type == GDA_TYPE_SHORT) {
+ attr->imax = G_MAXSHORT;
+ attr->imin = G_MINSHORT;
+ attr->is_int = TRUE;
+ }
+ else if (type == GDA_TYPE_USHORT) {
+ attr->uimax = G_MAXUSHORT;
+ attr->is_int = TRUE;
+ attr->is_signed = FALSE;
+ }
+ else {
+ attr->is_numerical = FALSE;
+ }
+}
+
+static gchar
+get_default_decimal_sep ()
+{
+ static gchar value = 0;
+
+ if (value == 0) {
+ gchar text[20];
+ sprintf (text, "%f", 1.23);
+ value = text[1];
+ }
+ return value;
+}
+
+static void
+gdaui_numeric_entry_init (GdauiNumericEntry *entry)
+{
+ entry->priv = g_new0 (GdauiNumericEntryPrivate, 1);
+ entry->priv->type = G_TYPE_INT64;
+ compute_numeric_attributes (entry->priv->type, &(entry->priv->num_attr));
+ entry->priv->decimal_sep = get_default_decimal_sep ();
+ entry->priv->thousands_sep = 0;
+ entry->priv->nb_decimals = G_MAXUINT16;
+}
+
+static void
+gdaui_numeric_entry_finalize (GObject *object)
+{
+ GdauiNumericEntry *entry;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDAUI_IS_ENTRY (object));
+
+ entry = GDAUI_NUMERIC_ENTRY (object);
+ if (entry->priv) {
+ g_free (entry->priv);
+ entry->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->finalize (object);
+}
+
+static void
+gdaui_numeric_entry_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiNumericEntry *entry;
+ gchar *otext;
+
+ entry = GDAUI_NUMERIC_ENTRY (object);
+ otext = gdaui_entry_get_text (GDAUI_ENTRY (entry));
+ if (entry->priv) {
+ switch (param_id) {
+ case PROP_TYPE: {
+ NumAttr num_attr;
+ compute_numeric_attributes (g_value_get_gtype (value), &num_attr);
+ if (num_attr.is_numerical == FALSE)
+ g_warning (_("Type %s is not numerical"), g_type_name (g_value_get_gtype (value)));
+ else {
+ entry->priv->type = g_value_get_gtype (value);
+ entry->priv->num_attr = num_attr;
+ }
+ break;
+ }
+ case PROP_N_DECIMALS:
+ entry->priv->nb_decimals = g_value_get_uint (value);
+ break;
+ case PROP_DECIMAL_SEP: {
+ gchar sep = g_value_get_char (value);
+ if ((sep == 0) || (sep == '+') || (sep == '-'))
+ g_warning (_("Decimal separator cannot be the '%c' character"), sep ? sep : '0');
+ else {
+ entry->priv->decimal_sep = g_value_get_char (value);
+ }
+ break;
+ }
+ case PROP_THOUSANDS_SEP: {
+ gchar sep = g_value_get_char (value);
+ if ((sep == '+') || (sep == '-') || (sep == '_'))
+ g_warning (_("Decimal thousands cannot be the '%c' character"), sep);
+ else {
+ entry->priv->thousands_sep = g_value_get_char (value);
+ }
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+ gdaui_entry_set_text (GDAUI_ENTRY (entry), otext);
+ g_free (otext);
+}
+
+static void
+gdaui_numeric_entry_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdauiNumericEntry *entry;
+
+ entry = GDAUI_NUMERIC_ENTRY (object);
+ if (entry->priv) {
+ switch (param_id) {
+ case PROP_TYPE:
+ g_value_set_gtype (value, entry->priv->type);
+ break;
+ case PROP_N_DECIMALS:
+ g_value_set_uint (value, entry->priv->nb_decimals);
+ break;
+ case PROP_DECIMAL_SEP:
+ g_value_set_char (value, entry->priv->decimal_sep);
+ break;
+ case PROP_THOUSANDS_SEP:
+ g_value_set_char (value, entry->priv->thousands_sep);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+/*
+ * text_unformat
+ * @pos: an inout parameter to keep track of a position
+ *
+ * Removes any thousand separator
+ *
+ * Returns: @str
+ */
+static gchar *
+text_unformat (GdauiNumericEntry *entry, gchar *str, gint *pos)
+{
+ g_assert (str);
+ gchar *ptr;
+ gint i, len;
+ len = strlen (str);
+ for (ptr = str, i = 0;
+ *ptr;
+ i++) {
+ if (*ptr == entry->priv->thousands_sep) {
+ g_memmove (ptr, ptr+1, len - (ptr - str));
+ len--;
+ if (*pos >= i)
+ *pos = *pos - 1;
+ }
+ else if ((*ptr == entry->priv->decimal_sep) &&
+ (ptr[1] == entry->priv->decimal_sep)) {
+ g_memmove (ptr, ptr+1, len - (ptr - str));
+ len--;
+ /*if (*pos > i)
+ *pos = *pos - 1;*/
+ }
+ else
+ ptr++;
+ }
+
+ return str;
+}
+
+/*
+ * text_reformat
+ * @pos: an inout parameter to keep track of a position
+ *
+ * Retunrs: a new string
+ */
+static gchar *
+text_reformat (GdauiNumericEntry *entry, gchar *str, gint *pos)
+{
+ g_assert (str);
+ GString *string;
+ gint len;
+ gchar *ptr;
+ gint i, last_th_sep_pos;
+ gint dec_pos = -1; /* position of the decimal */
+ gint cpos;
+
+ len = strlen (str);
+ string = g_string_new ("");
+ if (entry->priv->num_attr.is_int)
+ last_th_sep_pos = len - 1;
+ else
+ last_th_sep_pos = -1;
+
+ cpos = *pos;
+ for (i = len - 1, ptr = str + len - 1;
+ ptr >= str;
+ ptr --, i --) {
+ if (*ptr == entry->priv->decimal_sep) {
+ last_th_sep_pos = i - 1;
+ dec_pos = len - i - 1;
+ }
+ else if (i == last_th_sep_pos - 3) {
+ last_th_sep_pos = i;
+ if (entry->priv->thousands_sep) {
+ g_string_append_c (string, entry->priv->thousands_sep);
+ if (i < cpos)
+ cpos ++;
+ }
+ }
+
+ g_string_append_c (string, *ptr);
+ }
+ if (last_th_sep_pos == -1) {
+ cpos = *pos;
+ g_string_truncate (string, 0);
+ last_th_sep_pos = len - 1;
+ for (i = len - 1, ptr = str + len - 1;
+ ptr >= str;
+ ptr --, i --) {
+ if (i == last_th_sep_pos - 3) {
+ last_th_sep_pos = i;
+ if (entry->priv->thousands_sep) {
+ g_string_append_c (string, entry->priv->thousands_sep);
+ if (i < cpos)
+ cpos ++;
+ }
+ }
+
+ g_string_append_c (string, *ptr);
+ }
+ }
+ g_strreverse (string->str);
+
+ /* fix the number of decimals if necessary */
+ if ((! entry->priv->num_attr.is_int) &&
+ entry->priv->nb_decimals != G_MAXUINT16) {
+ if (dec_pos == -1) {
+ /* no decimal */
+ if (entry->priv->nb_decimals > 0) {
+ g_string_append_c (string, entry->priv->decimal_sep);
+ for (i = 0; i < entry->priv->nb_decimals; i++)
+ g_string_append_c (string, '0');
+ }
+ }
+ else {
+ gint nb_dec;
+ len = strlen (string->str);
+ nb_dec = dec_pos; /* FIXME */
+ if (nb_dec < entry->priv->nb_decimals) {
+ for (i = nb_dec; i < entry->priv->nb_decimals; i++)
+ g_string_append_c (string, '0');
+ }
+ else if (nb_dec > entry->priv->nb_decimals)
+ g_string_truncate (string, len - (nb_dec - entry->priv->nb_decimals));
+ }
+ }
+
+ *pos = cpos;
+
+ return g_string_free (string, FALSE);
+}
+
+static gboolean
+test_text_validity (GdauiNumericEntry *entry, const gchar *text)
+{
+ gboolean retval = TRUE;
+ gchar *endptr [1];
+
+#ifdef GDA_DEBUG_NO
+ g_print ("Validity text: #%s#", text);
+#endif
+
+ if (text && ((*text == '-') || (*text == '+')) && (text[1] == 0))
+ ;
+ else {
+ gchar *tmp = g_strdup (text);
+ if (entry->priv->num_attr.is_int) {
+ gchar *ptr;
+
+ for (ptr = tmp; *ptr; ) {
+ if (*ptr == entry->priv->thousands_sep)
+ /* remove that char */
+ memmove (ptr, ptr + 1, strlen (ptr));
+ else
+ ptr++;
+ }
+ if (entry->priv->num_attr.is_signed) {
+ gint64 value;
+ errno = 0;
+ value = g_ascii_strtoll (tmp, endptr, 10);
+ if (((value == G_MININT64) || (value == G_MAXINT64)) &&
+ (errno == ERANGE))
+ retval = FALSE;
+ if ((**endptr != 0) || (value < entry->priv->num_attr.imin) || (value > entry->priv->num_attr.imax))
+ retval = FALSE;
+ }
+ else {
+ guint64 value;
+ errno = 0;
+ value = g_ascii_strtoull (tmp, endptr, 10);
+ if ((value == G_MAXUINT64) && (errno == ERANGE))
+ retval = FALSE;
+ if ((**endptr != 0) || (value > entry->priv->num_attr.uimax))
+ retval = FALSE;
+ }
+ }
+ else {
+ gchar *ptr;
+ gdouble value;
+
+ for (ptr = tmp; *ptr; ) {
+ if (*ptr == entry->priv->decimal_sep) {
+ *ptr = get_default_decimal_sep ();
+ ptr++;
+ }
+ else if (*ptr == entry->priv->thousands_sep)
+ memmove (ptr, ptr + 1, strlen (ptr));
+ else
+ ptr++;
+ }
+ errno = 0;
+ value = g_strtod (tmp, endptr);
+ if (((value == HUGE_VAL) || (value == -HUGE_VAL)) &&
+ (errno == ERANGE))
+ retval = FALSE;
+ if ((**endptr != 0) ||
+ ((entry->priv->num_attr.fmax > 0) && (value > entry->priv->num_attr.fmax)))
+ retval = FALSE;
+ }
+ g_free (tmp);
+ }
+#ifdef GDA_DEBUG_NO
+ g_print ("retval=%d\n", retval);
+#endif
+ return retval;
+}
+
+
+static void
+gdaui_numeric_entry_assume_insert (GdauiEntry *entry, const gchar *text, gint text_length,
+ gint *virt_pos, gint offset)
+{
+ GdauiNumericEntry *fentry;
+ gchar *otext, *ptr, *ntext;
+ gchar tmp;
+ gint i;
+ GString *string;
+ gint olen, nlen;
+
+ fentry = (GdauiNumericEntry*) entry;
+ otext = gdaui_entry_get_text (GDAUI_ENTRY (entry));
+ olen = strlen (otext);
+ for (ptr = otext, i = 0; (i < *virt_pos) && *ptr; ptr = g_utf8_next_char (ptr), i++);
+ if (i != *virt_pos)
+ return;
+ tmp = *ptr;
+ *ptr = 0;
+ string = g_string_new ("");
+ g_string_append (string, otext);
+ *ptr = tmp;
+ g_string_append (string, text);
+ g_string_append (string, ptr);
+ g_free (otext);
+
+ /*g_print ("RAW: [%s]", string->str);*/
+ *virt_pos += text_length;
+ text_unformat (fentry, string->str, virt_pos);
+ /*g_print ("SANITIZED: [%s]", string->str);*/
+
+ if (!test_text_validity (fentry, string->str)) {
+ g_string_free (string, TRUE);
+ /*g_print ("ERROR!\n");*/
+ return;
+ }
+ ntext = text_reformat (fentry, string->str, virt_pos);
+ g_string_free (string, TRUE);
+ /*g_print ("NEW: [%s]\n", ntext);*/
+
+ i = offset;
+ nlen = strlen (ntext);
+ gtk_editable_delete_text ((GtkEditable*) entry, offset, olen + offset);
+ gtk_editable_insert_text ((GtkEditable*) entry, ntext, nlen, &i);
+ g_free (ntext);
+}
+
+static void
+gdaui_numeric_entry_assume_delete (GdauiEntry *entry, gint virt_start_pos, gint virt_end_pos, gint offset)
+{
+ GdauiNumericEntry *fentry;
+ GString *string;
+ gchar *otext, *ntext = NULL;
+ gint i, nlen, ndel, olen = 0;
+ gint cursor_pos;
+
+ fentry = (GdauiNumericEntry*) entry;
+ ndel = virt_end_pos - virt_start_pos;
+ otext = gdaui_entry_get_text (GDAUI_ENTRY (entry));
+ cursor_pos = gtk_editable_get_position (GTK_EDITABLE (entry));
+
+ if (otext) {
+ if ((ndel == 1) && (otext[virt_start_pos] == fentry->priv->decimal_sep) &&
+ (fentry->priv->nb_decimals != G_MAXUINT16)) {
+ gtk_editable_set_position (GTK_EDITABLE (entry), cursor_pos - 1);
+ g_free (otext);
+ return;
+ }
+ string = g_string_new (otext);
+ olen = g_utf8_strlen (otext, -1);
+ g_free (otext);
+ g_string_erase (string, virt_start_pos, ndel);
+ }
+ else
+ string = g_string_new (NULL);
+
+ cursor_pos -= (virt_end_pos - virt_start_pos);
+ /*g_print ("RAW: [%s]", string->str);*/
+ text_unformat (fentry, string->str, &cursor_pos);
+ /*g_print ("SANITIZED: [%s]", string->str);*/
+
+ if (!test_text_validity (fentry, string->str)) {
+ if ((string->str[0] == fentry->priv->decimal_sep) &&
+ string->str[1] == 0)
+ ntext = g_strdup ("");
+ g_string_free (string, TRUE);
+ if (!ntext) {
+ /*g_print ("ERROR!\n");*/
+ return;
+ }
+ }
+ else {
+ ntext = text_reformat (fentry, string->str, &cursor_pos);
+ g_string_free (string, TRUE);
+ }
+ /*g_print ("NEW: [%s]\n", ntext);*/
+
+ i = offset;
+ nlen = strlen (ntext);
+ gtk_editable_delete_text ((GtkEditable*) entry, offset, olen + offset);
+ gtk_editable_insert_text ((GtkEditable*) entry, ntext, nlen, &i);
+ g_free (ntext);
+ gtk_editable_set_position (GTK_EDITABLE (entry), cursor_pos);
+}
+
+/**
+ * gdaui_numeric_entry_new:
+ * @type: the numeric type
+ *
+ * Creates a new #GdauiNumericEntry widget.
+ *
+ * Returns: the newly created #GdauiNumericEntry widget.
+ */
+GtkWidget*
+gdaui_numeric_entry_new (GType type)
+{
+ GObject *obj;
+
+ obj = g_object_new (GDAUI_TYPE_NUMERIC_ENTRY, "type", type, NULL);
+ return GTK_WIDGET (obj);
+}
+
+/**
+ * gdaui_numeric_entry_get_text
+ * @entry: a #GdauiNumericEntry widget
+ *
+ * Get @entry's contents as a #GValue.
+ *
+ * Returns: a new #GValue, or %NULL
+ */
+GValue *
+gdaui_numeric_entry_get_value (GdauiNumericEntry *entry)
+{
+ gchar *text;
+ GValue *value = NULL;
+ g_return_val_if_fail (GDAUI_IS_NUMERIC_ENTRY (entry), NULL);
+
+ text = gdaui_entry_get_text ((GdauiEntry*) entry);
+ if (text) {
+ if (entry->priv->thousands_sep) {
+ gchar *ptr;
+ gint len;
+ len = strlen (text);
+ for (ptr = text; *ptr; ) {
+ if (*ptr == entry->priv->thousands_sep)
+ g_memmove (ptr, ptr+1, len - (ptr - text));
+ else
+ ptr++;
+ }
+ }
+ value = gda_value_new_from_string (text, entry->priv->type);
+ g_free (text);
+ }
+
+ return value;
+}
diff --git a/libgda-ui/data-entries/gdaui-numeric-entry.h b/libgda-ui/data-entries/gdaui-numeric-entry.h
new file mode 100644
index 0000000..815b70a
--- /dev/null
+++ b/libgda-ui/data-entries/gdaui-numeric-entry.h
@@ -0,0 +1,57 @@
+/* gdaui-numeric-entry.h
+ *
+ * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 __GDAUI_NUMERIC_ENTRY_H__
+#define __GDAUI_NUMERIC_ENTRY_H__
+
+#include "gdaui-entry.h"
+
+G_BEGIN_DECLS
+
+#define GDAUI_TYPE_NUMERIC_ENTRY (gdaui_numeric_entry_get_type ())
+#define GDAUI_NUMERIC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDAUI_TYPE_NUMERIC_ENTRY, GdauiNumericEntry))
+#define GDAUI_NUMERIC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDAUI_TYPE_NUMERIC_ENTRY, GdauiNumericEntry))
+#define GDAUI_IS_NUMERIC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDAUI_TYPE_NUMERIC_ENTRY))
+#define GDAUI_IS_NUMERIC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDAUI_TYPE_NUMERIC_ENTRY))
+#define GDAUI_NUMERIC_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDAUI_TYPE_NUMERIC_ENTRY, GdauiNumericEntry))
+
+
+typedef struct _GdauiNumericEntry GdauiNumericEntry;
+typedef struct _GdauiNumericEntryClass GdauiNumericEntryClass;
+typedef struct _GdauiNumericEntryPrivate GdauiNumericEntryPrivate;
+
+struct _GdauiNumericEntry
+{
+ GdauiEntry entry;
+ GdauiNumericEntryPrivate *priv;
+};
+
+struct _GdauiNumericEntryClass
+{
+ GdauiEntryClass parent_class;
+};
+
+GType gdaui_numeric_entry_get_type (void) G_GNUC_CONST;
+GtkWidget *gdaui_numeric_entry_new (GType type);
+GValue *gdaui_numeric_entry_get_value (GdauiNumericEntry *entry);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda-ui/data-entries/plugins/gdaui-entry-cidr.c b/libgda-ui/data-entries/plugins/gdaui-entry-cidr.c
index e908e60..5ddbd53 100644
--- a/libgda-ui/data-entries/plugins/gdaui-entry-cidr.c
+++ b/libgda-ui/data-entries/plugins/gdaui-entry-cidr.c
@@ -22,7 +22,7 @@
#include "gdaui-entry-cidr.h"
#include <libgda/gda-data-handler.h>
#include <string.h>
-#include "gdaui-format-entry.h"
+#include "gdaui-formatted-entry.h"
/*
* Main static functions
@@ -190,11 +190,8 @@ create_entry (GdauiEntryWrapper *mgwrap)
mgcidr = GDAUI_ENTRY_CIDR (mgwrap);
g_return_val_if_fail (mgcidr->priv, NULL);
- entry = gdaui_format_entry_new ();
+ entry = gdaui_formatted_entry_new ("000.000.000.000/000.000.000.000", "---.---.---.---/---.---.---.---");
mgcidr->priv->entry = entry;
- gdaui_format_entry_set_format (GDAUI_FORMAT_ENTRY (entry),
- "000.000.000.000/000.000.000.000", NULL,
- " . . . / . . . ");
gtk_entry_set_width_chars (GTK_ENTRY (entry), 19);
g_signal_connect (G_OBJECT (entry), "focus-out-event",
@@ -336,7 +333,7 @@ real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
if (value) {
if (gda_value_is_null ((GValue *) value))
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgcidr->priv->entry), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgcidr->priv->entry), NULL);
else {
SplitValues *svalues;
gchar *str, *ptr, *tok;
@@ -373,7 +370,7 @@ real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
}
}
else
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgcidr->priv->entry), NULL);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgcidr->priv->entry), NULL);
}
static void truncate_entries_to_mask_length (GdauiEntryCidr *mgcidr, gboolean target_mask, guint mask_nb_bits)
@@ -611,7 +608,7 @@ split_values_get (GdauiEntryCidr *mgcidr)
gchar *str;
values = g_new0 (SplitValues, 1);
- str = gdaui_format_entry_get_text (GDAUI_FORMAT_ENTRY (mgcidr->priv->entry));
+ str = gdaui_entry_get_text (GDAUI_ENTRY (mgcidr->priv->entry));
if (!str)
return NULL;
@@ -673,7 +670,7 @@ split_values_set (GdauiEntryCidr *mgcidr, SplitValues *svalues)
ip_str = g_strjoinv (".", svalues->ip_array);
mask_str = g_strjoinv (".", svalues->mask_array);
str = g_strdup_printf ("%s/%s", ip_str, mask_str);
- gdaui_format_entry_set_text (GDAUI_FORMAT_ENTRY (mgcidr->priv->entry), str);
+ gdaui_entry_set_text (GDAUI_ENTRY (mgcidr->priv->entry), str);
g_free (str);
}
diff --git a/libgda-ui/gdaui-init.c b/libgda-ui/gdaui-init.c
index f1f9ff4..c5ccd32 100644
--- a/libgda-ui/gdaui-init.c
+++ b/libgda-ui/gdaui-init.c
@@ -31,6 +31,7 @@
#include "data-entries/gdaui-entry-boolean.h"
#include "data-entries/gdaui-entry-bin.h"
#include "data-entries/gdaui-entry-string.h"
+#include "data-entries/gdaui-entry-number.h"
#include "data-entries/gdaui-entry-time.h"
#include "data-entries/gdaui-entry-date.h"
#include "data-entries/gdaui-entry-timestamp.h"
@@ -138,7 +139,7 @@ gdaui_new_data_entry (GType type, const gchar *plugin_name)
(type == G_TYPE_UCHAR) ||
(type == G_TYPE_ULONG) ||
(type == G_TYPE_UINT))
- entry = (GdauiDataEntry *) gdaui_entry_string_new (dh, type, spec_options);
+ entry = (GdauiDataEntry *) gdaui_entry_number_new (dh, type, spec_options);
else if (type == G_TYPE_BOOLEAN)
entry = (GdauiDataEntry *) gdaui_entry_boolean_new (dh, G_TYPE_BOOLEAN);
else if ((type == GDA_TYPE_BLOB) ||
@@ -225,6 +226,7 @@ static GdauiDataEntry *entry_none_create_func (GdaDataHandler *handler, GType ty
static GdauiDataEntry *entry_boolean_create_func (GdaDataHandler *handler, GType type, const gchar *options);
static GdauiDataEntry *entry_bin_create_func (GdaDataHandler *handler, GType type, const gchar *options);
static GdauiDataEntry *entry_string_create_func (GdaDataHandler *handler, GType type, const gchar *options);
+static GdauiDataEntry *entry_number_create_func (GdaDataHandler *handler, GType type, const gchar *options);
static GdauiDataEntry *entry_time_create_func (GdaDataHandler *handler, GType type, const gchar *options);
static GdauiDataEntry *entry_timestamp_create_func (GdaDataHandler *handler, GType type, const gchar *options);
static GdauiDataEntry *entry_date_create_func (GdaDataHandler *handler, GType type, const gchar *options);
@@ -292,7 +294,7 @@ init_plugins_hash (void)
plugin->entry_create_func = entry_string_create_func;
plugin->cell_create_func = cell_textual_create_func;
g_hash_table_insert (hash, plugin->plugin_name, plugin);
- file = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "ui", "gdaui-entry-string-string.xml", NULL);
+ file = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "ui", "gdaui-entry-string.xml", NULL);
if (! g_file_test (file, G_FILE_TEST_EXISTS)) {
g_message ("Could not find file '%s': '%s' data entry will not report any possible option",
file, plugin->plugin_name);
@@ -322,10 +324,10 @@ init_plugins_hash (void)
plugin->valid_g_types [10] = G_TYPE_ULONG;
plugin->valid_g_types [11] = G_TYPE_UINT;
plugin->options_xml_spec = NULL;
- plugin->entry_create_func = entry_string_create_func;
+ plugin->entry_create_func = entry_number_create_func;
plugin->cell_create_func = cell_textual_create_func;
g_hash_table_insert (hash, plugin->plugin_name, plugin);
- file = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "ui", "gdaui-entry-string-number.xml", NULL);
+ file = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "ui", "gdaui-entry-number.xml", NULL);
xmlChar *xml_spec = get_spec_with_isocodes (file);
if (xml_spec) {
plugin->options_xml_spec = g_strdup (xml_spec);
@@ -337,8 +339,9 @@ init_plugins_hash (void)
plugin->plugin_name = "textual";
plugin->plugin_descr = "Textual entry";
plugin->plugin_file = NULL;
- plugin->nb_g_types = 0;
- plugin->valid_g_types = NULL;
+ plugin->nb_g_types = 1;
+ plugin->valid_g_types = g_new (GType, plugin->nb_g_types);
+ plugin->valid_g_types [0] = G_TYPE_STRING;
plugin->options_xml_spec = NULL;
plugin->entry_create_func = entry_string_create_func;
plugin->cell_create_func = cell_textual_create_func;
@@ -484,6 +487,12 @@ entry_string_create_func (GdaDataHandler *handler, GType type, const gchar *opti
}
static GdauiDataEntry *
+entry_number_create_func (GdaDataHandler *handler, GType type, const gchar *options)
+{
+ return (GdauiDataEntry *) gdaui_entry_number_new (handler, type, options);
+}
+
+static GdauiDataEntry *
entry_time_create_func (GdaDataHandler *handler, GType type, const gchar *options)
{
return (GdauiDataEntry *) gdaui_entry_time_new (handler);
diff --git a/libgda-ui/libgda-ui.symbols b/libgda-ui/libgda-ui.symbols
index ea72fc2..3337f5d 100644
--- a/libgda-ui/libgda-ui.symbols
+++ b/libgda-ui/libgda-ui.symbols
@@ -96,8 +96,18 @@
gdaui_entry_common_time_new
gdaui_entry_date_get_type
gdaui_entry_date_new
+ gdaui_entry_get_text
+ gdaui_entry_get_type
+ gdaui_entry_new
gdaui_entry_none_get_type
gdaui_entry_none_new
+ gdaui_entry_number_get_type
+ gdaui_entry_number_is_type_numeric
+ gdaui_entry_number_new
+ gdaui_entry_set_max_length
+ gdaui_entry_set_prefix
+ gdaui_entry_set_suffix
+ gdaui_entry_set_text
gdaui_entry_shell_get_type
gdaui_entry_shell_pack_entry
gdaui_entry_shell_refresh
@@ -110,19 +120,11 @@
gdaui_entry_wrapper_contents_activated
gdaui_entry_wrapper_contents_changed
gdaui_entry_wrapper_get_type
- gdaui_format_entry_get_text
- gdaui_format_entry_get_type
- gdaui_format_entry_new
- gdaui_format_entry_set_decimal_places
- gdaui_format_entry_set_edited_type
- gdaui_format_entry_set_format
- gdaui_format_entry_set_max_length
- gdaui_format_entry_set_prefix
- gdaui_format_entry_set_separators
- gdaui_format_entry_set_suffix
- gdaui_format_entry_set_text
gdaui_form_get_type
gdaui_form_new
+ gdaui_formatted_entry_get_text
+ gdaui_formatted_entry_get_type
+ gdaui_formatted_entry_new
gdaui_grid_get_selection
gdaui_grid_get_type
gdaui_grid_new
@@ -136,6 +138,9 @@
gdaui_login_set_dsn
gdaui_login_set_mode
gdaui_new_data_entry
+ gdaui_numeric_entry_get_type
+ gdaui_numeric_entry_get_value
+ gdaui_numeric_entry_new
gdaui_plugins_hash
gdaui_provider_selector_get_provider
gdaui_provider_selector_get_provider_obj
diff --git a/libgda/handlers/gda-handler-time.c b/libgda/handlers/gda-handler-time.c
index b65e091..3f797fa 100644
--- a/libgda/handlers/gda-handler-time.c
+++ b/libgda/handlers/gda-handler-time.c
@@ -919,6 +919,8 @@ make_date (GdaHandlerTime *hdl, GDate *date, const gchar *value, LocaleSetting *
* 123015-02
* 123015.123
* taken from libgda/gda-value.h
+ *
+ * Also works if there is only 0 or 1 digit instead of 2
*/
static gboolean
make_time (GdaHandlerTime *hdl, GdaTime *timegda, const gchar *value)
@@ -933,25 +935,39 @@ make_time (GdaHandlerTime *hdl, GdaTime *timegda, const gchar *value)
timegda->timezone = GDA_TIMEZONE_INVALID;
ptr = value;
if ((*ptr >= '0') && (*ptr <= '9') &&
- (*(ptr+1) >= '0') && (*(ptr+1) <= '9'))
+ (*(ptr+1) >= '0') && (*(ptr+1) <= '9')) {
timegda->hour = (*ptr - '0') * 10 + *(ptr+1) - '0';
+ ptr += 2;
+ }
+ else if ((*ptr >= '0') && (*ptr <= '9') && (ptr[1] == ':')) {
+ timegda->hour = *ptr - '0';
+ ptr++;
+ }
+ else if (*ptr == ':')
+ timegda->hour = 0;
else
return FALSE;
/* minute */
- ptr += 2;
if (! *ptr)
return FALSE;
if (*ptr == ':')
ptr++;
if ((*ptr >= '0') && (*ptr <= '9') &&
- (*(ptr+1) >= '0') && (*(ptr+1) <= '9'))
+ (*(ptr+1) >= '0') && (*(ptr+1) <= '9')) {
timegda->minute = (*ptr - '0') * 10 + *(ptr+1) - '0';
+ ptr += 2;
+ }
+ else if ((*ptr >= '0') && (*ptr <= '9') && (ptr[1] == ':')) {
+ timegda->minute = *ptr - '0';
+ ptr++;
+ }
+ else if (*ptr == ':')
+ timegda->minute = 0;
else
return FALSE;
/* second */
- ptr += 2;
timegda->second = 0;
if (! *ptr) {
if ((timegda->hour > 24) || (timegda->minute > 60))
@@ -962,11 +978,18 @@ make_time (GdaHandlerTime *hdl, GdaTime *timegda, const gchar *value)
if (*ptr == ':')
ptr++;
if ((*ptr >= '0') && (*ptr <= '9') &&
- (*(ptr+1) >= '0') && (*(ptr+1) <= '9'))
+ (*(ptr+1) >= '0') && (*(ptr+1) <= '9')) {
timegda->second = (*ptr - '0') * 10 + *(ptr+1) - '0';
+ ptr += 2;
+ }
+ else if ((*ptr >= '0') && (*ptr <= '9')) {
+ timegda->second = *ptr - '0';
+ ptr++;
+ }
+ else if (*ptr == ':')
+ timegda->second = 0;
/* extra */
- ptr += 2;
if (! *ptr) {
if ((timegda->hour > 24) || (timegda->minute > 60) ||
(timegda->second > 60))
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cbc474e..4b8c75b 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -87,8 +87,8 @@ libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
libgda-ui/data-entries/gdaui-entry-common-time.c
libgda-ui/data-entries/gdaui-entry-none.c
libgda-ui/data-entries/gdaui-entry-shell.c
-libgda-ui/data-entries/gdaui-entry-string-number.xml.in
-libgda-ui/data-entries/gdaui-entry-string-string.xml.in
+libgda-ui/data-entries/gdaui-entry-number.xml.in
+libgda-ui/data-entries/gdaui-entry-string.xml.in
libgda-ui/data-entries/gdaui-entry-string.c
libgda-ui/data-entries/gdaui-format-entry.c
libgda-ui/data-entries/plugins/common-pict.c
diff --git a/testing/.gitignore b/testing/.gitignore
index b32f743..9fe6261 100644
--- a/testing/.gitignore
+++ b/testing/.gitignore
@@ -2,4 +2,5 @@ gda-test-connection-4.*
gda-test-blob
gda-provider-status
gdaui-test-data-entries
+gdaui-test-widget-entry
index.html
diff --git a/testing/Makefile.am b/testing/Makefile.am
index 8e553dc..ebcd1d5 100644
--- a/testing/Makefile.am
+++ b/testing/Makefile.am
@@ -6,7 +6,7 @@ AM_CPPFLAGS = \
bin_PROGRAMS = gda-test-connection-4.0
if HAVE_UI
-UI_PROGS=gdaui-test-data-entries
+UI_PROGS=gdaui-test-data-entries gdaui-test-widget-entry
endif
noinst_PROGRAMS = gda-test-blob gda-provider-status $(UI_PROGS)
@@ -44,4 +44,13 @@ gdaui_test_data_entries_LDADD = \
$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
$(LIBGDA_LIBS)
+gdaui_test_widget_entry_CFLAGS = $(GTK_CFLAGS)
+gdaui_test_widget_entry_SOURCES = \
+ gdaui-test-widget-entry.c
+
+gdaui_test_widget_entry_LDADD = \
+ $(top_builddir)/libgda/libgda-4.0.la \
+ $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+ $(LIBGDA_LIBS)
+
EXTRA_DIST =
diff --git a/testing/gdaui-test-widget-entry.c b/testing/gdaui-test-widget-entry.c
new file mode 100644
index 0000000..fabf4e8
--- /dev/null
+++ b/testing/gdaui-test-widget-entry.c
@@ -0,0 +1,409 @@
+#include <gtk/gtk.h>
+#include <libgda-ui/data-entries/gdaui-entry.h>
+#include <libgda-ui/data-entries/gdaui-formatted-entry.h>
+#include <libgda-ui/data-entries/gdaui-numeric-entry.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NB_ENTRIES 50
+static GtkWidget *entries[NB_ENTRIES];
+
+static void
+print_unicode (const gchar *ptr)
+{
+ gunichar wc;
+ wc = g_utf8_get_char_validated (ptr, -1);
+ g_assert (wc >= 0);
+ g_print ("%s <=> %u, IS_print: %d\n", ptr, wc, g_unichar_isprint (wc));
+}
+
+static void
+entry_changed_cb (GdauiEntry *entry, const gchar *id)
+{
+ gchar *tmp;
+ tmp = gdaui_entry_get_text (entry);
+ g_print ("Entry %s changed to: [%s]", id, tmp);
+ if (GDAUI_IS_FORMATTED_ENTRY (entry)) {
+ g_free (tmp);
+ tmp = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (entry));
+ g_print (" => [%s]", tmp);
+ }
+ g_print ("\n");
+
+ g_free (tmp);
+}
+
+static void
+prop_length_set_cb (GtkButton *buntton, GdauiEntry *entry)
+{
+ gchar *tmp;
+ gint max, i;
+ tmp = gdaui_entry_get_text (entry);
+ max = atoi (tmp);
+ g_free (tmp);
+ g_print ("Setting Max entries' length to %d\n", max);
+
+ for (i = 0; i < NB_ENTRIES; i++)
+ if (entries [i])
+ gdaui_entry_set_max_length (GDAUI_ENTRY (entries [i]), max);
+}
+
+static void
+prop_text_set_cb (GtkButton *buntton, GdauiEntry *entry)
+{
+ gchar *tmp;
+ gint i;
+ tmp = gdaui_entry_get_text (entry);
+ g_print ("Setting entries' text to [%s]\n", tmp);
+ for (i = 0; i < NB_ENTRIES; i++)
+ if (entries [i])
+ gdaui_entry_set_text (GDAUI_ENTRY (entries [i]), tmp);
+ g_free (tmp);
+}
+
+static void
+prop_text_null_cb (GtkButton *buntton, gpointer data)
+{
+ gint i;
+
+ g_print ("Setting entries' text to NULL\n");
+ for (i = 0; i < NB_ENTRIES; i++)
+ if (entries [i])
+ gdaui_entry_set_text (GDAUI_ENTRY (entries [i]), NULL);
+}
+
+GtkWidget *
+make_label (gint index, const gchar *text)
+{
+ GtkWidget *label;
+ gchar *tmp;
+ tmp = g_strdup_printf ("#%d: %s", index, text ? text : "");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+
+ return label;
+}
+
+int
+main (int argc, char* argv[])
+{
+ GtkWidget *entry, *label, *button;
+ GtkWidget *window, *hbox, *vbox, *table, *top_vbox;
+ gint index = 0;
+ gchar *tmp;
+
+ gtk_init (&argc, &argv);
+ memset (entries, 0, sizeof (entries));
+
+ print_unicode ("0");
+ print_unicode ("9");
+ print_unicode ("@");
+ print_unicode ("^");
+ print_unicode ("#");
+ print_unicode ("â?¬");
+
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ top_vbox = gtk_vbox_new (FALSE, 0);
+ g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
+ gtk_container_add(GTK_CONTAINER(window), top_vbox);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (top_vbox), hbox, FALSE, FALSE, 0);
+
+ /*
+ * GdauiEntry widgets
+ */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), "<b>GdauiEntry</b>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+#define HAVE_NORMAL
+#ifdef HAVE_NORMAL
+ /* #0 */
+ tmp = g_strdup_printf ("#%d", index);
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_entry_new (NULL, NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+ /* #1 */
+ tmp = g_strdup_printf ("#%d", index);
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_entry_new ("â?¬ ", NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #2 */
+ tmp = g_strdup_printf ("#%d", index);
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_entry_new (NULL, " Ã?");
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #3 */
+ tmp = g_strdup_printf ("#%d", index);
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_entry_new ("�� ", " êê");
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+#endif
+
+#define HAVE_FORMATTED
+#ifdef HAVE_FORMATTED
+ /*
+ * GdauiFormattedEntry widgets
+ */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), "<b>GdauiFormattedEntry</b>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ /* #4 */
+ tmp = g_strdup_printf ("#%d", index);
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_formatted_entry_new ("TIME=00:00:00", NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #5 */
+ tmp = g_strdup_printf ("#%d", index);
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_formatted_entry_new ("TIME=00â?¬00:00",
+ "------- -- ");
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+#endif
+
+#define HAVE_NUMERIC
+#ifdef HAVE_NUMERIC
+ /*
+ * GdauiNumericEntry widgets
+ */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), "<b>GdauiNumericEntry</b>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ /* #6 */
+ tmp = g_strdup_printf ("#%d: %s", index, "G_TYPE_CHAR");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_CHAR);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #7 */
+ tmp = g_strdup_printf ("#%d: %s", index, "G_TYPE_UINT, thousand sep=','");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_UINT);
+ g_object_set (G_OBJECT (entry), "thousands-sep", ',', NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #8 */
+ tmp = g_strdup_printf ("#%d: %s", index, "G_TYPE_FLOAT, n_decimals=2");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_FLOAT);
+ g_object_set (G_OBJECT (entry), "n-decimals", 2, NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #9 */
+ tmp = g_strdup_printf ("#%d: %s", index, "G_TYPE_DOUBLE");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_DOUBLE);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #10 */
+ tmp = g_strdup_printf ("#%d: %s", index, "G_TYPE_FLOAT, thousand sep=' ', n_decimals=2");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_FLOAT);
+ g_object_set (G_OBJECT (entry), "n-decimals", 2, NULL);
+ g_object_set (G_OBJECT (entry), "thousands-sep", ' ', NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+#endif
+
+#define HAVE_COMPLETE
+#ifdef HAVE_COMPLETE
+ /*
+ * complete tests
+ */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), "<b>Complete tests</b>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ /* #11 */
+ tmp = g_strdup_printf ("#%d: %s", index, "2 decimals with EURO");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_FLOAT);
+ g_object_set (G_OBJECT (entry), "suffix", "â?¬", "n-decimals", 2, NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #12 */
+ tmp = g_strdup_printf ("#%d: %s", index, "3 decimals between markers");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_numeric_entry_new (G_TYPE_FLOAT);
+ g_object_set (G_OBJECT (entry), "prefix", "[", "suffix", "]", "n-decimals", 3, NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #13 */
+ tmp = g_strdup_printf ("#%d: %s", index, "**.* between markers");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_formatted_entry_new ("**.*", NULL);
+ g_object_set (G_OBJECT (entry), "suffix", "]", "prefix", "[", NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+ /* #14 */
+ tmp = g_strdup_printf ("#%d: %s", index, "900//@@@//^^^/##** between markers");
+ label = gtk_label_new (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ entry = gdaui_formatted_entry_new ("900//@@@//^^^/##**", NULL);
+ g_object_set (G_OBJECT (entry), "suffix", "]", "prefix", "[", NULL);
+ entries[index] = entry;
+ index++;
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (entry_changed_cb), tmp);
+
+#endif
+
+ /* properties */
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), "<b>Common properties:</b>");
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (top_vbox), label, FALSE, FALSE, 10);
+ table = gtk_table_new (2, 3, FALSE);
+ gtk_box_pack_start (GTK_BOX (top_vbox), table, TRUE, TRUE, 0);
+
+ label = gtk_label_new ("MaxLen:");
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, 0, 0, 0, 0);
+ entry = gdaui_entry_new (NULL, NULL); /* FIXME: use a gint data entry */
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
+ button = gtk_button_new_with_label ("Set");
+ gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, 0, 0, 0, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (prop_length_set_cb), entry);
+
+ label = gtk_label_new ("Force text:");
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, 0, 0, 0, 0);
+ entry = gdaui_entry_new (NULL, NULL);
+ gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 1, 2);
+ button = gtk_button_new_with_label ("Set");
+ gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, 0, 0, 0, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (prop_text_set_cb), entry);
+
+ label = gtk_label_new ("Force text to NULL:");
+ gtk_table_attach (GTK_TABLE (table), label, 0, 2, 2, 3, 0, 0, 0, 0);
+ button = gtk_button_new_with_label ("Set");
+ gtk_table_attach (GTK_TABLE (table), button, 2, 3, 2, 3, 0, 0, 0, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (prop_text_null_cb), entry);
+
+
+ gtk_widget_show_all(window);
+ gtk_main();
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]