EggDateTime committed to libegg



Since Owen signalled interest in a date/time handling widget (post 2.4),
I have just committed my proposal EggDateTime to libegg. This is an initial
uncompleted and untested version. The API is not fixed and there are
some points that are not finished or that I am unhappy about.

API Proposal
============

To start the discussion, this is the current API:

  typedef enum
  {
        /* don't use the following values for now... */
        EGG_DATETIME_DISPLAY_YEAR       = 1 << 0,
        EGG_DATETIME_DISPLAY_MONTH      = 1 << 1,
        EGG_DATETIME_DISPLAY_DAY        = 1 << 2,
        EGG_DATETIME_DISPLAY_HOUR       = 1 << 3,
        EGG_DATETIME_DISPLAY_MINUTE     = 1 << 4,
        EGG_DATETIME_DISPLAY_SECOND     = 1 << 5,
        EGG_DATETIME_DISPLAY_YEAR_OPT   = 1 << 6,
        EGG_DATETIME_DISPLAY_MONTH_OPT  = 1 << 7,
        EGG_DATETIME_DISPLAY_DAY_OPT    = 1 << 8,
        EGG_DATETIME_DISPLAY_HOUR_OPT   = 1 << 9,
        EGG_DATETIME_DISPLAY_MINUTE_OPT = 1 << 10,
        EGG_DATETIME_DISPLAY_SECOND_OPT = 1 << 11
  } EggDateTimeDisplayMode;

This is a flag list that is used to determine, which parts of the widget
(date part, time part) are displayed and which information in them is
required or optional. To give an example: It is possible to specify the
flag list

  EGG_DATETIME_DISPLAY_YEAR | EGG_DATETIME_DISPLAY_MONTH |
  EGG_DATETIME_DISPLAY_DAY_OPT

This would mean that only the date part of the widget is shown and that
a year and a month must be specified, while the day of month part is
optional. The following are a few defines for the only modes that are
currently supported:

  /* ... use these instead */
  #define EGG_DATETIME_DISPLAY_DATE (EGG_DATETIME_DISPLAY_YEAR |
                                     EGG_DATETIME_DISPLAY_MONTH |
				     EGG_DATETIME_DISPLAY_DAY)

Display the date part.

  #define EGG_DATETIME_DISPLAY_TIME (EGG_DATETIME_DISPLAY_HOUR |
                                     EGG_DATETIME_DISPLAY_MINUTE)

Display the time part (without seconds).

  #define EGG_DATETIME_DISPLAY_TIME_SECONDS (EGG_DATETIME_DISPLAY_HOUR |
                                             EGG_DATETIME_DISPLAY_MINUTE |
					     EGG_DATETIME_DISPLAY_SECOND)

Display the time part (with seconds).

I am not too happy with this API. Please see the discussion below for a
different approach.

  #define EGG_DATETIME_INVALID_DATE (0)
  #define EGG_DATETIME_INVALID_TIME (0xff)

Some defines used later to signal that an invalid date or an invalid
time was specified.

  struct _EggDateTime
  {
        GtkHBox parent;
                                                                                
        EggDateTimePrivate *priv;
  };

The widget structure contains only private members.

  /* Constructors */
  GtkWidget *egg_datetime_new                (void);
  GtkWidget *egg_datetime_new_from_time_t    (time_t t);
  GtkWidget *egg_datetime_new_from_struct_tm (struct tm *tm);
  GtkWidget *egg_datetime_new_from_gdate     (GDate *date);
  GtkWidget *egg_datetime_new_from_datetime  (guint16 year,
                                              guint8  month,
					      guint8  day,
					      guint8  hour,
					      guint8  minute,
					      guint8 second);

The constructors. We should probably limit this to just three
constructors: _new, _new_from_gdate, and _new_from_datetime(). I just
notice that the _new_from_datetime constructor should be changed to take
arguments from type GDateYear, GDateMonth, and GDateYear.

  /* Accessors */
  void     egg_datetime_set_none (EggDateTime *edt);

