There is a fake change notify on timezone when either a corresponding file changes or the setting for "use system timezone" changes, to propagate the change in the code properly. This notify requires proper key identification for GSettings bindings, because without it the binding crashes on a runtime check.
388 lines
11 KiB
C
388 lines
11 KiB
C
/*
|
|
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
|
|
* Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation.
|
|
*
|
|
* 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 Lesser General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <glib/gi18n.h>
|
|
|
|
#include <calendar/gui/e-calendar-view.h>
|
|
#include <calendar/gui/e-cal-ops.h>
|
|
#include <calendar/importers/evolution-calendar-importer.h>
|
|
|
|
#include "e-calendar-preferences.h"
|
|
|
|
#include "e-cal-base-shell-sidebar.h"
|
|
#include "e-cal-shell-content.h"
|
|
#include "e-cal-shell-view.h"
|
|
#include "e-cal-shell-backend.h"
|
|
|
|
#define E_CAL_SHELL_BACKEND_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE \
|
|
((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendPrivate))
|
|
|
|
struct _ECalShellBackendPrivate {
|
|
gint placeholder;
|
|
};
|
|
|
|
G_DEFINE_DYNAMIC_TYPE (ECalShellBackend, e_cal_shell_backend, E_TYPE_CAL_BASE_SHELL_BACKEND)
|
|
|
|
static void
|
|
action_event_new_cb (GtkAction *action,
|
|
EShellWindow *shell_window)
|
|
{
|
|
EShell *shell;
|
|
EShellView *shell_view;
|
|
EShellBackend *shell_backend;
|
|
GSettings *settings;
|
|
const gchar *action_name;
|
|
gboolean is_all_day;
|
|
gboolean is_meeting;
|
|
|
|
shell = e_shell_window_get_shell (shell_window);
|
|
|
|
action_name = gtk_action_get_name (action);
|
|
is_all_day = g_strcmp0 (action_name, "event-all-day-new") == 0;
|
|
is_meeting = g_strcmp0 (action_name, "event-meeting-new") == 0;
|
|
|
|
/* With a 'calendar' active shell view pass the new appointment
|
|
* request to it, thus the event will inherit selected time from
|
|
* the view. */
|
|
shell_view = e_shell_window_peek_shell_view (shell_window, "calendar");
|
|
if (shell_view != NULL) {
|
|
EShellContent *shell_content;
|
|
ECalendarView *view;
|
|
|
|
shell_backend = e_shell_view_get_shell_backend (shell_view);
|
|
shell_content = e_shell_view_get_shell_content (shell_view);
|
|
|
|
e_shell_backend_set_prefer_new_item (shell_backend, action_name);
|
|
|
|
/* This forces the shell window to update the "New" toolbar
|
|
* button menu, and the toolbar button will then update its
|
|
* button image to reflect the "preferred new item" we just
|
|
* set on the shell backend. */
|
|
g_object_notify (G_OBJECT (shell_window), "active-view");
|
|
|
|
view = e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (shell_content));
|
|
if (view != NULL) {
|
|
e_calendar_view_new_appointment_full (view, is_all_day, is_meeting, TRUE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
shell_backend = e_shell_get_backend_by_name (shell, "calendar");
|
|
e_shell_backend_set_prefer_new_item (shell_backend, action_name);
|
|
|
|
settings = e_util_ref_settings ("org.gnome.evolution.calendar");
|
|
|
|
e_cal_ops_new_event_editor (shell_window, NULL, is_meeting, is_all_day,
|
|
g_settings_get_boolean (settings, "use-default-reminder"),
|
|
g_settings_get_int (settings, "default-reminder-interval"),
|
|
g_settings_get_enum (settings, "default-reminder-units"));
|
|
|
|
g_clear_object (&settings);
|
|
}
|
|
|
|
static void
|
|
action_calendar_new_cb (GtkAction *action,
|
|
EShellWindow *shell_window)
|
|
{
|
|
e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
|
|
}
|
|
|
|
static GtkActionEntry item_entries[] = {
|
|
|
|
{ "event-new",
|
|
"appointment-new",
|
|
NC_("New", "_Appointment"),
|
|
"<Shift><Control>a",
|
|
N_("Create a new appointment"),
|
|
G_CALLBACK (action_event_new_cb) },
|
|
|
|
{ "event-all-day-new",
|
|
"stock_new-24h-appointment",
|
|
NC_("New", "All Day A_ppointment"),
|
|
NULL,
|
|
N_("Create a new all-day appointment"),
|
|
G_CALLBACK (action_event_new_cb) },
|
|
|
|
{ "event-meeting-new",
|
|
"stock_new-meeting",
|
|
NC_("New", "M_eeting"),
|
|
"<Shift><Control>e",
|
|
N_("Create a new meeting request"),
|
|
G_CALLBACK (action_event_new_cb) }
|
|
};
|
|
|
|
static GtkActionEntry source_entries[] = {
|
|
|
|
{ "calendar-new",
|
|
"x-office-calendar",
|
|
NC_("New", "Cale_ndar"),
|
|
NULL,
|
|
N_("Create a new calendar"),
|
|
G_CALLBACK (action_calendar_new_cb) }
|
|
};
|
|
|
|
static void
|
|
cal_shell_backend_handle_uri_start_end_dates (EShellBackend *shell_backend,
|
|
const GDate *start_date,
|
|
const GDate *end_date)
|
|
{
|
|
g_return_if_fail (E_IS_CAL_SHELL_BACKEND (shell_backend));
|
|
g_return_if_fail (g_date_valid (start_date));
|
|
|
|
if (g_date_valid (end_date))
|
|
e_cal_shell_backend_open_date_range (E_CAL_SHELL_BACKEND (shell_backend), start_date, end_date);
|
|
else
|
|
e_cal_shell_backend_open_date_range (E_CAL_SHELL_BACKEND (shell_backend), start_date, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
e_cal_shell_backend_handle_uri (EShellBackend *shell_backend,
|
|
const gchar *uri)
|
|
{
|
|
if (strncmp (uri, "calendar:", 9) != 0)
|
|
return FALSE;
|
|
|
|
return e_cal_base_shell_backend_util_handle_uri (shell_backend,
|
|
E_CAL_CLIENT_SOURCE_TYPE_TASKS, uri, cal_shell_backend_handle_uri_start_end_dates);
|
|
}
|
|
|
|
static void
|
|
cal_shell_backend_init_importers (void)
|
|
{
|
|
EImportClass *import_class;
|
|
EImportImporter *importer;
|
|
|
|
import_class = g_type_class_ref (e_import_get_type ());
|
|
|
|
importer = gnome_calendar_importer_peek ();
|
|
e_import_class_add_importer (import_class, importer, NULL, NULL);
|
|
|
|
importer = ical_importer_peek ();
|
|
e_import_class_add_importer (import_class, importer, NULL, NULL);
|
|
|
|
importer = vcal_importer_peek ();
|
|
e_import_class_add_importer (import_class, importer, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
ensure_alarm_notify_is_running (void)
|
|
{
|
|
const gchar *base_dir;
|
|
gchar *filename;
|
|
|
|
#ifdef G_OS_WIN32
|
|
base_dir = EVOLUTION_BINDIR;
|
|
#else
|
|
base_dir = EVOLUTION_PRIVLIBEXECDIR;
|
|
#endif
|
|
|
|
filename = g_build_filename (base_dir, "evolution-alarm-notify", NULL);
|
|
|
|
if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE)) {
|
|
gchar *argv[2];
|
|
GError *error = NULL;
|
|
|
|
argv[0] = filename;
|
|
argv[1] = NULL;
|
|
|
|
g_spawn_async (
|
|
base_dir, argv, NULL, 0, NULL, NULL, NULL, &error);
|
|
|
|
if (error != NULL) {
|
|
g_message (
|
|
"Failed to start '%s': %s",
|
|
filename, error->message);
|
|
g_error_free (error);
|
|
}
|
|
}
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
static void
|
|
cal_shell_backend_use_system_timezone_changed_cb (GSettings *settings,
|
|
const gchar *key)
|
|
{
|
|
/* the '-1' is a trick to emit the change the first time */
|
|
static gint old_value = -1;
|
|
gboolean value;
|
|
|
|
value = g_settings_get_boolean (settings, key);
|
|
|
|
if ((value ? 1 : 0) != old_value) {
|
|
old_value = value ? 1 : 0;
|
|
|
|
/* GSettings Bindings rely on quarks */
|
|
g_signal_emit_by_name (settings, "changed::timezone",
|
|
g_quark_to_string (g_quark_from_string ("timezone")));
|
|
}
|
|
}
|
|
|
|
static void
|
|
cal_shell_backend_constructed (GObject *object)
|
|
{
|
|
EShellBackend *shell_backend;
|
|
GtkWidget *preferences_window;
|
|
GSettings *settings;
|
|
|
|
shell_backend = E_SHELL_BACKEND (object);
|
|
|
|
/* Setup preference widget factories */
|
|
preferences_window = e_shell_get_preferences_window (e_shell_backend_get_shell (shell_backend));
|
|
|
|
e_preferences_window_add_page (
|
|
E_PREFERENCES_WINDOW (preferences_window),
|
|
"calendar-and-tasks",
|
|
"preferences-calendar-and-tasks",
|
|
_("Calendar and Tasks"),
|
|
"index#calendar",
|
|
e_calendar_preferences_new,
|
|
600);
|
|
|
|
settings = e_util_ref_settings ("org.gnome.evolution.calendar");
|
|
|
|
g_settings_bind (
|
|
settings, "prefer-new-item",
|
|
shell_backend, "prefer-new-item",
|
|
G_SETTINGS_BIND_DEFAULT);
|
|
|
|
/* Changing whether or not to use the system timezone may change
|
|
* Evolution's current timezone. Need to emit "changed" signals
|
|
* for both keys. */
|
|
g_signal_connect (
|
|
settings, "changed::use-system-timezone",
|
|
G_CALLBACK (cal_shell_backend_use_system_timezone_changed_cb),
|
|
NULL);
|
|
|
|
g_object_unref (settings);
|
|
|
|
/* Chain up to parent's constructed() method. */
|
|
G_OBJECT_CLASS (e_cal_shell_backend_parent_class)->constructed (object);
|
|
|
|
cal_shell_backend_init_importers ();
|
|
|
|
ensure_alarm_notify_is_running ();
|
|
}
|
|
|
|
static void
|
|
e_cal_shell_backend_class_init (ECalShellBackendClass *class)
|
|
{
|
|
GObjectClass *object_class;
|
|
EShellBackendClass *shell_backend_class;
|
|
ECalBaseShellBackendClass *cal_base_shell_backend_class;
|
|
|
|
g_type_class_add_private (class, sizeof (ECalShellBackendPrivate));
|
|
|
|
object_class = G_OBJECT_CLASS (class);
|
|
object_class->constructed = cal_shell_backend_constructed;
|
|
|
|
shell_backend_class = E_SHELL_BACKEND_CLASS (class);
|
|
shell_backend_class->shell_view_type = E_TYPE_CAL_SHELL_VIEW;
|
|
shell_backend_class->name = "calendar";
|
|
shell_backend_class->aliases = "";
|
|
shell_backend_class->schemes = "calendar";
|
|
shell_backend_class->sort_order = 400;
|
|
shell_backend_class->preferences_page = "calendar-and-tasks";
|
|
shell_backend_class->start = NULL;
|
|
|
|
cal_base_shell_backend_class = E_CAL_BASE_SHELL_BACKEND_CLASS (class);
|
|
cal_base_shell_backend_class->new_item_entries = item_entries;
|
|
cal_base_shell_backend_class->new_item_n_entries = G_N_ELEMENTS (item_entries);
|
|
cal_base_shell_backend_class->source_entries = source_entries;
|
|
cal_base_shell_backend_class->source_n_entries = G_N_ELEMENTS (source_entries);
|
|
cal_base_shell_backend_class->handle_uri = e_cal_shell_backend_handle_uri;
|
|
}
|
|
|
|
static void
|
|
e_cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
|
|
{
|
|
cal_shell_backend->priv = E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
|
|
}
|
|
|
|
static void
|
|
e_cal_shell_backend_class_finalize (ECalShellBackendClass *class)
|
|
{
|
|
}
|
|
|
|
void
|
|
e_cal_shell_backend_type_register (GTypeModule *type_module)
|
|
{
|
|
/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
|
|
* function, so we have to wrap it with a public function in
|
|
* order to register types from a separate compilation unit. */
|
|
e_cal_shell_backend_register_type (type_module);
|
|
}
|
|
|
|
void
|
|
e_cal_shell_backend_open_date_range (ECalShellBackend *cal_shell_backend,
|
|
const GDate *start_date,
|
|
const GDate *end_date)
|
|
{
|
|
EShell *shell;
|
|
EShellView *shell_view;
|
|
EShellBackend *shell_backend;
|
|
EShellSidebar *shell_sidebar;
|
|
GtkWidget *shell_window = NULL;
|
|
GtkApplication *application;
|
|
ECalendar *calendar;
|
|
GList *list;
|
|
|
|
g_return_if_fail (E_IS_CAL_SHELL_BACKEND (cal_shell_backend));
|
|
|
|
shell_backend = E_SHELL_BACKEND (cal_shell_backend);
|
|
shell = e_shell_backend_get_shell (shell_backend);
|
|
|
|
application = GTK_APPLICATION (shell);
|
|
list = gtk_application_get_windows (application);
|
|
|
|
/* Try to find an EShellWindow already in calendar view. */
|
|
while (list != NULL) {
|
|
GtkWidget *window = GTK_WIDGET (list->data);
|
|
|
|
if (E_IS_SHELL_WINDOW (window)) {
|
|
const gchar *active_view;
|
|
|
|
active_view = e_shell_window_get_active_view (E_SHELL_WINDOW (window));
|
|
if (g_strcmp0 (active_view, "calendar") == 0) {
|
|
gtk_window_present (GTK_WINDOW (window));
|
|
shell_window = window;
|
|
break;
|
|
}
|
|
}
|
|
|
|
list = g_list_next (list);
|
|
}
|
|
|
|
/* Otherwise create a new EShellWindow in calendar view. */
|
|
if (shell_window == NULL)
|
|
shell_window = e_shell_create_shell_window (shell, "calendar");
|
|
|
|
/* Now dig up the date navigator and select the date range. */
|
|
|
|
shell_view = e_shell_window_get_shell_view (E_SHELL_WINDOW (shell_window), "calendar");
|
|
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
|
|
calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
|
|
|
|
e_calendar_item_set_selection (calendar->calitem, start_date, end_date);
|
|
}
|