Now that we keep precise control over GcalEvent instances, and can use simple pointer comparisons everywhere, GcalMonthView implemented its update function as a simple remove + add pair. The problem is that we're not passing the old event instance, so removals never actually happen, since the new instance is not yet available to subscribers. Pass old event in additio to the new one, and use it where it makes sense. Closes https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/1073
742 lines
20 KiB
C
742 lines
20 KiB
C
/* gcal-agenda-view.c
|
||
*
|
||
* Copyright (C) 2022 Purism SPC
|
||
*
|
||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#define G_LOG_DOMAIN "GcalAgendaView"
|
||
|
||
#include "gcal-agenda-view.h"
|
||
#include "gcal-debug.h"
|
||
#include "gcal-enums.h"
|
||
#include "gcal-event-widget.h"
|
||
#include "gcal-range-tree.h"
|
||
#include "gcal-timeline-subscriber.h"
|
||
#include "gcal-utils.h"
|
||
#include "gcal-view-private.h"
|
||
|
||
#include <adwaita.h>
|
||
#include <glib/gi18n.h>
|
||
|
||
#include <math.h>
|
||
|
||
typedef struct
|
||
{
|
||
GtkWidget *widget;
|
||
GcalEvent *event;
|
||
GcalAgendaView *self;
|
||
} ChildData;
|
||
|
||
struct _GcalAgendaView
|
||
{
|
||
GtkBox parent;
|
||
|
||
GtkWidget *list_box;
|
||
GtkWidget *no_events_row;
|
||
GtkWidget *scrolled_window;
|
||
|
||
/* property */
|
||
GDateTime *date;
|
||
GcalContext *context;
|
||
|
||
GcalRangeTree *events;
|
||
guint scroll_grid_timeout_id;
|
||
gulong stack_page_changed_id;
|
||
|
||
gint events_on_date;
|
||
gint clicked_cell;
|
||
};
|
||
|
||
static void schedule_position_scroll (GcalAgendaView *self);
|
||
|
||
static void gcal_view_interface_init (GcalViewInterface *iface);
|
||
|
||
static void gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface);
|
||
|
||
enum
|
||
{
|
||
PROP_0,
|
||
PROP_DATE,
|
||
PROP_CONTEXT,
|
||
N_PROPS,
|
||
};
|
||
|
||
|
||
G_DEFINE_TYPE_WITH_CODE (GcalAgendaView, gcal_agenda_view, GTK_TYPE_BOX,
|
||
G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init)
|
||
G_IMPLEMENT_INTERFACE (GCAL_TYPE_TIMELINE_SUBSCRIBER,
|
||
gcal_timeline_subscriber_interface_init));
|
||
|
||
/*
|
||
* Auxiliary methods
|
||
*/
|
||
|
||
static ChildData*
|
||
child_data_new (GtkWidget *widget,
|
||
GcalEvent *event,
|
||
GcalAgendaView *self)
|
||
{
|
||
ChildData *data;
|
||
|
||
data = g_new (ChildData, 1);
|
||
data->widget = widget;
|
||
data->event = g_object_ref (event);
|
||
data->self = self;
|
||
|
||
return data;
|
||
}
|
||
|
||
static void
|
||
child_data_free (gpointer data)
|
||
{
|
||
ChildData *child_data = data;
|
||
|
||
if (!child_data)
|
||
return;
|
||
|
||
if (child_data->widget && child_data->self)
|
||
{
|
||
gtk_list_box_remove (GTK_LIST_BOX (child_data->self->list_box), child_data->widget);
|
||
child_data->widget = NULL;
|
||
child_data->self = NULL;
|
||
}
|
||
g_clear_object (&child_data->event);
|
||
g_free (child_data);
|
||
}
|
||
|
||
static GDateTime *
|
||
get_start_date_for_row (GcalAgendaView *self,
|
||
GtkListBoxRow *row)
|
||
{
|
||
GtkWidget *widget = gtk_list_box_row_get_child (row);
|
||
|
||
if (GCAL_IS_EVENT_WIDGET (widget))
|
||
{
|
||
GDateTime *date = gcal_event_widget_get_date_start (GCAL_EVENT_WIDGET (widget));
|
||
|
||
/* Pretend events start at least on the selected date */
|
||
if (gcal_date_time_compare_date (date, self->date) > 0)
|
||
return date;
|
||
else
|
||
return self->date;
|
||
}
|
||
|
||
|
||
return self->date;
|
||
}
|
||
|
||
static GDateTime *
|
||
get_end_date_for_row (GcalAgendaView *self,
|
||
GtkListBoxRow *row)
|
||
{
|
||
GtkWidget *widget = gtk_list_box_row_get_child (row);
|
||
|
||
if (GCAL_IS_EVENT_WIDGET (widget))
|
||
return gcal_event_widget_get_date_end (GCAL_EVENT_WIDGET (widget));
|
||
|
||
return self->date;
|
||
}
|
||
|
||
static gboolean
|
||
get_row_is_multiday (GtkListBoxRow *row)
|
||
{
|
||
GtkWidget *widget = gtk_list_box_row_get_child (row);
|
||
|
||
if (GCAL_IS_EVENT_WIDGET (widget))
|
||
{
|
||
GcalEvent *event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
|
||
|
||
return gcal_event_is_multiday (event);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static gchar *
|
||
new_date_header_string (GDateTime *date)
|
||
{
|
||
g_autoptr (GDateTime) today = NULL;
|
||
g_autoptr (GDateTime) tomorrow = NULL;
|
||
g_autoptr (GDateTime) yesterday = NULL;
|
||
|
||
if (date == NULL)
|
||
return NULL;
|
||
|
||
today = g_date_time_new_now_local ();
|
||
tomorrow = g_date_time_add_days (today, 1);
|
||
yesterday = g_date_time_add_days (today, -1);
|
||
|
||
if (gcal_date_time_compare_date (date, today) == 0)
|
||
return g_strdup (_("Today"));
|
||
else if (gcal_date_time_compare_date (date, tomorrow) == 0)
|
||
return g_strdup (_("Tomorrow"));
|
||
else if (gcal_date_time_compare_date (date, yesterday) == 0)
|
||
return g_strdup (_("Yesterday"));
|
||
else
|
||
return g_date_time_format (date, "%A %B %e");
|
||
}
|
||
|
||
|
||
/*
|
||
* Callbacks
|
||
*/
|
||
|
||
static void
|
||
stack_visible_child_changed_cb (AdwViewStack *stack,
|
||
GParamSpec *pspec,
|
||
GcalAgendaView *self)
|
||
{
|
||
if (adw_view_stack_get_visible_child (stack) != (GtkWidget*) self)
|
||
return;
|
||
|
||
schedule_position_scroll (self);
|
||
|
||
g_clear_signal_handler (&self->stack_page_changed_id, stack);
|
||
}
|
||
|
||
/* Auxiliary methods */
|
||
static void
|
||
update_no_events_row (GcalAgendaView *self)
|
||
{
|
||
gboolean visible = !self->events_on_date;
|
||
gboolean was_visible = gtk_widget_get_visible (self->no_events_row);
|
||
|
||
if (visible != was_visible)
|
||
{
|
||
gtk_widget_set_visible (self->no_events_row, visible);
|
||
gtk_list_box_invalidate_headers (GTK_LIST_BOX (self->list_box));
|
||
}
|
||
}
|
||
|
||
static gboolean
|
||
update_grid_scroll_position (GcalAgendaView *self)
|
||
{
|
||
g_autoptr(GDateTime) week_start = NULL;
|
||
g_autoptr(GDateTime) week_end = NULL;
|
||
g_autoptr(GDateTime) now = NULL;
|
||
GtkAdjustment *vadjustment;
|
||
gdouble minutes, real_value;
|
||
gdouble max, page, page_increment, value;
|
||
gboolean dummy;
|
||
|
||
/* While the scrolled window is not mapped, we keep waiting */
|
||
if (!gtk_widget_get_realized (self->scrolled_window) ||
|
||
!gtk_widget_get_mapped (self->scrolled_window))
|
||
{
|
||
if (self->stack_page_changed_id == 0)
|
||
{
|
||
GtkWidget *stack = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_VIEW_STACK);
|
||
|
||
self->stack_page_changed_id = g_signal_connect_object (stack,
|
||
"notify::visible-child",
|
||
G_CALLBACK (stack_visible_child_changed_cb),
|
||
self,
|
||
0);
|
||
}
|
||
|
||
self->scroll_grid_timeout_id = 0;
|
||
|
||
GCAL_RETURN (G_SOURCE_REMOVE);
|
||
}
|
||
|
||
now = g_date_time_new_now_local ();
|
||
week_start = gcal_date_time_get_start_of_week (self->date);
|
||
week_end = gcal_date_time_get_end_of_week (self->date);
|
||
|
||
/* Don't animate when not today */
|
||
if (gcal_date_time_compare_date (now, week_start) < 0 || gcal_date_time_compare_date (now, week_end) >= 0)
|
||
GCAL_GOTO (out);
|
||
|
||
vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (self->scrolled_window));
|
||
minutes = g_date_time_get_hour (now) * 60 + g_date_time_get_minute (now);
|
||
page = gtk_adjustment_get_page_size (vadjustment);
|
||
max = gtk_adjustment_get_upper (vadjustment);
|
||
|
||
real_value = max / MINUTES_PER_DAY * minutes - (page / 2.0);
|
||
page_increment = gtk_adjustment_get_page_increment (vadjustment);
|
||
value = gtk_adjustment_get_value (vadjustment);
|
||
|
||
gtk_adjustment_set_page_increment (vadjustment, real_value - value);
|
||
|
||
g_signal_emit_by_name (self->scrolled_window,
|
||
"scroll-child",
|
||
GTK_SCROLL_PAGE_FORWARD,
|
||
FALSE,
|
||
&dummy);
|
||
|
||
gtk_adjustment_set_page_increment (vadjustment, page_increment);
|
||
|
||
out:
|
||
self->scroll_grid_timeout_id = 0;
|
||
GCAL_RETURN (G_SOURCE_REMOVE);
|
||
}
|
||
|
||
static void
|
||
schedule_position_scroll (GcalAgendaView *self)
|
||
{
|
||
/* Nothing is scheduled, we should do it now */
|
||
if (self->scroll_grid_timeout_id > 0)
|
||
g_source_remove (self->scroll_grid_timeout_id);
|
||
|
||
self->scroll_grid_timeout_id = g_timeout_add (200,
|
||
(GSourceFunc) update_grid_scroll_position,
|
||
self);
|
||
}
|
||
|
||
static int
|
||
sort_func (GtkListBoxRow *row1,
|
||
GtkListBoxRow *row2,
|
||
gpointer user_data)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (user_data);
|
||
gboolean multiday1, multiday2;
|
||
int result;
|
||
|
||
result = gcal_date_time_compare_date (get_start_date_for_row (self, row1),
|
||
get_start_date_for_row (self, row2));
|
||
|
||
if (result != 0)
|
||
return result;
|
||
|
||
multiday1 = get_row_is_multiday (row1);
|
||
multiday2 = get_row_is_multiday (row2);
|
||
|
||
/* Sort multi day events before multi single day events of the same day. */
|
||
if (multiday1 != multiday2)
|
||
return multiday1 ? -1 : 1;
|
||
|
||
return gcal_date_time_compare_date (get_end_date_for_row (self, row1),
|
||
get_end_date_for_row (self, row2));
|
||
}
|
||
|
||
static void
|
||
update_header (GtkListBoxRow *row,
|
||
GtkListBoxRow *before,
|
||
gpointer user_data)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (user_data);
|
||
GDateTime *start = get_start_date_for_row (self, row);
|
||
GDateTime *end = get_end_date_for_row (self, row);
|
||
g_autofree gchar *label = NULL;
|
||
GtkWidget *header;
|
||
g_autoptr (GDateTime) today = NULL;
|
||
|
||
today = g_date_time_new_now_local ();
|
||
|
||
if (before)
|
||
{
|
||
GDateTime *before_start = get_start_date_for_row (self, before);
|
||
GDateTime *before_end = get_end_date_for_row (self, before);
|
||
|
||
if (get_row_is_multiday (row) &&
|
||
get_row_is_multiday (before) &&
|
||
gcal_date_time_compare_date (start, before_start) == 0 &&
|
||
gcal_date_time_compare_date (start, today) == 0)
|
||
{
|
||
gtk_list_box_row_set_header (row, NULL);
|
||
return;
|
||
}
|
||
|
||
if (gcal_date_time_compare_date (start, before_start) == 0 &&
|
||
gcal_date_time_compare_date (end, before_end) == 0)
|
||
{
|
||
gtk_list_box_row_set_header (row, NULL);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (get_row_is_multiday (row))
|
||
{
|
||
g_autofree gchar *start_label = NULL;
|
||
g_autofree gchar *end_label = NULL;
|
||
if (gcal_date_time_compare_date (start, today) == 0)
|
||
{
|
||
label = g_strdup (_("On-going"));
|
||
}
|
||
else
|
||
{
|
||
start_label = new_date_header_string (start);
|
||
end_label = new_date_header_string (end);
|
||
|
||
label = g_strdup_printf ("%s – %s", start_label, end_label);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
label = new_date_header_string (start);
|
||
}
|
||
|
||
header = g_object_new (GTK_TYPE_LABEL,
|
||
"label", label,
|
||
"xalign", 0.0f,
|
||
NULL);
|
||
gtk_widget_add_css_class (header, "caption-heading");
|
||
|
||
gtk_list_box_row_set_header (row, header);
|
||
}
|
||
|
||
|
||
/*
|
||
* GcalView interface
|
||
*/
|
||
|
||
static GDateTime*
|
||
gcal_agenda_view_get_date (GcalView *view)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (view);
|
||
|
||
return self->date;
|
||
}
|
||
|
||
static inline gboolean
|
||
count_events_on_data (GcalRange *range,
|
||
gpointer data,
|
||
gpointer user_data)
|
||
{
|
||
ChildData *child_data = data;
|
||
GcalAgendaView *self = user_data;
|
||
|
||
if (gcal_date_time_compare_date (self->date, gcal_event_get_date_start (child_data->event)) == 0)
|
||
self->events_on_date++;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_set_date (GcalView *view,
|
||
GDateTime *date)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (view);
|
||
|
||
GCAL_ENTRY;
|
||
|
||
gcal_set_date_time (&self->date, date);
|
||
|
||
schedule_position_scroll (self);
|
||
|
||
self->events_on_date = 0;
|
||
gcal_range_tree_traverse (self->events, G_IN_ORDER, count_events_on_data, self);
|
||
update_no_events_row (self);
|
||
|
||
gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (view));
|
||
|
||
GCAL_EXIT;
|
||
}
|
||
|
||
static GList*
|
||
gcal_agenda_view_get_children_by_uuid (GcalView *view,
|
||
GcalRecurrenceModType mod,
|
||
const gchar *uuid)
|
||
{
|
||
GCAL_ENTRY;
|
||
|
||
/* FIXME Not sure what to do here. */
|
||
|
||
GCAL_RETURN (NULL);
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_clear_marks (GcalView *view)
|
||
{
|
||
/* FIXME Not sure what to do here. */
|
||
}
|
||
|
||
static GDateTime*
|
||
gcal_agenda_view_get_next_date (GcalView *view)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (view);
|
||
|
||
g_assert (self->date != NULL);
|
||
return g_date_time_add_weeks (self->date, 1);
|
||
}
|
||
|
||
|
||
static GDateTime*
|
||
gcal_agenda_view_get_previous_date (GcalView *view)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (view);
|
||
|
||
g_assert (self->date != NULL);
|
||
return g_date_time_add_weeks (self->date, -1);
|
||
}
|
||
|
||
static void
|
||
gcal_view_interface_init (GcalViewInterface *iface)
|
||
{
|
||
iface->get_date = gcal_agenda_view_get_date;
|
||
iface->set_date = gcal_agenda_view_set_date;
|
||
iface->get_children_by_uuid = gcal_agenda_view_get_children_by_uuid;
|
||
iface->clear_marks = gcal_agenda_view_clear_marks;
|
||
iface->get_next_date = gcal_agenda_view_get_next_date;
|
||
iface->get_previous_date = gcal_agenda_view_get_previous_date;
|
||
}
|
||
|
||
|
||
/*
|
||
* GcalTimelineSubscriber iface
|
||
*/
|
||
|
||
static void
|
||
on_event_widget_activated_cb (GcalEventWidget *event_widget,
|
||
GcalAgendaView *self)
|
||
{
|
||
gcal_view_event_activated (GCAL_VIEW (self), event_widget);
|
||
}
|
||
|
||
static GcalRange*
|
||
gcal_agenda_view_get_range (GcalTimelineSubscriber *subscriber)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (subscriber);
|
||
|
||
return gcal_range_new_take (g_date_time_ref (self->date),
|
||
gcal_date_time_get_end_of_week (self->date),
|
||
GCAL_RANGE_DEFAULT);
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_add_event (GcalTimelineSubscriber *subscriber,
|
||
GcalEvent *event)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (subscriber);
|
||
GtkWidget *widget, *row;
|
||
GcalTimestampPolicy timestamp_policy;
|
||
|
||
GCAL_ENTRY;
|
||
|
||
/* FIXME Check gcal_event_is_multiday (event) and gcal_event_get_all_day (event) */
|
||
|
||
g_object_ref (event);
|
||
|
||
if (gcal_date_time_compare_date (self->date, gcal_event_get_date_start (event)) == 0)
|
||
{
|
||
self->events_on_date++;
|
||
update_no_events_row (self);
|
||
}
|
||
|
||
/* Create and add the new event widget */
|
||
if (gcal_event_get_all_day (event) || gcal_event_is_multiday (event))
|
||
timestamp_policy = GCAL_TIMESTAMP_POLICY_END;
|
||
else
|
||
timestamp_policy = GCAL_TIMESTAMP_POLICY_START;
|
||
|
||
widget = g_object_new (GCAL_TYPE_EVENT_WIDGET,
|
||
"context", self->context,
|
||
"event", event,
|
||
"orientation", GTK_ORIENTATION_VERTICAL,
|
||
"timestamp-policy", timestamp_policy,
|
||
NULL);
|
||
|
||
row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
|
||
"activatable", FALSE,
|
||
"child", widget,
|
||
NULL);
|
||
|
||
gcal_range_tree_add_range (self->events,
|
||
gcal_event_get_range (event),
|
||
child_data_new (row, event, self));
|
||
|
||
g_signal_connect (widget, "activate", G_CALLBACK (on_event_widget_activated_cb), self);
|
||
|
||
gtk_list_box_append (GTK_LIST_BOX (self->list_box), row);
|
||
|
||
gtk_list_box_invalidate_headers (GTK_LIST_BOX (self->list_box));
|
||
|
||
GCAL_EXIT;
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_remove_event (GcalTimelineSubscriber *subscriber,
|
||
GcalEvent *event)
|
||
{
|
||
GcalAgendaView *self = GCAL_AGENDA_VIEW (subscriber);
|
||
const gchar *uid = gcal_event_get_uid (event);
|
||
GPtrArray *widgets;
|
||
guint i;
|
||
|
||
GCAL_ENTRY;
|
||
|
||
widgets = gcal_range_tree_get_all_data (self->events);
|
||
|
||
if (gcal_date_time_compare_date (self->date, gcal_event_get_date_start (event)) == 0)
|
||
{
|
||
self->events_on_date--;
|
||
update_no_events_row (self);
|
||
}
|
||
|
||
for (i = 0; widgets && i < widgets->len; i++)
|
||
{
|
||
ChildData *data;
|
||
GtkWidget *widget;
|
||
GcalEvent *event;
|
||
|
||
data = g_ptr_array_index (widgets, i);
|
||
widget = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (data->widget));
|
||
event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
|
||
|
||
if (g_strcmp0 (gcal_event_get_uid (event), uid) != 0)
|
||
continue;
|
||
|
||
gcal_range_tree_remove_range (self->events, gcal_event_get_range (event), data);
|
||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||
}
|
||
|
||
g_clear_pointer (&widgets, g_ptr_array_unref);
|
||
|
||
gtk_list_box_invalidate_headers (GTK_LIST_BOX (self->list_box));
|
||
|
||
GCAL_EXIT;
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_update_event (GcalTimelineSubscriber *subscriber,
|
||
GcalEvent *old_event,
|
||
GcalEvent *event)
|
||
{
|
||
GCAL_ENTRY;
|
||
|
||
gcal_agenda_view_remove_event (subscriber, old_event);
|
||
gcal_agenda_view_add_event (subscriber, event);
|
||
|
||
GCAL_EXIT;
|
||
}
|
||
|
||
static void
|
||
gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface)
|
||
{
|
||
iface->get_range = gcal_agenda_view_get_range;
|
||
iface->add_event = gcal_agenda_view_add_event;
|
||
iface->update_event = gcal_agenda_view_update_event;
|
||
iface->remove_event = gcal_agenda_view_remove_event;
|
||
}
|
||
|
||
|
||
/*
|
||
* GObject overrides
|
||
*/
|
||
|
||
static void
|
||
gcal_agenda_view_dispose (GObject *object)
|
||
{
|
||
GcalAgendaView *self;
|
||
|
||
self = GCAL_AGENDA_VIEW (object);
|
||
|
||
g_clear_pointer (&self->events, gcal_range_tree_unref);
|
||
|
||
/* Chain up to parent's dispose() method. */
|
||
G_OBJECT_CLASS (gcal_agenda_view_parent_class)->dispose (object);
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_finalize (GObject *object)
|
||
{
|
||
GcalAgendaView *self;
|
||
|
||
self = GCAL_AGENDA_VIEW (object);
|
||
|
||
g_clear_pointer (&self->date, g_date_time_unref);
|
||
|
||
g_clear_object (&self->context);
|
||
|
||
/* Chain up to parent's finalize() method. */
|
||
G_OBJECT_CLASS (gcal_agenda_view_parent_class)->finalize (object);
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_set_property (GObject *object,
|
||
guint property_id,
|
||
const GValue *value,
|
||
GParamSpec *pspec)
|
||
{
|
||
GcalAgendaView *self = (GcalAgendaView *) object;
|
||
|
||
switch (property_id)
|
||
{
|
||
case PROP_DATE:
|
||
gcal_view_set_date (GCAL_VIEW (object), g_value_get_boxed (value));
|
||
break;
|
||
|
||
case PROP_CONTEXT:
|
||
g_assert (self->context == NULL);
|
||
self->context = g_value_dup_object (value);
|
||
break;
|
||
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_get_property (GObject *object,
|
||
guint property_id,
|
||
GValue *value,
|
||
GParamSpec *pspec)
|
||
{
|
||
GcalAgendaView *self;
|
||
|
||
g_return_if_fail (GCAL_IS_AGENDA_VIEW (object));
|
||
self = GCAL_AGENDA_VIEW (object);
|
||
|
||
switch (property_id)
|
||
{
|
||
case PROP_DATE:
|
||
g_value_set_boxed (value, self->date);
|
||
break;
|
||
|
||
case PROP_CONTEXT:
|
||
g_value_set_object (value, self->context);
|
||
break;
|
||
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_class_init (GcalAgendaViewClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||
|
||
object_class->dispose = gcal_agenda_view_dispose;
|
||
object_class->finalize = gcal_agenda_view_finalize;
|
||
object_class->set_property = gcal_agenda_view_set_property;
|
||
object_class->get_property = gcal_agenda_view_get_property;
|
||
|
||
g_object_class_override_property (object_class, PROP_DATE, "active-date");
|
||
g_object_class_override_property (object_class, PROP_CONTEXT, "context");
|
||
|
||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/views/gcal-agenda-view.ui");
|
||
|
||
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, list_box);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, no_events_row);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalAgendaView, scrolled_window);
|
||
|
||
gtk_widget_class_set_css_name (widget_class, "agenda-view");
|
||
}
|
||
|
||
static void
|
||
gcal_agenda_view_init (GcalAgendaView *self)
|
||
{
|
||
gtk_widget_init_template (GTK_WIDGET (self));
|
||
|
||
self->events = gcal_range_tree_new_with_free_func (child_data_free);
|
||
|
||
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->list_box), sort_func, self, NULL);
|
||
gtk_list_box_set_header_func (GTK_LIST_BOX (self->list_box), update_header, self, NULL);
|
||
}
|