[gnome-calendar] Added GcalDateEntry widget.



commit 8594de0f28e34d22b3728c6ce9c33103401d454c
Author: Erick PÃrez Castellanos <erick red gmail com>
Date:   Tue Oct 16 14:25:10 2012 -0400

    Added GcalDateEntry widget.
    
    Initial approach. I really don't like the implementation, is kinda week.
    And it needs a lot of testing, localization kind of testing.

 src/Makefile.am       |    2 +
 src/gcal-date-entry.c |  404 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/gcal-date-entry.h |   69 +++++++++
 3 files changed, 475 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 459e836..356b732 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,6 +45,8 @@ gnome_calendar_SOURCES =                                  \
     gcal-edit-dialog.h                                    \
     gcal-time-entry.c                                     \
     gcal-time-entry.h                                     \
+    gcal-date-entry.c                                     \
+    gcal-date-entry.h                                     \
     gcal-manager.c                                        \
     gcal-manager.h                                        \
     gcal-utils.c                                          \
diff --git a/src/gcal-date-entry.c b/src/gcal-date-entry.c
new file mode 100644
index 0000000..56835d5
--- /dev/null
+++ b/src/gcal-date-entry.c
@@ -0,0 +1,404 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * gcal-date-entry.c
+ * Copyright (C) 2012 Erick PÃrez Castellanos <erickpc gnome org>
+ *
+ * gnome-calendar is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-calendar is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gcal-date-entry.h"
+
+#include <locale.h>
+#include <langinfo.h>
+#include <glib/gi18n.h>
+
+struct _GcalDateEntryPrivate
+{
+  gboolean  internal_skip;
+
+  guint     day;              /* 1 - 28 || 29 || 30 || 31 */
+  guint     month;            /* 1 - 12 */
+  guint     year;
+
+  gchar    *mask;
+  guint     day_pos;
+  guint     month_pos;
+  guint     year_pos;
+  gboolean  have_long_year;
+};
+
+static void     gtk_editable_iface_init                        (GtkEditableInterface *iface);
+
+static void     gcal_date_entry_constructed                    (GObject              *object);
+
+static void     gcal_date_entry_icon_press                     (GtkEntry             *entry,
+                                                                GtkEntryIconPosition  icon_pos,
+                                                                GdkEvent             *event,
+                                                                gpointer              user_data);
+
+static void     gcal_date_entry_insert_text                    (GtkEditable          *editable,
+                                                                const gchar          *new_text,
+                                                                gint                  new_text_length,
+                                                                gint                 *position);
+
+static void     gcal_date_entry_delete_text                    (GtkEditable          *editable,
+                                                                gint                  start_pos,
+                                                                gint                  end_pos);
+
+static void     gcal_date_entry_validate_and_insert            (GcalDateEntry        *entry);
+
+G_DEFINE_TYPE_WITH_CODE (GcalDateEntry,
+                         gcal_date_entry,
+                         GTK_TYPE_ENTRY,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
+                                                gtk_editable_iface_init));
+
+static void
+gcal_date_entry_class_init (GcalDateEntryClass *klass)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed = gcal_date_entry_constructed;
+
+  g_type_class_add_private ((gpointer)klass, sizeof(GcalDateEntryPrivate));
+}
+
+static void
+gcal_date_entry_init (GcalDateEntry *self)
+{
+  GcalDateEntryPrivate *priv;
+  gchar *have_y;
+
+  gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
+
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                            GCAL_TYPE_DATE_ENTRY,
+                                            GcalDateEntryPrivate);
+  priv = self->priv;
+
+  priv->internal_skip = FALSE;
+  priv->day = 1;
+  priv->month = 1;
+  priv->year = 1970;
+
+  setlocale (LC_ALL,"");
+  priv->mask = nl_langinfo (D_FMT);
+
+  priv->day_pos = - (priv->mask - g_strstr_len (priv->mask, -1, "%d"));
+  priv->month_pos = - (priv->mask - g_strstr_len (priv->mask, -1, "%m"));
+  if ((have_y = g_strstr_len (priv->mask, - 1, "%y")) != NULL)
+    {
+      priv->have_long_year = FALSE;
+      priv->year_pos = - (priv->mask - have_y);
+    }
+  else
+    {
+      priv->have_long_year = TRUE;
+      priv->year_pos = - (priv->mask - g_strstr_len (priv->mask, -1, "%Y"));
+      if (priv->year_pos < priv->day_pos)
+        priv->day_pos += 2;
+      if (priv->year_pos < priv->month_pos)
+        priv->month_pos += 2;
+    }
+}
+
+static void
+gtk_editable_iface_init (GtkEditableInterface *iface)
+{
+  iface->insert_text = gcal_date_entry_insert_text;
+  iface->delete_text = gcal_date_entry_delete_text;
+}
+
+static void
+gcal_date_entry_constructed (GObject *object)
+{
+  GcalDateEntryPrivate *priv;
+
+  priv = GCAL_DATE_ENTRY (object)->priv;
+
+  /* chaining up */
+  G_OBJECT_CLASS (gcal_date_entry_parent_class)->constructed (object);
+
+  gtk_entry_set_width_chars (
+      GTK_ENTRY (object),
+      strlen (priv->mask) + (priv->have_long_year ? 4 : 2));
+  gtk_entry_set_alignment (GTK_ENTRY (object), 0.5);
+
+  gtk_entry_set_icon_from_icon_name (GTK_ENTRY (object),
+                                     GTK_ENTRY_ICON_SECONDARY,
+                                     "x-office-calendar-symbolic");
+  gtk_entry_set_icon_tooltip_text (GTK_ENTRY (object),
+                                   GTK_ENTRY_ICON_SECONDARY,
+                                   _("Change the date"));
+
+  /* default text */
+  gcal_date_entry_validate_and_insert (GCAL_DATE_ENTRY (object));
+
+  /* setting signals */
+  g_signal_connect (object,
+                    "icon-press",
+                    G_CALLBACK (gcal_date_entry_icon_press),
+                    object);
+}
+
+static void
+gcal_date_entry_icon_press (GtkEntry             *entry,
+                            GtkEntryIconPosition  icon_pos,
+                            GdkEvent             *event,
+                            gpointer              user_data)
+{
+  g_debug ("Icon pressed");
+}
+
+static void
+gcal_date_entry_insert_text (GtkEditable *editable,
+                             const gchar *new_text,
+                             gint         new_text_length,
+                             gint        *position)
+{
+  GcalDateEntryPrivate *priv;
+  GtkEditableInterface *parent_editable_iface;
+  gboolean new_string_set;
+  gchar new_string [16];
+  gint i;
+
+  priv = GCAL_DATE_ENTRY (editable)->priv;
+  parent_editable_iface = g_type_interface_peek (gcal_date_entry_parent_class,
+                                                 GTK_TYPE_EDITABLE);
+
+  if (priv->internal_skip)
+    {
+      parent_editable_iface->insert_text (editable,
+                                          new_text,
+                                          new_text_length,
+                                          position);
+      *position = 0;
+      return;
+    }
+
+  new_string_set = FALSE;
+  memset (new_string, 0, 16);
+  /* Is it day */
+  if (*position >= priv->day_pos &&
+      *position < priv->day_pos + 2)
+    {
+      //trim string, decide what to remove
+      for (i = 0; i < priv->day_pos + 2 - *position; i++)
+        {
+          if (g_ascii_isdigit (new_text[i]))
+            {
+              new_string_set = TRUE;
+              new_string[i] = new_text[i];
+            }
+          else
+            {
+              break;
+            }
+        }
+    }
+
+  /* Is it month */
+  if (*position >= priv->month_pos &&
+      *position < priv->month_pos + 2)
+    {
+      //trim string, decide what to remove
+      for (i = 0; i < priv->month_pos + 2 - *position; i++)
+        {
+          if (g_ascii_isdigit (new_text[i]))
+            {
+              new_string_set = TRUE;
+              new_string[i] = new_text[i];
+            }
+          else
+            {
+              break;
+            }
+        }
+    }
+
+  /* Is it year */
+  if (*position >= priv->year_pos &&
+      *position < priv->year_pos + (priv->have_long_year ? 4 : 2))
+    {
+      //trim string, decide what to remove
+      for (i = 0;
+           i < priv->year_pos + (priv->have_long_year ? 4 : 2) - *position;
+           i++)
+        {
+          if (g_ascii_isdigit (new_text[i]))
+            {
+              new_string_set = TRUE;
+              new_string[i] = new_text[i];
+            }
+          else
+            {
+              break;
+            }
+        }
+    }
+
+  if (new_string_set)
+    {
+      gchar* unit_string;
+      const gchar* text;
+
+      /* making space for new_string */
+      priv->internal_skip = TRUE;
+      gtk_editable_delete_text (editable,
+                                *position,
+                                *position + strlen (new_string));
+      priv->internal_skip = FALSE;
+
+      parent_editable_iface->insert_text (editable,
+                                          new_string,
+                                          strlen (new_string),
+                                          position);
+
+      /* Updating internal data and validating */
+      text = gtk_entry_get_text (GTK_ENTRY (editable));
+      unit_string = g_strndup (text + priv->day_pos, 2);
+      priv->day = (guint) g_ascii_strtoull (unit_string, NULL, 10);
+      g_free (unit_string);
+
+      unit_string = g_strndup (text + priv->month_pos, 2);
+      priv->month = (guint) g_ascii_strtoull (unit_string, NULL, 10);
+      g_free (unit_string);
+
+      unit_string = g_strndup (text + priv->year_pos, (priv->have_long_year ? 4 : 2));
+      priv->year = (guint) g_ascii_strtoull (unit_string, NULL, 10);
+      g_free (unit_string);
+
+      gcal_date_entry_validate_and_insert (GCAL_DATE_ENTRY (editable));
+    }
+}
+
+static void
+gcal_date_entry_delete_text (GtkEditable *editable,
+                             gint         start_pos,
+                             gint         end_pos)
+{
+  /* do nothing, unless we mark it */
+  GcalDateEntryPrivate *priv;
+  GtkEditableInterface *parent_editable_iface;
+
+  priv = GCAL_DATE_ENTRY (editable)->priv;
+  parent_editable_iface = g_type_interface_peek (gcal_date_entry_parent_class,
+                                                 GTK_TYPE_EDITABLE);
+
+  if (priv->internal_skip)
+    {
+      parent_editable_iface->delete_text (editable,
+                                          start_pos,
+                                          end_pos);
+    }
+}
+
+static void
+gcal_date_entry_validate_and_insert (GcalDateEntry *entry)
+{
+  GcalDateEntryPrivate *priv;
+  gchar *tmp;
+  gchar *tmp1;
+  gchar **tokens;
+  gchar *unit;
+
+  priv = entry->priv;
+
+  if (priv->month > 12)
+    priv->month = 12;
+  if (priv->day > g_date_days_in_month (priv->month, priv->year))
+    priv->day = g_date_days_in_month (priv->month, priv->year);
+
+  tokens = g_strsplit (priv->mask, "%d", -1);
+  unit = g_strdup_printf ("%.2d", priv->day);
+  tmp = g_strjoinv (unit, tokens);
+  g_free (unit);
+  g_strfreev (tokens);
+
+  tokens = g_strsplit (tmp, "%m", -1);
+  unit = g_strdup_printf ("%.2d", priv->month);
+  tmp1 = g_strjoinv (unit, tokens);
+  g_free (unit);
+  g_strfreev (tokens);
+
+  g_free (tmp);
+  if (priv->have_long_year)
+    {
+      tokens = g_strsplit (tmp1, "%Y", -1);
+      unit = g_strdup_printf ("%.4d", priv->year);
+      tmp = g_strjoinv (unit, tokens);
+    }
+  else
+    {
+      tokens = g_strsplit (tmp1, "%y", -1);
+      unit = g_strdup_printf ("%.2d", priv->year);
+      tmp = g_strjoinv (unit, tokens);
+    }
+
+  g_free (unit);
+  g_strfreev (tokens);
+
+  priv->internal_skip = TRUE;
+  gtk_entry_set_text (GTK_ENTRY (entry), tmp);
+  priv->internal_skip = FALSE;
+
+  g_free (tmp);
+  g_free (tmp1);
+}
+
+/* Public API */
+GtkWidget*
+gcal_date_entry_new (void)
+{
+  return g_object_new (GCAL_TYPE_DATE_ENTRY, NULL);
+}
+
+void
+gcal_date_entry_set_date (GcalDateEntry *entry,
+                          guint          day,
+                          guint          month,
+                          guint          year)
+{
+  GcalDateEntryPrivate *priv;
+
+  g_return_if_fail (GCAL_IS_DATE_ENTRY (entry));
+  priv = entry->priv;
+
+  priv->day = day;
+  priv->month = month;
+  priv->year = year;
+
+  gcal_date_entry_validate_and_insert (entry);
+}
+
+void
+gcal_date_entry_get_date (GcalDateEntry *entry,
+                          guint         *day,
+                          guint         *month,
+                          guint         *year)
+{
+  GcalDateEntryPrivate *priv;
+
+  g_return_if_fail (GCAL_IS_DATE_ENTRY (entry));
+  priv = entry->priv;
+
+  if (day != NULL)
+    *day = priv->day;
+  if (month != NULL)
+    *month = priv->month;
+  if (year != NULL)
+    *year = priv->year;
+}
diff --git a/src/gcal-date-entry.h b/src/gcal-date-entry.h
new file mode 100644
index 0000000..38ba706
--- /dev/null
+++ b/src/gcal-date-entry.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * gcal-date-entry.h
+ * Copyright (C) 2012 Erick PÃrez Castellanos <erickpc gnome org>
+ *
+ * gnome-calendar is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-calendar is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GCAL_DATE_ENTRY_H__
+#define __GCAL_DATE_ENTRY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GCAL_TYPE_DATE_ENTRY                (gcal_date_entry_get_type ())
+#define GCAL_DATE_ENTRY(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), GCAL_TYPE_DATE_ENTRY, GcalDateEntry))
+#define GCAL_DATE_ENTRY_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass), GCAL_TYPE_DATE_ENTRY, GcalDateEntryClass))
+#define GCAL_IS_DATE_ENTRY(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), GCAL_TYPE_DATE_ENTRY))
+#define GCAL_IS_DATE_ENTRY_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass), GCAL_TYPE_DATE_ENTRY))
+#define GCAL_DATE_ENTRY_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), GCAL_TYPE_DATE_ENTRY, GcalDateEntryClass))
+
+typedef struct _GcalTime GcalTime;
+
+typedef struct _GcalDateEntry                GcalDateEntry;
+typedef struct _GcalDateEntryClass           GcalDateEntryClass;
+typedef struct _GcalDateEntryPrivate         GcalDateEntryPrivate;
+
+struct _GcalDateEntry
+{
+  GtkEntry parent;
+  /* add your public declarations here */
+
+  GcalDateEntryPrivate *priv;
+};
+
+struct _GcalDateEntryClass
+{
+  GtkEntryClass parent_class;
+};
+
+GType            gcal_date_entry_get_type        (void);
+
+GtkWidget*       gcal_date_entry_new             (void);
+
+void             gcal_date_entry_set_date        (GcalDateEntry *entry,
+                                                  guint          day,
+                                                  guint          month,
+                                                  guint          year);
+
+void             gcal_date_entry_get_date        (GcalDateEntry *entry,
+                                                  guint         *day,
+                                                  guint         *month,
+                                                  guint         *year);
+
+G_END_DECLS
+
+#endif /* __GCAL_DATE_ENTRY_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]