/*
* Copyright (C) 2015 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 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 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 .
*
*/
#include "evolution-config.h"
#include
#include
#include
#include
#include
#include
#include "comp-util.h"
#include "e-comp-editor.h"
#include "e-comp-editor-page.h"
#include "e-comp-editor-property-parts.h"
#include "e-meeting-list-view.h"
#include "itip-utils.h"
#include "e-comp-editor-page-general.h"
#define BACKEND_EMAIL_ID "backend-email-id"
struct _ECompEditorPageGeneralPrivate {
GtkWidget *source_label;
GtkWidget *source_combo_box;
GtkWidget *organizer_label;
GtkWidget *organizer_combo_box;
GtkWidget *organizer_hbox;
GtkWidget *attendees_button;
GtkWidget *attendees_hbox;
GtkWidget *attendees_list_view;
GtkWidget *attendees_button_box;
GtkWidget *attendees_button_add;
GtkWidget *attendees_button_edit;
GtkWidget *attendees_button_remove;
ECompEditorPropertyPart *comp_color;
gulong comp_color_changed_handler_id;
GtkWidget *source_and_color_hbox; /* has together source_combo_box and comp_color::edit_widget */
gint data_column_width;
gchar *source_label_text;
gchar *source_extension_name;
ESource *select_source;
gboolean show_attendees;
EMeetingStore *meeting_store;
GSList *orig_attendees; /* gchar *mail_addresses */
gchar *user_delegator;
};
enum {
PROP_0,
PROP_DATA_COLUMN_WIDTH,
PROP_SOURCE_LABEL,
PROP_SOURCE_EXTENSION_NAME,
PROP_SELECTED_SOURCE,
PROP_SHOW_ATTENDEES
};
G_DEFINE_TYPE (ECompEditorPageGeneral, e_comp_editor_page_general, E_TYPE_COMP_EDITOR_PAGE)
static void ecep_general_sensitize_widgets (ECompEditorPage *page,
gboolean force_insensitive);
static void
ecep_general_set_column_visible (ECompEditorPageGeneral *page_general,
EMeetingStoreColumns column,
gboolean visible)
{
EMeetingListView *meeting_list_view;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
meeting_list_view = E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view);
e_meeting_list_view_column_set_visible (meeting_list_view, column, visible);
}
static void
action_view_role_cb (GtkToggleAction *action,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
ecep_general_set_column_visible (page_general, E_MEETING_STORE_ROLE_COL,
gtk_toggle_action_get_active (action));
}
static void
action_view_rsvp_cb (GtkToggleAction *action,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
ecep_general_set_column_visible (page_general, E_MEETING_STORE_RSVP_COL,
gtk_toggle_action_get_active (action));
}
static void
action_view_status_cb (GtkToggleAction *action,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
ecep_general_set_column_visible (page_general, E_MEETING_STORE_STATUS_COL,
gtk_toggle_action_get_active (action));
}
static void
action_view_type_cb (GtkToggleAction *action,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
ecep_general_set_column_visible (page_general, E_MEETING_STORE_TYPE_COL,
gtk_toggle_action_get_active (action));
}
static void
ecep_general_fill_organizer_combo_box (ECompEditorPageGeneral *page_general)
{
GtkComboBoxText *combo_box_text;
ECompEditor *comp_editor;
EShell *shell;
ESourceRegistry *registry;
gchar **address_strings;
gint ii;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box));
combo_box_text = GTK_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
shell = e_comp_editor_get_shell (comp_editor);
registry = e_shell_get_registry (shell);
address_strings = itip_get_user_identities (registry);
for (ii = 0; address_strings && address_strings[ii]; ii++) {
gtk_combo_box_text_append_text (combo_box_text, address_strings[ii]);
}
gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box_text), 0);
g_strfreev (address_strings);
g_clear_object (&comp_editor);
}
static void
ecep_general_source_combo_box_changed_cb (ESourceComboBox *source_combo_box,
ECompEditorPageGeneral *page_general)
{
ESource *source;
g_return_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box));
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
source = e_source_combo_box_ref_active (source_combo_box);
e_comp_editor_page_general_set_selected_source (page_general, source);
g_clear_object (&source);
}
static void
ecep_general_attendees_clicked_cb (GtkWidget *widget,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
e_meeting_list_view_invite_others_dialog (E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view));
}
static void
ecep_general_attendees_add_clicked_cb (GtkButton *button,
ECompEditorPageGeneral *page_general)
{
ECompEditor *comp_editor;
EMeetingAttendee *attendee;
guint32 flags;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
flags = e_comp_editor_get_flags (comp_editor);
attendee = e_meeting_store_add_attendee_with_defaults (page_general->priv->meeting_store);
if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0) {
gchar *mailto;
mailto = g_strdup_printf ("mailto:%s",
page_general->priv->user_delegator ? page_general->priv->user_delegator : "");
e_meeting_attendee_set_delfrom (attendee, mailto);
g_free (mailto);
}
e_meeting_list_view_edit (E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view), attendee);
g_clear_object (&comp_editor);
}
static void
ecep_general_attendees_edit_clicked_cb (GtkButton *button,
ECompEditorPageGeneral *page_general)
{
GtkTreeView *tree_view;
GtkTreePath *path = NULL;
GtkTreeViewColumn *focus_col;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
tree_view = GTK_TREE_VIEW (page_general->priv->attendees_list_view);
gtk_tree_view_get_cursor (tree_view, &path, NULL);
g_return_if_fail (path != NULL);
gtk_tree_view_get_cursor (tree_view, &path, &focus_col);
gtk_tree_view_set_cursor (tree_view, path, focus_col, TRUE);
gtk_tree_path_free (path);
}
static void
ecep_general_remove_attendee (ECompEditorPageGeneral *page_general,
EMeetingAttendee *attendee)
{
ECompEditor *comp_editor;
gint pos = 0;
/* If this was a delegatee, no longer delegate */
if (e_meeting_attendee_is_set_delfrom (attendee)) {
EMeetingAttendee *ib;
ib = e_meeting_store_find_attendee (page_general->priv->meeting_store, e_meeting_attendee_get_delfrom (attendee), &pos);
if (ib != NULL) {
ECompEditor *comp_editor;
ECompEditorFlags flags;
e_meeting_attendee_set_delto (ib, NULL);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
flags = e_comp_editor_get_flags (comp_editor);
if (!(flags & E_COMP_EDITOR_FLAG_DELEGATE))
e_meeting_attendee_set_edit_level (ib, E_MEETING_ATTENDEE_EDIT_FULL);
g_clear_object (&comp_editor);
}
}
/* Handle deleting all attendees in the delegation chain */
while (attendee) {
EMeetingAttendee *ib = NULL;
if (e_meeting_attendee_get_delto (attendee)) {
ib = e_meeting_store_find_attendee (page_general->priv->meeting_store,
e_meeting_attendee_get_delto (attendee), NULL);
}
e_meeting_list_view_remove_attendee_from_name_selector (
E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view), attendee);
e_meeting_store_remove_attendee (page_general->priv->meeting_store, attendee);
attendee = ib;
}
ecep_general_sensitize_widgets (E_COMP_EDITOR_PAGE (page_general), FALSE);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
e_comp_editor_set_changed (comp_editor, TRUE);
g_clear_object (&comp_editor);
}
static void
ecep_general_attendees_remove_clicked_cb (GtkButton *button,
ECompEditorPageGeneral *page_general)
{
EMeetingAttendee *attendee;
GtkTreeSelection *selection;
GList *paths = NULL, *tmp;
GtkTreeIter iter;
GtkTreePath *path = NULL;
GtkTreeModel *model = NULL;
gboolean valid_iter;
gchar *address;
gint failures = 0;
GString *errors = NULL;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (page_general->priv->attendees_list_view));
paths = gtk_tree_selection_get_selected_rows (selection, &model);
g_return_if_fail (paths != NULL);
paths = g_list_reverse (paths);
for (tmp = paths; tmp; tmp = tmp->next) {
path = tmp->data;
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, E_MEETING_STORE_ADDRESS_COL, &address, -1);
attendee = e_meeting_store_find_attendee (E_MEETING_STORE (model), address, NULL);
if (!attendee) {
if (!errors)
errors = g_string_new ("");
else
g_string_append_c (errors, '\n');
g_string_append_printf (errors, _("Cannot find attendee “%s” in the list of attendees"), address);
failures++;
} else if (e_meeting_attendee_get_edit_level (attendee) != E_MEETING_ATTENDEE_EDIT_FULL) {
if (!errors)
errors = g_string_new ("");
else
g_string_append_c (errors, '\n');
g_string_append_printf (errors, _("Not enough rights to delete attendee “%s”"), e_meeting_attendee_get_address (attendee));
failures++;
} else {
ecep_general_remove_attendee (page_general, attendee);
}
g_free (address);
}
/* Select closest item after removal */
valid_iter = gtk_tree_model_get_iter (model, &iter, path);
if (!valid_iter) {
gtk_tree_path_prev (path);
valid_iter = gtk_tree_model_get_iter (model, &iter, path);
}
if (valid_iter) {
gtk_tree_selection_unselect_all (selection);
gtk_tree_selection_select_iter (selection, &iter);
}
g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
if (errors) {
ECompEditor *comp_editor;
EAlert *alert;
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
alert = e_comp_editor_add_error (comp_editor, g_dngettext (GETTEXT_PACKAGE,
"Failed to delete selected attendee",
"Failed to delete selected attendees",
failures), errors->str);
g_string_free (errors, TRUE);
g_clear_object (&alert);
g_clear_object (&comp_editor);
}
}
static void
ecep_general_attendees_selection_changed_cb (GtkTreeSelection *selection,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
ecep_general_sensitize_widgets (E_COMP_EDITOR_PAGE (page_general), FALSE);
}
static void
ecep_general_attendee_added_cb (EMeetingListView *meeting_list_view,
EMeetingAttendee *attendee,
ECompEditorPageGeneral *page_general)
{
ECompEditor *comp_editor;
ECompEditorFlags flags;
ECalClient *client;
gchar *mailto;
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
flags = e_comp_editor_get_flags (comp_editor);
e_comp_editor_set_changed (comp_editor, TRUE);
if (!(flags & E_COMP_EDITOR_FLAG_DELEGATE)) {
g_clear_object (&comp_editor);
return;
}
client = e_comp_editor_get_target_client (comp_editor);
/* do not remove here, it did EMeetingListView already */
mailto = g_strdup_printf ("mailto:%s", page_general->priv->user_delegator ? page_general->priv->user_delegator : "");
e_meeting_attendee_set_delfrom (attendee, mailto);
g_free (mailto);
if (client && !e_client_check_capability (E_CLIENT (client), E_CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY)) {
EMeetingAttendee *delegator;
delegator = e_meeting_store_find_attendee (page_general->priv->meeting_store,
page_general->priv->user_delegator, NULL);
g_return_if_fail (delegator != NULL);
e_meeting_attendee_set_delto (delegator, e_meeting_attendee_get_address (attendee));
}
ecep_general_sensitize_widgets (E_COMP_EDITOR_PAGE (page_general), FALSE);
g_clear_object (&comp_editor);
}
static void
ecep_general_attendee_row_changed_cb (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
ECompEditorPageGeneral *page_general)
{
ECompEditor *comp_editor;
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
if (comp_editor)
e_comp_editor_set_changed (comp_editor, TRUE);
g_clear_object (&comp_editor);
}
static void
ecep_general_attendee_show_address_notify_cb (GObject *store,
GParamSpec *param,
ECompEditorPageGeneral *page_general)
{
if (gtk_widget_get_realized (GTK_WIDGET (page_general)) &&
gtk_widget_get_realized (page_general->priv->attendees_list_view))
gtk_widget_queue_draw (page_general->priv->attendees_list_view);
}
static gboolean
ecep_general_get_organizer (ECompEditorPageGeneral *page_general,
gchar **out_name,
gchar **out_mailto,
const gchar **out_error_message)
{
gchar *organizer_text;
gboolean valid = FALSE;
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
organizer_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box));
if (organizer_text) {
CamelInternetAddress *address;
const gchar *str_name, *str_address;
address = camel_internet_address_new ();
if (camel_address_unformat (CAMEL_ADDRESS (address), organizer_text) == 1 &&
camel_internet_address_get (address, 0, &str_name, &str_address)) {
valid = TRUE;
if (out_name)
*out_name = g_strdup (str_name);
if (out_mailto)
*out_mailto = g_strconcat ("mailto:", itip_strip_mailto (str_address), NULL);
} else if (out_error_message) {
*out_error_message = _("Organizer address is not a valid user mail address");
}
g_object_unref (address);
g_free (organizer_text);
}
return valid;
}
static void
ecep_general_remove_organizer_backend_address (GtkComboBox *combo_box)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_combo_box_get_model (combo_box);
if (gtk_tree_model_get_iter_first (model, &iter)) {
gint id_column;
id_column = gtk_combo_box_get_id_column (combo_box);
do {
gchar *value = NULL;
gtk_tree_model_get (model, &iter, id_column, &value, -1);
if (g_strcmp0 (value, BACKEND_EMAIL_ID) == 0) {
g_free (value);
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
break;
}
g_free (value);
} while (gtk_tree_model_iter_next (model, &iter));
}
}
static gboolean
ecep_general_pick_organizer_for_email_address (ECompEditorPageGeneral *page_general,
const gchar *email_address,
gboolean can_add)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkComboBox *combo_box;
gint ii = 0, entry_text_column;
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
combo_box = GTK_COMBO_BOX (page_general->priv->organizer_combo_box);
model = gtk_combo_box_get_model (combo_box);
if (can_add)
ecep_general_remove_organizer_backend_address (combo_box);
email_address = itip_strip_mailto (email_address);
if (!email_address || !*email_address) {
if (can_add && gtk_combo_box_get_active (combo_box) == -1 &&
gtk_tree_model_get_iter_first (model, &iter))
gtk_combo_box_set_active (combo_box, 0);
return FALSE;
}
entry_text_column = gtk_combo_box_get_entry_text_column (combo_box);
if (gtk_tree_model_get_iter_first (model, &iter)) {
do {
gchar *value = NULL;
gtk_tree_model_get (model, &iter, entry_text_column, &value, -1);
if (value && g_strrstr (value, email_address)) {
g_free (value);
gtk_combo_box_set_active (combo_box, ii);
return TRUE;
}
g_free (value);
ii++;
} while (gtk_tree_model_iter_next (model, &iter));
}
if (can_add) {
/* The expected address is not in the list, thus add it */
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo_box), BACKEND_EMAIL_ID, email_address);
gtk_combo_box_set_active (combo_box, ii);
return TRUE;
}
return FALSE;
}
static void
ecep_general_target_client_notify_cb (ECompEditor *comp_editor,
GParamSpec *param,
ECompEditorPageGeneral *page_general)
{
g_return_if_fail (E_IS_COMP_EDITOR (comp_editor));
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
if ((e_comp_editor_get_flags (comp_editor) & E_COMP_EDITOR_FLAG_IS_NEW) != 0 ||
(e_comp_editor_get_source_client (comp_editor) != NULL &&
e_comp_editor_get_target_client (comp_editor) != e_comp_editor_get_source_client (comp_editor))) {
const gchar *cal_email_address;
cal_email_address = e_comp_editor_get_cal_email_address (comp_editor);
ecep_general_pick_organizer_for_email_address (page_general, cal_email_address, TRUE);
}
if (page_general->priv->comp_color) {
ECalClient *target_client;
gboolean supports_color = FALSE;
target_client = e_comp_editor_get_target_client (comp_editor);
if (target_client)
supports_color = e_client_check_capability (E_CLIENT (target_client), E_CAL_STATIC_CAPABILITY_COMPONENT_COLOR);
e_comp_editor_property_part_set_visible (page_general->priv->comp_color, supports_color);
}
}
static gboolean
ecep_general_list_view_event_cb (EMeetingListView *list_view,
GdkEvent *event,
ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_MEETING_LIST_VIEW (list_view), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
if (event->type == GDK_2BUTTON_PRESS && gtk_widget_get_sensitive (GTK_WIDGET (list_view)) &&
gtk_widget_get_sensitive (page_general->priv->attendees_button_add)) {
EMeetingAttendee *attendee;
ECompEditor *comp_editor;
guint32 flags;
attendee = e_meeting_store_add_attendee_with_defaults (page_general->priv->meeting_store);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
flags = e_comp_editor_get_flags (comp_editor);
if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0) {
gchar *mailto;
mailto = g_strdup_printf ("mailto:%s", page_general->priv->user_delegator);
e_meeting_attendee_set_delfrom (attendee, mailto);
g_free (mailto);
}
g_clear_object (&comp_editor);
e_meeting_list_view_edit (list_view, attendee);
return TRUE;
}
return FALSE;
}
static gboolean
ecep_general_list_view_key_press_cb (EMeetingListView *list_view,
GdkEventKey *event,
ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_MEETING_LIST_VIEW (list_view), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
if (event->keyval == GDK_KEY_Delete) {
if (gtk_widget_get_sensitive (page_general->priv->attendees_button_remove))
ecep_general_attendees_remove_clicked_cb (NULL, page_general);
return TRUE;
} else if (event->keyval == GDK_KEY_Insert) {
if (gtk_widget_get_sensitive (page_general->priv->attendees_button_add))
ecep_general_attendees_add_clicked_cb (NULL, page_general);
return TRUE;
}
return FALSE;
}
static void
ecep_general_init_ui (ECompEditorPageGeneral *page_general,
ECompEditor *comp_editor)
{
const gchar *ui =
""
" "
" "
" "
" "
"";
const GtkToggleActionEntry attendees_toggle_entry[] = {
{ "option-attendees",
NULL,
N_("A_ttendees"),
NULL,
N_("Toggles whether the Attendees are displayed"),
NULL,
FALSE }
};
const GtkToggleActionEntry columns_toggle_entries[] = {
{ "view-role",
NULL,
N_("R_ole Field"),
NULL,
N_("Toggles whether the Role field is displayed"),
G_CALLBACK (action_view_role_cb),
TRUE },
{ "view-rsvp",
NULL,
N_("_RSVP"),
NULL,
N_("Toggles whether the RSVP field is displayed"),
G_CALLBACK (action_view_rsvp_cb),
TRUE },
{ "view-status",
NULL,
N_("_Status Field"),
NULL,
N_("Toggles whether the Status field is displayed"),
G_CALLBACK (action_view_status_cb),
TRUE },
{ "view-type",
NULL,
N_("_Type Field"),
NULL,
N_("Toggles whether the Attendee Type is displayed"),
G_CALLBACK (action_view_type_cb),
TRUE }
};
GtkUIManager *ui_manager;
GtkActionGroup *action_group;
GtkAction *action;
GSettings *settings;
GError *error = NULL;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
g_return_if_fail (E_IS_COMP_EDITOR (comp_editor));
settings = e_comp_editor_get_settings (comp_editor);
ui_manager = e_comp_editor_get_ui_manager (comp_editor);
action_group = gtk_action_group_new ("columns");
gtk_action_group_set_translation_domain (
action_group, GETTEXT_PACKAGE);
gtk_action_group_add_toggle_actions (
action_group, columns_toggle_entries,
G_N_ELEMENTS (columns_toggle_entries), page_general);
gtk_ui_manager_insert_action_group (
ui_manager, action_group, 0);
e_binding_bind_property (
page_general, "show-attendees",
action_group, "sensitive",
G_BINDING_SYNC_CREATE);
g_object_unref (action_group);
action_group = e_comp_editor_get_action_group (comp_editor, "individual");
gtk_action_group_add_toggle_actions (
action_group, attendees_toggle_entry,
G_N_ELEMENTS (attendees_toggle_entry), page_general);
gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
if (error) {
g_critical ("%s: %s", G_STRFUNC, error->message);
g_error_free (error);
}
action = e_comp_editor_get_action (comp_editor, "option-attendees");
e_binding_bind_property (
page_general, "show-attendees",
action, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
action = e_comp_editor_get_action (comp_editor, "view-role");
g_settings_bind (
settings, "editor-show-role",
action, "active",
G_SETTINGS_BIND_DEFAULT);
action = e_comp_editor_get_action (comp_editor, "view-rsvp");
g_settings_bind (
settings, "editor-show-rsvp",
action, "active",
G_SETTINGS_BIND_DEFAULT);
action = e_comp_editor_get_action (comp_editor, "view-status");
g_settings_bind (
settings, "editor-show-status",
action, "active",
G_SETTINGS_BIND_DEFAULT);
action = e_comp_editor_get_action (comp_editor, "view-type");
g_settings_bind (
settings, "editor-show-type",
action, "active",
G_SETTINGS_BIND_DEFAULT);
}
static void
ecep_general_sensitize_widgets (ECompEditorPage *page,
gboolean force_insensitive)
{
ECompEditorPageGeneral *page_general;
GtkTreeSelection *selection;
GtkAction *action;
gboolean sensitive, organizer_is_user, delegate, delegate_to_many = FALSE, read_only = TRUE, any_selected = FALSE;
ECompEditor *comp_editor;
ECalClient *client;
guint32 flags;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page));
E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_general_parent_class)->sensitize_widgets (page, force_insensitive);
page_general = E_COMP_EDITOR_PAGE_GENERAL (page);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
flags = e_comp_editor_get_flags (comp_editor);
client = e_comp_editor_get_target_client (comp_editor);
if (client) {
EClient *cl = E_CLIENT (client);
read_only = e_client_is_readonly (cl);
delegate_to_many = e_client_check_capability (cl, E_CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY);
} else {
force_insensitive = TRUE;
}
delegate = (flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0;
organizer_is_user = (flags & (E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER | E_COMP_EDITOR_FLAG_IS_NEW)) != 0 ||
!e_comp_editor_page_general_get_show_attendees (page_general);
sensitive = (!read_only && organizer_is_user) || delegate;
if (!delegate)
delegate_to_many = TRUE;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (page_general->priv->attendees_list_view));
any_selected = selection && gtk_tree_selection_count_selected_rows (selection) > 0;
gtk_widget_set_sensitive (page_general->priv->organizer_label, !force_insensitive);
gtk_widget_set_sensitive (page_general->priv->organizer_combo_box, !read_only && !force_insensitive);
gtk_widget_set_sensitive (page_general->priv->attendees_button, sensitive && delegate_to_many && !force_insensitive);
gtk_widget_set_sensitive (page_general->priv->attendees_hbox, !force_insensitive);
gtk_widget_set_sensitive (page_general->priv->attendees_button_add, sensitive && delegate_to_many && !force_insensitive);
gtk_widget_set_sensitive (page_general->priv->attendees_button_edit, sensitive && delegate_to_many && !force_insensitive && any_selected);
gtk_widget_set_sensitive (page_general->priv->attendees_button_remove, sensitive && !force_insensitive && any_selected);
e_meeting_list_view_set_editable (E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view), sensitive && !force_insensitive);
gtk_widget_set_sensitive (page_general->priv->attendees_list_view, !read_only && !force_insensitive);
action = e_comp_editor_get_action (comp_editor, "option-attendees");
gtk_action_set_sensitive (action, !force_insensitive && !read_only);
if (page_general->priv->comp_color &&
!e_comp_editor_property_part_get_sensitize_handled (page_general->priv->comp_color)) {
e_comp_editor_property_part_sensitize_widgets (page_general->priv->comp_color, force_insensitive || read_only);
}
g_clear_object (&comp_editor);
}
static void
ecep_general_fill_widgets (ECompEditorPage *page,
ICalComponent *component)
{
ECompEditorPageGeneral *page_general;
EMeetingListView *attendees_list_view;
ICalProperty *prop;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page));
g_return_if_fail (I_CAL_IS_COMPONENT (component));
E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_general_parent_class)->fill_widgets (page, component);
page_general = E_COMP_EDITOR_PAGE_GENERAL (page);
if (page_general->priv->comp_color)
e_comp_editor_property_part_fill_widget (page_general->priv->comp_color, component);
g_slist_free_full (page_general->priv->orig_attendees, g_free);
page_general->priv->orig_attendees = NULL;
for (prop = i_cal_component_get_first_property (component, I_CAL_ATTENDEE_PROPERTY);
prop;
g_object_unref (prop), prop = i_cal_component_get_next_property (component, I_CAL_ATTENDEE_PROPERTY)) {
const gchar *address;
address = itip_strip_mailto (i_cal_property_get_attendee (prop));
if (address)
page_general->priv->orig_attendees = g_slist_prepend (page_general->priv->orig_attendees, g_strdup (address));
}
page_general->priv->orig_attendees = g_slist_reverse (page_general->priv->orig_attendees);
prop = i_cal_component_get_first_property (component, I_CAL_ORGANIZER_PROPERTY);
if (prop) {
ICalParameter *param;
const gchar *organizer;
organizer = i_cal_property_get_organizer (prop);
if (organizer && *organizer) {
ECompEditor *comp_editor;
ESourceRegistry *registry;
guint32 flags;
gchar *value = NULL;
comp_editor = e_comp_editor_page_ref_editor (page);
flags = e_comp_editor_get_flags (comp_editor);
registry = e_shell_get_registry (e_comp_editor_get_shell (comp_editor));
flags = flags & E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER;
if (itip_address_is_user (registry, itip_strip_mailto (organizer))) {
flags = flags | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER;
} else {
param = i_cal_property_get_first_parameter (prop, I_CAL_SENTBY_PARAMETER);
if (param) {
const gchar *sentby = i_cal_parameter_get_sentby (param);
if (sentby && *sentby &&
itip_address_is_user (registry, itip_strip_mailto (organizer))) {
flags = flags | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER;
}
g_object_unref (param);
}
}
e_comp_editor_page_general_set_show_attendees (page_general, TRUE);
param = i_cal_property_get_first_parameter (prop, I_CAL_CN_PARAMETER);
if (param) {
const gchar *cn;
cn = i_cal_parameter_get_cn (param);
if (cn && *cn) {
value = camel_internet_address_format_address (cn, itip_strip_mailto (organizer));
}
g_object_unref (param);
}
if (!value)
value = g_strdup (itip_strip_mailto (organizer));
if (!(flags & E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER) ||
!ecep_general_pick_organizer_for_email_address (page_general, organizer, FALSE)) {
GtkComboBoxText *combo_box_text;
combo_box_text = GTK_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box);
gtk_combo_box_text_remove_all (combo_box_text);
gtk_combo_box_text_append_text (combo_box_text, value);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box_text), 0);
}
e_comp_editor_set_flags (comp_editor, flags);
g_clear_object (&comp_editor);
g_free (value);
}
g_object_unref (prop);
}
attendees_list_view = E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view);
e_meeting_store_remove_all_attendees (page_general->priv->meeting_store);
e_meeting_list_view_remove_all_attendees_from_name_selector (attendees_list_view);
for (prop = i_cal_component_get_first_property (component, I_CAL_ATTENDEE_PROPERTY);
prop;
g_object_unref (prop), prop = i_cal_component_get_next_property (component, I_CAL_ATTENDEE_PROPERTY)) {
const gchar *address;
address = itip_strip_mailto (i_cal_property_get_attendee (prop));
if (address) {
EMeetingAttendee *attendee;
ECalComponentAttendee *comp_attendee;
comp_attendee = e_cal_component_attendee_new_from_property (prop);
if (!comp_attendee) {
g_warn_if_reached ();
continue;
}
attendee = E_MEETING_ATTENDEE (e_meeting_attendee_new_from_e_cal_component_attendee (comp_attendee));
e_cal_component_attendee_free (comp_attendee);
e_meeting_store_add_attendee (page_general->priv->meeting_store, attendee);
e_meeting_list_view_add_attendee_to_name_selector (attendees_list_view, attendee);
g_object_unref (attendee);
}
}
}
static gboolean
ecep_general_fill_component (ECompEditorPage *page,
ICalComponent *component)
{
ECompEditorPageGeneral *page_general;
ICalProperty *prop;
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page), FALSE);
g_return_val_if_fail (I_CAL_IS_COMPONENT (component), FALSE);
page_general = E_COMP_EDITOR_PAGE_GENERAL (page);
if (page_general->priv->comp_color)
e_comp_editor_property_part_fill_component (page_general->priv->comp_color, component);
e_cal_util_component_remove_property_by_kind (component, I_CAL_ATTENDEE_PROPERTY, TRUE);
if (e_comp_editor_page_general_get_show_attendees (page_general)) {
const GPtrArray *attendees;
GHashTable *known_attendees;
ECompEditor *comp_editor;
gchar *organizer_name = NULL, *organizer_mailto = NULL;
guint32 flags;
gint ii, added_attendees = 0;
const gchar *error_message = NULL;
comp_editor = e_comp_editor_page_ref_editor (page);
flags = e_comp_editor_get_flags (comp_editor);
if ((flags & (E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER)) != 0 &&
!ecep_general_get_organizer (page_general, NULL, NULL, &error_message)) {
e_comp_editor_set_validation_error (comp_editor, page,
page_general->priv->organizer_combo_box,
error_message ? error_message : _("An organizer is required."));
g_clear_object (&comp_editor);
return FALSE;
}
if (e_meeting_store_count_actual_attendees (page_general->priv->meeting_store) < 1) {
e_comp_editor_set_validation_error (comp_editor, page,
page_general->priv->attendees_list_view,
_("At least one attendee is required."));
g_clear_object (&comp_editor);
return FALSE;
}
/* Organizer */
if ((flags & (E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER)) != 0 &&
ecep_general_get_organizer (page_general, &organizer_name, &organizer_mailto, NULL)) {
const gchar *cal_email_address;
ICalParameter *param;
prop = i_cal_component_get_first_property (component, I_CAL_ORGANIZER_PROPERTY);
if (!prop) {
prop = i_cal_property_new_organizer (organizer_mailto ? organizer_mailto : organizer_name);
i_cal_component_take_property (component, prop);
prop = i_cal_component_get_first_property (component, I_CAL_ORGANIZER_PROPERTY);
} else {
i_cal_property_set_organizer (prop, organizer_mailto ? organizer_mailto : organizer_name);
}
param = i_cal_property_get_first_parameter (prop, I_CAL_CN_PARAMETER);
if (organizer_name && *organizer_name) {
if (!param) {
param = i_cal_parameter_new_cn (organizer_name);
i_cal_property_add_parameter (prop, param);
} else {
i_cal_parameter_set_cn (param, organizer_name);
}
} else if (param) {
i_cal_property_remove_parameter_by_kind (prop, I_CAL_CN_PARAMETER);
}
g_clear_object (¶m);
param = i_cal_property_get_first_parameter (prop, I_CAL_SENTBY_PARAMETER);
cal_email_address = e_comp_editor_get_cal_email_address (comp_editor);
if (cal_email_address && *cal_email_address) {
gchar *sentby;
gboolean differs;
sentby = g_strconcat ("mailto:", cal_email_address, NULL);
differs = !organizer_mailto || g_ascii_strcasecmp (sentby, organizer_mailto) != 0;
if (differs) {
if (!param) {
param = i_cal_parameter_new_sentby (sentby);
i_cal_property_add_parameter (prop, param);
} else {
i_cal_parameter_set_sentby (param, sentby);
}
} else if (param) {
i_cal_property_remove_parameter_by_kind (prop, I_CAL_SENTBY_PARAMETER);
}
g_free (sentby);
} else if (param) {
i_cal_property_remove_parameter_by_kind (prop, I_CAL_SENTBY_PARAMETER);
}
g_clear_object (¶m);
g_object_unref (prop);
}
/* Attendees */
known_attendees = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
attendees = e_meeting_store_get_attendees (page_general->priv->meeting_store);
for (ii = 0; ii < attendees->len; ii++) {
EMeetingAttendee *attendee = g_ptr_array_index (attendees, ii);
const gchar *address;
address = itip_strip_mailto (e_meeting_attendee_get_address (attendee));
if (address) {
ICalParameter *param;
if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0 &&
(e_meeting_attendee_is_set_delfrom (attendee) || e_meeting_attendee_is_set_delto (attendee)) &&
g_hash_table_contains (known_attendees, address))
continue;
g_hash_table_insert (known_attendees, (gpointer) address, GINT_TO_POINTER (1));
prop = i_cal_property_new_attendee (e_meeting_attendee_get_address (attendee));
added_attendees++;
if (e_meeting_attendee_is_set_member (attendee)) {
param = i_cal_parameter_new_member (e_meeting_attendee_get_member (attendee));
i_cal_property_take_parameter (prop, param);
}
param = i_cal_parameter_new_cutype (e_meeting_attendee_get_cutype (attendee));
if (param)
i_cal_property_take_parameter (prop, param);
param = i_cal_parameter_new_role (e_meeting_attendee_get_role (attendee));
if (param)
i_cal_property_take_parameter (prop, param);
param = i_cal_parameter_new_partstat (e_meeting_attendee_get_partstat (attendee));
if (param)
i_cal_property_take_parameter (prop, param);
param = i_cal_parameter_new_rsvp (e_meeting_attendee_get_rsvp (attendee) ? I_CAL_RSVP_TRUE : I_CAL_RSVP_FALSE);
i_cal_property_take_parameter (prop, param);
if (e_meeting_attendee_is_set_delfrom (attendee)) {
param = i_cal_parameter_new_delegatedfrom (e_meeting_attendee_get_delfrom (attendee));
i_cal_property_take_parameter (prop, param);
}
if (e_meeting_attendee_is_set_delto (attendee)) {
param = i_cal_parameter_new_delegatedto (e_meeting_attendee_get_delto (attendee));
i_cal_property_take_parameter (prop, param);
}
if (e_meeting_attendee_is_set_sentby (attendee)) {
param = i_cal_parameter_new_sentby (e_meeting_attendee_get_sentby (attendee));
i_cal_property_take_parameter (prop, param);
}
if (e_meeting_attendee_is_set_cn (attendee)) {
param = i_cal_parameter_new_cn (e_meeting_attendee_get_cn (attendee));
i_cal_property_take_parameter (prop, param);
}
if (e_meeting_attendee_is_set_language (attendee)) {
param = i_cal_parameter_new_language (e_meeting_attendee_get_language (attendee));
i_cal_property_take_parameter (prop, param);
}
e_cal_component_parameter_bag_fill_property (e_meeting_attendee_get_parameter_bag (attendee), prop);
i_cal_component_take_property (component, prop);
}
}
g_hash_table_destroy (known_attendees);
g_free (organizer_name);
g_free (organizer_mailto);
if (!added_attendees) {
e_comp_editor_set_validation_error (comp_editor, page,
page_general->priv->attendees_list_view,
_("At least one attendee is required."));
g_clear_object (&comp_editor);
return FALSE;
}
g_clear_object (&comp_editor);
} else {
e_cal_util_component_remove_property_by_kind (component, I_CAL_ORGANIZER_PROPERTY, TRUE);
}
return E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_general_parent_class)->fill_component (page, component);
}
static void
ecep_general_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_DATA_COLUMN_WIDTH:
e_comp_editor_page_general_set_data_column_width (
E_COMP_EDITOR_PAGE_GENERAL (object),
g_value_get_int (value));
return;
case PROP_SOURCE_LABEL:
e_comp_editor_page_general_set_source_label (
E_COMP_EDITOR_PAGE_GENERAL (object),
g_value_get_string (value));
return;
case PROP_SOURCE_EXTENSION_NAME:
e_comp_editor_page_general_set_source_extension_name (
E_COMP_EDITOR_PAGE_GENERAL (object),
g_value_get_string (value));
return;
case PROP_SELECTED_SOURCE:
e_comp_editor_page_general_set_selected_source (
E_COMP_EDITOR_PAGE_GENERAL (object),
g_value_get_object (value));
return;
case PROP_SHOW_ATTENDEES:
e_comp_editor_page_general_set_show_attendees (
E_COMP_EDITOR_PAGE_GENERAL (object),
g_value_get_boolean (value));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
ecep_general_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_DATA_COLUMN_WIDTH:
g_value_set_int (
value,
e_comp_editor_page_general_get_data_column_width (
E_COMP_EDITOR_PAGE_GENERAL (object)));
return;
case PROP_SOURCE_LABEL:
g_value_set_string (
value,
e_comp_editor_page_general_get_source_label (
E_COMP_EDITOR_PAGE_GENERAL (object)));
return;
case PROP_SOURCE_EXTENSION_NAME:
g_value_set_string (
value,
e_comp_editor_page_general_get_source_extension_name (
E_COMP_EDITOR_PAGE_GENERAL (object)));
return;
case PROP_SELECTED_SOURCE:
g_value_take_object (
value,
e_comp_editor_page_general_ref_selected_source (
E_COMP_EDITOR_PAGE_GENERAL (object)));
return;
case PROP_SHOW_ATTENDEES:
g_value_set_boolean (
value,
e_comp_editor_page_general_get_show_attendees (
E_COMP_EDITOR_PAGE_GENERAL (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
ecep_general_constructed (GObject *object)
{
ECompEditor *comp_editor;
ECompEditorPageGeneral *page_general;
ECompEditorPropertyPart *part;
GtkWidget *widget, *scrolled_window;
GtkTreeSelection *selection;
GtkGrid *grid;
EShell *shell;
page_general = E_COMP_EDITOR_PAGE_GENERAL (object);
G_OBJECT_CLASS (e_comp_editor_page_general_parent_class)->constructed (object);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
g_return_if_fail (comp_editor != NULL);
page_general->priv->meeting_store = E_MEETING_STORE (e_meeting_store_new ());
grid = GTK_GRID (page_general);
widget = gtk_label_new_with_mnemonic (_("Or_ganizer:"));
g_object_set (G_OBJECT (widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_END,
"vexpand", FALSE,
"valign", GTK_ALIGN_CENTER,
NULL);
gtk_grid_attach (grid, widget, 0, 0, 1, 1);
gtk_widget_hide (widget);
page_general->priv->organizer_label = widget;
widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set (G_OBJECT (widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_FILL,
NULL);
gtk_grid_attach (grid, widget, 1, 0, page_general->priv->data_column_width, 1);
gtk_widget_hide (widget);
page_general->priv->organizer_hbox = widget;
widget = e_ellipsized_combo_box_text_new (FALSE);
g_object_set (G_OBJECT (widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
page_general->priv->organizer_combo_box = widget;
ecep_general_fill_organizer_combo_box (page_general);
g_signal_connect_swapped (page_general->priv->organizer_combo_box, "changed",
G_CALLBACK (e_comp_editor_ensure_changed), comp_editor);
widget = gtk_label_new_with_mnemonic (page_general->priv->source_label_text);
g_object_set (G_OBJECT (widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_END,
"vexpand", FALSE,
"valign", GTK_ALIGN_CENTER,
NULL);
gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
page_general->priv->source_label = widget;
widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set (G_OBJECT (widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_CENTER,
NULL);
gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
page_general->priv->source_and_color_hbox = widget;
shell = e_comp_editor_get_shell (comp_editor);
widget = e_source_combo_box_new (
e_shell_get_registry (shell),
page_general->priv->source_extension_name);
e_source_combo_box_set_show_colors (E_SOURCE_COMBO_BOX (widget), TRUE);
g_object_set (G_OBJECT (widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_box_pack_start (GTK_BOX (page_general->priv->source_and_color_hbox), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
page_general->priv->source_combo_box = widget;
gtk_label_set_mnemonic_widget (GTK_LABEL (page_general->priv->source_label),
page_general->priv->source_combo_box);
g_signal_connect (page_general->priv->source_combo_box, "changed",
G_CALLBACK (ecep_general_source_combo_box_changed_cb), page_general);
part = e_comp_editor_property_part_color_new ();
widget = e_comp_editor_property_part_get_edit_widget (part);
if (widget) {
const gchar *tooltip;
gtk_box_pack_start (GTK_BOX (page_general->priv->source_and_color_hbox), widget, FALSE, FALSE, 0);
if (g_strcmp0 (page_general->priv->source_extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0) {
tooltip = _("Override color of the event. If not set, then color of the calendar is used.");
} else if (g_strcmp0 (page_general->priv->source_extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0) {
tooltip = _("Override color of the memo. If not set, then color of the memo list is used.");
} else { /* E_SOURCE_EXTENSION_TASK_LIST */
tooltip = _("Override color of the task. If not set, then color of the task list is used.");
}
gtk_widget_set_tooltip_text (widget, tooltip);
}
page_general->priv->comp_color_changed_handler_id = g_signal_connect_swapped (part, "changed",
G_CALLBACK (e_comp_editor_page_emit_changed), page_general);
page_general->priv->comp_color = part;
widget = gtk_button_new_with_mnemonic (C_("ECompEditor", "Atte_ndees…"));
g_object_set (G_OBJECT (widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_END,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_grid_attach (grid, widget, 0, 1, 1, 1);
gtk_widget_hide (widget);
page_general->priv->attendees_button = widget;
g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_clicked_cb), page_general);
widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
g_object_set (G_OBJECT (widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_FILL,
NULL);
gtk_grid_attach (grid, widget, 1, 1, page_general->priv->data_column_width, 1);
gtk_widget_hide (widget);
page_general->priv->attendees_hbox = widget;
widget = GTK_WIDGET (e_meeting_list_view_new (page_general->priv->meeting_store));
g_object_set (G_OBJECT (widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_FILL,
NULL);
gtk_widget_show (widget);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
gtk_widget_show (scrolled_window);
gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_hbox), scrolled_window, TRUE, TRUE, 0);
page_general->priv->attendees_list_view = widget;
g_signal_connect_object (page_general->priv->attendees_list_view, "attendee-added",
G_CALLBACK (ecep_general_attendee_added_cb), page_general, 0);
g_signal_connect_object (page_general->priv->meeting_store, "row-changed",
G_CALLBACK (ecep_general_attendee_row_changed_cb), page_general, 0);
e_signal_connect_notify_object (page_general->priv->meeting_store, "notify::show-address",
G_CALLBACK (ecep_general_attendee_show_address_notify_cb), page_general, 0);
g_signal_connect_object (page_general->priv->attendees_list_view, "event",
G_CALLBACK (ecep_general_list_view_event_cb), page_general, 0);
g_signal_connect_object (page_general->priv->attendees_list_view, "key_press_event",
G_CALLBACK (ecep_general_list_view_key_press_cb), page_general, 0);
widget = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
g_object_set (G_OBJECT (widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_START,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
page_general->priv->attendees_button_box = widget;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (page_general->priv->attendees_list_view));
g_signal_connect (selection, "changed", G_CALLBACK (ecep_general_attendees_selection_changed_cb), page_general);
widget = gtk_button_new_with_mnemonic (_("_Add"));
gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_button_box), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
page_general->priv->attendees_button_add = widget;
g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_add_clicked_cb), page_general);
widget = gtk_button_new_with_mnemonic (_("_Edit"));
gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_button_box), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
page_general->priv->attendees_button_edit = widget;
g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_edit_clicked_cb), page_general);
widget = gtk_button_new_with_mnemonic (_("_Remove"));
gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_button_box), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
page_general->priv->attendees_button_remove = widget;
g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_remove_clicked_cb), page_general);
e_signal_connect_notify (comp_editor, "notify::target-client", G_CALLBACK (ecep_general_target_client_notify_cb), page_general);
ecep_general_init_ui (page_general, comp_editor);
g_clear_object (&comp_editor);
}
static void
ecep_general_finalize (GObject *object)
{
ECompEditorPageGeneral *page_general;
page_general = E_COMP_EDITOR_PAGE_GENERAL (object);
g_free (page_general->priv->source_label_text);
page_general->priv->source_label_text = NULL;
g_free (page_general->priv->source_extension_name);
page_general->priv->source_extension_name = NULL;
g_free (page_general->priv->user_delegator);
page_general->priv->user_delegator = NULL;
if (page_general->priv->comp_color && page_general->priv->comp_color_changed_handler_id) {
g_signal_handler_disconnect (page_general->priv->comp_color, page_general->priv->comp_color_changed_handler_id);
page_general->priv->comp_color_changed_handler_id = 0;
}
g_clear_object (&page_general->priv->comp_color);
g_clear_object (&page_general->priv->select_source);
g_clear_object (&page_general->priv->meeting_store);
g_slist_free_full (page_general->priv->orig_attendees, g_free);
page_general->priv->orig_attendees = NULL;
G_OBJECT_CLASS (e_comp_editor_page_general_parent_class)->finalize (object);
}
static void
e_comp_editor_page_general_init (ECompEditorPageGeneral *page_general)
{
page_general->priv = G_TYPE_INSTANCE_GET_PRIVATE (page_general,
E_TYPE_COMP_EDITOR_PAGE_GENERAL,
ECompEditorPageGeneralPrivate);
}
static void
e_comp_editor_page_general_class_init (ECompEditorPageGeneralClass *klass)
{
ECompEditorPageClass *page_class;
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (ECompEditorPageGeneralPrivate));
page_class = E_COMP_EDITOR_PAGE_CLASS (klass);
page_class->sensitize_widgets = ecep_general_sensitize_widgets;
page_class->fill_widgets = ecep_general_fill_widgets;
page_class->fill_component = ecep_general_fill_component;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = ecep_general_set_property;
object_class->get_property = ecep_general_get_property;
object_class->constructed = ecep_general_constructed;
object_class->finalize = ecep_general_finalize;
g_object_class_install_property (
object_class,
PROP_DATA_COLUMN_WIDTH,
g_param_spec_int (
"data-column-width",
"Data Column Width",
"How many columns should the data column occupy",
1, G_MAXINT, 1,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
PROP_SOURCE_LABEL,
g_param_spec_string (
"source-label",
"Source Label",
"Label to use for the source selector",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
PROP_SOURCE_EXTENSION_NAME,
g_param_spec_string (
"source-extension-name",
"Source Extension Name",
"Extension name to use for the source selector",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
PROP_SELECTED_SOURCE,
g_param_spec_object (
"selected-source",
"Selected Source",
"Which source is currently selected in the source selector",
E_TYPE_SOURCE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
PROP_SHOW_ATTENDEES,
g_param_spec_boolean (
"show-attendees",
"Show Attendees",
"Whether to show also attendees",
TRUE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
}
ECompEditorPage *
e_comp_editor_page_general_new (ECompEditor *editor,
const gchar *source_label,
const gchar *source_extension_name,
ESource *select_source,
gboolean show_attendees,
gint data_column_width)
{
g_return_val_if_fail (E_IS_COMP_EDITOR (editor), NULL);
g_return_val_if_fail (source_label != NULL, NULL);
g_return_val_if_fail (source_extension_name != NULL, NULL);
if (select_source)
g_return_val_if_fail (E_IS_SOURCE (select_source), NULL);
return g_object_new (E_TYPE_COMP_EDITOR_PAGE_GENERAL,
"editor", editor,
"source-label", source_label,
"source-extension-name", source_extension_name,
"selected-source", select_source,
"show-attendees", show_attendees,
"data-column-width", data_column_width,
NULL);
}
const gchar *
e_comp_editor_page_general_get_source_label (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
if (page_general->priv->source_label)
return gtk_label_get_text (GTK_LABEL (page_general->priv->source_label));
return page_general->priv->source_label_text;
}
void
e_comp_editor_page_general_set_source_label (ECompEditorPageGeneral *page_general,
const gchar *source_label)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
g_return_if_fail (source_label != NULL);
if (page_general->priv->source_label) {
if (g_strcmp0 (source_label, gtk_label_get_text (GTK_LABEL (page_general->priv->source_label))) != 0) {
gtk_label_set_text (GTK_LABEL (page_general->priv->source_label), source_label);
g_object_notify (G_OBJECT (page_general), "source-label");
}
} else {
g_free (page_general->priv->source_label_text);
page_general->priv->source_label_text = g_strdup (source_label);
g_object_notify (G_OBJECT (page_general), "source-label");
}
}
const gchar *
e_comp_editor_page_general_get_source_extension_name (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
if (page_general->priv->source_combo_box)
return e_source_combo_box_get_extension_name (E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box));
return page_general->priv->source_extension_name;
}
void
e_comp_editor_page_general_set_source_extension_name (ECompEditorPageGeneral *page_general,
const gchar *source_extension_name)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
if (g_strcmp0 (page_general->priv->source_extension_name, source_extension_name) == 0)
return;
g_free (page_general->priv->source_extension_name);
page_general->priv->source_extension_name = g_strdup (source_extension_name);
g_object_notify (G_OBJECT (page_general), "source-extension-name");
if (page_general->priv->source_combo_box) {
e_source_combo_box_set_extension_name (
E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box),
source_extension_name);
}
}
ESource *
e_comp_editor_page_general_ref_selected_source (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
g_return_val_if_fail (page_general->priv->source_combo_box != NULL, NULL);
return e_source_combo_box_ref_active (E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box));
}
void
e_comp_editor_page_general_set_selected_source (ECompEditorPageGeneral *page_general,
ESource *source)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
if (source)
g_return_if_fail (E_IS_SOURCE (source));
if (!page_general->priv->source_combo_box) {
g_clear_object (&page_general->priv->select_source);
page_general->priv->select_source = g_object_ref (source);
g_object_notify (G_OBJECT (page_general), "selected-source");
return;
}
if (source)
e_source_combo_box_set_active (E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box), source);
g_object_notify (G_OBJECT (page_general), "selected-source");
}
gboolean
e_comp_editor_page_general_get_show_attendees (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
return page_general->priv->show_attendees;
}
void
e_comp_editor_page_general_set_show_attendees (ECompEditorPageGeneral *page_general,
gboolean show_attendees)
{
ECompEditor *comp_editor;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
if ((show_attendees ? 1 : 0) == (page_general->priv->show_attendees ? 1 : 0))
return;
page_general->priv->show_attendees = show_attendees;
g_object_notify (G_OBJECT (page_general), "show-attendees");
e_comp_editor_page_general_update_view (page_general);
comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
if (comp_editor)
e_comp_editor_set_changed (comp_editor, TRUE);
g_clear_object (&comp_editor);
}
gint
e_comp_editor_page_general_get_data_column_width (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), 0);
return page_general->priv->data_column_width;
}
void
e_comp_editor_page_general_set_data_column_width (ECompEditorPageGeneral *page_general,
gint data_column_width)
{
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
if (data_column_width == page_general->priv->data_column_width)
return;
page_general->priv->data_column_width = data_column_width;
g_object_notify (G_OBJECT (page_general), "data-column-width");
e_comp_editor_page_general_update_view (page_general);
}
void
e_comp_editor_page_general_update_view (ECompEditorPageGeneral *page_general)
{
GtkContainer *grid;
g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
if (!page_general->priv->source_label)
return;
grid = GTK_CONTAINER (page_general);
gtk_container_child_set (grid, page_general->priv->organizer_hbox,
"left-attach", 1, "width", page_general->priv->data_column_width, NULL);
gtk_container_child_set (grid, page_general->priv->attendees_hbox,
"width", page_general->priv->data_column_width, NULL);
if (page_general->priv->show_attendees) {
if (gtk_widget_get_parent (page_general->priv->source_label) == GTK_WIDGET (grid)) {
g_object_ref (page_general->priv->source_label);
g_object_ref (page_general->priv->source_and_color_hbox);
gtk_container_remove (grid, page_general->priv->source_label);
gtk_container_remove (grid, page_general->priv->source_and_color_hbox);
gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox),
page_general->priv->source_label, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox),
page_general->priv->source_and_color_hbox, TRUE, TRUE, 0);
g_object_unref (page_general->priv->source_label);
g_object_unref (page_general->priv->source_and_color_hbox);
}
gtk_container_child_set (grid, page_general->priv->organizer_label,
"left-attach", 0, NULL);
gtk_widget_show (page_general->priv->organizer_label);
gtk_widget_show (page_general->priv->organizer_hbox);
gtk_widget_show (page_general->priv->attendees_button);
gtk_widget_show (page_general->priv->attendees_hbox);
gtk_widget_show (page_general->priv->attendees_list_view);
gtk_widget_show (page_general->priv->attendees_button_box);
} else {
if (gtk_widget_get_parent (page_general->priv->source_label) != GTK_WIDGET (grid)) {
GtkContainer *container;
GtkGrid *ggrid;
container = GTK_CONTAINER (page_general->priv->organizer_hbox);
ggrid = GTK_GRID (grid);
g_object_ref (page_general->priv->source_label);
g_object_ref (page_general->priv->source_and_color_hbox);
gtk_container_remove (container, page_general->priv->source_label);
gtk_container_remove (container, page_general->priv->source_and_color_hbox);
gtk_grid_attach (ggrid, page_general->priv->source_label, 0, 0, 1, 1);
gtk_grid_attach (ggrid, page_general->priv->source_and_color_hbox, 1, 0, 1, 1);
g_object_unref (page_general->priv->source_label);
g_object_unref (page_general->priv->source_and_color_hbox);
}
gtk_container_child_set (grid, page_general->priv->source_label,
"left-attach", 0, NULL);
gtk_container_child_set (grid, page_general->priv->source_and_color_hbox,
"left-attach", 1, "width", page_general->priv->data_column_width, NULL);
gtk_widget_hide (page_general->priv->organizer_label);
gtk_widget_hide (page_general->priv->organizer_hbox);
gtk_widget_hide (page_general->priv->attendees_button);
gtk_widget_hide (page_general->priv->attendees_hbox);
gtk_widget_hide (page_general->priv->attendees_list_view);
gtk_widget_hide (page_general->priv->attendees_button_box);
}
}
EMeetingStore *
e_comp_editor_page_general_get_meeting_store (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
return page_general->priv->meeting_store;
}
/* Element is a string, an email address; free with g_slist_free_full (slist, g_free); */
GSList *
e_comp_editor_page_general_get_added_attendees (ECompEditorPageGeneral *page_general)
{
const GPtrArray *attendees;
GHashTable *orig_attendees = NULL;
GSList *added_attendees = NULL, *link;
gint ii;
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
if (!page_general->priv->show_attendees)
return NULL;
if (page_general->priv->orig_attendees) {
for (link = page_general->priv->orig_attendees; link; link = g_slist_next (link)) {
const gchar *address = link->data;
if (address) {
if (!orig_attendees)
orig_attendees = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
g_hash_table_insert (orig_attendees, (gpointer) address, GINT_TO_POINTER (1));
}
}
}
attendees = e_meeting_store_get_attendees (page_general->priv->meeting_store);
for (ii = 0; ii < attendees->len; ii++) {
EMeetingAttendee *attendee = g_ptr_array_index (attendees, ii);
const gchar *address;
address = itip_strip_mailto (e_meeting_attendee_get_address (attendee));
if (address && (!orig_attendees || !g_hash_table_contains (orig_attendees, address)))
added_attendees = g_slist_prepend (added_attendees, g_strdup (address));
}
if (orig_attendees)
g_hash_table_destroy (orig_attendees);
return g_slist_reverse (added_attendees);
}
/* Element is a string, an email address; free with g_slist_free_full (slist, g_free); */
GSList *
e_comp_editor_page_general_get_removed_attendees (ECompEditorPageGeneral *page_general)
{
const GPtrArray *attendees;
GHashTable *new_attendees;
GSList *removed_attendees = NULL, *link;
gint ii;
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
if (!page_general->priv->orig_attendees)
return NULL;
if (!page_general->priv->show_attendees) {
GSList *copy, *link;
copy = g_slist_copy (page_general->priv->orig_attendees);
for (link = copy; link; link = g_slist_next (link)) {
link->data = g_strdup (link->data);
}
return copy;
}
new_attendees = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
attendees = e_meeting_store_get_attendees (page_general->priv->meeting_store);
for (ii = 0; ii < attendees->len; ii++) {
EMeetingAttendee *attendee = g_ptr_array_index (attendees, ii);
const gchar *address;
address = itip_strip_mailto (e_meeting_attendee_get_address (attendee));
if (address)
g_hash_table_insert (new_attendees, (gpointer) address, GINT_TO_POINTER (1));
}
for (link = page_general->priv->orig_attendees; link; link = g_slist_next (link)) {
const gchar *address = link->data;
if (address && !g_hash_table_contains (new_attendees, address)) {
removed_attendees = g_slist_prepend (removed_attendees, g_strdup (address));
}
}
g_hash_table_destroy (new_attendees);
return g_slist_reverse (removed_attendees);
}
GtkWidget *
e_comp_editor_page_general_get_source_combo_box (ECompEditorPageGeneral *page_general)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
return page_general->priv->source_combo_box;
}