822 lines
25 KiB
C
822 lines
25 KiB
C
/* gcal-event-popover.c
|
||
*
|
||
* Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||
*
|
||
* 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/>.
|
||
*
|
||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||
*/
|
||
|
||
#define G_LOG_DOMAIN "GcalEventPopover"
|
||
|
||
#include "gcal-calendar.h"
|
||
#include "gcal-debug.h"
|
||
#include "gcal-event-popover.h"
|
||
#include "gcal-meeting-row.h"
|
||
#include "gcal-utils.h"
|
||
|
||
#include <glib/gi18n.h>
|
||
|
||
struct _GcalEventPopover
|
||
{
|
||
GtkPopover parent;
|
||
|
||
GtkWidget *action_button;
|
||
GtkLabel *date_time_label;
|
||
GtkLabel *description_label;
|
||
GtkScrolledWindow *description_scrolled_window;
|
||
GtkWidget *location_box;
|
||
GtkLabel *location_label;
|
||
GtkListBox *meetings_listbox;
|
||
GtkBox *meetings_box;
|
||
GtkLabel *placeholder_label;
|
||
GtkLabel *summary_label;
|
||
GtkImage *read_only_icon;
|
||
|
||
GcalEvent *event;
|
||
};
|
||
|
||
static void on_join_meeting_cb (GcalMeetingRow *meeting_row,
|
||
const gchar *url,
|
||
GcalEventPopover *self);
|
||
|
||
G_DEFINE_TYPE (GcalEventPopover, gcal_event_popover, GTK_TYPE_POPOVER)
|
||
|
||
enum
|
||
{
|
||
PROP_0,
|
||
PROP_EVENT,
|
||
N_PROPS
|
||
};
|
||
|
||
enum
|
||
{
|
||
EDIT,
|
||
NUM_SIGNALS
|
||
};
|
||
|
||
static guint signals[NUM_SIGNALS] = { 0, };
|
||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||
|
||
|
||
/*
|
||
* Auxiliary methods
|
||
*/
|
||
|
||
static gint
|
||
get_number_of_days_from_today (GDateTime *now,
|
||
GDateTime *day)
|
||
{
|
||
GDate event_day;
|
||
GDate today;
|
||
|
||
g_date_set_dmy (&today,
|
||
g_date_time_get_day_of_month (now),
|
||
g_date_time_get_month (now),
|
||
g_date_time_get_year (now));
|
||
|
||
g_date_set_dmy (&event_day,
|
||
g_date_time_get_day_of_month (day),
|
||
g_date_time_get_month (day),
|
||
g_date_time_get_year (day));
|
||
|
||
return g_date_days_between (&today, &event_day);
|
||
}
|
||
|
||
static gchar*
|
||
format_time (GcalEventPopover *self,
|
||
GDateTime *date)
|
||
{
|
||
GcalContext *context = gcal_application_get_context (GCAL_DEFAULT_APPLICATION);
|
||
GcalTimeFormat time_format;
|
||
|
||
time_format = gcal_context_get_time_format (context);
|
||
|
||
switch (time_format)
|
||
{
|
||
case GCAL_TIME_FORMAT_12H:
|
||
return g_date_time_format (date, "%I:%M %P");
|
||
|
||
case GCAL_TIME_FORMAT_24H:
|
||
return g_date_time_format (date, "%R");
|
||
|
||
default:
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static const gchar*
|
||
get_month_name (gint month)
|
||
{
|
||
const gchar *month_names[] = {
|
||
N_("January"),
|
||
N_("February"),
|
||
N_("March"),
|
||
N_("April"),
|
||
N_("May"),
|
||
N_("June"),
|
||
N_("July"),
|
||
N_("August"),
|
||
N_("September"),
|
||
N_("October"),
|
||
N_("November"),
|
||
N_("December"),
|
||
NULL
|
||
};
|
||
|
||
return gettext (month_names[month]);
|
||
}
|
||
|
||
static gchar*
|
||
format_multiday_date (GcalEventPopover *self,
|
||
GDateTime *dt,
|
||
gboolean force_show_year,
|
||
gboolean show_time)
|
||
{
|
||
g_autoptr (GDateTime) now = NULL;
|
||
gint n_days_from_dt;
|
||
|
||
now = g_date_time_new_now_local ();
|
||
n_days_from_dt = get_number_of_days_from_today (now, dt);
|
||
|
||
if (show_time)
|
||
{
|
||
g_autofree gchar *hours = format_time (self, dt);
|
||
|
||
if (n_days_from_dt == 0)
|
||
{
|
||
return g_strdup_printf (_("Today %s"), hours);
|
||
}
|
||
else if (n_days_from_dt == 1)
|
||
{
|
||
return g_strdup_printf (_("Tomorrow %s"), hours);
|
||
}
|
||
else if (n_days_from_dt == -1)
|
||
{
|
||
return g_strdup_printf (_("Yesterday %s"), hours);
|
||
}
|
||
else if (!force_show_year && g_date_time_get_year (now) == g_date_time_get_year (dt))
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), %2$d is the day
|
||
* of month, and %3$ is the hour. This format string results in dates
|
||
* like "November 21, 22:00".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d, %3$s"),
|
||
get_month_name (g_date_time_get_month (dt) - 1),
|
||
g_date_time_get_day_of_month (dt),
|
||
hours);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), %2$d is the day
|
||
* of month, %3$d is the year, and %4$s is the hour. This format string
|
||
* results in dates like "November 21, 2020, 22:00".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d, %3$d, %4$s"),
|
||
get_month_name (g_date_time_get_month (dt) - 1),
|
||
g_date_time_get_day_of_month (dt),
|
||
g_date_time_get_year (dt),
|
||
hours);
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
if (n_days_from_dt == 0)
|
||
{
|
||
return g_strdup (_("Today"));
|
||
}
|
||
else if (n_days_from_dt == 1)
|
||
{
|
||
return g_strdup (_("Tomorrow"));
|
||
}
|
||
else if (n_days_from_dt == -1)
|
||
{
|
||
return g_strdup (_("Yesterday"));
|
||
}
|
||
else if (!force_show_year && g_date_time_get_year (now) == g_date_time_get_year (dt))
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), and %2$d is
|
||
* the day of month. This format string results in dates like
|
||
* "November 21".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d"),
|
||
get_month_name (g_date_time_get_month (dt) - 1),
|
||
g_date_time_get_day_of_month (dt));
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), %2$d is the day
|
||
* of month, and %3$d is the year. This format string results in dates
|
||
* like "November 21, 2020".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d, %3$d"),
|
||
get_month_name (g_date_time_get_month (dt) - 1),
|
||
g_date_time_get_day_of_month (dt),
|
||
g_date_time_get_year (dt));
|
||
}
|
||
|
||
}
|
||
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
static gchar*
|
||
format_single_day (GcalEventPopover *self,
|
||
GDateTime *start_dt,
|
||
GDateTime *end_dt,
|
||
gboolean show_time)
|
||
{
|
||
g_autoptr (GDateTime) now = NULL;
|
||
gint n_days_from_dt;
|
||
|
||
now = g_date_time_new_now_local ();
|
||
n_days_from_dt = get_number_of_days_from_today (now, start_dt);
|
||
|
||
if (show_time)
|
||
{
|
||
g_autofree gchar *start_hours = format_time (self, start_dt);
|
||
g_autofree gchar *end_hours = format_time (self, end_dt);
|
||
|
||
if (n_days_from_dt == 0)
|
||
{
|
||
/*
|
||
* Translators: %1$s is the start hour, and %2$s is the end hour, for
|
||
* example: "Today, 19:00 – 22:00"
|
||
*/
|
||
return g_strdup_printf (_("Today, %1$s – %2$s"), start_hours, end_hours);
|
||
}
|
||
else if (n_days_from_dt == 1)
|
||
{
|
||
/*
|
||
* Translators: %1$s is the start hour, and %2$s is the end hour, for
|
||
* example: "Tomorrow, 19:00 – 22:00"
|
||
*/
|
||
return g_strdup_printf (_("Tomorrow, %1$s – %2$s"), start_hours, end_hours);
|
||
}
|
||
else if (n_days_from_dt == -1)
|
||
{
|
||
/*
|
||
* Translators: %1$s is the start hour, and %2$s is the end hour, for
|
||
* example: "Tomorrow, 19:00 – 22:00"
|
||
*/
|
||
return g_strdup_printf (_("Yesterday, %1$s – %2$s"), start_hours, end_hours);
|
||
}
|
||
else if (g_date_time_get_year (now) == g_date_time_get_year (start_dt))
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), %2$d is the day
|
||
* of month, %3$s is the start hour, and %4$s is the end hour. This
|
||
* format string results in dates like "November 21, 19:00 – 22:00".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d, %3$s – %4$s"),
|
||
get_month_name (g_date_time_get_month (start_dt) - 1),
|
||
g_date_time_get_day_of_month (start_dt),
|
||
start_hours,
|
||
end_hours);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), %2$d is the day
|
||
* of month, %3$d is the year, %4$s is the start hour, and %5$s is the
|
||
* end hour. This format string results in dates like:
|
||
*
|
||
* "November 21, 2021, 19:00 – 22:00".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d, %3$d, %4$s – %5$s"),
|
||
get_month_name (g_date_time_get_month (start_dt) - 1),
|
||
g_date_time_get_day_of_month (start_dt),
|
||
g_date_time_get_year (start_dt),
|
||
start_hours,
|
||
end_hours);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (n_days_from_dt == 0)
|
||
{
|
||
return g_strdup (_("Today"));
|
||
}
|
||
else if (n_days_from_dt == 1)
|
||
{
|
||
return g_strdup (_("Tomorrow"));
|
||
}
|
||
else if (n_days_from_dt == -1)
|
||
{
|
||
return g_strdup (_("Yesterday"));
|
||
}
|
||
else if (g_date_time_get_year (now) == g_date_time_get_year (start_dt))
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), and %2$d is
|
||
* the day of month. This format string results in dates like
|
||
* "November 21".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d"),
|
||
get_month_name (g_date_time_get_month (start_dt) - 1),
|
||
g_date_time_get_day_of_month (start_dt));
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Translators: %1$s is a month name (e.g. November), %2$d is the day
|
||
* of month, and %3$d is the year. This format string results in dates
|
||
* like "November 21, 2020".
|
||
*/
|
||
return g_strdup_printf (_("%1$s %2$d, %3$d"),
|
||
get_month_name (g_date_time_get_month (start_dt) - 1),
|
||
g_date_time_get_day_of_month (start_dt),
|
||
g_date_time_get_year (start_dt));
|
||
}
|
||
}
|
||
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
static void
|
||
update_decorations (GcalEventPopover *self,
|
||
GcalEvent *event)
|
||
{
|
||
GcalCalendar *calendar;
|
||
gboolean calendar_is_read_only;
|
||
|
||
calendar = gcal_event_get_calendar (event);
|
||
calendar_is_read_only = gcal_calendar_is_read_only (calendar);
|
||
|
||
gtk_widget_set_visible (GTK_WIDGET (self->read_only_icon), calendar_is_read_only);
|
||
|
||
if (calendar_is_read_only)
|
||
{
|
||
gtk_button_set_icon_name (GTK_BUTTON (self->action_button), "info-outline-symbolic");
|
||
gtk_widget_set_tooltip_text (self->action_button, _("View Additional Details"));
|
||
}
|
||
else
|
||
{
|
||
gtk_button_set_icon_name (GTK_BUTTON (self->action_button), "edit-symbolic");
|
||
gtk_widget_set_tooltip_text (self->action_button, _("Edit Additional Details"));
|
||
}
|
||
}
|
||
|
||
static void
|
||
update_date_time_label (GcalEventPopover *self)
|
||
{
|
||
g_autoptr (GDateTime) start_dt = NULL;
|
||
g_autoptr (GDateTime) end_dt = NULL;
|
||
g_autoptr (GString) string = NULL;
|
||
gboolean show_hours;
|
||
gboolean multiday;
|
||
gboolean all_day;
|
||
|
||
string = g_string_new ("");
|
||
all_day = gcal_event_get_all_day (self->event);
|
||
multiday = gcal_event_is_multiday (self->event);
|
||
show_hours = !all_day;
|
||
|
||
if (all_day)
|
||
{
|
||
start_dt = g_date_time_ref (gcal_event_get_date_start (self->event));
|
||
end_dt = g_date_time_ref (gcal_event_get_date_end (self->event));
|
||
}
|
||
else
|
||
{
|
||
start_dt = g_date_time_to_local (gcal_event_get_date_start (self->event));
|
||
end_dt = g_date_time_to_local (gcal_event_get_date_end (self->event));
|
||
}
|
||
|
||
if (multiday)
|
||
{
|
||
g_autofree gchar *start_str = NULL;
|
||
g_autofree gchar *end_str = NULL;
|
||
gboolean show_year;
|
||
g_autoptr (GDateTime) real_end_dt = NULL;
|
||
|
||
show_year = g_date_time_get_year (start_dt) != g_date_time_get_year (end_dt);
|
||
start_str = format_multiday_date (self, start_dt, show_year, show_hours);
|
||
|
||
if (!show_hours)
|
||
real_end_dt = g_date_time_add_days (end_dt, -1);
|
||
else
|
||
real_end_dt = g_date_time_ref (end_dt);
|
||
|
||
end_str = format_multiday_date (self, real_end_dt, show_year, show_hours);
|
||
|
||
/* Translators: %1$s is the start date, and %2$s. For example: June 21 – November 29, 2022 */
|
||
g_string_printf (string, _("%1$s – %2$s"), start_str, end_str);
|
||
|
||
}
|
||
else
|
||
{
|
||
g_autofree gchar *str = format_single_day (self, start_dt, end_dt, show_hours);
|
||
g_string_append (string, str);
|
||
}
|
||
|
||
gtk_label_set_label (self->date_time_label, string->str);
|
||
}
|
||
|
||
static void
|
||
update_placeholder_label (GcalEventPopover *self)
|
||
{
|
||
gtk_widget_set_visible (GTK_WIDGET (self->placeholder_label),
|
||
!gtk_widget_get_visible (GTK_WIDGET (self->description_scrolled_window)));
|
||
}
|
||
|
||
static void
|
||
add_meeting (GcalEventPopover *self,
|
||
const gchar *url)
|
||
{
|
||
GtkWidget *row;
|
||
|
||
row = gcal_meeting_row_new (url);
|
||
g_signal_connect (row, "join-meeting", G_CALLBACK (on_join_meeting_cb), self);
|
||
gtk_list_box_append (self->meetings_listbox, row);
|
||
|
||
gtk_widget_set_visible (GTK_WIDGET (self->meetings_box), TRUE);
|
||
}
|
||
|
||
static void
|
||
setup_location_label (GcalEventPopover *self)
|
||
{
|
||
g_autoptr (GUri) guri = NULL;
|
||
g_autofree gchar *location = NULL;
|
||
|
||
location = g_strdup (gcal_event_get_location (self->event));
|
||
g_strstrip (location);
|
||
|
||
guri = g_uri_parse (location, SOUP_HTTP_URI_FLAGS | G_URI_FLAGS_PARSE_RELAXED, NULL);
|
||
if (guri)
|
||
{
|
||
GString *string;
|
||
|
||
string = g_string_new (NULL);
|
||
g_string_append (string, "<a href=\"");
|
||
g_string_append (string, location);
|
||
g_string_append (string, "\">");
|
||
g_string_append (string, location);
|
||
g_string_append (string, "</a>");
|
||
|
||
add_meeting (self, location);
|
||
|
||
g_clear_pointer (&location, g_free);
|
||
location = g_string_free (string, FALSE);
|
||
}
|
||
|
||
gtk_widget_set_visible (self->location_box,
|
||
location && g_utf8_strlen (location, -1) > 0 &&
|
||
!gtk_widget_get_visible (GTK_WIDGET (self->meetings_box)));
|
||
gtk_label_set_markup (self->location_label, location);
|
||
}
|
||
|
||
static void
|
||
setup_description_label (GcalEventPopover *self)
|
||
{
|
||
g_autofree gchar *description = NULL;
|
||
g_autofree gchar *meeting_url = NULL;
|
||
g_autoptr (GString) string = NULL;
|
||
|
||
gcal_util_extract_meeting_url (gcal_event_get_description (self->event), &description, &meeting_url);
|
||
|
||
g_strstrip (description);
|
||
|
||
if (meeting_url)
|
||
add_meeting (self, meeting_url);
|
||
|
||
string = g_string_new (description);
|
||
g_string_replace (string, "<br>", "\n", 0);
|
||
g_string_replace (string, " ", " ", 0);
|
||
|
||
gtk_label_set_markup (self->description_label, string->str);
|
||
gtk_widget_set_visible (GTK_WIDGET (self->description_scrolled_window), string->str && *string->str);
|
||
}
|
||
|
||
static void
|
||
set_event_internal (GcalEventPopover *self,
|
||
GcalEvent *event)
|
||
{
|
||
g_set_object (&self->event, event);
|
||
|
||
gtk_label_set_label (self->summary_label, gcal_event_get_summary (event));
|
||
|
||
setup_description_label (self);
|
||
setup_location_label (self);
|
||
update_placeholder_label (self);
|
||
update_date_time_label (self);
|
||
update_decorations (self, event);
|
||
|
||
gtk_widget_grab_focus (self->action_button);
|
||
}
|
||
|
||
|
||
/*
|
||
* Callbacks
|
||
*/
|
||
|
||
static void
|
||
on_action_button_clicked_cb (GtkButton *action_button,
|
||
GcalEventPopover *self)
|
||
{
|
||
g_signal_emit (self, signals[EDIT], 0);
|
||
gtk_popover_popdown (GTK_POPOVER (self));
|
||
}
|
||
|
||
static void
|
||
on_file_dialog_save_cb (GObject *object,
|
||
GAsyncResult *res,
|
||
gpointer user_data)
|
||
{
|
||
g_autoptr (GcalEventPopover) self = user_data;
|
||
g_autofree gchar* contents = NULL;
|
||
g_autoptr (GError) error = NULL;
|
||
g_autoptr (GFile) file = NULL;
|
||
ECalComponent *component = NULL;
|
||
ICalComponent *icalcomp = NULL;
|
||
GcalCalendar *calendar = NULL;
|
||
ECalClient *client = NULL;
|
||
|
||
file = gtk_file_dialog_save_finish (GTK_FILE_DIALOG (object), res, &error);
|
||
if (error)
|
||
{
|
||
if (!g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED))
|
||
g_warning ("Error saving file: %s", error->message);
|
||
return;
|
||
}
|
||
|
||
component = gcal_event_get_component (self->event);
|
||
icalcomp = e_cal_component_get_icalcomponent (component);
|
||
calendar = gcal_event_get_calendar (self->event);
|
||
client = gcal_calendar_get_client (calendar);
|
||
contents = e_cal_client_get_component_as_string (client, icalcomp);
|
||
|
||
g_file_replace_contents (file,
|
||
contents,
|
||
strlen (contents),
|
||
NULL,
|
||
FALSE,
|
||
G_FILE_CREATE_REPLACE_DESTINATION,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
}
|
||
|
||
|
||
static void
|
||
on_ics_export_button_clicked_cb (GtkButton *button,
|
||
GcalEventPopover *self)
|
||
{
|
||
g_autofree gchar *filename = NULL;
|
||
GtkFileDialog *file_dialog = NULL;
|
||
GtkWindow *window = NULL;
|
||
|
||
window = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
|
||
file_dialog = gtk_file_dialog_new ();
|
||
filename = g_strconcat (gcal_event_get_summary (self->event), ".ics", NULL);
|
||
|
||
gtk_file_dialog_set_title (file_dialog, _("Export Event"));
|
||
gtk_file_dialog_set_initial_name (file_dialog, filename);
|
||
|
||
/*
|
||
* We need to close the popover before showing the dialog, as otherwise the
|
||
* popover will continue to capture the first click (i.e. first click will
|
||
* appear unresponsive as it closes the popover)
|
||
*/
|
||
gtk_popover_popdown (GTK_POPOVER (self));
|
||
|
||
gtk_file_dialog_save (file_dialog,
|
||
window,
|
||
NULL,
|
||
on_file_dialog_save_cb,
|
||
g_object_ref (self));
|
||
}
|
||
|
||
static void
|
||
on_uri_launched_cb (GObject *source_object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
g_autoptr (GcalEventPopover) self = user_data;
|
||
g_autoptr (GError) error = NULL;
|
||
|
||
if (!gtk_uri_launcher_launch_finish (GTK_URI_LAUNCHER (source_object), result, &error))
|
||
{
|
||
g_warning ("Error launching URI: %s", error->message);
|
||
return;
|
||
}
|
||
|
||
gtk_popover_popdown (GTK_POPOVER (self));
|
||
}
|
||
|
||
static void
|
||
on_join_meeting_cb (GcalMeetingRow *meeting_row,
|
||
const gchar *url,
|
||
GcalEventPopover *self)
|
||
{
|
||
g_autoptr (GtkUriLauncher) uri_launcher = NULL;
|
||
GtkWindow *window;
|
||
|
||
window = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
|
||
g_assert (window != NULL);
|
||
|
||
uri_launcher = gtk_uri_launcher_new (url);
|
||
gtk_uri_launcher_launch (uri_launcher,
|
||
window,
|
||
NULL,
|
||
on_uri_launched_cb,
|
||
g_object_ref (self));
|
||
}
|
||
|
||
static void
|
||
on_map_button_clicked_cb (GtkButton *action_button,
|
||
GcalEventPopover *self)
|
||
{
|
||
g_autoptr (GtkUriLauncher) uri_launcher = NULL;
|
||
g_autofree gchar *location = NULL;
|
||
g_autofree gchar *uri = NULL;
|
||
GtkWindow *window;
|
||
|
||
window = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
|
||
g_assert (window != NULL);
|
||
|
||
location = g_strdup (gcal_event_get_location (self->event));
|
||
g_strstrip (location);
|
||
|
||
uri = g_strconcat ("maps:q=", location, NULL);
|
||
g_assert (g_uri_is_valid (uri, G_URI_FLAGS_NONE, NULL));
|
||
uri_launcher = gtk_uri_launcher_new (uri);
|
||
gtk_uri_launcher_launch (uri_launcher,
|
||
window,
|
||
NULL,
|
||
on_uri_launched_cb,
|
||
g_object_ref (self));
|
||
}
|
||
|
||
static void
|
||
on_time_format_changed_cb (GcalEventPopover *self)
|
||
{
|
||
GCAL_ENTRY;
|
||
|
||
update_date_time_label (self);
|
||
|
||
GCAL_EXIT;
|
||
}
|
||
|
||
|
||
/*
|
||
* GtkWidget overrides
|
||
*/
|
||
|
||
static void
|
||
gcal_event_popover_map (GtkWidget *widget)
|
||
{
|
||
GcalEventPopover *self = (GcalEventPopover *) widget;
|
||
|
||
GTK_WIDGET_CLASS (gcal_event_popover_parent_class)->map (widget);
|
||
|
||
gtk_widget_grab_focus (self->action_button);
|
||
}
|
||
|
||
|
||
/*
|
||
* GObject overrides
|
||
*/
|
||
|
||
static void
|
||
gcal_event_popover_finalize (GObject *object)
|
||
{
|
||
GcalEventPopover *self = (GcalEventPopover *)object;
|
||
|
||
g_clear_object (&self->event);
|
||
|
||
G_OBJECT_CLASS (gcal_event_popover_parent_class)->finalize (object);
|
||
}
|
||
|
||
static void
|
||
gcal_event_popover_get_property (GObject *object,
|
||
guint prop_id,
|
||
GValue *value,
|
||
GParamSpec *pspec)
|
||
{
|
||
GcalEventPopover *self = GCAL_EVENT_POPOVER (object);
|
||
|
||
switch (prop_id)
|
||
{
|
||
case PROP_EVENT:
|
||
g_value_set_object (value, self->event);
|
||
break;
|
||
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
}
|
||
}
|
||
|
||
static void
|
||
gcal_event_popover_set_property (GObject *object,
|
||
guint prop_id,
|
||
const GValue *value,
|
||
GParamSpec *pspec)
|
||
{
|
||
GcalEventPopover *self = GCAL_EVENT_POPOVER (object);
|
||
|
||
switch (prop_id)
|
||
{
|
||
case PROP_EVENT:
|
||
g_assert (self->event == NULL);
|
||
set_event_internal (self, g_value_get_object (value));
|
||
break;
|
||
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
}
|
||
}
|
||
|
||
static void
|
||
gcal_event_popover_class_init (GcalEventPopoverClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||
|
||
object_class->finalize = gcal_event_popover_finalize;
|
||
object_class->get_property = gcal_event_popover_get_property;
|
||
object_class->set_property = gcal_event_popover_set_property;
|
||
|
||
widget_class->map = gcal_event_popover_map;
|
||
|
||
/**
|
||
* GcalEventPopover::event:
|
||
*
|
||
* The event this popover represents.
|
||
*/
|
||
properties[PROP_EVENT] = g_param_spec_object ("event",
|
||
"Event",
|
||
"The event this popover represents",
|
||
GCAL_TYPE_EVENT,
|
||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||
|
||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||
|
||
signals[EDIT] = g_signal_new ("edit",
|
||
GCAL_TYPE_EVENT_POPOVER,
|
||
G_SIGNAL_RUN_LAST,
|
||
0,
|
||
NULL, NULL,
|
||
g_cclosure_marshal_VOID__VOID,
|
||
G_TYPE_NONE,
|
||
0);
|
||
|
||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/gcal-event-popover.ui");
|
||
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, date_time_label);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, description_label);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, description_scrolled_window);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, action_button);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, location_box);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, location_label);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, meetings_box);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, meetings_listbox);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, placeholder_label);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, summary_label);
|
||
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, read_only_icon);
|
||
|
||
gtk_widget_class_bind_template_callback (widget_class, on_action_button_clicked_cb);
|
||
gtk_widget_class_bind_template_callback (widget_class, on_ics_export_button_clicked_cb);
|
||
gtk_widget_class_bind_template_callback (widget_class, on_map_button_clicked_cb);
|
||
}
|
||
|
||
static void
|
||
gcal_event_popover_init (GcalEventPopover *self)
|
||
{
|
||
GcalContext *context = gcal_application_get_context (GCAL_DEFAULT_APPLICATION);
|
||
|
||
gtk_widget_init_template (GTK_WIDGET (self));
|
||
|
||
g_signal_connect_object (context,
|
||
"notify::time-format",
|
||
G_CALLBACK (on_time_format_changed_cb),
|
||
self,
|
||
G_CONNECT_SWAPPED);
|
||
}
|
||
|
||
GtkWidget*
|
||
gcal_event_popover_new (GcalEvent *event)
|
||
{
|
||
return g_object_new (GCAL_TYPE_EVENT_POPOVER,
|
||
"event", event,
|
||
NULL);
|
||
}
|