Sets the date/time to an invalid value and blanks the date and time
widget. Works only in lazy mode. (See below.)

  void     egg_datetime_set_from_time_t (EggDateTime *edt, time_t t);
  gboolean egg_datetime_get_as_time_t   (EggDateTime *edt, time_t *t);
  void     egg_datetime_set_from_struct_tm (EggDateTime *edt, struct tm *tm);
  gboolean egg_datetime_get_as_struct_tm   (EggDateTime *edt, struct tm *tm);
  void     egg_datetime_set_from_gdate (EggDateTime *edt, GDate *date);
  gboolean egg_datetime_get_as_gdate   (EggDateTime *edt, GDate *date);
  void     egg_datetime_set_date (EggDateTime *edt,
                                  guint16 year,
				  guint8  month,
				  guint8  day);
  gboolean egg_datetime_get_date (EggDateTime *edt,
                                  guint16 *year,
				  guint8  *month,
				  guint8  *day);
  void     egg_datetime_set_time (EggDateTime *edt,
                                  guint8 hour,
				  guint8 minute,
				  guint8 second);
  gboolean egg_datetime_get_time (EggDateTime *edt,
                                  guint8 *hour,
				  guint8 *minute,
				  guint8 *second);

Accessors to set/get the date and time. As above we should probably
limit them to GDate and direct date/time accessors. In lazy mode (see
below) the return value of the getters signify whether the currently
entered date/time is valid. The comment above about using GDateYear and
friends applies to _[gs]et_date, too.

  void     egg_datetime_set_lazy (EggDateTime *edt, gboolean lazy);
  gboolean egg_datetime_get_lazy (EggDateTime *edt);

These set the so-called "lazy mode". If the widget is in lazy mode,
invalid date/time entries are allowed. In this case the accessors will
return FALSE if the entered date/time is invalid. If lazy mode is turned
off, all invalid entries will be normalized to a valid value.

  void egg_datetime_set_display_mode (EggDateTime *edt,
                                      EggDateTimeDisplayMode mode);
  EggDateTimeDisplayMode egg_datetime_get_display_mode (EggDateTime *edt);

This is used to set/get the desired display mode. (See above.)

  void egg_datetime_set_clamp_date (EggDateTime *edt,
                                    guint16 minyear,
				    guint8  minmonth,
				    guint8  minday,
				    guint16 maxyear,
				    guint8  maxmonth,
				    guint8  maxday);
  void egg_datetime_set_clamp_time (EggDateTime *edt,
                                    guint8 minhour,
				    guint8 minminute,
				    guint8 minsecond,
				    guint8 maxhour, guint8 maxminute,
				    guint8 maxsecond);
  void egg_datetime_set_clamp_time_t (EggDateTime *edt);
  void egg_datetime_get_clamp_date (EggDateTime *edt,
                                    guint16 *minyear,
				    guint8  *minmonth,
				    guint8  *minday,
				    guint16 *maxyear,
				    guint8  *maxmonth,
				    guint8 *maxday);
  void egg_datetime_get_clamp_time (EggDateTime *edt,
                                    guint8 *minhour,
				    guint8 *minminute,
				    guint8 *minsecond,
				    guint8 *maxhour,
				    guint8 *maxminute,
				    guint8 *maxsecond);

This sets/gets the clamp date and/or clamp time. If this is set, valid
dates/times are only between the given minimum and maximum date/time.
Again, the comment about using GDateYear etc. applies.

Discussion
==========

As mentioned above, I am unhappy about the way the displayed parts of
the widget are handled. I think that the flag list is ugly. Here is a
proposal for a different approach:

  typedef enum
  {
    EGG_DATETIME_DATE_NONE,
    EGG_DATETIME_DATE_FULL,
    EGG_DATETIME_DATE_YEARMONTH
  } EggDateTimeDateMode;

  typedef enum
  {
    EGG_DATETIME_TIME_NONE,
    EGG_DATETIME_TIME_FULL,
    EGG_DATETIME_TIME_NOSECONDS
  };

  void egg_datetime_set_date_display (EggDateTime *edt,
                                      EggDateTimeDateMode mode);
  EggDateTimeDateMode egg_datetime_get_date_display (EggDateTime *edt);
  void egg_datetime_set_time_display (EggDateTime *edt,
                                      EggDateTimeTimeMode mode);
  EggDateTimeTimeMode egg_datetime_get_time_display (EggDateTime *edt);

Further display modes could be added as required. This takes away
flexibility in favor of a cleaner API and a much simpler implementation,
since only useful cases need to be considered.

Another thing that is missing is an optional method for determining the
time zone. This could be in form of a small time zone button (not shown
by default, can be enabled via the API) that pops up a time zone
chooser. This is how it's handled in Evolution and maybe we could just
steal some code from there. API proposal:

  void     egg_datetime_set_show_timezone (EggDateTime *edt, gboolean show);
  gboolean egg_datetime_get_show_timezone (EggDateTime *edt);
  void     egg_datetime_set_timezone (EggDateTime *edt, gint16 timezone);
  gint16   egg_datetime_get_timezone (EggDateTime *edt);

 - Sebastian




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