/* Evolution calendar - Main page of the memo editor dialog * * Copyright (C) 2001 Ximian, Inc. * * Authors: Federico Mena-Quintero * Miguel de Icaza * Seth Alves * JP Rosevear * Nathan Owens * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "common/authentication.h" #include "e-util/e-dialog-widgets.h" #include "e-util/e-categories-config.h" #include "e-util/e-util-private.h" #include "../calendar-config.h" #include "comp-editor.h" #include "comp-editor-util.h" #include "e-send-options-utils.h" #include "memo-page.h" /* Private part of the TaskPage structure */ struct _MemoPagePrivate { /* Glade XML data */ GladeXML *xml; /* Widgets from the Glade file */ GtkWidget *main; GtkWidget *memo_content; /* Bonobo Controller for the menu/toolbar */ BonoboUIComponent *uic; ECalComponentClassification classification; GtkWidget *categories_btn; GtkWidget *categories; GtkWidget *source_selector; gboolean updating; }; static const int classification_map[] = { E_CAL_COMPONENT_CLASS_PUBLIC, E_CAL_COMPONENT_CLASS_PRIVATE, E_CAL_COMPONENT_CLASS_CONFIDENTIAL, -1 }; static void memo_page_finalize (GObject *object); static GtkWidget *memo_page_get_widget (CompEditorPage *page); static void memo_page_focus_main_widget (CompEditorPage *page); static gboolean memo_page_fill_widgets (CompEditorPage *page, ECalComponent *comp); static gboolean memo_page_fill_component (CompEditorPage *page, ECalComponent *comp); G_DEFINE_TYPE (MemoPage, memo_page, TYPE_COMP_EDITOR_PAGE); /** * memo_page_get_type: * * Registers the #TaskPage class if necessary, and returns the type ID * associated to it. * * Return value: The type ID of the #TaskPage class. **/ /* Class initialization function for the memo page */ static void memo_page_class_init (MemoPageClass *klass) { CompEditorPageClass *editor_page_class; GObjectClass *object_class; editor_page_class = (CompEditorPageClass *) klass; object_class = (GObjectClass *) klass; editor_page_class->get_widget = memo_page_get_widget; editor_page_class->focus_main_widget = memo_page_focus_main_widget; editor_page_class->fill_widgets = memo_page_fill_widgets; editor_page_class->fill_component = memo_page_fill_component; object_class->finalize = memo_page_finalize; } /* Object initialization function for the memo page */ static void memo_page_init (MemoPage *mpage) { MemoPagePrivate *priv; priv = g_new0 (MemoPagePrivate, 1); mpage->priv = priv; priv->xml = NULL; priv->main = NULL; priv->memo_content = NULL; priv->classification = E_CAL_COMPONENT_CLASS_NONE; priv->categories_btn = NULL; priv->categories = NULL; priv->updating = FALSE; } /* Destroy handler for the memo page */ static void memo_page_finalize (GObject *object) { MemoPage *mpage; MemoPagePrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (IS_MEMO_PAGE (object)); mpage = MEMO_PAGE (object); priv = mpage->priv; if (priv->main) gtk_widget_unref (priv->main); if (priv->xml) { g_object_unref (priv->xml); priv->xml = NULL; } g_free (priv); mpage->priv = NULL; if (G_OBJECT_CLASS (memo_page_parent_class)->finalize) (* G_OBJECT_CLASS (memo_page_parent_class)->finalize) (object); } static void set_classification_menu (MemoPage *page, gint class) { bonobo_ui_component_freeze (page->priv->uic, NULL); switch (class) { case E_CAL_COMPONENT_CLASS_PUBLIC: bonobo_ui_component_set_prop ( page->priv->uic, "/commands/ActionClassPublic", "state", "1", NULL); break; case E_CAL_COMPONENT_CLASS_CONFIDENTIAL: bonobo_ui_component_set_prop ( page->priv->uic, "/commands/ActionClassConfidential", "state", "1", NULL); break; case E_CAL_COMPONENT_CLASS_PRIVATE: bonobo_ui_component_set_prop ( page->priv->uic, "/commands/ActionClassPrivate", "state", "1", NULL); break; } bonobo_ui_component_thaw (page->priv->uic, NULL); } /* get_widget handler for the task page */ static GtkWidget * memo_page_get_widget (CompEditorPage *page) { MemoPage *mpage; MemoPagePrivate *priv; mpage = MEMO_PAGE (page); priv = mpage->priv; return priv->main; } /* focus_main_widget handler for the memo page */ static void memo_page_focus_main_widget (CompEditorPage *page) { MemoPage *mpage; MemoPagePrivate *priv; mpage = MEMO_PAGE (page); priv = mpage->priv; gtk_widget_grab_focus (priv->memo_content); } /* Fills the widgets with default values */ static void clear_widgets (MemoPage *mpage) { MemoPagePrivate *priv; priv = mpage->priv; /* memo content */ gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)), "", 0); /* Classification */ priv->classification = E_CAL_COMPONENT_CLASS_PRIVATE; set_classification_menu (mpage, priv->classification); /* Categories */ e_dialog_editable_set (priv->categories, NULL); } void memo_page_set_classification (MemoPage *page, ECalComponentClassification class) { page->priv->classification = class; } static void sensitize_widgets (MemoPage *mpage) { gboolean read_only, sens, sensitize; MemoPagePrivate *priv; priv = mpage->priv; if (!e_cal_is_read_only (COMP_EDITOR_PAGE (mpage)->client, &read_only, NULL)) read_only = TRUE; if (COMP_EDITOR_PAGE (mpage)->flags & COMP_EDITOR_IS_ASSIGNED) sens = COMP_EDITOR_PAGE (mpage)->flags & COMP_EDITOR_PAGE_USER_ORG; sensitize = (!read_only && sens); priv = mpage->priv; if (!e_cal_is_read_only (COMP_EDITOR_PAGE (mpage)->client, &read_only, NULL)) read_only = TRUE; gtk_widget_set_sensitive (priv->memo_content, !read_only); gtk_widget_set_sensitive (priv->categories_btn, !read_only); gtk_entry_set_editable (GTK_ENTRY (priv->categories), !read_only); bonobo_ui_component_set_prop (priv->uic, "/commands/ActionClassPublic", "sensitive", sensitize ? "1" : "0" , NULL); bonobo_ui_component_set_prop (priv->uic, "/commands/ActionClassPrivate", "sensitive", sensitize ? "1" : "0" , NULL); bonobo_ui_component_set_prop (priv->uic, "/commands/ActionClassConfidential", "sensitive", sensitize ? "1" : "0", NULL); bonobo_ui_component_set_prop (priv->uic, "/commands/ViewCategories", "sensitive", sensitize ? "1" : "0" , NULL); } /* fill_widgets handler for the memo page */ static gboolean memo_page_fill_widgets (CompEditorPage *page, ECalComponent *comp) { MemoPage *mpage; MemoPagePrivate *priv; ECalComponentClassification cl; GSList *l; const char *categories; ESource *source; mpage = MEMO_PAGE (page); priv = mpage->priv; priv->updating = TRUE; /* Clean the screen */ clear_widgets (mpage); e_cal_component_get_description_list (comp, &l); if (l && l->data) { ECalComponentText *dtext; dtext = l->data; gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)), dtext->value ? dtext->value : "", -1); } else { gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)), "", 0); } e_cal_component_free_text_list (l); /* Classification. */ e_cal_component_get_classification (comp, &cl); switch (cl) { case E_CAL_COMPONENT_CLASS_PUBLIC: { cl = E_CAL_COMPONENT_CLASS_PUBLIC; break; } case E_CAL_COMPONENT_CLASS_PRIVATE: { cl = E_CAL_COMPONENT_CLASS_PRIVATE; break; } case E_CAL_COMPONENT_CLASS_CONFIDENTIAL: { cl = E_CAL_COMPONENT_CLASS_CONFIDENTIAL; break; } default: /* default to PUBLIC */ cl = E_CAL_COMPONENT_CLASS_PUBLIC; break; } set_classification_menu (mpage, cl); /* Categories */ e_cal_component_get_categories (comp, &categories); e_dialog_editable_set (priv->categories, categories); /* Source */ source = e_cal_get_source (page->client); e_source_option_menu_select (E_SOURCE_OPTION_MENU (priv->source_selector), source); priv->updating = FALSE; sensitize_widgets (mpage); return TRUE; } /* fill_component handler for the memo page */ static gboolean memo_page_fill_component (CompEditorPage *page, ECalComponent *comp) { MemoPage *mpage; MemoPagePrivate *priv; char *cat, *str; int i; GtkTextBuffer *text_buffer; GtkTextIter text_iter_start, text_iter_end; mpage = MEMO_PAGE (page); priv = mpage->priv; text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)); /* Memo Content */ gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start); gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end); str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE); if (!str || strlen (str) == 0){ e_cal_component_set_description_list (comp, NULL); e_cal_component_set_summary(comp, NULL); } else { int idxToUse = -1, nstr = strlen(str); gboolean foundNL = FALSE; GSList l; ECalComponentText text, sumText; char *txt; for(i = 0; i 50){ sumText.value = txt = g_strndup(str, 50); } else{ sumText.value = txt = g_strdup(str); } } else{ sumText.value = txt = g_strndup(str, idxToUse); /* cuts off '\n' */ } sumText.altrep = NULL; text.value = str; text.altrep = NULL; l.data = &text; l.next = NULL; e_cal_component_set_summary(comp, &sumText); e_cal_component_set_description_list (comp, &l); g_free(txt); } if (str) g_free (str); /* Classification. */ e_cal_component_set_classification (comp, priv->classification); /* Categories */ cat = e_dialog_editable_get (priv->categories); str = comp_editor_strip_categories (cat); if (cat) g_free (cat); e_cal_component_set_categories (comp, str); if (str) g_free (str); return TRUE; } void memo_page_set_show_categories (MemoPage *page, gboolean state) { if (state) { gtk_widget_show (page->priv->categories_btn); gtk_widget_show (page->priv->categories); } else { gtk_widget_hide (page->priv->categories_btn); gtk_widget_hide (page->priv->categories); } } /* Gets the widgets from the XML file and returns if they are all available. */ static gboolean get_widgets (MemoPage *mpage) { CompEditorPage *page = COMP_EDITOR_PAGE (mpage); MemoPagePrivate *priv; GSList *accel_groups; GtkWidget *toplevel; priv = mpage->priv; #define GW(name) glade_xml_get_widget (priv->xml, name) priv->main = GW ("memo-page"); if (!priv->main){ g_warning("couldn't find memo-page!"); return FALSE; } /* Get the GtkAccelGroup from the toplevel window, so we can install it when the notebook page is mapped. */ toplevel = gtk_widget_get_toplevel (priv->main); accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel)); if (accel_groups) { page->accel_group = accel_groups->data; gtk_accel_group_ref (page->accel_group); } gtk_widget_ref (priv->main); gtk_container_remove (GTK_CONTAINER (priv->main->parent), priv->main); priv->memo_content = GW ("memo_content"); priv->categories_btn = GW ("categories-button"); priv->categories = GW ("categories"); priv->source_selector = GW ("source"); #undef GW return (priv->memo_content && priv->categories_btn && priv->categories); } /* Callback used when the categories button is clicked; we must bring up the * category list dialog. */ static void categories_clicked_cb (GtkWidget *button, gpointer data) { MemoPage *mpage; MemoPagePrivate *priv; GtkWidget *entry; mpage = MEMO_PAGE (data); priv = mpage->priv; entry = priv->categories; e_categories_config_open_dialog_for_entry (GTK_ENTRY (entry)); } /* This is called when any field is changed; it notifies upstream. */ static void field_changed_cb (GtkWidget *widget, gpointer data) { MemoPage *mpage; MemoPagePrivate *priv; mpage = MEMO_PAGE (data); priv = mpage->priv; if (!priv->updating) comp_editor_page_notify_changed (COMP_EDITOR_PAGE (mpage)); } static void source_changed_cb (GtkWidget *widget, ESource *source, gpointer data) { MemoPage *mpage; MemoPagePrivate *priv; mpage = MEMO_PAGE (data); priv = mpage->priv; if (!priv->updating) { ECal *client; client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL); if (!client || !e_cal_open (client, FALSE, NULL)) { GtkWidget *dialog; if (client) g_object_unref (client); e_source_option_menu_select (E_SOURCE_OPTION_MENU (priv->source_selector), e_cal_get_source (COMP_EDITOR_PAGE (mpage)->client)); dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Unable to open memos in '%s'."), e_source_peek_name (source)); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } else { comp_editor_notify_client_changed ( COMP_EDITOR (gtk_widget_get_toplevel (priv->main)), client); sensitize_widgets (mpage); } } } /*sets the current focused widget */ static gboolean widget_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data) { MemoPage *tpage; tpage = MEMO_PAGE (data); comp_editor_page_set_focused_widget (COMP_EDITOR_PAGE (tpage), widget); return FALSE; } /*unset the current focused widget */ static gboolean widget_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data) { MemoPage *tpage; tpage = MEMO_PAGE (data); comp_editor_page_unset_focused_widget (COMP_EDITOR_PAGE (tpage), widget); return FALSE; } /* Hooks the widget signals */ static gboolean init_widgets (MemoPage *mpage) { MemoPagePrivate *priv; GtkTextBuffer *text_buffer; priv = mpage->priv; /* Memo Content */ text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->memo_content), GTK_WRAP_WORD); g_signal_connect(priv->memo_content, "focus-in-event", G_CALLBACK (widget_focus_in_cb), tpage); g_signal_connect(priv->memo_content, "focus-out-event", G_CALLBACK (widget_focus_out_cb), tpage); /* Categories button */ g_signal_connect((priv->categories_btn), "clicked", G_CALLBACK (categories_clicked_cb), mpage); /* Source selector */ g_signal_connect((priv->source_selector), "source_selected", G_CALLBACK (source_changed_cb), mpage); /* Connect the default signal handler to use to make sure the "changed" field gets set whenever a field is changed. */ /* Belongs to priv->memo_content */ g_signal_connect ((text_buffer), "changed", G_CALLBACK (field_changed_cb), mpage); g_signal_connect((priv->categories), "changed", G_CALLBACK (field_changed_cb), mpage); memo_page_set_show_categories (mpage, calendar_config_get_show_categories()); return TRUE; } /** * memo_page_construct: * @mpage: An memo page. * * Constructs an memo page by loading its Glade data. * * Return value: The same object as @mpage, or NULL if the widgets could not be * created. **/ MemoPage * memo_page_construct (MemoPage *mpage) { MemoPagePrivate *priv; char *gladefile; priv = mpage->priv; gladefile = g_build_filename (EVOLUTION_GLADEDIR, "memo-page.glade", NULL); priv->xml = glade_xml_new (gladefile, NULL, NULL); g_free (gladefile); if (!priv->xml) { g_message ("memo_page_construct(): " "Could not load the Glade XML file!"); return NULL; } if (!get_widgets (mpage)) { g_message ("memo_page_construct(): " "Could not find all widgets in the XML file!"); return NULL; } if (!init_widgets (mpage)) { g_message ("memo_page_construct(): " "Could not initialize the widgets!"); return NULL; } return mpage; } /** * memo_page_new: * * Creates a new memo page. * * Return value: A newly-created task page, or NULL if the page could * not be created. **/ MemoPage * memo_page_new (BonoboUIComponent *uic) { MemoPage *mpage; mpage = gtk_type_new (TYPE_MEMO_PAGE); mpage->priv->uic = uic; if (!memo_page_construct (mpage)) { g_object_unref (mpage); return NULL; } return mpage; } GtkWidget *memo_page_create_source_option_menu (void); GtkWidget * memo_page_create_source_option_menu (void) { GtkWidget *menu; GConfClient *gconf_client; ESourceList *source_list; gconf_client = gconf_client_get_default (); source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/memos/sources"); menu = e_source_option_menu_new (source_list); g_object_unref (source_list); gtk_widget_show (menu); return menu; }