
2001-03-18 Damon Chaplin <damon@ximian.com> * e-cell-date-edit.c (e_cell_date_edit_show_time_invalid_warning): use gnome_dialog_run() to make the warning dialog modal. Also created a better warning message showing the format expected. Also used e_time_format_time() to format all times. svn path=/trunk/; revision=8823
870 lines
24 KiB
C
870 lines
24 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
|
|
/*
|
|
* Author :
|
|
* Damon Chaplin <damon@ximian.com>
|
|
*
|
|
* Copyright 2001, Ximian, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
* USA
|
|
*/
|
|
|
|
/*
|
|
* ECellDateEdit - a subclass of ECellPopup used to show a date with a popup
|
|
* window to edit it.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <gal/util/e-i18n.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include "gal/util/e-util.h"
|
|
#include <gal/e-table/e-table-item.h>
|
|
#include <e-util/e-time-utils.h>
|
|
#include "e-cell-date-edit.h"
|
|
|
|
/* This depends on ECalendar which is why I didn't put it in gal. */
|
|
#include "e-calendar.h"
|
|
|
|
static void e_cell_date_edit_class_init (GtkObjectClass *object_class);
|
|
static void e_cell_date_edit_init (ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_destroy (GtkObject *object);
|
|
static void e_cell_date_edit_get_arg (GtkObject *o,
|
|
GtkArg *arg,
|
|
guint arg_id);
|
|
static void e_cell_date_edit_set_arg (GtkObject *o,
|
|
GtkArg *arg,
|
|
guint arg_id);
|
|
|
|
static gint e_cell_date_edit_do_popup (ECellPopup *ecp,
|
|
GdkEvent *event);
|
|
static void e_cell_date_edit_set_popup_values (ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_select_matching_time(ECellDateEdit *ecde,
|
|
char *time);
|
|
static void e_cell_date_edit_show_popup (ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_get_popup_pos (ECellDateEdit *ecde,
|
|
gint *x,
|
|
gint *y,
|
|
gint *height,
|
|
gint *width);
|
|
|
|
static void e_cell_date_edit_rebuild_time_list (ECellDateEdit *ecde);
|
|
|
|
static int e_cell_date_edit_key_press (GtkWidget *popup_window,
|
|
GdkEventKey *event,
|
|
ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_on_ok_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_show_time_invalid_warning (ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_on_now_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_on_none_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_on_today_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_update_cell (ECellDateEdit *ecde,
|
|
char *text);
|
|
static void e_cell_date_edit_on_time_selected (GtkList *list,
|
|
ECellDateEdit *ecde);
|
|
static void e_cell_date_edit_hide_popup (ECellDateEdit *ecde);
|
|
|
|
/* Our arguments. */
|
|
enum {
|
|
ARG_0,
|
|
ARG_SHOW_TIME,
|
|
ARG_SHOW_NOW_BUTTON,
|
|
ARG_SHOW_TODAY_BUTTON,
|
|
ARG_ALLOW_NO_DATE_SET,
|
|
ARG_USE_24_HOUR_FORMAT,
|
|
ARG_LOWER_HOUR,
|
|
ARG_UPPER_HOUR
|
|
};
|
|
|
|
static ECellPopupClass *parent_class;
|
|
|
|
|
|
E_MAKE_TYPE (e_cell_date_edit, "ECellDateEdit", ECellDateEdit,
|
|
e_cell_date_edit_class_init, e_cell_date_edit_init,
|
|
e_cell_popup_get_type());
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_class_init (GtkObjectClass *object_class)
|
|
{
|
|
ECellPopupClass *ecpc = (ECellPopupClass *) object_class;
|
|
|
|
gtk_object_add_arg_type ("ECellDateEdit::show_time",
|
|
GTK_TYPE_BOOL, GTK_ARG_READWRITE,
|
|
ARG_SHOW_TIME);
|
|
gtk_object_add_arg_type ("ECellDateEdit::show_now_button",
|
|
GTK_TYPE_BOOL, GTK_ARG_READWRITE,
|
|
ARG_SHOW_NOW_BUTTON);
|
|
gtk_object_add_arg_type ("ECellDateEdit::show_today_button",
|
|
GTK_TYPE_BOOL, GTK_ARG_READWRITE,
|
|
ARG_SHOW_TODAY_BUTTON);
|
|
gtk_object_add_arg_type ("ECellDateEdit::allow_no_date_set",
|
|
GTK_TYPE_BOOL, GTK_ARG_READWRITE,
|
|
ARG_ALLOW_NO_DATE_SET);
|
|
gtk_object_add_arg_type ("ECellDateEdit::use_24_hour_format",
|
|
GTK_TYPE_BOOL, GTK_ARG_READWRITE,
|
|
ARG_USE_24_HOUR_FORMAT);
|
|
gtk_object_add_arg_type ("ECellDateEdit::lower_hour",
|
|
GTK_TYPE_INT, GTK_ARG_READWRITE,
|
|
ARG_LOWER_HOUR);
|
|
gtk_object_add_arg_type ("ECellDateEdit::upper_hour",
|
|
GTK_TYPE_INT, GTK_ARG_READWRITE,
|
|
ARG_UPPER_HOUR);
|
|
|
|
object_class->destroy = e_cell_date_edit_destroy;
|
|
object_class->get_arg = e_cell_date_edit_get_arg;
|
|
object_class->set_arg = e_cell_date_edit_set_arg;
|
|
|
|
ecpc->popup = e_cell_date_edit_do_popup;
|
|
|
|
parent_class = gtk_type_class (e_cell_popup_get_type ());
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_init (ECellDateEdit *ecde)
|
|
{
|
|
GtkWidget *frame, *vbox, *hbox, *vbox2;
|
|
GtkWidget *scrolled_window, *list, *bbox;
|
|
GtkWidget *now_button, *today_button, *none_button, *ok_button;
|
|
|
|
ecde->lower_hour = 0;
|
|
ecde->upper_hour = 24;
|
|
ecde->use_24_hour_format = TRUE;
|
|
ecde->need_time_list_rebuild = TRUE;
|
|
ecde->freeze_count = 0;
|
|
|
|
/* We create one popup window for the ECell, since there will only
|
|
ever be one popup in use at a time. */
|
|
ecde->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
|
|
|
|
gtk_window_set_policy (GTK_WINDOW (ecde->popup_window),
|
|
TRUE, TRUE, FALSE);
|
|
|
|
frame = gtk_frame_new (NULL);
|
|
gtk_container_add (GTK_CONTAINER (ecde->popup_window), frame);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
ecde->calendar = e_calendar_new ();
|
|
gnome_canvas_item_set (GNOME_CANVAS_ITEM (E_CALENDAR (ecde->calendar)->calitem),
|
|
"move_selection_when_moving", FALSE,
|
|
NULL);
|
|
gtk_box_pack_start (GTK_BOX (hbox), ecde->calendar, TRUE, TRUE, 0);
|
|
gtk_widget_show (ecde->calendar);
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 2);
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
|
|
gtk_widget_show (vbox2);
|
|
|
|
ecde->time_entry = gtk_entry_new ();
|
|
gtk_widget_set_usize (ecde->time_entry, 50, -1);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), ecde->time_entry,
|
|
FALSE, FALSE, 0);
|
|
gtk_widget_show (ecde->time_entry);
|
|
|
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), scrolled_window, TRUE, TRUE, 0);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
GTK_POLICY_NEVER,
|
|
GTK_POLICY_ALWAYS);
|
|
gtk_widget_show (scrolled_window);
|
|
|
|
list = gtk_list_new ();
|
|
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), list);
|
|
gtk_container_set_focus_vadjustment (GTK_CONTAINER (list),
|
|
gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
|
|
gtk_widget_show (list);
|
|
ecde->time_list = list;
|
|
gtk_signal_connect (GTK_OBJECT (list), "selection-changed",
|
|
GTK_SIGNAL_FUNC (e_cell_date_edit_on_time_selected),
|
|
ecde);
|
|
|
|
bbox = gtk_hbutton_box_new ();
|
|
gtk_container_set_border_width (GTK_CONTAINER (bbox), 4);
|
|
gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 2);
|
|
gtk_button_box_set_child_ipadding (GTK_BUTTON_BOX (bbox), 2, 0);
|
|
gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), 0, 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (bbox);
|
|
|
|
now_button = gtk_button_new_with_label (_("Now"));
|
|
gtk_container_add (GTK_CONTAINER (bbox), now_button);
|
|
gtk_widget_show (now_button);
|
|
gtk_signal_connect (GTK_OBJECT (now_button), "clicked",
|
|
GTK_SIGNAL_FUNC (e_cell_date_edit_on_now_clicked),
|
|
ecde);
|
|
ecde->now_button = now_button;
|
|
|
|
today_button = gtk_button_new_with_label (_("Today"));
|
|
gtk_container_add (GTK_CONTAINER (bbox), today_button);
|
|
gtk_widget_show (today_button);
|
|
gtk_signal_connect (GTK_OBJECT (today_button), "clicked",
|
|
GTK_SIGNAL_FUNC (e_cell_date_edit_on_today_clicked),
|
|
ecde);
|
|
ecde->today_button = today_button;
|
|
|
|
none_button = gtk_button_new_with_label (_("None"));
|
|
gtk_container_add (GTK_CONTAINER (bbox), none_button);
|
|
gtk_widget_show (none_button);
|
|
gtk_signal_connect (GTK_OBJECT (none_button), "clicked",
|
|
GTK_SIGNAL_FUNC (e_cell_date_edit_on_none_clicked),
|
|
ecde);
|
|
ecde->none_button = none_button;
|
|
|
|
ok_button = gtk_button_new_with_label (_("OK"));
|
|
gtk_container_add (GTK_CONTAINER (bbox), ok_button);
|
|
gtk_widget_show (ok_button);
|
|
gtk_signal_connect (GTK_OBJECT (ok_button), "clicked",
|
|
GTK_SIGNAL_FUNC (e_cell_date_edit_on_ok_clicked),
|
|
ecde);
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ecde->popup_window),
|
|
"key_press_event",
|
|
GTK_SIGNAL_FUNC (e_cell_date_edit_key_press),
|
|
ecde);
|
|
}
|
|
|
|
|
|
/**
|
|
* e_cell_date_edit_new:
|
|
*
|
|
* Creates a new ECellDateEdit renderer.
|
|
*
|
|
* Returns: an ECellDateEdit object.
|
|
*/
|
|
ECell *
|
|
e_cell_date_edit_new (void)
|
|
{
|
|
ECellDateEdit *ecde = gtk_type_new (e_cell_date_edit_get_type ());
|
|
|
|
return (ECell*) ecde;
|
|
}
|
|
|
|
|
|
/*
|
|
* GtkObject::destroy method
|
|
*/
|
|
static void
|
|
e_cell_date_edit_destroy (GtkObject *object)
|
|
{
|
|
ECellDateEdit *ecde = E_CELL_DATE_EDIT (object);
|
|
|
|
gtk_widget_unref (ecde->popup_window);
|
|
|
|
GTK_OBJECT_CLASS (parent_class)->destroy (object);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_get_arg (GtkObject *o,
|
|
GtkArg *arg,
|
|
guint arg_id)
|
|
{
|
|
ECellDateEdit *ecde;
|
|
|
|
ecde = E_CELL_DATE_EDIT (o);
|
|
|
|
switch (arg_id) {
|
|
case ARG_SHOW_TIME:
|
|
GTK_VALUE_BOOL (*arg) = GTK_WIDGET_VISIBLE (ecde->time_entry) ? TRUE : FALSE;
|
|
break;
|
|
case ARG_SHOW_NOW_BUTTON:
|
|
GTK_VALUE_BOOL (*arg) = GTK_WIDGET_VISIBLE (ecde->now_button) ? TRUE : FALSE;
|
|
break;
|
|
case ARG_SHOW_TODAY_BUTTON:
|
|
GTK_VALUE_BOOL (*arg) = GTK_WIDGET_VISIBLE (ecde->today_button) ? TRUE : FALSE;
|
|
break;
|
|
case ARG_ALLOW_NO_DATE_SET:
|
|
GTK_VALUE_BOOL (*arg) = GTK_WIDGET_VISIBLE (ecde->none_button) ? TRUE : FALSE;
|
|
break;
|
|
case ARG_USE_24_HOUR_FORMAT:
|
|
GTK_VALUE_BOOL (*arg) = ecde->use_24_hour_format;
|
|
break;
|
|
case ARG_LOWER_HOUR:
|
|
GTK_VALUE_INT (*arg) = ecde->lower_hour;
|
|
break;
|
|
case ARG_UPPER_HOUR:
|
|
GTK_VALUE_INT (*arg) = ecde->upper_hour;
|
|
break;
|
|
default:
|
|
g_warning ("Invalid arg");
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_set_arg (GtkObject *o,
|
|
GtkArg *arg,
|
|
guint arg_id)
|
|
{
|
|
ECellDateEdit *ecde;
|
|
gint ivalue;
|
|
gboolean bvalue;
|
|
|
|
ecde = E_CELL_DATE_EDIT (o);
|
|
|
|
switch (arg_id){
|
|
case ARG_SHOW_TIME:
|
|
bvalue = GTK_VALUE_BOOL (*arg);
|
|
if (bvalue) {
|
|
gtk_widget_show (ecde->time_entry);
|
|
gtk_widget_show (ecde->time_list);
|
|
} else {
|
|
gtk_widget_hide (ecde->time_entry);
|
|
gtk_widget_hide (ecde->time_list);
|
|
}
|
|
break;
|
|
case ARG_SHOW_NOW_BUTTON:
|
|
bvalue = GTK_VALUE_BOOL (*arg);
|
|
if (bvalue) {
|
|
gtk_widget_show (ecde->now_button);
|
|
} else {
|
|
gtk_widget_hide (ecde->now_button);
|
|
}
|
|
break;
|
|
case ARG_SHOW_TODAY_BUTTON:
|
|
bvalue = GTK_VALUE_BOOL (*arg);
|
|
if (bvalue) {
|
|
gtk_widget_show (ecde->today_button);
|
|
} else {
|
|
gtk_widget_hide (ecde->today_button);
|
|
}
|
|
break;
|
|
case ARG_ALLOW_NO_DATE_SET:
|
|
bvalue = GTK_VALUE_BOOL (*arg);
|
|
if (bvalue) {
|
|
gtk_widget_show (ecde->none_button);
|
|
} else {
|
|
/* FIXME: What if we have no date set now. */
|
|
gtk_widget_hide (ecde->none_button);
|
|
}
|
|
break;
|
|
case ARG_USE_24_HOUR_FORMAT:
|
|
bvalue = GTK_VALUE_BOOL (*arg);
|
|
if (ecde->use_24_hour_format != bvalue) {
|
|
ecde->use_24_hour_format = bvalue;
|
|
ecde->need_time_list_rebuild = TRUE;
|
|
}
|
|
break;
|
|
case ARG_LOWER_HOUR:
|
|
ivalue = GTK_VALUE_INT (*arg);
|
|
ivalue = CLAMP (ivalue, 0, 24);
|
|
if (ecde->lower_hour != ivalue) {
|
|
ecde->lower_hour = ivalue;
|
|
ecde->need_time_list_rebuild = TRUE;
|
|
}
|
|
break;
|
|
case ARG_UPPER_HOUR:
|
|
ivalue = GTK_VALUE_INT (*arg);
|
|
ivalue = CLAMP (ivalue, 0, 24);
|
|
if (ecde->upper_hour != ivalue) {
|
|
ecde->upper_hour = ivalue;
|
|
ecde->need_time_list_rebuild = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
g_warning ("Invalid arg");
|
|
}
|
|
|
|
#if 0
|
|
if (ecde->need_time_list_rebuild && ecde->freeze_count == 0)
|
|
e_cell_date_edit_rebuild_time_list (ecde);
|
|
#endif
|
|
}
|
|
|
|
|
|
static gint
|
|
e_cell_date_edit_do_popup (ECellPopup *ecp,
|
|
GdkEvent *event)
|
|
{
|
|
ECellDateEdit *ecde = E_CELL_DATE_EDIT (ecp);
|
|
guint32 time;
|
|
|
|
e_cell_date_edit_show_popup (ecde);
|
|
e_cell_date_edit_set_popup_values (ecde);
|
|
|
|
if (event->type == GDK_BUTTON_PRESS) {
|
|
time = event->button.time;
|
|
} else {
|
|
time = event->key.time;
|
|
}
|
|
|
|
gtk_grab_add (ecde->popup_window);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_set_popup_values (ECellDateEdit *ecde)
|
|
{
|
|
ECellPopup *ecp = E_CELL_POPUP (ecde);
|
|
ECellView *ecv = (ECellView*) ecp->popup_cell_view;
|
|
ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
|
|
ETableCol *ecol;
|
|
char *cell_text;
|
|
ETimeParseStatus status;
|
|
struct tm date_tm;
|
|
GDate date;
|
|
ECalendarItem *calitem;
|
|
char buffer[64];
|
|
|
|
ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
|
|
cell_text = e_table_model_value_at (ecv->e_table_model,
|
|
ecol->col_idx, ecp->popup_row);
|
|
|
|
status = e_time_parse_date_and_time (cell_text, &date_tm);
|
|
|
|
/* If there is no date and time set, or the date is invalid, we clear
|
|
the selections, else we select the appropriate date & time. */
|
|
calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
|
|
if (status == E_TIME_PARSE_NONE || status == E_TIME_PARSE_INVALID) {
|
|
gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), "");
|
|
e_calendar_item_set_selection (calitem, NULL, NULL);
|
|
gtk_list_unselect_all (GTK_LIST (ecde->time_list));
|
|
} else {
|
|
e_time_format_time (&date_tm, ecde->use_24_hour_format, FALSE,
|
|
buffer, sizeof (buffer));
|
|
gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), buffer);
|
|
|
|
g_date_clear (&date, 1);
|
|
g_date_set_dmy (&date, date_tm.tm_mday, date_tm.tm_mon + 1,
|
|
date_tm.tm_year + 1900);
|
|
e_calendar_item_set_selection (calitem, &date, &date);
|
|
|
|
e_cell_date_edit_select_matching_time (ecde, buffer);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_select_matching_time (ECellDateEdit *ecde,
|
|
char *time)
|
|
{
|
|
GtkList *list;
|
|
GtkWidget *listitem, *label;
|
|
GList *elem;
|
|
gboolean found = FALSE;
|
|
char *list_item_text;
|
|
|
|
list = GTK_LIST (ecde->time_list);
|
|
elem = list->children;
|
|
while (elem) {
|
|
listitem = GTK_WIDGET (elem->data);
|
|
label = GTK_BIN (listitem)->child;
|
|
gtk_label_get (GTK_LABEL (label), &list_item_text);
|
|
|
|
if (!strcmp (list_item_text, time)) {
|
|
found = TRUE;
|
|
gtk_list_select_child (list, listitem);
|
|
break;
|
|
}
|
|
|
|
elem = elem->next;
|
|
}
|
|
|
|
if (!found)
|
|
gtk_list_unselect_all (list);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_show_popup (ECellDateEdit *ecde)
|
|
{
|
|
gint x, y, width, height, old_width, old_height;
|
|
|
|
if (ecde->need_time_list_rebuild)
|
|
e_cell_date_edit_rebuild_time_list (ecde);
|
|
|
|
/* This code is practically copied from GtkCombo. */
|
|
old_width = ecde->popup_window->allocation.width;
|
|
old_height = ecde->popup_window->allocation.height;
|
|
|
|
e_cell_date_edit_get_popup_pos (ecde, &x, &y, &height, &width);
|
|
|
|
gtk_widget_set_uposition (ecde->popup_window, x, y);
|
|
gtk_widget_set_usize (ecde->popup_window, width, height);
|
|
gtk_widget_realize (ecde->popup_window);
|
|
gdk_window_resize (ecde->popup_window->window, width, height);
|
|
gtk_widget_show (ecde->popup_window);
|
|
|
|
/* Set the focus to the first widget. */
|
|
gtk_widget_grab_focus (ecde->time_entry);
|
|
|
|
E_CELL_POPUP (ecde)->popup_shown = TRUE;
|
|
}
|
|
|
|
|
|
/* Calculates the size and position of the popup window (like GtkCombo). */
|
|
static void
|
|
e_cell_date_edit_get_popup_pos (ECellDateEdit *ecde,
|
|
gint *x,
|
|
gint *y,
|
|
gint *height,
|
|
gint *width)
|
|
{
|
|
ECellPopup *ecp = E_CELL_POPUP (ecde);
|
|
ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
|
|
GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas);
|
|
GtkRequisition popup_requisition;
|
|
gint avail_height, screen_width, column_width, row_height;
|
|
double x1, y1;
|
|
|
|
gdk_window_get_origin (canvas->window, x, y);
|
|
|
|
x1 = e_table_header_col_diff (eti->header, 0, eti->editing_col + 1);
|
|
y1 = e_table_item_row_diff (eti, 0, eti->editing_row + 1);
|
|
column_width = e_table_header_col_diff (eti->header, eti->editing_col,
|
|
eti->editing_col + 1);
|
|
row_height = e_table_item_row_diff (eti, eti->editing_row,
|
|
eti->editing_row + 1);
|
|
gnome_canvas_item_i2w (GNOME_CANVAS_ITEM (eti), &x1, &y1);
|
|
|
|
*x += x1;
|
|
/* The ETable positions don't include the grid lines, I think, so we
|
|
add 1. */
|
|
*y += y1 + 1;
|
|
|
|
avail_height = gdk_screen_height () - *y;
|
|
|
|
/* We'll use the entire screen width if needed, but we save space for
|
|
the vertical scrollbar in case we need to show that. */
|
|
screen_width = gdk_screen_width ();
|
|
|
|
gtk_widget_size_request (ecde->popup_window, &popup_requisition);
|
|
|
|
/* Calculate the desired width. */
|
|
*width = popup_requisition.width;
|
|
|
|
/* Use at least the same width as the column. */
|
|
if (*width < column_width)
|
|
*width = column_width;
|
|
|
|
/* Check if it fits in the available height. */
|
|
if (popup_requisition.height > avail_height) {
|
|
/* It doesn't fit, so we see if we have the minimum space
|
|
needed. */
|
|
if (*y - row_height > avail_height) {
|
|
/* We don't, so we show the popup above the cell
|
|
instead of below it. */
|
|
avail_height = *y - row_height;
|
|
*y -= (popup_requisition.height + row_height);
|
|
if (*y < 0)
|
|
*y = 0;
|
|
}
|
|
}
|
|
|
|
/* We try to line it up with the right edge of the column, but we don't
|
|
want it to go off the edges of the screen. */
|
|
if (*x > screen_width)
|
|
*x = screen_width;
|
|
*x -= *width;
|
|
if (*x < 0)
|
|
*x = 0;
|
|
|
|
*height = popup_requisition.height;
|
|
}
|
|
|
|
|
|
/* This handles key press events in the popup window. If the Escape key is
|
|
pressed we hide the popup, and do not change the cell contents. */
|
|
static int
|
|
e_cell_date_edit_key_press (GtkWidget *popup_window,
|
|
GdkEventKey *event,
|
|
ECellDateEdit *ecde)
|
|
{
|
|
g_print ("In e_cell_date_edit_key_press\n");
|
|
|
|
/* If the Escape key is pressed we hide the popup. */
|
|
if (event->keyval != GDK_Escape)
|
|
return FALSE;
|
|
|
|
e_cell_date_edit_hide_popup (ecde);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Clears the time list and rebuilds it using the lower_hour, upper_hour
|
|
and use_24_hour_format settings. */
|
|
static void
|
|
e_cell_date_edit_rebuild_time_list (ECellDateEdit *ecde)
|
|
{
|
|
GtkList *list;
|
|
GtkWidget *listitem;
|
|
char buffer[40], *format;
|
|
struct tm tmp_tm;
|
|
gint hour, min;
|
|
|
|
list = GTK_LIST (ecde->time_list);
|
|
|
|
gtk_list_clear_items (list, 0, -1);
|
|
|
|
/* Fill the struct tm with some sane values. */
|
|
tmp_tm.tm_year = 2000;
|
|
tmp_tm.tm_mon = 0;
|
|
tmp_tm.tm_mday = 1;
|
|
tmp_tm.tm_sec = 0;
|
|
tmp_tm.tm_isdst = 0;
|
|
|
|
for (hour = ecde->lower_hour; hour <= ecde->upper_hour; hour++) {
|
|
|
|
/* We don't want to display midnight at the end, since that is
|
|
really in the next day. */
|
|
if (hour == 24)
|
|
break;
|
|
|
|
/* We want to finish on upper_hour, with min == 0. */
|
|
for (min = 0;
|
|
min == 0 || (min < 60 && hour != ecde->upper_hour);
|
|
min += 30) {
|
|
tmp_tm.tm_hour = hour;
|
|
tmp_tm.tm_min = min;
|
|
e_time_format_time (&tmp_tm, ecde->use_24_hour_format,
|
|
FALSE, buffer, sizeof (buffer));
|
|
listitem = gtk_list_item_new_with_label (buffer);
|
|
gtk_widget_show (listitem);
|
|
gtk_container_add (GTK_CONTAINER (list), listitem);
|
|
}
|
|
}
|
|
|
|
ecde->need_time_list_rebuild = FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_on_ok_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde)
|
|
{
|
|
ECalendarItem *calitem;
|
|
GDate start_date, end_date;
|
|
gboolean day_selected;
|
|
struct tm date_tm;
|
|
char buffer[64], *text;
|
|
ETimeParseStatus status;
|
|
|
|
calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
|
|
day_selected = e_calendar_item_get_selection (calitem, &start_date,
|
|
&end_date);
|
|
|
|
text = gtk_entry_get_text (GTK_ENTRY (ecde->time_entry));
|
|
status = e_time_parse_time (text, &date_tm);
|
|
if (status == E_TIME_PARSE_INVALID) {
|
|
e_cell_date_edit_show_time_invalid_warning (ecde);
|
|
return;
|
|
}
|
|
|
|
if (day_selected) {
|
|
date_tm.tm_year = g_date_year (&start_date) - 1900;
|
|
date_tm.tm_mon = g_date_month (&start_date) - 1;
|
|
date_tm.tm_mday = g_date_day (&start_date);
|
|
/* We need to call this to set the weekday. */
|
|
mktime (&date_tm);
|
|
e_time_format_date_and_time (&date_tm,
|
|
ecde->use_24_hour_format,
|
|
TRUE, FALSE,
|
|
buffer, sizeof (buffer));
|
|
} else {
|
|
buffer[0] = '\0';
|
|
}
|
|
|
|
e_cell_date_edit_update_cell (ecde, buffer);
|
|
e_cell_date_edit_hide_popup (ecde);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_show_time_invalid_warning (ECellDateEdit *ecde)
|
|
{
|
|
GtkWidget *dialog;
|
|
struct tm date_tm;
|
|
char buffer[64], *message;
|
|
|
|
/* Create a useful error message showing the correct format. */
|
|
date_tm.tm_year = 100;
|
|
date_tm.tm_mon = 0;
|
|
date_tm.tm_mday = 1;
|
|
date_tm.tm_hour = 1;
|
|
date_tm.tm_min = 30;
|
|
date_tm.tm_sec = 0;
|
|
date_tm.tm_isdst = -1;
|
|
e_time_format_time (&date_tm, ecde->use_24_hour_format, FALSE,
|
|
buffer, sizeof (buffer));
|
|
|
|
message = g_strdup_printf (_("The time must be in the format: %s"),
|
|
buffer);
|
|
|
|
dialog = gnome_message_box_new (message, GNOME_MESSAGE_BOX_ERROR,
|
|
GNOME_STOCK_BUTTON_OK, NULL);
|
|
/* FIXME: Fix transient settings - I'm not sure it works with popup
|
|
windows. Maybe we need to use a normal window without decorations.*/
|
|
gtk_window_set_transient_for (GTK_WINDOW (dialog),
|
|
GTK_WINDOW (ecde->popup_window));
|
|
gnome_dialog_run (GNOME_DIALOG (dialog));
|
|
|
|
g_free (message);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_on_now_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde)
|
|
{
|
|
struct tm *tmp_tm;
|
|
time_t t;
|
|
char buffer[64];
|
|
|
|
g_print ("In e_cell_date_edit_on_now_clicked\n");
|
|
|
|
t = time (NULL);
|
|
tmp_tm = localtime (&t);
|
|
e_time_format_date_and_time (tmp_tm,
|
|
ecde->use_24_hour_format,
|
|
TRUE, FALSE,
|
|
buffer, sizeof (buffer));
|
|
|
|
e_cell_date_edit_update_cell (ecde, buffer);
|
|
e_cell_date_edit_hide_popup (ecde);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_on_none_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde)
|
|
{
|
|
g_print ("In e_cell_date_edit_on_none_clicked\n");
|
|
|
|
e_cell_date_edit_update_cell (ecde, "");
|
|
e_cell_date_edit_hide_popup (ecde);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_on_today_clicked (GtkWidget *button,
|
|
ECellDateEdit *ecde)
|
|
{
|
|
struct tm *tmp_tm;
|
|
time_t t;
|
|
char buffer[64];
|
|
|
|
g_print ("In e_cell_date_edit_on_today_clicked\n");
|
|
|
|
t = time (NULL);
|
|
tmp_tm = localtime (&t);
|
|
tmp_tm->tm_hour = 0;
|
|
tmp_tm->tm_min = 0;
|
|
tmp_tm->tm_sec = 0;
|
|
e_time_format_date_and_time (tmp_tm,
|
|
ecde->use_24_hour_format,
|
|
FALSE, FALSE,
|
|
buffer, sizeof (buffer));
|
|
|
|
e_cell_date_edit_update_cell (ecde, buffer);
|
|
e_cell_date_edit_hide_popup (ecde);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_update_cell (ECellDateEdit *ecde,
|
|
char *text)
|
|
{
|
|
ECellPopup *ecp = E_CELL_POPUP (ecde);
|
|
ECellView *ecv = (ECellView*) ecp->popup_cell_view;
|
|
ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
|
|
ETableCol *ecol;
|
|
gchar *old_text;
|
|
|
|
/* Compare the new text with the existing cell contents. */
|
|
ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
|
|
old_text = e_table_model_value_at (ecv->e_table_model,
|
|
ecol->col_idx, ecp->popup_row);
|
|
|
|
/* If they are different, update the cell contents. */
|
|
if (strcmp (old_text, text)) {
|
|
e_table_model_set_value_at (ecv->e_table_model,
|
|
ecol->col_idx, ecp->popup_row,
|
|
text);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_on_time_selected (GtkList *list,
|
|
ECellDateEdit *ecde)
|
|
{
|
|
GtkWidget *listitem, *label;
|
|
char *list_item_text;
|
|
|
|
g_print ("In e_cell_date_edit_on_time_selected\n");
|
|
|
|
if (!list->selection)
|
|
return;
|
|
|
|
listitem = list->selection->data;
|
|
label = GTK_BIN (listitem)->child;
|
|
gtk_label_get (GTK_LABEL (label), &list_item_text);
|
|
gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), list_item_text);
|
|
}
|
|
|
|
|
|
static void
|
|
e_cell_date_edit_hide_popup (ECellDateEdit *ecde)
|
|
{
|
|
gtk_grab_remove (ecde->popup_window);
|
|
gtk_widget_hide (ecde->popup_window);
|
|
E_CELL_POPUP (ecde)->popup_shown = FALSE;
|
|
}
|
|
|
|
|
|
/* These freeze and thaw the rebuilding of the time list. They are useful when
|
|
setting several properties which result in rebuilds of the list, e.g. the
|
|
lower_hour, upper_hour and use_24_hour_format properties. */
|
|
void
|
|
e_cell_date_edit_freeze (ECellDateEdit *ecde)
|
|
{
|
|
g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
|
|
|
|
ecde->freeze_count++;
|
|
}
|
|
|
|
|
|
void
|
|
e_cell_date_edit_thaw (ECellDateEdit *ecde)
|
|
{
|
|
g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
|
|
|
|
if (ecde->freeze_count > 0) {
|
|
ecde->freeze_count--;
|
|
|
|
if (ecde->freeze_count == 0)
|
|
e_cell_date_edit_rebuild_time_list (ecde);
|
|
}
|
|
}
|
|
|