diff options
author | Milan Crha <mcrha@redhat.com> | 2010-12-22 04:11:10 +0800 |
---|---|---|
committer | Rodrigo Moya <rodrigo@gnome-db.org> | 2011-06-30 00:41:13 +0800 |
commit | 97fac153c5e0099774de9960ae14a0dced8d7cab (patch) | |
tree | 3b91aa477ed64d5645eb2719718cf853b8eaf70b | |
parent | c3d6ab4b55699dfde141fc1c89e759bda14db38b (diff) | |
download | gsoc2013-evolution-97fac153c5e0099774de9960ae14a0dced8d7cab.tar.gz gsoc2013-evolution-97fac153c5e0099774de9960ae14a0dced8d7cab.tar.zst gsoc2013-evolution-97fac153c5e0099774de9960ae14a0dced8d7cab.zip |
Bug #567879 - Add View >> Gallery Option In Email Composer
-rw-r--r-- | composer/e-composer-actions.c | 16 | ||||
-rw-r--r-- | composer/e-composer-actions.h | 2 | ||||
-rw-r--r-- | composer/e-composer-private.c | 81 | ||||
-rw-r--r-- | composer/e-composer-private.h | 5 | ||||
-rw-r--r-- | composer/e-msg-composer.c | 32 | ||||
-rw-r--r-- | composer/evolution-composer.ui | 6 | ||||
-rw-r--r-- | mail/evolution-mail.schemas.in | 14 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-settings.c | 4 | ||||
-rw-r--r-- | widgets/misc/Makefile.am | 2 | ||||
-rw-r--r-- | widgets/misc/e-picture-gallery.c | 419 | ||||
-rw-r--r-- | widgets/misc/e-picture-gallery.h | 67 |
11 files changed, 641 insertions, 7 deletions
diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c index 3b2aabfefc..1f1cb44a7c 100644 --- a/composer/e-composer-actions.c +++ b/composer/e-composer-actions.c @@ -353,6 +353,14 @@ static GtkToggleActionEntry toggle_entries[] = { G_CALLBACK (action_pgp_sign_cb), FALSE }, + { "picture-gallery", + "emblem-photos", + N_("_Picture Gallery"), + NULL, + N_("Show a collection of pictures that you can drag to your message"), + NULL, /* no callback */ + FALSE }, + { "prioritize-message", NULL, N_("_Prioritize Message"), @@ -461,9 +469,17 @@ e_composer_actions_init (EMsgComposer *composer) ACTION (ATTACH), "short-label", _("Attach"), NULL); g_object_set ( + ACTION (PICTURE_GALLERY), "is-important", TRUE, NULL); + + g_object_set ( ACTION (SAVE_DRAFT), "short-label", _("Save Draft"), NULL); g_object_bind_property ( + composer, "html-mode", + ACTION (PICTURE_GALLERY), "sensitive", + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( web_view, "editable", GTKHTML_EDITOR_ACTION_EDIT_MENU (editor), "sensitive", G_BINDING_SYNC_CREATE); diff --git a/composer/e-composer-actions.h b/composer/e-composer-actions.h index 80147a8f24..4aed102a64 100644 --- a/composer/e-composer-actions.h +++ b/composer/e-composer-actions.h @@ -29,6 +29,8 @@ E_COMPOSER_ACTION ((composer), "pgp-encrypt") #define E_COMPOSER_ACTION_PGP_SIGN(composer) \ E_COMPOSER_ACTION ((composer), "pgp-sign") +#define E_COMPOSER_ACTION_PICTURE_GALLERY(composer) \ + E_COMPOSER_ACTION ((composer), "picture-gallery") #define E_COMPOSER_ACTION_PRINT(composer) \ E_COMPOSER_ACTION ((composer), "print") #define E_COMPOSER_ACTION_PRINT_PREVIEW(composer) \ diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c index f9840bd929..816ea10b16 100644 --- a/composer/e-composer-private.c +++ b/composer/e-composer-private.c @@ -20,6 +20,9 @@ #include "e-composer-private.h" #include "e-util/e-util-private.h" +/* Initial height of the picture gallery. */ +#define GALLERY_INITIAL_HEIGHT 150 + static void composer_setup_charset_menu (EMsgComposer *composer) { @@ -124,12 +127,36 @@ msg_composer_url_requested_cb (GtkHTML *html, g_signal_stop_emission_by_name (html, "url-requested"); } +static void +composer_update_gallery_visibility (EMsgComposer *composer) +{ + GtkhtmlEditor *editor; + GtkToggleAction *toggle_action; + gboolean gallery_active; + gboolean html_mode; + + editor = GTKHTML_EDITOR (composer); + html_mode = gtkhtml_editor_get_html_mode (editor); + + toggle_action = GTK_TOGGLE_ACTION (ACTION (PICTURE_GALLERY)); + gallery_active = gtk_toggle_action_get_active (toggle_action); + + if (html_mode && gallery_active) { + gtk_widget_show (composer->priv->gallery_scrolled_window); + gtk_widget_show (composer->priv->gallery_icon_view); + } else { + gtk_widget_hide (composer->priv->gallery_scrolled_window); + gtk_widget_hide (composer->priv->gallery_icon_view); + } +} + void e_composer_private_constructed (EMsgComposer *composer) { EMsgComposerPrivate *priv = composer->priv; EFocusTracker *focus_tracker; EShell *shell; + EShellSettings *shell_settings; EWebView *web_view; GtkhtmlEditor *editor; GtkUIManager *ui_manager; @@ -140,7 +167,7 @@ e_composer_private_constructed (EMsgComposer *composer) GtkWindow *window; const gchar *path; gboolean small_screen_mode; - gchar *filename; + gchar *filename, *gallery_path; gint ii; GError *error = NULL; @@ -148,6 +175,7 @@ e_composer_private_constructed (EMsgComposer *composer) ui_manager = gtkhtml_editor_get_ui_manager (editor); shell = e_msg_composer_get_shell (composer); + shell_settings = e_shell_get_shell_settings (shell); web_view = e_msg_composer_get_web_view (composer); small_screen_mode = e_shell_get_small_screen_mode (shell); @@ -289,6 +317,7 @@ e_composer_private_constructed (EMsgComposer *composer) e_attachment_paned_set_default_height (75); /* short attachment bar for Anjal */ e_attachment_icon_view_set_default_icon_size (GTK_ICON_SIZE_BUTTON); } + widget = e_attachment_paned_new (); gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); priv->attachment_paned = g_object_ref (widget); @@ -354,18 +383,53 @@ e_composer_private_constructed (EMsgComposer *composer) gtk_box_pack_end (GTK_BOX (container), tmp_box, FALSE, FALSE, 3); } - g_object_set_data ((GObject *)composer, "vbox", editor->vbox); + container = e_attachment_paned_get_content_area ( + E_ATTACHMENT_PANED (priv->attachment_paned)); + + widget = gtk_vpaned_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_widget_set_size_request (widget, -1, GALLERY_INITIAL_HEIGHT); + gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, FALSE); + priv->gallery_scrolled_window = g_object_ref (widget); + gtk_widget_show (widget); /* Reparent the scrolled window containing the GtkHTML widget * into the content area of the top attachment pane. */ widget = GTK_WIDGET (web_view); widget = gtk_widget_get_parent (widget); - container = e_attachment_paned_get_content_area ( - E_ATTACHMENT_PANED (priv->attachment_paned)); gtk_widget_reparent (widget, container); - gtk_box_set_child_packing ( - GTK_BOX (container), widget, TRUE, TRUE, 0, GTK_PACK_START); + + /* Construct the picture gallery. */ + + container = priv->gallery_scrolled_window; + + gallery_path = e_shell_settings_get_string (shell_settings, "composer-gallery-path"); + widget = e_picture_gallery_new (gallery_path); + gtk_container_add (GTK_CONTAINER (container), widget); + priv->gallery_icon_view = g_object_ref (widget); + g_free (gallery_path); + + g_signal_connect ( + composer, "notify::html-mode", + G_CALLBACK (composer_update_gallery_visibility), NULL); + + g_signal_connect_swapped ( + ACTION (PICTURE_GALLERY), "toggled", + G_CALLBACK (composer_update_gallery_visibility), composer); + + /* XXX What is this for? */ + g_object_set_data (G_OBJECT (composer), "vbox", editor->vbox); composer_setup_recent_menu (composer); @@ -498,6 +562,11 @@ e_composer_private_dispose (EMsgComposer *composer) composer->priv->composer_actions = NULL; } + if (composer->priv->gallery_scrolled_window != NULL) { + g_object_unref (composer->priv->gallery_scrolled_window); + composer->priv->gallery_scrolled_window = NULL; + } + g_hash_table_remove_all (composer->priv->inline_images); g_hash_table_remove_all (composer->priv->inline_images_by_url); diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h index b4818d4c57..230d2f4fec 100644 --- a/composer/e-composer-private.h +++ b/composer/e-composer-private.h @@ -51,6 +51,7 @@ #include "widgets/misc/e-attachment-icon-view.h" #include "widgets/misc/e-attachment-paned.h" #include "widgets/misc/e-attachment-store.h" +#include "widgets/misc/e-picture-gallery.h" #include "widgets/misc/e-signature-combo-box.h" #include "widgets/misc/e-web-view.h" #include "shell/e-shell.h" @@ -113,7 +114,6 @@ struct _EMsgComposerPrivate { /*** UI Management ***/ - GtkWidget *html_editor; GtkWidget *header_table; GtkWidget *activity_bar; GtkWidget *alert_bar; @@ -132,6 +132,9 @@ struct _EMsgComposerPrivate { GtkWidget *focused_entry; + GtkWidget *gallery_icon_view; + GtkWidget *gallery_scrolled_window; + GtkWidget *address_dialog; GHashTable *inline_images; diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 227df24277..b79eaa3a71 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -1976,6 +1976,34 @@ msg_composer_finalize (GObject *object) } static void +msg_composer_gallery_drag_data_get (GtkIconView *icon_view, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint target_type, + guint time) +{ + GtkTreePath *path; + GtkCellRenderer *cell; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *str_data; + + if (!gtk_icon_view_get_cursor (icon_view, &path, &cell)) + return; + + model = gtk_icon_view_get_model (icon_view); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, 1, &str_data, -1); + gtk_tree_path_free (path); + + /* only supports "text/uri-list" */ + gtk_selection_data_set ( + selection_data, selection_data->target, 8, + (guchar *) str_data, strlen (str_data)); + g_free (str_data); +} + +static void msg_composer_constructed (GObject *object) { EShell *shell; @@ -2072,6 +2100,10 @@ msg_composer_constructed (GObject *object) web_view, "drag-data-received", G_CALLBACK (msg_composer_drag_data_received_cb), composer); + g_signal_connect ( + composer->priv->gallery_icon_view, "drag-data-get", + G_CALLBACK (msg_composer_gallery_drag_data_get), NULL); + /* Configure Headers */ e_composer_header_table_set_account_list ( diff --git a/composer/evolution-composer.ui b/composer/evolution-composer.ui index f283d35dcb..d1eb10c76c 100644 --- a/composer/evolution-composer.ui +++ b/composer/evolution-composer.ui @@ -25,6 +25,8 @@ <menuitem action='view-reply-to'/> <menuitem action='view-cc'/> <menuitem action='view-bcc'/> + <separator/> + <menuitem action='picture-gallery'/> </menu> </placeholder> <menu action='insert-menu'> @@ -56,4 +58,8 @@ <separator/> </placeholder> </toolbar> + <toolbar name='html-toolbar'> + <separator/> + <toolitem action='picture-gallery'/> + </toolbar> </ui> diff --git a/mail/evolution-mail.schemas.in b/mail/evolution-mail.schemas.in index 4af7680412..1503d7b0fe 100644 --- a/mail/evolution-mail.schemas.in +++ b/mail/evolution-mail.schemas.in @@ -346,6 +346,20 @@ </locale> </schema> + <schema> + <key>/schemas/apps/evolution/mail/composer/gallery_path</key> + <applyto>/apps/evolution/mail/composer/gallery_path</applyto> + <owner>evolution-mail</owner> + <type>string</type> + <default></default> + <locale name="C"> + <short>Path where image gallery should search for its content</short> + <long>This value can be an empty string, which means it'll use + the system Picture folder, usually set to ~/Pictures. This folder will + be also used when the set path is not pointing to the existent folder.</long> + </locale> + </schema> + <!-- Display Settings --> <schema> diff --git a/modules/mail/e-mail-shell-settings.c b/modules/mail/e-mail-shell-settings.c index 1b70289ded..18e8407bba 100644 --- a/modules/mail/e-mail-shell-settings.c +++ b/modules/mail/e-mail-shell-settings.c @@ -308,6 +308,10 @@ e_mail_shell_settings_init (EShellBackend *shell_backend) "composer-no-signature-delim", "/apps/evolution/mail/composer/no_signature_delim"); + e_shell_settings_install_property_for_key ( + "composer-gallery-path", + "/apps/evolution/mail/composer/gallery_path"); + /* These properties use transform functions to convert * GConf values to forms more useful to Evolution. We * have to use separate properties because GConfBridge diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index 4375c0641e..7e9ce9ca2b 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -44,6 +44,7 @@ widgetsinclude_HEADERS = \ e-menu-tool-button.h \ e-online-button.h \ e-paned.h \ + e-picture-gallery.h \ e-popup-action.h \ e-popup-menu.h \ e-preferences-window.h \ @@ -122,6 +123,7 @@ libemiscwidgets_la_SOURCES = \ e-menu-tool-button.c \ e-online-button.c \ e-paned.c \ + e-picture-gallery.c \ e-popup-action.c \ e-popup-menu.c \ e-preferences-window.c \ diff --git a/widgets/misc/e-picture-gallery.c b/widgets/misc/e-picture-gallery.c new file mode 100644 index 0000000000..163a160ff8 --- /dev/null +++ b/widgets/misc/e-picture-gallery.c @@ -0,0 +1,419 @@ +/* + * e-picture-gallery.c + * + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-util/e-icon-factory.h" + +#include "e-picture-gallery.h" + +#define E_PICTURE_GALLERY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_PICTURE_GALLERY, EPictureGalleryPrivate)) + +struct _EPictureGalleryPrivate { + gboolean initialized; + gchar *path; + GFileMonitor *monitor; +}; + +enum { + PROP_0, + PROP_PATH +}; + +enum { + COL_PIXBUF = 0, + COL_URI, + COL_FILENAME_TEXT +}; + +G_DEFINE_TYPE (EPictureGallery, e_picture_gallery, GTK_TYPE_ICON_VIEW) + +static gboolean +update_file_iter (GtkListStore *list_store, GtkTreeIter *iter, GFile *file, gboolean force_thumbnail_update) +{ + GFileInfo *file_info; + gchar *uri; + gboolean res = FALSE; + + g_return_val_if_fail (list_store != NULL, FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (file != NULL, FALSE); + + uri = g_file_get_uri (file); + + file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_THUMBNAIL_PATH "," + G_FILE_ATTRIBUTE_THUMBNAILING_FAILED "," + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + if (file_info != NULL) { + const gchar *existing_thumb = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH); + gchar *new_thumb = NULL; + + if (!existing_thumb || force_thumbnail_update) { + gchar *filename; + + filename = g_file_get_path (file); + if (filename) { + new_thumb = e_icon_factory_create_thumbnail (filename); + if (new_thumb) + existing_thumb = new_thumb; + g_free (filename); + } + } + + if (existing_thumb && !g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED)) { + GdkPixbuf* pixbuf; + + pixbuf = gdk_pixbuf_new_from_file (existing_thumb, NULL); + + if (pixbuf) { + const gchar *filename; + gchar *filename_text = NULL; + guint64 filesize; + + filename = g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME); + if (filename) { + filesize = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_STANDARD_SIZE); + if (filesize) { + gchar *tmp = g_format_size_for_display ((goffset) filesize); + filename_text = g_strdup_printf ("%s (%s)", filename, tmp); + g_free (tmp); + } + + res = TRUE; + gtk_list_store_set (list_store, iter, + COL_PIXBUF, pixbuf, + COL_URI, uri, + COL_FILENAME_TEXT, filename_text ? filename_text : filename, + -1); + } + + g_object_unref (pixbuf); + g_free (filename_text); + } + } + + g_free (new_thumb); + } + + g_free (uri); + + return res; +} + +static void +add_file (GtkListStore *list_store, GFile *file) +{ + GtkTreeIter iter; + + g_return_if_fail (list_store != NULL); + g_return_if_fail (file != NULL); + + gtk_list_store_append (list_store, &iter); + if (!update_file_iter (list_store, &iter, file, FALSE)) + gtk_list_store_remove (list_store, &iter); +} + +static gboolean +find_file_uri (GtkListStore *list_store, const gchar *uri, GtkTreeIter *iter) +{ + GtkTreeModel *model; + + g_return_val_if_fail (list_store != NULL, FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + model = GTK_TREE_MODEL (list_store); + g_return_val_if_fail (model != NULL, FALSE); + + if (!gtk_tree_model_get_iter_first (model, iter)) + return FALSE; + + do { + gchar *iter_uri = NULL; + + gtk_tree_model_get (model, iter, + COL_URI, &iter_uri, + -1); + + if (iter_uri && g_ascii_strcasecmp (uri, iter_uri) == 0) { + g_free (iter_uri); + return TRUE; + } + + g_free (iter_uri); + } while (gtk_tree_model_iter_next (model, iter)); + + return FALSE; +} + +static void +picture_gallery_dir_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, EPictureGallery *gallery) +{ + gchar *uri; + GtkListStore *list_store; + GtkTreeIter iter; + + g_return_if_fail (gallery != NULL); + g_return_if_fail (gallery->priv != NULL); + g_return_if_fail (file != NULL); + + list_store = GTK_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (gallery))); + g_return_if_fail (list_store != NULL); + + uri = g_file_get_uri (file); + if (!uri) + return; + + switch (event_type) { + case G_FILE_MONITOR_EVENT_CREATED: + if (find_file_uri (list_store, uri, &iter)) { + if (!update_file_iter (list_store, &iter, file, TRUE)) + gtk_list_store_remove (list_store, &iter); + } else { + add_file (list_store, file); + } + break; + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + if (find_file_uri (list_store, uri, &iter)) { + if (!update_file_iter (list_store, &iter, file, TRUE)) + gtk_list_store_remove (list_store, &iter); + } + break; + case G_FILE_MONITOR_EVENT_DELETED: + if (find_file_uri (list_store, uri, &iter)) + gtk_list_store_remove (list_store, &iter); + break; + default: + break; + } + + g_free (uri); +} + +static gboolean +picture_gallery_start_loading_cb (EPictureGallery *gallery) +{ + GtkIconView *icon_view; + GtkListStore *list_store; + GDir *dir; + const gchar *dirname; + + icon_view = GTK_ICON_VIEW (gallery); + list_store = GTK_LIST_STORE (gtk_icon_view_get_model (icon_view)); + g_return_val_if_fail (list_store != NULL, FALSE); + + dirname = e_picture_gallery_get_path (gallery); + if (!dirname) + return FALSE; + + dir = g_dir_open (dirname, 0, NULL); + if (dir) { + GFile *file; + const gchar *basename; + + while ((basename = g_dir_read_name (dir)) != NULL) { + gchar *filename; + + filename = g_build_filename (dirname, basename, NULL); + file = g_file_new_for_path (filename); + + add_file (list_store, file); + + g_free (filename); + g_object_unref (file); + } + + g_dir_close (dir); + + file = g_file_new_for_path (dirname); + gallery->priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + + if (gallery->priv->monitor) + g_signal_connect (gallery->priv->monitor, "changed", G_CALLBACK (picture_gallery_dir_changed_cb), gallery); + } + + g_object_unref (icon_view); + + return FALSE; +} + +const gchar * +e_picture_gallery_get_path (EPictureGallery *gallery) +{ + g_return_val_if_fail (gallery != NULL, NULL); + g_return_val_if_fail (E_IS_PICTURE_GALLERY (gallery), NULL); + g_return_val_if_fail (gallery->priv != NULL, NULL); + + return gallery->priv->path; +} + +static void +picture_gallery_set_path (EPictureGallery *gallery, const gchar *path) +{ + g_return_if_fail (gallery != NULL); + g_return_if_fail (E_IS_PICTURE_GALLERY (gallery)); + g_return_if_fail (gallery->priv != NULL); + + g_free (gallery->priv->path); + + if (!path || !*path || !g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) + gallery->priv->path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)); + else + gallery->priv->path = g_strdup (path); +} + +static void +picture_gallery_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + switch (property_id) { + case PROP_PATH: + g_value_set_string (value, e_picture_gallery_get_path (E_PICTURE_GALLERY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +picture_gallery_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + switch (property_id) { + case PROP_PATH: + picture_gallery_set_path (E_PICTURE_GALLERY (object), g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +visible_cb (EPictureGallery *gallery) +{ + g_return_if_fail (gallery != NULL); + g_return_if_fail (gallery->priv != NULL); + + if (!gallery->priv->initialized && gtk_widget_get_visible (GTK_WIDGET (gallery))) { + gallery->priv->initialized = TRUE; + + g_idle_add ((GSourceFunc) picture_gallery_start_loading_cb, gallery); + } +} + +static void +picture_gallery_constructed (GObject *object) +{ + if (G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed) + G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed (object); + + g_signal_connect (object, "notify::visible", G_CALLBACK (visible_cb), NULL); +} + +static void +picture_gallery_dispose (GObject *object) +{ + EPictureGallery *gallery; + + gallery = E_PICTURE_GALLERY (object); + + g_return_if_fail (gallery != NULL); + g_return_if_fail (gallery->priv != NULL); + + if (gallery->priv->monitor) { + g_object_unref (gallery->priv->monitor); + gallery->priv->monitor = NULL; + } + + if (G_OBJECT_CLASS (e_picture_gallery_parent_class)->dispose) + G_OBJECT_CLASS (e_picture_gallery_parent_class)->dispose (object); +} + +static void +e_picture_gallery_class_init (EPictureGalleryClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EPictureGalleryPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->get_property = picture_gallery_get_property; + object_class->set_property = picture_gallery_set_property; + object_class->constructed = picture_gallery_constructed; + object_class->dispose = picture_gallery_dispose; + + g_object_class_install_property ( + object_class, + PROP_PATH, + g_param_spec_string ( + "path", + "Gallery path", + NULL, + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +e_picture_gallery_init (EPictureGallery *gallery) +{ + GtkIconView *icon_view; + GtkListStore *list_store; + GtkTargetEntry *targets; + GtkTargetList *list; + gint n_targets; + + gallery->priv = E_PICTURE_GALLERY_GET_PRIVATE (gallery); + gallery->priv->initialized = FALSE; + gallery->priv->monitor = NULL; + picture_gallery_set_path (gallery, NULL); + + icon_view = GTK_ICON_VIEW (gallery); + + list_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); + gtk_icon_view_set_model (icon_view, GTK_TREE_MODEL (list_store)); + g_object_unref (list_store); + + gtk_icon_view_set_pixbuf_column (icon_view, COL_PIXBUF); + gtk_icon_view_set_text_column (icon_view, COL_FILENAME_TEXT); + gtk_icon_view_set_tooltip_column (icon_view, -1); + + list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_uri_targets (list, 0); + targets = gtk_target_table_new_from_list (list, &n_targets); + + gtk_icon_view_enable_model_drag_source ( + icon_view, GDK_BUTTON1_MASK, + targets, n_targets, GDK_ACTION_COPY); + + gtk_target_table_free (targets, n_targets); + gtk_target_list_unref (list); +} + +GtkWidget * +e_picture_gallery_new (const gchar *path) +{ + return g_object_new (E_TYPE_PICTURE_GALLERY, "path", path, NULL); +} diff --git a/widgets/misc/e-picture-gallery.h b/widgets/misc/e-picture-gallery.h new file mode 100644 index 0000000000..6da23294c4 --- /dev/null +++ b/widgets/misc/e-picture-gallery.h @@ -0,0 +1,67 @@ +/* + * e-picture-gallery.h + * + * 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; either + * version 2 of the License, or (at your option) version 3. + * + * 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 the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_PICTURE_GALLERY_H +#define E_PICTURE_GALLERY_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_PICTURE_GALLERY \ + (e_picture_gallery_get_type ()) +#define E_PICTURE_GALLERY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_PICTURE_GALLERY, EPictureGallery)) +#define E_PICTURE_GALLERY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_PICTURE_GALLERY, EPictureGalleryClass)) +#define E_IS_PICTURE_GALLERY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_PICTURE_GALLERY)) +#define E_IS_PICTURE_GALLERY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_PICTURE_GALLERY)) +#define E_PICTURE_GALLERY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_PICTURE_GALLERY, EPictureGalleryClass)) + +G_BEGIN_DECLS + +typedef struct _EPictureGallery EPictureGallery; +typedef struct _EPictureGalleryClass EPictureGalleryClass; +typedef struct _EPictureGalleryPrivate EPictureGalleryPrivate; + +struct _EPictureGallery { + GtkIconView parent; + EPictureGalleryPrivate *priv; +}; + +struct _EPictureGalleryClass { + GtkIconViewClass parent_class; +}; + +GType e_picture_gallery_get_type (void); +GtkWidget * e_picture_gallery_new (const gchar *path); +const gchar * e_picture_gallery_get_path (EPictureGallery *gallery); + +G_END_DECLS + +#endif /* E_PICTURE_GALLERY_H */ |