aboutsummaryrefslogtreecommitdiffstats
path: root/widgets
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@src.gnome.org>2009-03-09 11:31:24 +0800
committerMatthew Barnes <mbarnes@src.gnome.org>2009-03-09 11:31:24 +0800
commitf963cc39a7d21f64f578dae50fd08c44181a3bf6 (patch)
tree7cdf0c0c9bab037272ba6fca48aebbccd4c0de74 /widgets
parent85d0142d21286ce87cd5f6c3d1e2f71aa994151f (diff)
downloadgsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.tar
gsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.tar.gz
gsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.tar.bz2
gsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.tar.lz
gsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.tar.xz
gsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.tar.zst
gsoc2013-evolution-f963cc39a7d21f64f578dae50fd08c44181a3bf6.zip
Cleaning up the attachment bar, centralizing its popup menu, and converting
everything to GtkUIManager/GtkActions. Saving progress mid-stream... not sure about the MIME part utilities yet. Also, add some EActivity subclasses. Considering an EFileActivity subclass for asynchronous GIO operations (loading/saving attachments, etc.), but still ironing out details. svn path=/branches/kill-bonobo/; revision=37389
Diffstat (limited to 'widgets')
-rw-r--r--widgets/misc/Makefile.am90
-rw-r--r--widgets/misc/e-activity.c249
-rw-r--r--widgets/misc/e-activity.h17
-rw-r--r--widgets/misc/e-alert-activity.c254
-rw-r--r--widgets/misc/e-alert-activity.h70
-rw-r--r--widgets/misc/e-attachment-bar.c1982
-rw-r--r--widgets/misc/e-attachment-bar.h135
-rw-r--r--widgets/misc/e-attachment-dialog.c413
-rw-r--r--widgets/misc/e-attachment-dialog.h73
-rw-r--r--widgets/misc/e-attachment.c743
-rw-r--r--widgets/misc/e-attachment.h116
-rw-r--r--widgets/misc/e-mime-part-utils.c223
-rw-r--r--widgets/misc/e-mime-part-utils.h46
-rw-r--r--widgets/misc/e-timeout-activity.c180
-rw-r--r--widgets/misc/e-timeout-activity.h71
15 files changed, 3449 insertions, 1213 deletions
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index c422ae9972..ffbe7fa5fb 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -17,7 +17,6 @@ INCLUDES = \
privsolib_LTLIBRARIES = \
libemiscwidgets.la
-# libefilterbar.la
widgetsincludedir = $(privincludedir)/misc
@@ -39,51 +38,55 @@ widgetsinclude_HEADERS = \
e-action-combo-box.h \
e-activity.h \
e-activity-proxy.h \
- e-attachment-bar.h \
+ e-alert-activity.h \
e-attachment.h \
- e-spinner.c \
- e-spinner.h \
+ e-attachment-bar.h \
+ e-attachment-dialog.h \
e-calendar.h \
e-calendar-item.h \
+ e-canvas.h \
+ e-canvas-background.h \
+ e-canvas-utils.h \
+ e-canvas-vbox.h \
e-cell-date-edit.h \
e-cell-percent.h \
e-cell-renderer-combo.h \
e-charset-picker.h \
+ e-colors.h \
e-combo-cell-editable.h \
+ e-cursors.h \
e-dateedit.h \
e-expander.h \
+ e-gui-utils.h \
+ e-hsv-utils.h \
e-icon-entry.h \
e-image-chooser.h \
e-map.h \
e-menu-tool-button.h \
- e-popup-action.h \
- e-preferences-window.h \
+ e-mime-part-utils.h \
e-online-button.h \
- e-search-bar.h \
- e-send-options.h \
- e-url-entry.h \
- e-canvas-background.h \
- e-canvas-utils.h \
- e-canvas-vbox.h \
- e-canvas.h \
- e-cursors.h \
- e-gui-utils.h \
- e-hsv-utils.h \
+ e-popup-action.h \
e-popup-menu.h \
+ e-preferences-window.h \
e-printable.h \
- e-reflow-model.h \
e-reflow.h \
+ e-reflow-model.h \
+ e-search-bar.h \
+ e-selection-model.h \
e-selection-model-array.h \
e-selection-model-simple.h \
- e-selection-model.h \
+ e-send-options.h \
e-signature-combo-box.h \
e-signature-editor.h \
e-signature-manager.h \
e-signature-preview.h \
e-signature-script-dialog.h \
e-signature-tree-view.h \
+ e-spinner.c \
+ e-spinner.h \
+ e-timeout-activity.h \
e-unicode.h \
- e-colors.h
+ e-url-entry.h
libemiscwidgets_la_SOURCES = \
$(widgetsinclude_HEADERS) \
@@ -92,54 +95,57 @@ libemiscwidgets_la_SOURCES = \
e-action-combo-box.c \
e-activity.c \
e-activity-proxy.c \
- e-calendar.c \
+ e-alert-activity.c \
e-attachment.c \
e-attachment-bar.c \
+ e-attachment-dialog.c \
+ e-calendar.c \
e-calendar-item.c \
+ e-canvas.c \
+ e-canvas-background.c \
+ e-canvas-utils.c \
+ e-canvas-vbox.c \
e-cell-date-edit.c \
e-cell-percent.c \
e-cell-renderer-combo.c \
e-charset-picker.c \
+ e-colors.c \
e-combo-cell-editable.c \
+ e-cursors.c \
e-dateedit.c \
e-expander.c \
+ e-gui-utils.c \
+ e-hsv-utils.c \
e-icon-entry.c \
e-image-chooser.c \
e-map.c \
e-menu-tool-button.c \
- e-popup-action.c \
- e-preferences-window.c \
+ e-mime-part-utils.c \
e-online-button.c \
- e-search-bar.c \
- e-send-options.c \
- e-url-entry.c \
- e-canvas-background.c \
- e-canvas-utils.c \
- e-canvas-vbox.c \
- e-canvas.c \
- e-cursors.c \
- e-gui-utils.c \
- e-hsv-utils.c \
+ e-popup-action.c \
e-popup-menu.c \
+ e-preferences-window.c \
e-printable.c \
e-reflow-model.c \
e-reflow.c \
+ e-search-bar.c \
+ e-selection-model.c \
e-selection-model-array.c \
e-selection-model-simple.c \
- e-selection-model.c \
+ e-send-options.c \
e-signature-combo-box.c \
e-signature-editor.c \
e-signature-manager.c \
e-signature-preview.c \
e-signature-script-dialog.c \
e-signature-tree-view.c \
+ e-timeout-activity.c \
e-unicode.c \
- e-colors.c
-
+ e-url-entry.c
libemiscwidgets_la_LDFLAGS = $(NO_UNDEFINED)
-libemiscwidgets_la_LIBADD = $(top_builddir)/e-util/libeutil.la \
+libemiscwidgets_la_LIBADD = \
$(top_builddir)/e-util/libeutil.la \
$(top_builddir)/filter/libfilter.la \
$(top_builddir)/widgets/table/libetable.la \
@@ -148,20 +154,8 @@ libemiscwidgets_la_LIBADD = $(top_builddir)/e-util/libeutil.la \
$(top_builddir)/a11y/libevolution-a11y.la \
$(EVOLUTION_MAIL_LIBS) \
$(GNOME_PLATFORM_LIBS) \
- $(EVOLUTON_MAIL_LIBS) \
$(ICONV_LIBS)
-#libefilterbar_la_SOURCES = \
-# e-filter-bar.c \
-# e-filter-bar.h
-#
-#libefilterbar_la_LDFLAGS = $(NO_UNDEFINED)
-#
-#libefilterbar_la_LIBADD = \
-# $(WIN32_BOOTSTRAP_LIBS) \
-# libemiscwidgets.la \
-# $(E_WIDGETS_LIBS)
-
noinst_PROGRAMS = \
test-calendar \
test-dateedit \
diff --git a/widgets/misc/e-activity.c b/widgets/misc/e-activity.c
index 34e902f5a6..40ee0df35a 100644
--- a/widgets/misc/e-activity.c
+++ b/widgets/misc/e-activity.c
@@ -32,7 +32,6 @@ struct _EActivityPrivate {
gchar *primary_text;
gchar *secondary_text;
gdouble percent;
- guint timeout_id;
guint blocking : 1;
guint cancellable : 1;
@@ -56,21 +55,12 @@ enum {
CANCELLED,
CLICKED,
COMPLETED,
- TIMEOUT,
LAST_SIGNAL
};
static gpointer parent_class;
static gulong signals[LAST_SIGNAL];
-static gboolean
-activity_timeout_cb (EActivity *activity)
-{
- g_signal_emit (activity, signals[TIMEOUT], 0);
-
- return FALSE;
-}
-
static void
activity_set_property (GObject *object,
guint property_id,
@@ -188,13 +178,64 @@ activity_finalize (GObject *object)
g_free (priv->primary_text);
g_free (priv->secondary_text);
- if (priv->timeout_id > 0)
- g_source_remove (priv->timeout_id);
-
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static gchar *
+activity_describe (EActivity *activity)
+{
+ GString *string;
+ const gchar *text;
+ gboolean cancelled;
+ gboolean completed;
+ gdouble percent;
+
+ string = g_string_sized_new (256);
+ text = e_activity_get_primary_text (activity);
+ cancelled = e_activity_is_cancelled (activity);
+ completed = e_activity_is_completed (activity);
+ percent = e_activity_get_percent (activity);
+
+ if (cancelled) {
+ /* Translators: This is a cancelled activity. */
+ g_string_printf (string, _("%s (cancelled)"), text);
+ } else if (completed) {
+ /* Translators: This is a completed activity. */
+ g_string_printf (string, _("%s (completed)"), text);
+ } else if (percent < 0.0) {
+ /* Translators: This is an activity whose percent
+ * complete is unknown. */
+ g_string_printf (string, _("%s..."), text);
+ } else {
+ /* Translators: This is an activity whose percent
+ * complete is known. */
+ g_string_printf (
+ string, _("%s (%d%% complete)"), text,
+ (gint) (percent * 100.0 + 0.5));
+ }
+
+ return g_string_free (string, FALSE);
+}
+
+static void
+activity_cancelled (EActivity *activity)
+{
+ activity->priv->cancelled = TRUE;
+}
+
+static void
+activity_completed (EActivity *activity)
+{
+ activity->priv->completed = TRUE;
+}
+
+static void
+activity_clicked (EActivity *activity)
+{
+ /* Allow subclasses to safely chain up. */
+}
+
static void
activity_class_init (EActivityClass *class)
{
@@ -208,6 +249,11 @@ activity_class_init (EActivityClass *class)
object_class->get_property = activity_get_property;
object_class->finalize = activity_finalize;
+ class->describe = activity_describe;
+ class->cancelled = activity_cancelled;
+ class->completed = activity_completed;
+ class->clicked = activity_clicked;
+
g_object_class_install_property (
object_class,
PROP_BLOCKING,
@@ -291,7 +337,8 @@ activity_class_init (EActivityClass *class)
"cancelled",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
- 0, NULL, NULL,
+ G_STRUCT_OFFSET (EActivityClass, cancelled),
+ NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -299,7 +346,8 @@ activity_class_init (EActivityClass *class)
"clicked",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
- 0, NULL, NULL,
+ G_STRUCT_OFFSET (EActivityClass, clicked),
+ NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -307,15 +355,8 @@ activity_class_init (EActivityClass *class)
"completed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- signals[TIMEOUT] = g_signal_new (
- "timeout",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL,
+ G_STRUCT_OFFSET (EActivityClass, completed),
+ NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
@@ -372,7 +413,6 @@ e_activity_cancel (EActivity *activity)
if (activity->priv->completed)
return;
- activity->priv->cancelled = TRUE;
g_signal_emit (activity, signals[CANCELLED], 0);
}
@@ -387,7 +427,6 @@ e_activity_complete (EActivity *activity)
if (activity->priv->completed)
return;
- activity->priv->completed = TRUE;
g_signal_emit (activity, signals[COMPLETED], 0);
}
@@ -402,39 +441,14 @@ e_activity_clicked (EActivity *activity)
gchar *
e_activity_describe (EActivity *activity)
{
- GString *string;
- const gchar *text;
- gboolean cancelled;
- gboolean completed;
- gdouble percent;
+ EActivityClass *class;
g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
- string = g_string_sized_new (256);
- text = e_activity_get_primary_text (activity);
- cancelled = e_activity_is_cancelled (activity);
- completed = e_activity_is_completed (activity);
- percent = e_activity_get_percent (activity);
-
- if (cancelled) {
- /* Translators: This is a cancelled activity. */
- g_string_printf (string, _("%s (cancelled)"), text);
- } else if (completed) {
- /* Translators: This is a completed activity. */
- g_string_printf (string, _("%s (completed)"), text);
- } else if (percent < 0.0) {
- /* Translators: This is an activity whose percent
- * complete is unknown. */
- g_string_printf (string, _("%s..."), text);
- } else {
- /* Translators: This is an activity whose percent
- * complete is known. */
- g_string_printf (
- string, _("%s (%d%% complete)"), text,
- (gint) (percent * 100.0 + 0.5));
- }
+ class = E_ACTIVITY_GET_CLASS (activity);
+ g_return_val_if_fail (class->describe != NULL, NULL);
- return g_string_free (string, FALSE);
+ return class->describe (activity);
}
gboolean
@@ -453,29 +467,6 @@ e_activity_is_completed (EActivity *activity)
return activity->priv->completed;
}
-void
-e_activity_add_timeout (EActivity *activity,
- guint seconds)
-{
- g_return_if_fail (E_IS_ACTIVITY (activity));
-
- e_activity_cancel_timeout (activity);
-
- activity->priv->timeout_id = g_timeout_add_seconds (
- seconds, (GSourceFunc) activity_timeout_cb, activity);
-}
-
-void
-e_activity_cancel_timeout (EActivity *activity)
-{
- g_return_if_fail (E_IS_ACTIVITY (activity));
-
- if (activity->priv->timeout_id > 0) {
- g_source_remove (activity->priv->timeout_id);
- activity->priv->timeout_id = 0;
- }
-}
-
gboolean
e_activity_get_blocking (EActivity *activity)
{
@@ -611,105 +602,3 @@ e_activity_set_secondary_text (EActivity *activity,
g_object_notify (G_OBJECT (activity), "secondary-text");
}
-
-/************************* Error Dialog Integration **************************/
-
-void
-e_activity_error (EActivity *activity,
- GtkWidget *error_dialog)
-{
- GObject *object;
- const gchar *primary_text;
- const gchar *secondary_text;
-
- /* XXX Convert an activity to a clickable error message.
- * Clicking on the activity completes it and displays
- * the error dialog. Eventually I'd like to eliminate
- * error dialogs altogether and show errors directly
- * in the shell window. */
-
- g_return_if_fail (E_IS_ACTIVITY (activity));
- g_return_if_fail (GTK_IS_DIALOG (error_dialog));
-
- object = G_OBJECT (error_dialog);
- primary_text = g_object_get_data (object, "primary");
- secondary_text = g_object_get_data (object, "secondary");
-
- e_activity_set_primary_text (activity, primary_text);
- e_activity_set_secondary_text (activity, secondary_text);
- e_activity_set_icon_name (activity, "dialog-warning");
- e_activity_set_clickable (activity, TRUE);
-
- g_signal_connect (
- activity, "cancelled",
- G_CALLBACK (e_activity_cancel_timeout), NULL);
-
- g_signal_connect (
- activity, "completed",
- G_CALLBACK (e_activity_cancel_timeout), NULL);
-
- g_signal_connect (
- activity, "clicked",
- G_CALLBACK (e_activity_complete), NULL);
-
- g_signal_connect_swapped (
- activity, "clicked",
- G_CALLBACK (gtk_dialog_run), error_dialog);
-
- g_signal_connect (
- activity, "timeout",
- G_CALLBACK (e_activity_complete), NULL);
-
- /* XXX Allow for a configurable timeout. */
- e_activity_add_timeout (activity, 60);
-}
-
-void
-e_activity_info (EActivity *activity,
- GtkWidget *info_dialog)
-{
- GObject *object;
- const gchar *primary_text;
- const gchar *secondary_text;
-
- /* XXX Convert an activity to a clickable info message.
- * Clicking on the activity completes it and displays
- * the info dialog. Eventually I'd like to eliminate
- * info dialogs altogether and show errors directly
- * in the shell window. */
-
- g_return_if_fail (E_IS_ACTIVITY (activity));
- g_return_if_fail (GTK_IS_DIALOG (info_dialog));
-
- object = G_OBJECT (info_dialog);
- primary_text = g_object_get_data (object, "primary");
- secondary_text = g_object_get_data (object, "secondary");
-
- e_activity_set_primary_text (activity, primary_text);
- e_activity_set_secondary_text (activity, secondary_text);
- e_activity_set_icon_name (activity, "dialog-warning");
- e_activity_set_clickable (activity, TRUE);
-
- g_signal_connect (
- activity, "cancelled",
- G_CALLBACK (e_activity_cancel_timeout), NULL);
-
- g_signal_connect (
- activity, "completed",
- G_CALLBACK (e_activity_cancel_timeout), NULL);
-
- g_signal_connect (
- activity, "clicked",
- G_CALLBACK (e_activity_complete), NULL);
-
- g_signal_connect_swapped (
- activity, "clicked",
- G_CALLBACK (gtk_dialog_run), info_dialog);
-
- g_signal_connect (
- activity, "timeout",
- G_CALLBACK (e_activity_complete), NULL);
-
- /* XXX Allow for a configurable timeout. */
- e_activity_add_timeout (activity, 60);
-}
diff --git a/widgets/misc/e-activity.h b/widgets/misc/e-activity.h
index d949860333..5050d9e611 100644
--- a/widgets/misc/e-activity.h
+++ b/widgets/misc/e-activity.h
@@ -56,6 +56,14 @@ struct _EActivity {
struct _EActivityClass {
GObjectClass parent_class;
+
+ /* Methods */
+ gchar * (*describe) (EActivity *activity);
+
+ /* Signals */
+ void (*cancelled) (EActivity *activity);
+ void (*completed) (EActivity *activity);
+ void (*clicked) (EActivity *activity);
};
GType e_activity_get_type (void);
@@ -66,9 +74,6 @@ void e_activity_clicked (EActivity *activity);
gchar * e_activity_describe (EActivity *activity);
gboolean e_activity_is_cancelled (EActivity *activity);
gboolean e_activity_is_completed (EActivity *activity);
-void e_activity_add_timeout (EActivity *activity,
- guint seconds);
-void e_activity_cancel_timeout (EActivity *activity);
gboolean e_activity_get_blocking (EActivity *activity);
void e_activity_set_blocking (EActivity *activity,
gboolean blocking);
@@ -91,12 +96,6 @@ const gchar * e_activity_get_secondary_text (EActivity *activity);
void e_activity_set_secondary_text (EActivity *activity,
const gchar *secondary_text);
-/* XXX Hacky integration with error dialogs. */
-void e_activity_error (EActivity *activity,
- GtkWidget *error_dialog);
-void e_activity_info (EActivity *activity,
- GtkWidget *info_dialog);
-
G_END_DECLS
#endif /* E_ACTIVITY_H */
diff --git a/widgets/misc/e-alert-activity.c b/widgets/misc/e-alert-activity.c
new file mode 100644
index 0000000000..d8b9d6f3f3
--- /dev/null
+++ b/widgets/misc/e-alert-activity.c
@@ -0,0 +1,254 @@
+/*
+ * e-alert-activity.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-alert-activity.h"
+
+#define E_ALERT_ACTIVITY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityPrivate))
+
+struct _EAlertActivityPrivate {
+ GtkWidget *message_dialog;
+};
+
+enum {
+ PROP_0,
+ PROP_MESSAGE_DIALOG
+};
+
+static gpointer parent_class;
+
+static void
+alert_activity_set_message_dialog (EAlertActivity *alert_activity,
+ GtkWidget *message_dialog)
+{
+ g_return_if_fail (alert_activity->priv->message_dialog == NULL);
+
+ alert_activity->priv->message_dialog = g_object_ref (message_dialog);
+}
+
+static void
+alert_activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MESSAGE_DIALOG:
+ alert_activity_set_message_dialog (
+ E_ALERT_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+alert_activity_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MESSAGE_DIALOG:
+ g_value_set_object (
+ value, e_alert_activity_get_message_dialog (
+ E_ALERT_ACTIVITY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+alert_activity_dispose (GObject *object)
+{
+ EAlertActivityPrivate *priv;
+
+ priv = E_ALERT_ACTIVITY_GET_PRIVATE (object);
+
+ if (priv->message_dialog != NULL) {
+ g_object_unref (priv->message_dialog);
+ priv->message_dialog = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+alert_activity_constructed (GObject *object)
+{
+ EActivity *activity;
+ EAlertActivity *alert_activity;
+ GtkWidget *message_dialog;
+ const gchar *primary_text;
+ const gchar *secondary_text;
+
+ alert_activity = E_ALERT_ACTIVITY (object);
+ message_dialog = e_alert_activity_get_message_dialog (alert_activity);
+
+ object = G_OBJECT (message_dialog);
+ primary_text = g_object_get_data (object, "primary");
+ secondary_text = g_object_get_data (object, "secondary");
+
+ activity = E_ACTIVITY (alert_activity);
+ e_activity_set_primary_text (activity, primary_text);
+ e_activity_set_secondary_text (activity, secondary_text);
+}
+
+static void
+alert_activity_clicked (EActivity *activity)
+{
+ EAlertActivity *alert_activity;
+ GtkWidget *message_dialog;
+
+ e_activity_complete (activity);
+
+ alert_activity = E_ALERT_ACTIVITY (activity);
+ message_dialog = e_alert_activity_get_message_dialog (alert_activity);
+ gtk_dialog_run (GTK_DIALOG (message_dialog));
+ gtk_widget_hide (message_dialog);
+
+ /* Chain up to parent's clicked() method. */
+ E_ACTIVITY_CLASS (parent_class)->clicked (activity);
+}
+
+static void
+alert_activity_timeout (ETimeoutActivity *activity)
+{
+ e_activity_complete (E_ACTIVITY (activity));
+
+ /* Chain up to parent's timeout() method. */
+ E_TIMEOUT_ACTIVITY_CLASS (parent_class)->timeout (activity);
+}
+
+static void
+alert_activity_class_init (EAlertActivityClass *class)
+{
+ GObjectClass *object_class;
+ EActivityClass *activity_class;
+ ETimeoutActivityClass *timeout_activity_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAlertActivityPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = alert_activity_set_property;
+ object_class->get_property = alert_activity_get_property;
+ object_class->dispose = alert_activity_dispose;
+ object_class->constructed = alert_activity_constructed;
+
+ activity_class = E_ACTIVITY_CLASS (class);
+ activity_class->clicked = alert_activity_clicked;
+
+ timeout_activity_class = E_TIMEOUT_ACTIVITY_CLASS (class);
+ timeout_activity_class->timeout = alert_activity_timeout;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE_DIALOG,
+ g_param_spec_object (
+ "message-dialog",
+ NULL,
+ NULL,
+ GTK_TYPE_DIALOG,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+alert_activity_init (EAlertActivity *alert_activity)
+{
+ alert_activity->priv = E_ALERT_ACTIVITY_GET_PRIVATE (alert_activity);
+
+ e_activity_set_clickable (E_ACTIVITY (alert_activity), TRUE);
+ e_timeout_activity_set_timeout (E_TIMEOUT_ACTIVITY (alert_activity), 60);
+}
+
+GType
+e_alert_activity_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAlertActivityClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) alert_activity_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAlertActivity),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) alert_activity_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_TIMEOUT_ACTIVITY, "EAlertActivity",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EActivity *
+e_alert_activity_new_info (GtkWidget *message_dialog)
+{
+ g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+ return g_object_new (
+ E_TYPE_ALERT_ACTIVITY,
+ "icon-name", "dialog-information",
+ "message-dialog", message_dialog, NULL);
+}
+
+EActivity *
+e_alert_activity_new_error (GtkWidget *message_dialog)
+{
+ g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+ return g_object_new (
+ E_TYPE_ALERT_ACTIVITY,
+ "icon-name", "dialog-error",
+ "message-dialog", message_dialog, NULL);
+}
+
+EActivity *
+e_alert_activity_new_warning (GtkWidget *message_dialog)
+{
+ g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+ return g_object_new (
+ E_TYPE_ALERT_ACTIVITY,
+ "icon-name", "dialog-warning",
+ "message-dialog", message_dialog, NULL);
+}
+
+GtkWidget *
+e_alert_activity_get_message_dialog (EAlertActivity *alert_activity)
+{
+ g_return_val_if_fail (E_IS_ALERT_ACTIVITY (alert_activity), NULL);
+
+ return alert_activity->priv->message_dialog;
+}
diff --git a/widgets/misc/e-alert-activity.h b/widgets/misc/e-alert-activity.h
new file mode 100644
index 0000000000..4c5547d7fa
--- /dev/null
+++ b/widgets/misc/e-alert-activity.h
@@ -0,0 +1,70 @@
+/*
+ * e-alert-activity.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_ALERT_ACTIVITY_H
+#define E_ALERT_ACTIVITY_H
+
+#include <e-timeout-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ALERT_ACTIVITY \
+ (e_alert_activity_get_type ())
+#define E_ALERT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivity))
+#define E_ALERT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
+#define E_IS_ALERT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ALERT_ACTIVITY))
+#define E_IS_ALERT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ALERT_ACTIVITY))
+#define E_ALERT_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAlertActivity EAlertActivity;
+typedef struct _EAlertActivityClass EAlertActivityClass;
+typedef struct _EAlertActivityPrivate EAlertActivityPrivate;
+
+struct _EAlertActivity {
+ ETimeoutActivity parent;
+ EAlertActivityPrivate *priv;
+};
+
+struct _EAlertActivityClass {
+ ETimeoutActivityClass parent_class;
+};
+
+GType e_alert_activity_get_type (void);
+EActivity * e_alert_activity_new_info (GtkWidget *message_dialog);
+EActivity * e_alert_activity_new_error (GtkWidget *message_dialog);
+EActivity * e_alert_activity_new_warning (GtkWidget *message_dialog);
+GtkWidget * e_alert_activity_get_message_dialog
+ (EAlertActivity *alert_activity);
+
+G_END_DECLS
+
+#endif /* E_ALERT_ACTIVITY_H */
diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c
index 316aa85a0e..4608d77b9d 100644
--- a/widgets/misc/e-attachment-bar.c
+++ b/widgets/misc/e-attachment-bar.c
@@ -43,6 +43,7 @@
#include "e-attachment.h"
#include "e-attachment-bar.h"
+#include "e-mime-part-utils.h"
#include <libedataserver/e-data-server-util.h>
@@ -56,11 +57,13 @@
#include <camel/camel-mime-filter-bestenc.h>
#include <camel/camel-mime-part.h>
-#include "e-util/e-util.h"
+#include "e-util/e-binding.h"
+#include "e-util/e-error.h"
#include "e-util/e-gui-utils.h"
#include "e-util/e-icon-factory.h"
-#include "e-util/e-error.h"
#include "e-util/e-mktemp.h"
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
#define ICON_WIDTH 64
#define ICON_SEPARATORS " /-_"
@@ -70,84 +73,418 @@
#define ICON_BORDER 2
#define ICON_TEXT_SPACING 2
-
-static GnomeIconListClass *parent_class = NULL;
+#define E_ATTACHMENT_BAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarPrivate))
struct _EAttachmentBarPrivate {
- GtkWidget *attach; /* attachment file dialogue, if active */
-
gboolean batch_unref;
GPtrArray *attachments;
+ gchar *current_folder;
char *path;
+
+ GtkUIManager *ui_manager;
+ GtkActionGroup *standard_actions;
+ GtkActionGroup *editable_actions;
+ GtkActionGroup *open_actions;
+ guint merge_id;
+
+ gchar *background_filename;
+ gchar *background_options;
+
+ guint editable : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_BACKGROUND_FILENAME,
+ PROP_BACKGROUND_OPTIONS,
+ PROP_CURRENT_FOLDER,
+ PROP_EDITABLE,
+ PROP_UI_MANAGER
};
-
enum {
CHANGED,
+ UPDATE_ACTIONS,
LAST_SIGNAL
};
-static guint signals[LAST_SIGNAL] = { 0 };
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static const gchar *ui =
+"<ui>"
+" <popup name='attachment-popup'>"
+" <menuitem action='save-as'/>"
+" <menuitem action='set-background'/>"
+" <menuitem action='remove'/>"
+" <menuitem action='properties'/>"
+" <placeholder name='custom-actions'/>"
+" <separator/>"
+" <menuitem action='add'/>"
+" <separator/>"
+" <placeholder name='open-actions'/>"
+" </popup>"
+"</ui>";
-
-static void update (EAttachmentBar *bar);
+static void
+action_add_cb (GtkAction *action,
+ EAttachmentBar *attachment_bar)
+{
+ GtkWidget *dialog;
+ GtkWidget *option;
+ GSList *uris, *iter;
+ const gchar *disposition;
+ gboolean active;
+ gpointer parent;
+ gint response;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (attachment_bar));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Insert Attachment"), parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("A_ttach"), GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_file_chooser_set_local_only (
+ GTK_FILE_CHOOSER (dialog), FALSE);
+ gtk_file_chooser_set_select_multiple (
+ GTK_FILE_CHOOSER (dialog), TRUE);
+ gtk_window_set_icon_name (
+ GTK_WINDOW (dialog), "mail-attachment");
+
+ option = gtk_check_button_new_with_mnemonic (
+ _("_Suggest automatic display of attachment"));
+ gtk_file_chooser_set_extra_widget (
+ GTK_FILE_CHOOSER (dialog), option);
+ gtk_widget_show (option);
+
+ response = e_attachment_bar_file_chooser_dialog_run (
+ attachment_bar, dialog);
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
+ disposition = active ? "inline" : "attachment";
+
+ for (iter = uris; iter != NULL; iter = iter->next) {
+ CamelURL *url;
+
+ url = camel_url_new (iter->data, NULL);
+ if (url == NULL)
+ continue;
-/* Attachment handling functions. */
+ /* XXX Do we really need two different attach functions? */
+ if (g_ascii_strcasecmp (url->protocol, "file") == 0)
+ e_attachment_bar_attach (
+ attachment_bar, url->path, disposition);
+ else
+ e_attachment_bar_attach_remote_file (
+ attachment_bar, iter->data, disposition);
+
+ camel_url_free (url);
+ }
+
+ g_slist_foreach (uris, (GFunc) g_free, NULL);
+ g_slist_free (uris);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
static void
-attachment_destroy (EAttachmentBar *bar, EAttachment *attachment)
+action_properties_cb (GtkAction *action,
+ EAttachmentBar *attachment_bar)
{
- if (bar->priv->batch_unref)
- return;
+ GnomeIconList *icon_list;
+ GPtrArray *array;
+ GList *selection;
+ gpointer parent;
- if (g_ptr_array_remove (bar->priv->attachments, attachment)) {
- update (bar);
- g_signal_emit (bar, signals[CHANGED], 0);
+ array = attachment_bar->priv->attachments;
+
+ icon_list = GNOME_ICON_LIST (attachment_bar);
+ selection = gnome_icon_list_get_selection (icon_list);
+ g_return_if_fail (selection != NULL);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (icon_list));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ while (selection != NULL) {
+ gint index = GPOINTER_TO_INT (selection->data);
+ EAttachment *attachment;
+
+ selection = g_list_next (selection);
+
+ if (index >= array->len)
+ continue;
+
+ attachment = array->pdata[index];
+ e_attachment_edit (attachment, parent);
}
}
static void
-attachment_changed_cb (EAttachment *attachment,
- gpointer data)
+action_recent_cb (GtkAction *action,
+ EAttachmentBar *attachment_bar)
{
- update (E_ATTACHMENT_BAR (data));
+ GtkRecentChooser *chooser;
+ GFile *file;
+ gchar *uri;
+
+ chooser = GTK_RECENT_CHOOSER (action);
+
+ /* Wish: gtk_recent_chooser_get_current_file() */
+ uri = gtk_recent_chooser_get_current_uri (chooser);
+ file = g_file_new_for_uri (uri);
+ g_free (uri);
+
+ if (g_file_is_native (file))
+ e_attachment_bar_attach (
+ E_ATTACHMENT_BAR (attachment_bar),
+ g_file_get_path (file), "attachment");
+ else
+ e_attachment_bar_attach_remote_file (
+ E_ATTACHMENT_BAR (attachment_bar),
+ g_file_get_uri (file), "attachment");
+
+ g_object_unref (file);
}
static void
-add_common (EAttachmentBar *bar, EAttachment *attachment)
+action_remove_cb (GtkAction *action,
+ EAttachmentBar *attachment_bar)
{
- g_return_if_fail (attachment != NULL);
+ GnomeIconList *icon_list;
+ GPtrArray *array;
+ GList *selection;
+ GList *trash = NULL;
- g_ptr_array_add (bar->priv->attachments, attachment);
- g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
- g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
+ array = attachment_bar->priv->attachments;
- update (bar);
+ icon_list = GNOME_ICON_LIST (attachment_bar);
+ selection = gnome_icon_list_get_selection (icon_list);
+ g_return_if_fail (selection != NULL);
- g_signal_emit (bar, signals[CHANGED], 0);
+ while (selection != NULL) {
+ gint index = GPOINTER_TO_INT (selection->data);
+
+ selection = g_list_next (selection);
+
+ if (index >= array->len)
+ continue;
+
+ /* We can't unref the attachment here because that may
+ * change the selection and invalidate the list we are
+ * iterating over. So move it to a trash list instead. */
+ trash = g_list_prepend (trash, array->pdata[index]);
+ array->pdata[index] = NULL;
+ }
+
+ /* Compress the attachment array. */
+ while (g_ptr_array_remove (array, NULL));
+
+ /* Take out the trash. */
+ g_list_foreach (trash, (GFunc) g_object_unref, NULL);
+ g_list_free (trash);
+
+ e_attachment_bar_refresh (attachment_bar);
+
+ g_signal_emit (attachment_bar, signals[CHANGED], 0);
}
static void
-add_from_mime_part (EAttachmentBar *bar, CamelMimePart *part)
+action_save_as_cb (GtkAction *action,
+ EAttachmentBar *attachment_bar)
{
- add_common (bar, e_attachment_new_from_mime_part (part));
}
static void
-add_from_file (EAttachmentBar *bar, const char *file_name, const char *disposition)
+action_set_background_cb (GtkAction *action,
+ EAttachmentBar *attachment_bar)
{
+ GnomeIconList *icon_list;
+ CamelContentType *content_type;
+ CamelMimePart *mime_part;
EAttachment *attachment;
- CamelException ex;
+ GPtrArray *array;
+ GList *selection;
+ gchar *basename;
+ gchar *filename;
+ gchar *dirname;
+ GFile *file;
+ gint index;
+ GError *error = NULL;
+
+ icon_list = GNOME_ICON_LIST (attachment_bar);
+ selection = gnome_icon_list_get_selection (icon_list);
+ g_return_if_fail (selection != NULL);
+
+ array = attachment_bar->priv->attachments;
+ index = GPOINTER_TO_INT (selection->data);
+ attachment = E_ATTACHMENT (array->pdata[index]);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+ content_type = camel_mime_part_get_content_type (mime_part);
+ basename = g_strdup (camel_mime_part_get_filename (mime_part));
+
+ if (basename == NULL || basename == '\0') {
+ g_free (basename);
+ basename = g_strdup_printf (
+ _("untitled_image.%s"),
+ content_type->subtype);
+ }
- camel_exception_init (&ex);
+ dirname = g_build_filename (
+ g_get_home_dir (), ".gnome2", "wallpapers", NULL);
- if ((attachment = e_attachment_new (file_name, disposition, &ex))) {
- add_common (bar, attachment);
- } else {
- /* FIXME: Avoid using error from mailer */
- e_error_run ((GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar), "mail-composer:no-attach",
- file_name, camel_exception_get_description (&ex), NULL);
- camel_exception_clear (&ex);
+ index = 0;
+ filename = g_build_filename (dirname, basename, NULL);
+
+ while (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ gchar *temp;
+ gchar *ext;
+
+ ext = strrchr (filename, '.');
+ if (ext != NULL)
+ *ext++ = '\0';
+
+ if (ext == NULL)
+ temp = g_strdup_printf (
+ "%s (%d)", basename, index++);
+ else
+ temp = g_strdup_printf (
+ "%s (%d).%s", basename, index++, ext);
+
+ g_free (basename);
+ g_free (filename);
+ basename = temp;
+
+ filename = g_build_filename (dirname, basename, NULL);
+ }
+
+ g_free (basename);
+ g_free (dirname);
+
+ file = g_file_new_for_path (filename);
+
+ if (e_mime_part_utils_save_to_file (mime_part, file, &error)) {
+ const gchar *background_filename;
+ const gchar *background_options;
+
+ background_filename =
+ e_attachment_bar_get_background_filename (
+ attachment_bar);
+ background_options =
+ e_attachment_bar_get_background_options (
+ attachment_bar);
+
+ if (g_strcmp0 (background_filename, filename) == 0)
+ e_attachment_bar_set_background_filename (
+ attachment_bar, NULL);
+
+ e_attachment_bar_set_background_filename (
+ attachment_bar, filename);
+
+ if (g_strcmp0 (background_options, "none") == 0)
+ e_attachment_bar_set_background_options (
+ attachment_bar, "wallpaper");
+ }
+
+ g_object_unref (file);
+ g_free (filename);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static GtkActionEntry standard_entries[] = {
+
+ { "save-as",
+ GTK_STOCK_SAVE_AS,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_save_as_cb) },
+
+ { "set-background",
+ NULL,
+ N_("Set as _Background"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_set_background_cb) }
+};
+
+static GtkActionEntry editable_entries[] = {
+
+ { "add",
+ GTK_STOCK_ADD,
+ N_("A_dd Attachment..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_add_cb) },
+
+ { "properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_properties_cb) },
+
+ { "remove",
+ GTK_STOCK_REMOVE,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_remove_cb) }
+};
+
+static void
+attachment_bar_show_popup_menu (EAttachmentBar *attachment_bar,
+ GdkEventButton *event)
+{
+ GtkUIManager *ui_manager;
+ GtkWidget *menu;
+
+ ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
+ menu = gtk_ui_manager_get_widget (ui_manager, "/attachment-popup");
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ e_attachment_bar_update_actions (attachment_bar);
+
+ if (event != NULL)
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+ else
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL,
+ 0, gtk_get_current_event_time ());
+}
+
+/* Attachment handling functions. */
+
+static void
+attachment_destroy (EAttachmentBar *bar,
+ EAttachment *attachment)
+{
+ if (bar->priv->batch_unref)
+ return;
+
+ if (g_ptr_array_remove (bar->priv->attachments, attachment)) {
+ e_attachment_bar_refresh (bar);
+ g_signal_emit (bar, signals[CHANGED], 0);
}
}
@@ -161,6 +498,7 @@ get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type)
{
GdkPixbuf *pixbuf = NULL;
#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
+ CamelMimePart *mime_part;
struct stat file_stat;
char *file_uri = NULL;
gboolean is_tmp = FALSE;
@@ -168,9 +506,11 @@ get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type)
if (!attachment || !attachment->is_available_local)
return NULL;
+ mime_part = e_attachment_get_mime_part (attachment);
+
if (attachment->store_uri && g_str_has_prefix (attachment->store_uri, "file://"))
file_uri = attachment->store_uri;
- else if (attachment->body) {
+ else if (mime_part != NULL) {
/* save part to the temp directory */
char *tmp_file;
@@ -182,7 +522,7 @@ get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type)
char *mfilename = NULL;
const char * filename;
- filename = camel_mime_part_get_filename (attachment->body);
+ filename = camel_mime_part_get_filename (mime_part);
if (filename == NULL)
filename = "unknown";
else {
@@ -202,7 +542,7 @@ get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type)
if (stream) {
CamelDataWrapper *content;
- content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
+ content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
if (camel_data_wrapper_decode_to_stream (content, stream) == -1
|| camel_stream_flush (stream) == -1) {
@@ -298,17 +638,24 @@ scale_pixbuf (GdkPixbuf *pixbuf)
/* Icon list contents handling. */
static void
-calculate_height_width(EAttachmentBar *bar, int *new_width, int *new_height)
+calculate_height_width (EAttachmentBar *bar,
+ gint *new_width,
+ gint *new_height)
{
int width, height, icon_width;
PangoFontMetrics *metrics;
PangoContext *context;
- context = gtk_widget_get_pango_context ((GtkWidget *) bar);
- metrics = pango_context_get_metrics (context, ((GtkWidget *) bar)->style->font_desc, pango_context_get_language (context));
- width = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width (metrics)) * 15;
+ context = gtk_widget_get_pango_context (GTK_WIDGET (bar));
+ metrics = pango_context_get_metrics (
+ context, GTK_WIDGET (bar)->style->font_desc,
+ pango_context_get_language (context));
+ width = PANGO_PIXELS (
+ pango_font_metrics_get_approximate_char_width (metrics)) * 15;
/* This should be *2, but the icon list creates too much space above ... */
- height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) * 3;
+ height = PANGO_PIXELS (
+ pango_font_metrics_get_ascent (metrics) +
+ pango_font_metrics_get_descent (metrics)) * 3;
pango_font_metrics_unref (metrics);
icon_width = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING;
@@ -316,21 +663,23 @@ calculate_height_width(EAttachmentBar *bar, int *new_width, int *new_height)
*new_width = MAX (icon_width, width);
if (new_height)
- *new_height = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING + height;
-
- return;
+ *new_height = ICON_WIDTH + ICON_SPACING +
+ ICON_BORDER + ICON_TEXT_SPACING + height;
}
void
e_attachment_bar_create_attachment_cache (EAttachment *attachment)
{
-
CamelContentType *content_type;
+ CamelMimePart *mime_part;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
- if (!attachment->body)
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part == NULL)
return;
- content_type = camel_mime_part_get_content_type (attachment->body);
+ content_type = camel_mime_part_get_content_type (mime_part);
if (camel_content_type_is(content_type, "image", "*")) {
CamelDataWrapper *wrapper;
@@ -339,7 +688,7 @@ e_attachment_bar_create_attachment_cache (EAttachment *attachment)
gboolean error = TRUE;
GdkPixbuf *pixbuf;
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
mstream = (CamelStreamMem *) camel_stream_mem_new ();
camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
@@ -350,12 +699,15 @@ e_attachment_bar_create_attachment_cache (EAttachment *attachment)
gdk_pixbuf_loader_close (loader, NULL);
if (!error) {
+ /* The loader owns the reference. */
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
- attachment->pixbuf_cache = scale_pixbuf (pixbuf);
- pixbuf = attachment->pixbuf_cache;
- g_object_ref(pixbuf);
+
+ /* This returns a new GdkPixbuf. */
+ pixbuf = scale_pixbuf (pixbuf);
+ e_attachment_set_thumbnail (attachment, pixbuf);
+ g_object_unref (pixbuf);
} else {
- attachment->pixbuf_cache = NULL;
+ e_attachment_set_thumbnail (attachment, NULL);
g_warning ("GdkPixbufLoader Error");
}
@@ -366,244 +718,40 @@ e_attachment_bar_create_attachment_cache (EAttachment *attachment)
}
static void
-update (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- GnomeIconList *icon_list;
- int bar_width, bar_height;
- int i;
-
- priv = bar->priv;
- icon_list = GNOME_ICON_LIST (bar);
-
- gnome_icon_list_freeze (icon_list);
-
- gnome_icon_list_clear (icon_list);
-
- /* FIXME could be faster, but we don't care. */
- for (i = 0; i < priv->attachments->len; i++) {
- EAttachment *attachment;
- CamelContentType *content_type;
- char *size_string, *label;
- GdkPixbuf *pixbuf = NULL;
- const char *desc;
-
- attachment = priv->attachments->pdata[i];
-
- if (!attachment->is_available_local || !attachment->body) {
- if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) {
- attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, "");
- g_object_unref (pixbuf);
- }
- continue;
- }
-
- content_type = camel_mime_part_get_content_type (attachment->body);
- /* Get the image out of the attachment
- and create a thumbnail for it */
- if ((pixbuf = attachment->pixbuf_cache)) {
- g_object_ref(pixbuf);
- } else if (camel_content_type_is(content_type, "image", "*")) {
- CamelDataWrapper *wrapper;
- CamelStreamMem *mstream;
- GdkPixbufLoader *loader;
- gboolean error = TRUE;
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
- mstream = (CamelStreamMem *) camel_stream_mem_new ();
-
- camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
-
- /* Stream image into pixbuf loader */
- loader = gdk_pixbuf_loader_new ();
- error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
- gdk_pixbuf_loader_close (loader, NULL);
-
- if (!error) {
- pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
- attachment->pixbuf_cache = scale_pixbuf (pixbuf);
- pixbuf = attachment->pixbuf_cache;
- g_object_ref (pixbuf);
- } else {
- pixbuf = NULL;
- g_warning ("GdkPixbufLoader Error");
- }
-
- /* Destroy everything */
- g_object_unref (loader);
- camel_object_unref (mstream);
- } else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) {
- attachment->pixbuf_cache = scale_pixbuf (pixbuf);
- pixbuf = attachment->pixbuf_cache;
- g_object_ref (pixbuf);
- }
-
- desc = camel_mime_part_get_description (attachment->body);
- if (!desc || *desc == '\0') {
- if (attachment->file_name)
- desc = attachment->file_name;
- else
- desc = camel_mime_part_get_filename (attachment->body);
- }
-
- if (!desc)
- desc = _("attachment");
-
- if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) {
- label = g_strdup_printf ("%s (%s)", desc, size_string);
- g_free (size_string);
- } else
- label = g_strdup (desc);
-
- if (pixbuf == NULL) {
- char *mime_type;
-
- mime_type = camel_content_type_simple (content_type);
- pixbuf = e_icon_for_mime_type (mime_type, 48);
- if (pixbuf == NULL) {
- g_warning("cannot find icon for mime type %s (installation problem?)", mime_type);
- pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG);
- }
- g_free (mime_type);
-
- /* remember this picture and use it later again */
- if (pixbuf)
- attachment->pixbuf_cache = g_object_ref (pixbuf);
- }
-
- if (pixbuf) {
- GdkPixbuf *pixbuf_orig = pixbuf;
- pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255);
-
- /* gdk_pixbuf_add_alpha returns a newly allocated pixbuf,
- free the original one.
- */
- g_object_unref (pixbuf_orig);
-
- /* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/
- if (attachment->sign) {
- /* Show the signature status at the right-bottom.*/
- GdkPixbuf *sign = NULL;
- int x, y;
-
- if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD)
- sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU);
- else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD)
- sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU);
- else
- sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU);
-
- x = gdk_pixbuf_get_width (pixbuf) - 17;
- y = gdk_pixbuf_get_height (pixbuf) - 17;
-
- gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y);
- g_object_unref (sign);
- }
-
- if (attachment->encrypt) {
- /* Show the encryption status at the top left.*/
- GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU);
-
- gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1);
- g_object_unref (encrypt);
- }
-
- gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label);
- g_object_unref (pixbuf);
- }
-
- g_free (label);
- }
-
- gnome_icon_list_thaw (icon_list);
-
- /* Resize */
- if (bar->expand) {
- gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height);
-
- if (bar->priv->attachments->len) {
- int per_col, rows, height, width;
-
- calculate_height_width(bar, &width, &height);
- per_col = bar_width / width;
- per_col = (per_col ? per_col : 1);
- rows = (bar->priv->attachments->len + per_col -1) / per_col;
- gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height);
- }
- }
-}
-
-static void
update_remote_file (EAttachment *attachment, EAttachmentBar *bar)
{
GnomeIconList *icon_list;
GnomeIconTextItem *item;
+ const gchar *filename;
char *msg, *base;
if (attachment->percentage == -1) {
- update (bar);
+ e_attachment_bar_refresh (bar);
return;
}
- base = g_path_get_basename(attachment->file_name);
- msg = g_strdup_printf("%s (%d%%)", base, attachment->percentage);
- g_free(base);
+ filename = e_attachment_get_filename (attachment);
+ base = g_path_get_basename (filename);
+ msg = g_strdup_printf ("%s (%d%%)", base, attachment->percentage);
+ g_free (base);
icon_list = GNOME_ICON_LIST (bar);
gnome_icon_list_freeze (icon_list);
- item = gnome_icon_list_get_icon_text_item (icon_list, attachment->index);
+ item = gnome_icon_list_get_icon_text_item (
+ icon_list, attachment->index);
if (!item->is_text_allocated)
g_free (item->text);
- gnome_icon_text_item_configure (item, item->x, item->y, item->width, item->fontname, msg, item->is_editable, TRUE);
+ gnome_icon_text_item_configure (
+ item, item->x, item->y, item->width,
+ item->fontname, msg, item->is_editable, TRUE);
gnome_icon_list_thaw (icon_list);
}
void
-e_attachment_bar_remove_selected (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- int id, left, nrem = 0;
- GList *items;
- GPtrArray *temp_arr;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- priv = bar->priv;
-
- if (!(items = gnome_icon_list_get_selection ((GnomeIconList *) bar)))
- return;
-
- temp_arr = g_ptr_array_new ();
- while (items != NULL) {
- if ((id = GPOINTER_TO_INT (items->data) - nrem) < priv->attachments->len) {
- attachment = E_ATTACHMENT(g_ptr_array_index (priv->attachments, id));
- g_ptr_array_add (temp_arr, (gpointer)attachment);
- g_ptr_array_remove_index (priv->attachments, id);
- nrem++;
- }
-
- items = items->next;
- }
-
- g_ptr_array_foreach (temp_arr, (GFunc)g_object_unref, NULL);
- g_ptr_array_free (temp_arr, TRUE);
-
- update (bar);
-
- g_signal_emit (bar, signals[CHANGED], 0);
-
- id++;
-
- if ((left = gnome_icon_list_get_num_icons ((GnomeIconList *) bar)) > 0)
- gnome_icon_list_focus_icon ((GnomeIconList *) bar, left > id ? id : left - 1);
-}
-
-void
e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width)
{
int per_col, rows, height, width;
@@ -615,37 +763,6 @@ e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width)
gtk_widget_set_size_request ((GtkWidget *)bar, bar_width, rows * height);
}
-void
-e_attachment_bar_edit_selected (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- GList *items;
- int id;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- priv = bar->priv;
-
- items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
- while (items != NULL) {
- if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
- attachment = priv->attachments->pdata[id];
- e_attachment_edit (attachment, GTK_WIDGET (bar));
- }
-
- items = items->next;
- }
-}
-
-GtkWidget **
-e_attachment_bar_get_selector(EAttachmentBar *bar)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- return &bar->priv->attach;
-}
-
/**
* e_attachment_bar_get_selected:
* @bar: an #EAttachmentBar object
@@ -656,7 +773,7 @@ e_attachment_bar_get_selector(EAttachmentBar *bar)
GSList *
e_attachment_bar_get_selected (EAttachmentBar *bar)
{
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
GSList *attachments = NULL;
EAttachment *attachment;
GList *items;
@@ -696,7 +813,7 @@ e_attachment_bar_get_selected (EAttachmentBar *bar)
GSList *
e_attachment_bar_get_attachment (EAttachmentBar *bar, int id)
{
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
EAttachment *attachment;
GSList *attachments;
@@ -724,7 +841,7 @@ e_attachment_bar_get_attachment (EAttachmentBar *bar, int id)
GSList *
e_attachment_bar_get_all_attachments (EAttachmentBar *bar)
{
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
GSList *attachments = NULL;
EAttachment *attachment;
int i;
@@ -748,7 +865,7 @@ e_attachment_bar_get_all_attachments (EAttachmentBar *bar)
GSList *
e_attachment_bar_get_parts (EAttachmentBar *bar)
{
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
EAttachment *attachment;
GSList *parts = NULL;
int i;
@@ -758,50 +875,22 @@ e_attachment_bar_get_parts (EAttachmentBar *bar)
priv = bar->priv;
for (i = 0; i < priv->attachments->len; i++) {
+ CamelMimePart *mime_part;
+
attachment = priv->attachments->pdata[i];
+ mime_part = e_attachment_get_mime_part (attachment);
+
if (attachment->is_available_local)
- parts = g_slist_prepend (parts, attachment->body);
+ parts = g_slist_prepend (parts, mime_part);
}
return parts;
}
-/* GtkObject methods. */
-
-static void
-destroy (GtkObject *object)
-{
- EAttachmentBar *bar = (EAttachmentBar *) object;
- struct _EAttachmentBarPrivate *priv = bar->priv;
- EAttachment *attachment;
- int i;
-
- if ((priv = bar->priv)) {
- priv->batch_unref = TRUE;
- for (i = 0; i < priv->attachments->len; i++) {
- attachment = priv->attachments->pdata[i];
- g_object_weak_unref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
- g_object_unref (attachment);
- }
- g_ptr_array_free (priv->attachments, TRUE);
-
- if (priv->attach)
- gtk_widget_destroy (priv->attach);
-
- if (priv->path)
- g_free (priv->path);
-
- g_free (priv);
- bar->priv = NULL;
- }
-
- if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
- (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
-}
-
static char *
-temp_save_part (CamelMimePart *part, gboolean readonly)
+temp_save_part (EAttachment *attachment, gboolean readonly)
{
+ CamelMimePart *mime_part;
const char *filename;
char *tmpdir, *path, *mfilename = NULL, *utf8_mfilename = NULL;
CamelStream *stream;
@@ -810,7 +899,9 @@ temp_save_part (CamelMimePart *part, gboolean readonly)
if (!(tmpdir = e_mkdtemp ("evolution-tmp-XXXXXX")))
return NULL;
- if (!(filename = camel_mime_part_get_filename (part))) {
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ if (!(filename = camel_mime_part_get_filename (mime_part))) {
/* This is the default filename used for temporary file creation */
filename = _("Unknown");
} else {
@@ -825,7 +916,7 @@ temp_save_part (CamelMimePart *part, gboolean readonly)
g_free (tmpdir);
g_free (mfilename);
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
if (readonly)
stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0444);
else
@@ -853,9 +944,344 @@ temp_save_part (CamelMimePart *part, gboolean readonly)
}
static void
-eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *data, guint info, guint time)
+attachment_bar_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKGROUND_FILENAME:
+ e_attachment_bar_set_background_filename (
+ E_ATTACHMENT_BAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_BACKGROUND_OPTIONS:
+ e_attachment_bar_set_background_options (
+ E_ATTACHMENT_BAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_CURRENT_FOLDER:
+ e_attachment_bar_set_current_folder (
+ E_ATTACHMENT_BAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_EDITABLE:
+ e_attachment_bar_set_editable (
+ E_ATTACHMENT_BAR (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_bar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKGROUND_FILENAME:
+ g_value_set_string (
+ value,
+ e_attachment_bar_get_background_filename (
+ E_ATTACHMENT_BAR (object)));
+ return;
+
+ case PROP_BACKGROUND_OPTIONS:
+ g_value_set_string (
+ value,
+ e_attachment_bar_get_background_options (
+ E_ATTACHMENT_BAR (object)));
+ return;
+
+ case PROP_CURRENT_FOLDER:
+ g_value_set_string (
+ value,
+ e_attachment_bar_get_current_folder (
+ E_ATTACHMENT_BAR (object)));
+ return;
+
+ case PROP_EDITABLE:
+ g_value_set_boolean (
+ value,
+ e_attachment_bar_get_editable (
+ E_ATTACHMENT_BAR (object)));
+ return;
+
+ case PROP_UI_MANAGER:
+ g_value_set_object (
+ value,
+ e_attachment_bar_get_ui_manager (
+ E_ATTACHMENT_BAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_bar_dispose (GObject *object)
+{
+ EAttachmentBarPrivate *priv;
+ guint ii;
+
+ priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
+
+ priv->batch_unref = TRUE;
+
+ for (ii = 0; ii < priv->attachments->len; ii++) {
+ EAttachment *attachment;
+
+ attachment = priv->attachments->pdata[ii];
+ g_object_weak_unref (
+ G_OBJECT (attachment), (GWeakNotify)
+ attachment_destroy, object);
+ g_object_unref (attachment);
+ }
+ g_ptr_array_set_size (priv->attachments, 0);
+
+ if (priv->ui_manager != NULL) {
+ g_object_unref (priv->ui_manager);
+ priv->ui_manager = NULL;
+ }
+
+ if (priv->standard_actions != NULL) {
+ g_object_unref (priv->standard_actions);
+ priv->standard_actions = NULL;
+ }
+
+ if (priv->editable_actions != NULL) {
+ g_object_unref (priv->editable_actions);
+ priv->editable_actions = NULL;
+ }
+
+ if (priv->open_actions != NULL) {
+ g_object_unref (priv->open_actions);
+ priv->open_actions = NULL;
+ }
+
+ /* Chain up to parent's dipose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_bar_finalize (GObject *object)
+{
+ EAttachmentBarPrivate *priv;
+
+ priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
+
+ g_ptr_array_free (priv->attachments, TRUE);
+ g_free (priv->current_folder);
+ g_free (priv->path);
+
+ g_free (priv->background_filename);
+ g_free (priv->background_options);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_bar_constructed (GObject *object)
+{
+ EAttachmentBarPrivate *priv;
+ GtkActionGroup *action_group;
+ GConfBridge *bridge;
+ const gchar *prop;
+ const gchar *key;
+
+ priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
+ action_group = priv->editable_actions;
+ bridge = gconf_bridge_get ();
+
+ e_mutual_binding_new (
+ G_OBJECT (object), "editable",
+ G_OBJECT (action_group), "visible");
+
+ prop = "background-filename";
+ key = "/desktop/gnome/background/picture_filename";
+ gconf_bridge_bind_property (bridge, key, object, prop);
+
+ prop = "background-options";
+ key = "/desktop/gnome/background/picture_options";
+ gconf_bridge_bind_property (bridge, key, object, prop);
+}
+
+static gboolean
+attachment_bar_event (GtkWidget *widget,
+ GdkEvent *event)
{
- struct _EAttachmentBarPrivate *priv = bar->priv;
+ EAttachment *attachment;
+ gboolean ret = FALSE;
+ gpointer parent;
+ CamelURL *url;
+ char *path;
+ GSList *p;
+
+ if (event->type != GDK_2BUTTON_PRESS)
+ return FALSE;
+
+ parent = gtk_widget_get_toplevel (widget);
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ p = e_attachment_bar_get_selected (E_ATTACHMENT_BAR (widget));
+ /* check if has body already, remote files can take longer to fetch */
+ if (p && p->next == NULL && e_attachment_get_mime_part (p->data) != NULL) {
+ attachment = p->data;
+
+ /* Check if the file is stored already */
+ if (!attachment->store_uri) {
+ path = temp_save_part (attachment, TRUE);
+ url = camel_url_new ("file://", NULL);
+ camel_url_set_path (url, path);
+ attachment->store_uri = camel_url_to_string (url, 0);
+ camel_url_free (url);
+ g_free (path);
+ }
+
+ e_show_uri (parent, attachment->store_uri);
+
+ ret = TRUE;
+ }
+
+ g_slist_foreach (p, (GFunc) g_object_unref, NULL);
+ g_slist_free (p);
+
+ return ret;
+}
+
+static gboolean
+attachment_bar_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GnomeIconList *icon_list;
+ GList *selected, *tmp;
+ int length, icon_number;
+ gboolean take_selected = FALSE;
+
+ GtkTargetEntry drag_types[] = {
+ { "text/uri-list", 0, 0 },
+ };
+
+ icon_list = GNOME_ICON_LIST (widget);
+ selected = gnome_icon_list_get_selection (icon_list);
+ length = g_list_length (selected);
+
+ icon_number = gnome_icon_list_get_icon_at (
+ icon_list, event->x, event->y);
+ if (icon_number < 0) {
+ /* When nothing is selected, deselect all */
+ gnome_icon_list_unselect_all (icon_list);
+ length = 0;
+ selected = NULL;
+ }
+
+ if (event->button == 1) {
+ /* If something is selected, then allow drag or else help to select */
+ if (length)
+ gtk_drag_source_set (
+ widget, GDK_BUTTON1_MASK, drag_types,
+ G_N_ELEMENTS (drag_types), GDK_ACTION_COPY);
+ else
+ gtk_drag_source_unset (widget);
+ goto exit;
+ }
+
+ /* If not r-click dont progress any more.*/
+ if (event->button != 3)
+ goto exit;
+
+ /* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things
+ * or deselect all and select only this for r-click
+ */
+ if (icon_number >= 0) {
+ for (tmp = selected; tmp; tmp = tmp->next) {
+ if (GPOINTER_TO_INT (tmp->data) == icon_number)
+ take_selected = TRUE;
+ }
+
+ if (!take_selected) {
+ gnome_icon_list_unselect_all (icon_list);
+ gnome_icon_list_select_icon (icon_list, icon_number);
+ }
+ }
+
+ attachment_bar_show_popup_menu (E_ATTACHMENT_BAR (widget), event);
+
+exit:
+ /* Chain up to parent's button_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ button_press_event (widget, event);
+}
+
+static gboolean
+attachment_bar_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GnomeIconList *icon_list;
+ GList *selected;
+
+ GtkTargetEntry drag_types[] = {
+ { "text/uri-list", 0, 0 },
+ };
+
+ if (event->button != 1)
+ goto exit;
+
+ icon_list = GNOME_ICON_LIST (widget);
+ selected = gnome_icon_list_get_selection (icon_list);
+
+ if (selected != NULL)
+ gtk_drag_source_set (
+ widget, GDK_BUTTON1_MASK, drag_types,
+ G_N_ELEMENTS (drag_types), GDK_ACTION_COPY);
+ else
+ gtk_drag_source_unset (widget);
+
+exit:
+ /* Chain up to parent's button_release_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ button_release_event (widget, event);
+}
+
+static gboolean
+attachment_bar_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ EAttachmentBar *attachment_bar;
+ gboolean editable;
+
+ attachment_bar = E_ATTACHMENT_BAR (widget);
+ editable = e_attachment_bar_get_editable (attachment_bar);
+
+ if (editable && event->keyval == GDK_Delete) {
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ action_group = attachment_bar->priv->editable_actions;
+ action = gtk_action_group_get_action (action_group, "remove");
+ gtk_action_activate (action);
+ }
+
+ /* Chain up to parent's key_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ key_press_event (widget, event);
+}
+
+static void
+attachment_bar_drag_data_get (GtkWidget *widget,
+ GdkDragContext *drag,
+ GtkSelectionData *data,
+ guint info,
+ guint time)
+{
+ EAttachmentBarPrivate *priv;
EAttachment *attachment;
char *path, **uris;
int len, n, i = 0;
@@ -865,7 +1291,8 @@ eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *d
if (info)
return;
- items = gnome_icon_list_get_selection (GNOME_ICON_LIST (bar));
+ priv = E_ATTACHMENT_BAR_GET_PRIVATE (widget);
+ items = gnome_icon_list_get_selection (GNOME_ICON_LIST (widget));
len = g_list_length (items);
uris = g_malloc0 (sizeof (char *) * (len + 1));
@@ -885,7 +1312,7 @@ eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *d
}
/* If we are not able to save, ignore it */
- if (!(path = temp_save_part (attachment->body, FALSE)))
+ if (!(path = temp_save_part (attachment, FALSE)))
continue;
url = camel_url_new ("file://", NULL);
@@ -902,227 +1329,280 @@ eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *d
gtk_selection_data_set_uris (data, uris);
g_free (uris);
-
- return;
}
static gboolean
-eab_button_release_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
+attachment_bar_popup_menu (GtkWidget *widget)
{
- GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
- GList *selected;
- int length;
- GtkTargetEntry drag_types[] = {
- { "text/uri-list", 0, 0 },
- };
-
- if (event && event->button == 1) {
- selected = gnome_icon_list_get_selection(icon_list);
- length = g_list_length (selected);
- if (length)
- gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
- else
- gtk_drag_source_unset((GtkWidget *)bar);
- }
+ attachment_bar_show_popup_menu (E_ATTACHMENT_BAR (widget), NULL);
- return FALSE;
+ return TRUE;
}
-static gboolean
-eab_button_press_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
+static void
+attachment_bar_update_actions (EAttachmentBar *attachment_bar)
{
- GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
- GList *selected = NULL, *tmp;
- int length, icon_number;
- gboolean take_selected = FALSE;
- GtkTargetEntry drag_types[] = {
- { "text/uri-list", 0, 0 },
- };
+ GnomeIconList *icon_list;
+ CamelMimePart *mime_part;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GList *selection;
+ guint n_selected;
+ gboolean is_image;
+ gpointer parent;
+ guint merge_id;
- selected = gnome_icon_list_get_selection(icon_list);
- length = g_list_length (selected);
+ icon_list = GNOME_ICON_LIST (attachment_bar);
+ selection = gnome_icon_list_get_selection (icon_list);
+ n_selected = g_list_length (selection);
- if (event) {
- icon_number = gnome_icon_list_get_icon_at(icon_list, event->x, event->y);
- if (icon_number < 0) {
- /* When nothing is selected, deselect all */
- gnome_icon_list_unselect_all (icon_list);
- length = 0;
- selected = NULL;
- }
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (attachment_bar));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
- if (event->button == 1) {
- /* If something is selected, then allow drag or else help to select */
- if (length)
- gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
- else
- gtk_drag_source_unset((GtkWidget *)bar);
- return FALSE;
- }
+ is_image = FALSE;
+ mime_part = NULL;
- /* If not r-click dont progress any more.*/
- if (event->button != 3)
- return FALSE;
-
- /* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things
- * or deselect all and select only this for r-click
- */
- if (icon_number >= 0) {
- for (tmp = selected; tmp; tmp = tmp->next) {
- if (GPOINTER_TO_INT(tmp->data) == icon_number)
- take_selected = TRUE;
- }
+ if (n_selected == 1) {
+ GPtrArray *array;
+ EAttachment *attachment;
+ gint index;
- if (!take_selected) {
- gnome_icon_list_unselect_all(icon_list);
- gnome_icon_list_select_icon(icon_list, icon_number);
- }
- }
+ array = attachment_bar->priv->attachments;
+ index = GPOINTER_TO_INT (selection->data);
+ attachment = E_ATTACHMENT (array->pdata[index]);
+ mime_part = e_attachment_get_mime_part (attachment);
+ is_image = e_attachment_is_image (attachment);
}
- return FALSE;
-}
-
-static gboolean
-eab_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, gpointer *dummy)
-{
- EAttachment *attachment;
- gboolean ret = FALSE;
- CamelURL *url;
- char *path;
- GSList *p;
-
- if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS) {
- p = e_attachment_bar_get_selected (bar);
- /* check if has body already, remote files can take longer to fetch */
- if (p && p->next == NULL && ((EAttachment *)p->data)->body) {
- attachment = p->data;
-
- /* Check if the file is stored already */
- if (!attachment->store_uri) {
- path = temp_save_part (attachment->body, TRUE);
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, path);
- attachment->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
- g_free (path);
- }
+ ui_manager = e_attachment_bar_get_ui_manager (attachment_bar);
- /* FIXME Pass a parent window. */
- e_show_uri (NULL, attachment->store_uri);
+ action_group = attachment_bar->priv->standard_actions;
- ret = TRUE;
- }
+ action = gtk_action_group_get_action (action_group, "save-as");
+ gtk_action_set_visible (action, n_selected > 0);
- if (p) {
- g_slist_foreach (p, (GFunc) g_object_unref, NULL);
- g_slist_free (p);
- }
- }
+ action = gtk_action_group_get_action (action_group, "set-background");
+ gtk_action_set_visible (action, is_image);
- return ret;
-}
+ action_group = attachment_bar->priv->editable_actions;
-/* Initialization. */
+ action = gtk_action_group_get_action (action_group, "properties");
+ gtk_action_set_visible (action, n_selected == 1);
-static void
-class_init (EAttachmentBarClass *klass)
-{
- GtkObjectClass *object_class;
+ action = gtk_action_group_get_action (action_group, "remove");
+ gtk_action_set_visible (action, n_selected > 0);
- object_class = GTK_OBJECT_CLASS (klass);
+ action_group = attachment_bar->priv->open_actions;
- parent_class = g_type_class_ref (gnome_icon_list_get_type ());
+ merge_id = attachment_bar->priv->merge_id;
+ gtk_ui_manager_remove_ui (ui_manager, merge_id);
+ e_action_group_remove_all_actions (action_group);
- object_class->destroy = destroy;
+ if (mime_part == NULL)
+ return;
- /* Setup signals. */
+ e_mime_part_utils_add_open_actions (
+ mime_part, ui_manager, action_group,
+ "/attachment-popup/open-actions", parent, merge_id);
+}
- signals[CHANGED] =
- g_signal_new ("changed",
- E_TYPE_ATTACHMENT_BAR,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EAttachmentBarClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+static void
+attachment_bar_class_init (EAttachmentBarClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentBarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = attachment_bar_set_property;
+ object_class->get_property = attachment_bar_get_property;
+ object_class->dispose = attachment_bar_dispose;
+ object_class->finalize = attachment_bar_finalize;
+ object_class->constructed = attachment_bar_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->event = attachment_bar_event;
+ widget_class->button_press_event = attachment_bar_button_press_event;
+ widget_class->button_release_event = attachment_bar_button_release_event;
+ widget_class->key_press_event = attachment_bar_key_press_event;
+ widget_class->drag_data_get = attachment_bar_drag_data_get;
+ widget_class->popup_menu = attachment_bar_popup_menu;
+
+ class->update_actions = attachment_bar_update_actions;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKGROUND_FILENAME,
+ g_param_spec_string (
+ "background-filename",
+ "Background Filename",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKGROUND_OPTIONS,
+ g_param_spec_string (
+ "background-options",
+ "Background Options",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURRENT_FOLDER,
+ g_param_spec_string (
+ "current-folder",
+ "Current Folder",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EDITABLE,
+ g_param_spec_boolean (
+ "editable",
+ "Editable",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_UI_MANAGER,
+ g_param_spec_object (
+ "ui-manager",
+ "UI Manager",
+ NULL,
+ GTK_TYPE_UI_MANAGER,
+ G_PARAM_READABLE));
+
+ signals[CHANGED] = g_signal_new (
+ "changed",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentBarClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[UPDATE_ACTIONS] = g_signal_new (
+ "update-actions",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EAttachmentBarClass, update_actions),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
-init (EAttachmentBar *bar)
+attachment_bar_init (EAttachmentBar *bar)
{
- struct _EAttachmentBarPrivate *priv;
+ GnomeIconList *icon_list;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ gint icon_width, window_height;
+ const gchar *domain = GETTEXT_PACKAGE;
+ GError *error = NULL;
+
+ bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar);
+ bar->priv->attachments = g_ptr_array_new ();
+
+ GTK_WIDGET_SET_FLAGS (bar, GTK_CAN_FOCUS);
+
+ icon_list = GNOME_ICON_LIST (bar);
- priv = g_new (struct _EAttachmentBarPrivate, 1);
+ calculate_height_width (bar, &icon_width, &window_height);
+ gnome_icon_list_construct (icon_list, icon_width, NULL, 0);
- priv->attach = NULL;
- priv->batch_unref = FALSE;
- priv->attachments = g_ptr_array_new ();
+ gtk_widget_set_size_request (
+ GTK_WIDGET (bar), icon_width * 4, window_height);
- priv->path = NULL;
+ atk_object_set_name (
+ gtk_widget_get_accessible (GTK_WIDGET (bar)),
+ _("Attachment Bar"));
- bar->priv = priv;
- bar->expand = FALSE;
+ gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
+ gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
+ gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
+ gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
+ gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
+ gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
+
+ ui_manager = gtk_ui_manager_new ();
+ bar->priv->ui_manager = ui_manager;
+ bar->priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
+
+ action_group = gtk_action_group_new ("standard");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, standard_entries,
+ G_N_ELEMENTS (standard_entries), bar);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ bar->priv->standard_actions = action_group;
+
+ action_group = gtk_action_group_new ("editable");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, editable_entries,
+ G_N_ELEMENTS (editable_entries), bar);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ bar->priv->editable_actions = action_group;
+
+ action_group = gtk_action_group_new ("open");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ bar->priv->open_actions = action_group;
+
+ /* Because we are loading from a hard-coded string, there is
+ * no chance of I/O errors. Failure here imples a malformed
+ * UI definition. Full stop. */
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+ if (error != NULL)
+ g_error ("%s", error->message);
}
-
GType
e_attachment_bar_get_type (void)
{
static GType type = 0;
- if (type == 0) {
- static const GTypeInfo info = {
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
sizeof (EAttachmentBarClass),
- NULL, NULL,
- (GClassInitFunc) class_init,
- NULL, NULL,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_bar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
sizeof (EAttachmentBar),
- 0,
- (GInstanceInitFunc) init,
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_bar_init,
+ NULL /* value_table */
};
- type = g_type_register_static (GNOME_TYPE_ICON_LIST, "EAttachmentBar", &info, 0);
+ type = g_type_register_static (
+ GNOME_TYPE_ICON_LIST, "EAttachmentBar", &type_info, 0);
}
return type;
}
GtkWidget *
-e_attachment_bar_new (GtkAdjustment *adj)
+e_attachment_bar_new (void)
{
- EAttachmentBar *new;
- GnomeIconList *icon_list;
- int icon_width, window_height;
-
- new = g_object_new (e_attachment_bar_get_type (), NULL);
-
- icon_list = GNOME_ICON_LIST (new);
-
- calculate_height_width (new, &icon_width, &window_height);
-
- gnome_icon_list_construct (icon_list, icon_width, adj, 0);
-
- gtk_widget_set_size_request (GTK_WIDGET (new), icon_width * 4, window_height);
-
- GTK_WIDGET_SET_FLAGS (new, GTK_CAN_FOCUS);
-
- gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
- gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
- gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
- gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
- gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
- gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
-
- atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (new)),
- _("Attachment Bar"));
-
- g_signal_connect (new, "button_release_event", G_CALLBACK(eab_button_release_event), NULL);
- g_signal_connect (new, "button_press_event", G_CALLBACK(eab_button_press_event), NULL);
- g_signal_connect (new, "drag-data-get", G_CALLBACK(eab_drag_data_get), NULL);
- g_signal_connect (icon_list, "event", G_CALLBACK (eab_icon_clicked_cb), NULL);
-
- return GTK_WIDGET (new);
+ return g_object_new (E_TYPE_ATTACHMENT_BAR, NULL);
}
static char *
@@ -1159,12 +1639,14 @@ attach_to_multipart (CamelMultipart *multipart,
{
CamelContentType *content_type;
CamelDataWrapper *content;
+ CamelMimePart *mime_part;
- if (!attachment->body)
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part == NULL)
return;
- content_type = camel_mime_part_get_content_type (attachment->body);
- content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
+ content_type = camel_mime_part_get_content_type (mime_part);
+ content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
if (!CAMEL_IS_MULTIPART (content)) {
if (camel_content_type_is (content_type, "text", "*")) {
@@ -1188,7 +1670,7 @@ attach_to_multipart (CamelMultipart *multipart,
camel_object_unref (filter_stream);
encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, CAMEL_BESTENC_8BIT);
- camel_mime_part_set_encoding (attachment->body, encoding);
+ camel_mime_part_set_encoding (mime_part, encoding);
if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
/* the text fits within us-ascii so this is safe */
@@ -1207,24 +1689,26 @@ attach_to_multipart (CamelMultipart *multipart,
/* looks kinda nasty, but this is how ya have to do it */
camel_content_type_set_param (content_type, "charset", default_charset);
type = camel_content_type_format (content_type);
- camel_mime_part_set_content_type (attachment->body, type);
+ camel_mime_part_set_content_type (mime_part, type);
g_free (type);
g_free (buf);
}
camel_object_unref (bestenc);
} else if (!CAMEL_IS_MIME_MESSAGE (content)) {
- camel_mime_part_set_encoding (attachment->body, CAMEL_TRANSFER_ENCODING_BASE64);
+ camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
}
}
- camel_multipart_add_part (multipart, attachment->body);
+ camel_multipart_add_part (multipart, mime_part);
}
void
-e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart, const char *default_charset)
+e_attachment_bar_to_multipart (EAttachmentBar *bar,
+ CamelMultipart *multipart,
+ const gchar *default_charset)
{
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
EAttachment *attachment;
int i;
@@ -1249,32 +1733,73 @@ e_attachment_bar_get_num_attachments (EAttachmentBar *bar)
}
void
-e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition)
+e_attachment_bar_attach (EAttachmentBar *bar,
+ const gchar *filename,
+ const gchar *disposition)
{
+ EAttachment *attachment;
+ CamelException ex;
+
g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
- g_return_if_fail (file_name != NULL && disposition != NULL);
+ g_return_if_fail (filename != NULL);
+ g_return_if_fail (disposition != NULL);
+
+ camel_exception_init (&ex);
+
+ attachment = e_attachment_new (filename, disposition, &ex);
- add_from_file (bar, file_name, disposition);
+ if (attachment != NULL)
+ e_attachment_bar_add_attachment (bar, attachment);
+ else {
+ GtkWidget *toplevel;
+
+ /* FIXME: Avoid using error from mailer */
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (bar));
+ e_error_run (
+ GTK_WINDOW (toplevel), "mail-composer:no-attach",
+ filename, camel_exception_get_description (&ex), NULL);
+ camel_exception_clear (&ex);
+ }
}
void
-e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment)
+e_attachment_bar_add_attachment (EAttachmentBar *bar,
+ EAttachment *attachment)
{
g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_ptr_array_add (bar->priv->attachments, attachment);
- add_common (bar, attachment);
+ g_object_weak_ref (
+ G_OBJECT (attachment), (GWeakNotify)
+ attachment_destroy, bar);
+
+ g_signal_connect_swapped (
+ attachment, "changed",
+ G_CALLBACK (e_attachment_bar_refresh), bar);
+
+ e_attachment_bar_refresh (bar);
+
+ g_signal_emit (bar, signals[CHANGED], 0);
}
void
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment)
+e_attachment_bar_add_attachment_silent (EAttachmentBar *bar,
+ EAttachment *attachment)
{
g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
- g_return_if_fail (attachment != NULL);
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
g_ptr_array_add (bar->priv->attachments, attachment);
- g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
- g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
+ g_object_weak_ref (
+ G_OBJECT (attachment), (GWeakNotify)
+ attachment_destroy, bar);
+
+ g_signal_connect_swapped (
+ attachment, "changed",
+ G_CALLBACK (e_attachment_bar_refresh), bar);
g_signal_emit (bar, signals[CHANGED], 0);
}
@@ -1282,13 +1807,180 @@ e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attach
void
e_attachment_bar_refresh (EAttachmentBar *bar)
{
- update (bar);
+ EAttachmentBarPrivate *priv;
+ GnomeIconList *icon_list;
+ int bar_width, bar_height;
+ int i;
+
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+
+ priv = bar->priv;
+ icon_list = GNOME_ICON_LIST (bar);
+
+ gnome_icon_list_freeze (icon_list);
+
+ gnome_icon_list_clear (icon_list);
+
+ /* FIXME could be faster, but we don't care. */
+ for (i = 0; i < priv->attachments->len; i++) {
+ EAttachment *attachment;
+ CamelContentType *content_type;
+ CamelMimePart *mime_part;
+ char *size_string, *label;
+ GdkPixbuf *pixbuf = NULL;
+ const char *desc;
+
+ attachment = priv->attachments->pdata[i];
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ if (!attachment->is_available_local || mime_part == NULL) {
+ if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) {
+ attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, "");
+ g_object_unref (pixbuf);
+ }
+ continue;
+ }
+
+ content_type = camel_mime_part_get_content_type (mime_part);
+ /* Get the image out of the attachment
+ and create a thumbnail for it */
+ pixbuf = e_attachment_get_thumbnail (attachment);
+ if (pixbuf != NULL)
+ g_object_ref (pixbuf);
+ else if (camel_content_type_is(content_type, "image", "*")) {
+ CamelDataWrapper *wrapper;
+ CamelStreamMem *mstream;
+ GdkPixbufLoader *loader;
+ gboolean error = TRUE;
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+ mstream = (CamelStreamMem *) camel_stream_mem_new ();
+
+ camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
+
+ /* Stream image into pixbuf loader */
+ loader = gdk_pixbuf_loader_new ();
+ error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ if (!error) {
+ /* The loader owns the reference. */
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+ /* This returns a new GdkPixbuf. */
+ pixbuf = scale_pixbuf (pixbuf);
+ e_attachment_set_thumbnail (attachment, pixbuf);
+ } else {
+ pixbuf = NULL;
+ g_warning ("GdkPixbufLoader Error");
+ }
+
+ /* Destroy everything */
+ g_object_unref (loader);
+ camel_object_unref (mstream);
+ } else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) {
+ /* This returns a new GdkPixbuf. */
+ pixbuf = scale_pixbuf (pixbuf);
+ e_attachment_set_thumbnail (attachment, pixbuf);
+ }
+
+ desc = camel_mime_part_get_description (mime_part);
+ if (desc == NULL || *desc == '\0')
+ desc = e_attachment_get_filename (attachment);
+ if (desc == NULL || *desc == '\0')
+ desc = camel_mime_part_get_filename (mime_part);
+
+ if (!desc)
+ desc = _("attachment");
+
+ if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) {
+ label = g_strdup_printf ("%s (%s)", desc, size_string);
+ g_free (size_string);
+ } else
+ label = g_strdup (desc);
+
+ if (pixbuf == NULL) {
+ char *mime_type;
+
+ mime_type = camel_content_type_simple (content_type);
+ pixbuf = e_icon_for_mime_type (mime_type, 48);
+ if (pixbuf == NULL) {
+ g_warning("cannot find icon for mime type %s (installation problem?)", mime_type);
+ pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG);
+ }
+ g_free (mime_type);
+
+ /* remember this picture and use it later again */
+ if (pixbuf)
+ e_attachment_set_thumbnail (attachment, pixbuf);
+ }
+
+ if (pixbuf) {
+ GdkPixbuf *pixbuf_orig = pixbuf;
+ pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255);
+
+ /* gdk_pixbuf_add_alpha returns a newly allocated pixbuf,
+ free the original one.
+ */
+ g_object_unref (pixbuf_orig);
+
+ /* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/
+ if (attachment->sign) {
+ /* Show the signature status at the right-bottom.*/
+ GdkPixbuf *sign = NULL;
+ int x, y;
+
+ if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD)
+ sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU);
+ else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD)
+ sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU);
+ else
+ sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU);
+
+ x = gdk_pixbuf_get_width (pixbuf) - 17;
+ y = gdk_pixbuf_get_height (pixbuf) - 17;
+
+ gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y);
+ g_object_unref (sign);
+ }
+
+ if (attachment->encrypt) {
+ /* Show the encryption status at the top left.*/
+ GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU);
+
+ gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1);
+ g_object_unref (encrypt);
+ }
+
+ gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label);
+ g_object_unref (pixbuf);
+ }
+
+ g_free (label);
+ }
+
+ gnome_icon_list_thaw (icon_list);
+
+ /* Resize */
+ if (bar->expand) {
+ gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height);
+
+ if (bar->priv->attachments->len) {
+ int per_col, rows, height, width;
+
+ calculate_height_width(bar, &width, &height);
+ per_col = bar_width / width;
+ per_col = (per_col ? per_col : 1);
+ rows = (bar->priv->attachments->len + per_col -1) / per_col;
+ gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height);
+ }
+ }
}
int
e_attachment_bar_get_download_count (EAttachmentBar *bar)
{
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
EAttachment *attachment;
int i, n = 0;
@@ -1306,68 +1998,57 @@ e_attachment_bar_get_download_count (EAttachmentBar *bar)
}
void
-e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition)
+e_attachment_bar_attach_remote_file (EAttachmentBar *bar,
+ const gchar *url,
+ const gchar *disposition)
{
EAttachment *attachment;
CamelException ex;
- GtkWindow *parent;
+ GtkWidget *parent;
g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
- if (!bar->priv->path)
+ if (bar->priv->path == NULL)
bar->priv->path = e_mkdtemp ("attach-XXXXXX");
- parent = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar);
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (bar));
camel_exception_init (&ex);
- if ((attachment = e_attachment_new_remote_file (parent, url, disposition, bar->priv->path, &ex))) {
- add_common (bar, attachment);
- g_signal_connect (attachment, "update", G_CALLBACK (update_remote_file), bar);
+
+ attachment = e_attachment_new_remote_file (
+ GTK_WINDOW (parent), url, disposition, bar->priv->path, &ex);
+
+ if (attachment != NULL) {
+ e_attachment_bar_add_attachment (bar, attachment);
+ g_signal_connect (
+ attachment, "update",
+ G_CALLBACK (update_remote_file), bar);
} else {
- e_error_run (parent, "mail-composer:no-attach",
- url, camel_exception_get_description (&ex), NULL);
+ e_error_run (
+ GTK_WINDOW (parent), "mail-composer:no-attach",
+ url, camel_exception_get_description (&ex), NULL);
camel_exception_clear (&ex);
}
}
void
-e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part)
+e_attachment_bar_attach_mime_part (EAttachmentBar *bar,
+ CamelMimePart *part)
{
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- add_from_mime_part (bar, part);
-}
-
-static void
-action_recent_cb (GtkAction *action,
- EAttachmentBar *attachment_bar)
-{
- GtkRecentChooser *chooser;
- GFile *file;
- gchar *uri;
-
- chooser = GTK_RECENT_CHOOSER (action);
+ EAttachment *attachment;
- /* Wish: gtk_recent_chooser_get_current_file() */
- uri = gtk_recent_chooser_get_current_uri (chooser);
- file = g_file_new_for_uri (uri);
- g_free (uri);
+ /* XXX Is this function really worth keeping? */
- if (g_file_is_native (file))
- e_attachment_bar_attach (
- E_ATTACHMENT_BAR (attachment_bar),
- g_file_get_path (file), "attachment");
- else
- e_attachment_bar_attach_remote_file (
- E_ATTACHMENT_BAR (attachment_bar),
- g_file_get_uri (file), "attachment");
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+ g_return_if_fail (CAMEL_IS_MIME_PART (part));
- g_object_unref (file);
+ attachment = e_attachment_new_from_mime_part (part);
+ e_attachment_bar_add_attachment (bar, attachment);
}
GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar,
- const gchar *action_name,
- const gchar *action_label)
+e_attachment_bar_recent_action_new (EAttachmentBar *bar,
+ const gchar *action_name,
+ const gchar *action_label)
{
GtkAction *action;
GtkRecentChooser *chooser;
@@ -1392,3 +2073,148 @@ e_attachment_bar_recent_action_new (EAttachmentBar *bar,
return action;
}
+gint
+e_attachment_bar_file_chooser_dialog_run (EAttachmentBar *attachment_bar,
+ GtkWidget *dialog)
+{
+ GtkFileChooser *file_chooser;
+ gint response = GTK_RESPONSE_NONE;
+ const gchar *current_folder;
+ gboolean save_folder;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), response);
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), response);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog);
+ current_folder = e_attachment_bar_get_current_folder (attachment_bar);
+ gtk_file_chooser_set_current_folder (file_chooser, current_folder);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ save_folder =
+ (response == GTK_RESPONSE_ACCEPT) ||
+ (response == GTK_RESPONSE_OK) ||
+ (response == GTK_RESPONSE_YES) ||
+ (response == GTK_RESPONSE_APPLY);
+
+ if (save_folder) {
+ gchar *folder;
+
+ folder = gtk_file_chooser_get_current_folder (file_chooser);
+ e_attachment_bar_set_current_folder (attachment_bar, folder);
+ g_free (folder);
+ }
+
+ return response;
+}
+
+void
+e_attachment_bar_update_actions (EAttachmentBar *attachment_bar)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+ g_signal_emit (attachment_bar, signals[UPDATE_ACTIONS], 0);
+}
+
+const gchar *
+e_attachment_bar_get_background_filename (EAttachmentBar *attachment_bar)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
+
+ return attachment_bar->priv->background_filename;
+}
+
+void
+e_attachment_bar_set_background_filename (EAttachmentBar *attachment_bar,
+ const gchar *background_filename)
+{
+ EAttachmentBarPrivate *priv;
+
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+ if (background_filename == NULL)
+ background_filename = "";
+
+ priv = attachment_bar->priv;
+ g_free (priv->background_filename);
+ priv->background_filename = g_strdup (background_filename);
+
+ g_object_notify (G_OBJECT (attachment_bar), "background-filename");
+}
+
+const gchar *
+e_attachment_bar_get_background_options (EAttachmentBar *attachment_bar)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
+
+ return attachment_bar->priv->background_options;
+}
+
+void
+e_attachment_bar_set_background_options (EAttachmentBar *attachment_bar,
+ const gchar *background_options)
+{
+ EAttachmentBarPrivate *priv;
+
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+ if (background_options == NULL)
+ background_options = "none";
+
+ priv = attachment_bar->priv;
+ g_free (priv->background_options);
+ priv->background_options = g_strdup (background_options);
+
+ g_object_notify (G_OBJECT (attachment_bar), "background-options");
+}
+
+const gchar *
+e_attachment_bar_get_current_folder (EAttachmentBar *attachment_bar)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
+
+ return attachment_bar->priv->current_folder;
+}
+
+void
+e_attachment_bar_set_current_folder (EAttachmentBar *attachment_bar,
+ const gchar *current_folder)
+{
+
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+ if (current_folder == NULL)
+ current_folder = g_get_home_dir ();
+
+ g_free (attachment_bar->priv->current_folder);
+ attachment_bar->priv->current_folder = g_strdup (current_folder);
+
+ g_object_notify (G_OBJECT (attachment_bar), "current-folder");
+}
+
+gboolean
+e_attachment_bar_get_editable (EAttachmentBar *attachment_bar)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), FALSE);
+
+ return attachment_bar->priv->editable;
+}
+
+void
+e_attachment_bar_set_editable (EAttachmentBar *attachment_bar,
+ gboolean editable)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar));
+
+ attachment_bar->priv->editable = editable;
+
+ g_object_notify (G_OBJECT (attachment_bar), "editable");
+}
+
+GtkUIManager *
+e_attachment_bar_get_ui_manager (EAttachmentBar *attachment_bar)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), NULL);
+
+ return attachment_bar->priv->ui_manager;
+}
diff --git a/widgets/misc/e-attachment-bar.h b/widgets/misc/e-attachment-bar.h
index 363b7f0fb8..a55dcb11f6 100644
--- a/widgets/misc/e-attachment-bar.h
+++ b/widgets/misc/e-attachment-bar.h
@@ -21,8 +21,8 @@
*
*/
-#ifndef __E_ATTACHMENT_BAR_H__
-#define __E_ATTACHMENT_BAR_H__
+#ifndef E_ATTACHMENT_BAR_H
+#define E_ATTACHMENT_BAR_H
#include <gtk/gtk.h>
#include <libgnomeui/gnome-icon-list.h>
@@ -30,70 +30,107 @@
#include <camel/camel-multipart.h>
#include "e-attachment.h"
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
#define E_TYPE_ATTACHMENT_BAR \
(e_attachment_bar_get_type ())
#define E_ATTACHMENT_BAR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
-#define E_ATTACHMENT_BAR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
+#define E_ATTACHMENT_BAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
#define E_IS_ATTACHMENT_BAR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
-#define E_IS_ATTACHMENT_BAR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_BAR))
+#define E_IS_ATTACHMENT_BAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_BAR))
+#define E_ATTACHMENT_BAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
+
+G_BEGIN_DECLS
typedef struct _EAttachmentBar EAttachmentBar;
typedef struct _EAttachmentBarClass EAttachmentBarClass;
+typedef struct _EAttachmentBarPrivate EAttachmentBarPrivate;
struct _EAttachmentBar {
GnomeIconList parent;
gboolean expand;
-
- struct _EAttachmentBarPrivate *priv;
+ EAttachmentBarPrivate *priv;
};
struct _EAttachmentBarClass {
GnomeIconListClass parent_class;
- void (* changed) (EAttachmentBar *bar);
+ /* Signals */
+ void (*changed) (EAttachmentBar *bar);
+ void (*update_actions) (EAttachmentBar *bar);
};
+GType e_attachment_bar_get_type (void);
+GtkWidget * e_attachment_bar_new (void);
+void e_attachment_bar_to_multipart (EAttachmentBar *bar,
+ CamelMultipart *multipart,
+ const gchar *default_charset);
+guint e_attachment_bar_get_num_attachments
+ (EAttachmentBar *bar);
+void e_attachment_bar_attach (EAttachmentBar *bar,
+ const gchar *filename,
+ const gchar *disposition);
+void e_attachment_bar_attach_mime_part
+ (EAttachmentBar *bar,
+ CamelMimePart *part);
+gint e_attachment_bar_get_download_count
+ (EAttachmentBar *bar);
+void e_attachment_bar_attach_remote_file
+ (EAttachmentBar *bar,
+ const gchar *url,
+ const gchar *disposition);
+GSList * e_attachment_bar_get_attachment (EAttachmentBar *bar,
+ gint id);
+void e_attachment_bar_add_attachment (EAttachmentBar *bar,
+ EAttachment *attachment);
+GSList * e_attachment_bar_get_parts (EAttachmentBar *bar);
+GSList * e_attachment_bar_get_selected (EAttachmentBar *bar);
+void e_attachment_bar_set_width (EAttachmentBar *bar,
+ gint bar_width);
+GSList * e_attachment_bar_get_all_attachments
+ (EAttachmentBar *bar);
+void e_attachment_bar_create_attachment_cache
+ (EAttachment *attachment);
+GtkAction * e_attachment_bar_recent_action_new
+ (EAttachmentBar *bar,
+ const gchar *action_name,
+ const gchar *action_label);
+void e_attachment_bar_add_attachment_silent
+ (EAttachmentBar *bar,
+ EAttachment *attachment);
+void e_attachment_bar_refresh (EAttachmentBar *bar);
+gint e_attachment_bar_file_chooser_dialog_run
+ (EAttachmentBar *attachment_bar,
+ GtkWidget *dialog);
+void e_attachment_bar_update_actions (EAttachmentBar *attachment_bar);
+const gchar * e_attachment_bar_get_background_filename
+ (EAttachmentBar *attachment_bar);
+void e_attachment_bar_set_background_filename
+ (EAttachmentBar *attachment_bar,
+ const gchar *background_filename);
+const gchar * e_attachment_bar_get_background_options
+ (EAttachmentBar *attachment_bar);
+void e_attachment_bar_set_background_options
+ (EAttachmentBar *attachment_bar,
+ const gchar *background_options);
+const gchar * e_attachment_bar_get_current_folder
+ (EAttachmentBar *attachment_bar);
+void e_attachment_bar_set_current_folder
+ (EAttachmentBar *attachment_bar,
+ const gchar *current_folder);
+gboolean e_attachment_bar_get_editable (EAttachmentBar *attachment_bar);
+void e_attachment_bar_set_editable (EAttachmentBar *attachment_bar,
+ gboolean editable);
+GtkUIManager * e_attachment_bar_get_ui_manager (EAttachmentBar *attachment_bar);
-GType e_attachment_bar_get_type (void);
-
-GtkWidget *e_attachment_bar_new (GtkAdjustment *adj);
-void e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart,
- const char *default_charset);
-guint e_attachment_bar_get_num_attachments (EAttachmentBar *bar);
-void e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition);
-void e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part);
-int e_attachment_bar_get_download_count (EAttachmentBar *bar);
-void e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition);
-GSList *e_attachment_bar_get_attachment (EAttachmentBar *bar, int id);
-void e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment);
-void e_attachment_bar_edit_selected (EAttachmentBar *bar);
-void e_attachment_bar_remove_selected (EAttachmentBar *bar);
-GtkWidget ** e_attachment_bar_get_selector(EAttachmentBar *bar);
-GSList *e_attachment_bar_get_parts (EAttachmentBar *bar);
-GSList *e_attachment_bar_get_selected (EAttachmentBar *bar);
-void e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width);
-GSList * e_attachment_bar_get_all_attachments (EAttachmentBar *bar);
-void e_attachment_bar_create_attachment_cache (EAttachment *attachment);
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar,
- const gchar *action_name,
- const gchar *action_label);
-void
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment);
-void
-e_attachment_bar_refresh (EAttachmentBar *bar);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+G_END_DECLS
-#endif /* __E_ATTACHMENT_BAR_H__ */
+#endif /* E_ATTACHMENT_BAR_H */
diff --git a/widgets/misc/e-attachment-dialog.c b/widgets/misc/e-attachment-dialog.c
new file mode 100644
index 0000000000..0668a7358d
--- /dev/null
+++ b/widgets/misc/e-attachment-dialog.c
@@ -0,0 +1,413 @@
+/*
+ * e-attachment-dialog.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-attachment-dialog.h"
+
+#include <glib/gi18n.h>
+
+#define E_ATTACHMENT_DIALOG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialogPrivate))
+
+struct _EAttachmentDialogPrivate {
+ EAttachment *attachment;
+ GtkWidget *filename_entry;
+ GtkWidget *description_entry;
+ GtkWidget *mime_type_label;
+ GtkWidget *disposition_checkbox;
+};
+
+enum {
+ PROP_0,
+ PROP_ATTACHMENT
+};
+
+static gpointer parent_class;
+
+static void
+attachment_dialog_update (EAttachmentDialog *dialog)
+{
+ EAttachment *attachment;
+ CamelMimePart *mime_part;
+ GtkWidget *widget;
+ gboolean sensitive;
+ const gchar *text;
+ gboolean active;
+
+ /* XXX This is too complex. I shouldn't have to use the
+ * MIME part at all. */
+
+ attachment = e_attachment_dialog_get_attachment (dialog);
+ if (attachment != NULL)
+ mime_part = e_attachment_get_mime_part (attachment);
+ else
+ mime_part = NULL;
+
+ sensitive = (attachment != NULL);
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
+
+ text = NULL;
+ if (attachment != NULL)
+ text = e_attachment_get_filename (attachment);
+ text = (text != NULL) ? text : "";
+ widget = dialog->priv->filename_entry;
+ gtk_widget_set_sensitive (widget, sensitive);
+ gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+ text = NULL;
+ if (attachment != NULL)
+ text = e_attachment_get_description (attachment);
+ text = (text != NULL) ? text : "";
+ widget = dialog->priv->description_entry;
+ gtk_widget_set_sensitive (widget, sensitive);
+ gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+ text = NULL;
+ if (attachment != NULL)
+ text = e_attachment_get_mime_type (attachment);
+ text = (text != NULL) ? text : "";
+ widget = dialog->priv->mime_type_label;
+ gtk_label_set_text (GTK_LABEL (widget), text);
+
+ active = FALSE;
+ if (mime_part != NULL) {
+ const gchar *disposition;
+
+ disposition = camel_mime_part_get_disposition (mime_part);
+ active = (g_ascii_strcasecmp (disposition, "inline") == 0);
+ } else if (attachment != NULL)
+ active = e_attachment_is_inline (attachment);
+ widget = dialog->priv->disposition_checkbox;
+ gtk_widget_set_sensitive (widget, sensitive);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+}
+
+static void
+attachment_dialog_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ATTACHMENT:
+ e_attachment_dialog_set_attachment (
+ E_ATTACHMENT_DIALOG (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_dialog_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ATTACHMENT:
+ g_value_set_object (
+ value, e_attachment_dialog_get_attachment (
+ E_ATTACHMENT_DIALOG (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_dialog_dispose (GObject *object)
+{
+ EAttachmentDialogPrivate *priv;
+
+ priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (object);
+
+ if (priv->attachment != NULL) {
+ g_object_unref (priv->attachment);
+ priv->attachment = NULL;
+ }
+
+ if (priv->filename_entry != NULL) {
+ g_object_unref (priv->filename_entry);
+ priv->filename_entry = NULL;
+ }
+
+ if (priv->description_entry != NULL) {
+ g_object_unref (priv->description_entry);
+ priv->description_entry = NULL;
+ }
+
+ if (priv->mime_type_label != NULL) {
+ g_object_unref (priv->mime_type_label);
+ priv->mime_type_label = NULL;
+ }
+
+ if (priv->disposition_checkbox != NULL) {
+ g_object_unref (priv->disposition_checkbox);
+ priv->disposition_checkbox = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+attachment_dialog_map (GtkWidget *widget)
+{
+ GtkWidget *action_area;
+ GtkWidget *content_area;
+
+ /* Chain up to parent's map() method. */
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ /* XXX Override GtkDialog's broken style property defaults. */
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (widget));
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (widget));
+
+ gtk_box_set_spacing (GTK_BOX (content_area), 12);
+ gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
+ gtk_container_set_border_width (GTK_CONTAINER (content_area), 12);
+}
+
+static void
+attachment_dialog_response (GtkDialog *dialog,
+ gint response_id)
+{
+ EAttachmentDialogPrivate *priv;
+ EAttachment *attachment;
+ GtkToggleButton *button;
+ GtkEntry *entry;
+ const gchar *text;
+ gboolean active;
+
+ if (response_id != GTK_RESPONSE_OK)
+ return;
+
+ priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (dialog);
+ g_return_if_fail (priv->attachment != NULL);
+ attachment = priv->attachment;
+
+ entry = GTK_ENTRY (priv->filename_entry);
+ text = gtk_entry_get_text (entry);
+ e_attachment_set_filename (attachment, text);
+
+ entry = GTK_ENTRY (priv->description_entry);
+ text = gtk_entry_get_text (entry);
+ e_attachment_set_description (attachment, text);
+
+ button = GTK_TOGGLE_BUTTON (priv->disposition_checkbox);
+ active = gtk_toggle_button_get_active (button);
+ text = active ? "inline" : "attachment";
+ e_attachment_set_disposition (attachment, text);
+}
+
+static void
+attachment_dialog_class_init (EAttachmentDialogClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkDialogClass *dialog_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentDialogPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = attachment_dialog_set_property;
+ object_class->get_property = attachment_dialog_get_property;
+ object_class->dispose = attachment_dialog_dispose;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->map = attachment_dialog_map;
+
+ dialog_class = GTK_DIALOG_CLASS (class);
+ dialog_class->response = attachment_dialog_response;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ATTACHMENT,
+ g_param_spec_object (
+ "attachment",
+ "Attachment",
+ NULL,
+ E_TYPE_ATTACHMENT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+attachment_dialog_init (EAttachmentDialog *dialog)
+{
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ dialog->priv = E_ATTACHMENT_DIALOG_GET_PRIVATE (dialog);
+
+ gtk_dialog_add_button (
+ GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (
+ GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
+ gtk_window_set_icon_name (
+ GTK_WINDOW (dialog), "mail-attachment");
+ gtk_window_set_title (
+ GTK_WINDOW (dialog), _("Attachment Properties"));
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ widget = gtk_table_new (4, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_entry_new ();
+ gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ dialog->priv->filename_entry = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new_with_mnemonic (_("_Filename:"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), dialog->priv->filename_entry);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_entry_new ();
+ gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ dialog->priv->description_entry = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new_with_mnemonic (_("_Description:"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), dialog->priv->description_entry);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (NULL);
+ gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ dialog->priv->mime_type_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (_("MIME Type:"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_check_button_new_with_mnemonic (
+ _("_Suggest automatic display of attachment"));
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 2, 3, 4, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ dialog->priv->disposition_checkbox = g_object_ref (widget);
+ gtk_widget_show (widget);
+}
+
+GType
+e_attachment_dialog_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentDialogClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_dialog_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_init */
+ sizeof (EAttachmentDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_dialog_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_DIALOG, "EAttachmentDialog", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_attachment_dialog_new (GtkWindow *parent,
+ EAttachment *attachment)
+{
+ if (parent != NULL)
+ g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
+ if (attachment != NULL)
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return g_object_new (
+ E_TYPE_ATTACHMENT_DIALOG,
+ "transient-for", parent, "attachment", attachment, NULL);
+}
+
+EAttachment *
+e_attachment_dialog_get_attachment (EAttachmentDialog *dialog)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT_DIALOG (dialog), NULL);
+
+ return dialog->priv->attachment;
+}
+
+void
+e_attachment_dialog_set_attachment (EAttachmentDialog *dialog,
+ EAttachment *attachment)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_DIALOG (dialog));
+
+ if (attachment != NULL) {
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_object_ref (attachment);
+ }
+
+ if (dialog->priv->attachment != NULL)
+ g_object_unref (dialog->priv->attachment);
+
+ dialog->priv->attachment = attachment;
+
+ attachment_dialog_update (dialog);
+
+ g_object_notify (G_OBJECT (dialog), "attachment");
+}
diff --git a/widgets/misc/e-attachment-dialog.h b/widgets/misc/e-attachment-dialog.h
new file mode 100644
index 0000000000..8e24e1840c
--- /dev/null
+++ b/widgets/misc/e-attachment-dialog.h
@@ -0,0 +1,73 @@
+/*
+ * e-attachment-dialog.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_ATTACHMENT_DIALOG_H
+#define E_ATTACHMENT_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <widgets/misc/e-attachment.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_DIALOG \
+ (e_attachment_dialog_get_type ())
+#define E_ATTACHMENT_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialog))
+#define E_ATTACHMENT_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialogClass))
+#define E_IS_ATTACHMENT_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_DIALOG))
+#define E_IS_ATTACHMENT_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_DIALOG))
+#define E_ATTACHMENT_DIALOG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_DIALOG, EAttachmentDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentDialog EAttachmentDialog;
+typedef struct _EAttachmentDialogClass EAttachmentDialogClass;
+typedef struct _EAttachmentDialogPrivate EAttachmentDialogPrivate;
+
+struct _EAttachmentDialog {
+ GtkDialog parent;
+ EAttachmentDialogPrivate *priv;
+};
+
+struct _EAttachmentDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType e_attachment_dialog_get_type (void);
+GtkWidget * e_attachment_dialog_new (GtkWindow *parent,
+ EAttachment *attachment);
+EAttachment * e_attachment_dialog_get_attachment
+ (EAttachmentDialog *dialog);
+void e_attachment_dialog_set_attachment
+ (EAttachmentDialog *dialog,
+ EAttachment *attachment);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_DIALOG_H */
diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c
index 4f5e9ace34..9bb6f09ade 100644
--- a/widgets/misc/e-attachment.c
+++ b/widgets/misc/e-attachment.c
@@ -27,6 +27,9 @@
#include <config.h>
#endif
+#include "e-attachment.h"
+#include "e-attachment-dialog.h"
+
#ifdef G_OS_WIN32
/* Include <windows.h> early (as the gio stuff below will
* include it anyway, sigh) to workaround the DATADIR problem.
@@ -56,7 +59,27 @@
#include "e-util/e-mktemp.h"
#include "e-util/e-util-private.h"
-#include "e-attachment.h"
+#define E_ATTACHMENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate))
+
+struct _EAttachmentPrivate {
+ gchar *filename;
+ gchar *description;
+ gchar *disposition;
+ gchar *mime_type;
+
+ GdkPixbuf *thumbnail;
+ CamelMimePart *mime_part;
+};
+
+enum {
+ PROP_0,
+ PROP_DESCRIPTION,
+ PROP_DISPOSITION,
+ PROP_FILENAME,
+ PROP_THUMBNAIL
+};
enum {
CHANGED,
@@ -64,112 +87,207 @@ enum {
LAST_SIGNAL
};
-static guint signals[LAST_SIGNAL] = { 0 };
-
-static GObjectClass *parent_class = NULL;
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
static void
-changed (EAttachment *attachment)
+attachment_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- g_signal_emit (attachment, signals[CHANGED], 0);
+ switch (property_id) {
+ case PROP_DESCRIPTION:
+ e_attachment_set_description (
+ E_ATTACHMENT (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_DISPOSITION:
+ e_attachment_set_disposition (
+ E_ATTACHMENT (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_FILENAME:
+ e_attachment_set_filename (
+ E_ATTACHMENT (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_THUMBNAIL:
+ e_attachment_set_thumbnail (
+ E_ATTACHMENT (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
+static void
+attachment_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_DESCRIPTION:
+ g_value_set_string (
+ value, e_attachment_get_description (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_DISPOSITION:
+ g_value_set_string (
+ value, e_attachment_get_disposition (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_FILENAME:
+ g_value_set_string (
+ value, e_attachment_get_filename (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_THUMBNAIL:
+ g_value_set_object (
+ value, e_attachment_get_thumbnail (
+ E_ATTACHMENT (object)));
+ return;
+ }
-/* GtkObject methods. */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
static void
-finalise (GObject *object)
+attachment_dispose (GObject *object)
{
- EAttachment *attachment = (EAttachment *) object;
- GtkWidget *dialog;
+ EAttachmentPrivate *priv;
- if (attachment->editor_gui != NULL) {
- dialog = glade_xml_get_widget (attachment->editor_gui, "dialog");
- g_signal_emit_by_name (dialog, "response", GTK_RESPONSE_CLOSE);
- }
+ priv = E_ATTACHMENT_GET_PRIVATE (object);
- if (attachment->is_available_local) {
- camel_object_unref (attachment->body);
- if (attachment->pixbuf_cache != NULL)
- g_object_unref (attachment->pixbuf_cache);
- } else {
- if (attachment->cancellable) {
- /* the operation is still running, so cancel it */
- g_cancellable_cancel (attachment->cancellable);
- attachment->cancellable = NULL;
- }
- g_free (attachment->description);
+ if (priv->thumbnail != NULL) {
+ g_object_unref (priv->thumbnail);
+ priv->thumbnail = NULL;
}
- g_free (attachment->file_name);
- g_free (attachment->store_uri);
+ if (priv->mime_part != NULL) {
+ camel_object_unref (priv->mime_part);
+ priv->mime_part = NULL;
+ }
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
-
-/* Signals. */
-
static void
-real_changed (EAttachment *attachment)
+attachment_finalize (GObject *object)
{
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
-}
+ EAttachment *attachment = (EAttachment *) object;
-static void
-real_update_attachment (EAttachment *attachment, char *msg)
-{
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
-}
+ if (attachment->cancellable) {
+ /* the operation is still running, so cancel it */
+ g_cancellable_cancel (attachment->cancellable);
+ attachment->cancellable = NULL;
+ }
+
+ g_free (attachment->store_uri);
+
+ g_free (attachment->priv->filename);
+ g_free (attachment->priv->description);
+ g_free (attachment->priv->disposition);
+ g_free (attachment->priv->mime_type);
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
static void
-class_init (EAttachmentClass *klass)
+attachment_class_init (EAttachmentClass *class)
{
GObjectClass *object_class;
- object_class = (GObjectClass*) klass;
- parent_class = g_type_class_ref (G_TYPE_OBJECT);
-
- object_class->finalize = finalise;
- klass->changed = real_changed;
- klass->update = real_update_attachment;
-
- signals[CHANGED] = g_signal_new ("changed",
- E_TYPE_ATTACHMENT,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EAttachmentClass, changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- signals[UPDATE] = g_signal_new ("update",
- E_TYPE_ATTACHMENT,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EAttachmentClass, update),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = attachment_set_property;
+ object_class->get_property = attachment_get_property;
+ object_class->dispose = attachment_dispose;
+ object_class->finalize = attachment_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DESCRIPTION,
+ g_param_spec_string (
+ "description",
+ "Description",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DESCRIPTION,
+ g_param_spec_string (
+ "disposition",
+ "Disposition",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DESCRIPTION,
+ g_param_spec_string (
+ "filename",
+ "Filename",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_THUMBNAIL,
+ g_param_spec_object (
+ "thumbnail",
+ "Thumbnail Image",
+ NULL,
+ GDK_TYPE_PIXBUF,
+ G_PARAM_READWRITE));
+
+ signals[CHANGED] = g_signal_new (
+ "changed",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EAttachmentClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[UPDATE] = g_signal_new (
+ "update",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EAttachmentClass, update),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
-init (EAttachment *attachment)
+attachment_init (EAttachment *attachment)
{
- attachment->editor_gui = NULL;
- attachment->body = NULL;
- attachment->size = 0;
- attachment->pixbuf_cache = NULL;
+ attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment);
+
attachment->index = -1;
- attachment->file_name = NULL;
attachment->percentage = -1;
- attachment->description = NULL;
- attachment->disposition = FALSE;
attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
- attachment->store_uri = NULL;
- attachment->cancellable = NULL;
}
GType
@@ -177,20 +295,22 @@ e_attachment_get_type (void)
{
static GType type = 0;
- if (type == 0) {
- static const GTypeInfo info = {
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
sizeof (EAttachmentClass),
- NULL,
- NULL,
- (GClassInitFunc) class_init,
- NULL,
- NULL,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
sizeof (EAttachment),
- 0,
- (GInstanceInitFunc) init,
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_init,
+ NULL /* value_table */
};
- type = g_type_register_static (G_TYPE_OBJECT, "EAttachment", &info, 0);
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EAttachment", &type_info, 0);
}
return type;
@@ -198,42 +318,42 @@ e_attachment_get_type (void)
/**
* file_ext_is:
- * @param file_name: path for file
+ * @param filename: path for file
* @param ext: desired extension, with a dot
- * @return if file_name has extension ext or not
+ * @return if filename has extension ext or not
**/
static gboolean
-file_ext_is (const char *file_name, const char *ext)
+file_ext_is (const char *filename, const char *ext)
{
int i, dot = -1;
- if (!file_name || !ext)
+ if (!filename || !ext)
return FALSE;
- for (i = 0; file_name[i]; i++) {
- if (file_name [i] == '.')
+ for (i = 0; filename[i]; i++) {
+ if (filename [i] == '.')
dot = i;
}
if (dot > 0) {
- return 0 == g_ascii_strcasecmp (file_name + dot, ext);
+ return 0 == g_ascii_strcasecmp (filename + dot, ext);
}
return FALSE;
}
static char *
-attachment_guess_mime_type (const char *file_name)
+attachment_guess_mime_type (const char *filename)
{
char *type;
gchar *content = NULL;
- type = e_util_guess_mime_type (file_name, TRUE);
+ type = e_util_guess_mime_type (filename, TRUE);
if (type && strcmp (type, "text/directory") == 0 &&
- file_ext_is (file_name, ".vcf") &&
- g_file_get_contents (file_name, &content, NULL, NULL) &&
+ file_ext_is (filename, ".vcf") &&
+ g_file_get_contents (filename, &content, NULL, NULL) &&
content) {
EVCard *vc = e_vcard_new_from_string (content);
@@ -265,30 +385,30 @@ attachment_guess_mime_type (const char *file_name)
/**
* e_attachment_new:
- * @file_name: filename to attach
+ * @filename: filename to attach
* @disposition: Content-Disposition of the attachment
* @ex: exception
*
* Return value: the new attachment, or %NULL on error
**/
EAttachment *
-e_attachment_new (const char *file_name, const char *disposition, CamelException *ex)
+e_attachment_new (const char *filename, const char *disposition, CamelException *ex)
{
EAttachment *new;
CamelMimePart *part;
CamelDataWrapper *wrapper;
CamelStream *stream;
struct stat statbuf;
- char *mime_type;
- char *filename;
+ gchar *mime_type;
+ gchar *basename;
CamelURL *url;
- g_return_val_if_fail (file_name != NULL, NULL);
+ g_return_val_if_fail (filename != NULL, NULL);
- if (g_stat (file_name, &statbuf) < 0) {
+ if (g_stat (filename, &statbuf) < 0) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
+ filename, g_strerror (errno));
return NULL;
}
@@ -296,18 +416,18 @@ e_attachment_new (const char *file_name, const char *disposition, CamelException
if (!S_ISREG (statbuf.st_mode)) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot attach file %s: not a regular file"),
- file_name);
+ filename);
return NULL;
}
- if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
+ if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
+ filename, g_strerror (errno));
return NULL;
}
- if ((mime_type = attachment_guess_mime_type (file_name))) {
+ if ((mime_type = attachment_guess_mime_type (filename))) {
if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
wrapper = (CamelDataWrapper *) camel_mime_message_new ();
} else {
@@ -330,8 +450,8 @@ e_attachment_new (const char *file_name, const char *disposition, CamelException
camel_object_unref (wrapper);
camel_mime_part_set_disposition (part, disposition);
- filename = g_path_get_basename (file_name);
- camel_mime_part_set_filename (part, filename);
+ basename = g_path_get_basename (filename);
+ camel_mime_part_set_filename (part, basename);
#if 0
/* Note: Outlook 2002 is broken with respect to Content-Ids on
@@ -344,17 +464,15 @@ e_attachment_new (const char *file_name, const char *disposition, CamelException
g_free (content_id);
#endif
- new = g_object_new (E_TYPE_ATTACHMENT, NULL);
- new->editor_gui = NULL;
- new->body = part;
+ new = g_object_new (E_TYPE_ATTACHMENT, "filename", basename, NULL);
+ new->priv->mime_part = part;
new->size = statbuf.st_size;
new->guessed_type = TRUE;
new->cancellable = NULL;
new->is_available_local = TRUE;
- new->file_name = filename;
url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, file_name);
+ camel_url_set_path (url, filename);
new->store_uri = camel_url_to_string (url, 0);
camel_url_free (url);
@@ -364,7 +482,7 @@ e_attachment_new (const char *file_name, const char *disposition, CamelException
typedef struct {
EAttachment *attachment;
- char *file_name;
+ char *filename;
char *uri;
GtkWindow *parent; /* for error dialog */
@@ -394,7 +512,7 @@ download_info_free (DownloadInfo *download_info)
if (download_info->cancellable)
g_object_unref (download_info->cancellable);
- g_free (download_info->file_name);
+ g_free (download_info->filename);
g_free (download_info->uri);
g_free (download_info->buffer);
g_free (download_info);
@@ -450,7 +568,7 @@ data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
download_info->attachment->cancellable = NULL;
camel_exception_init (&ex);
- e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex);
+ e_attachment_build_remote_file (download_info->filename, download_info->attachment, &ex);
if (camel_exception_is_set (&ex)) {
download_info->was_error = TRUE;
@@ -482,7 +600,7 @@ download_to_local_path (DownloadInfo *download_info, CamelException *ex)
{
GError *error = NULL;
GFile *src = g_file_new_for_uri (download_info->uri);
- GFile *des = g_file_new_for_path (download_info->file_name);
+ GFile *des = g_file_new_for_path (download_info->filename);
gboolean res = FALSE;
g_return_val_if_fail (src != NULL && des != NULL, FALSE);
@@ -538,6 +656,7 @@ e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, cons
DownloadInfo *download_info;
CamelURL *url;
char *base;
+ gchar *filename;
g_return_val_if_fail (uri != NULL, NULL);
@@ -545,25 +664,26 @@ e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, cons
base = g_path_get_basename (url->path);
camel_url_free (url);
- new = g_object_new (E_TYPE_ATTACHMENT, NULL);
- new->editor_gui = NULL;
- new->body = NULL;
+ filename = g_build_filename (path, base, NULL);
+
+ new = g_object_new (E_TYPE_ATTACHMENT, "filename", filename, NULL);
new->size = 0;
new->guessed_type = FALSE;
new->cancellable = NULL;
new->is_available_local = FALSE;
new->percentage = 0;
- new->file_name = g_build_filename (path, base, NULL);
g_free (base);
download_info = g_new0 (DownloadInfo, 1);
download_info->attachment = new;
- download_info->file_name = g_strdup (new->file_name);
+ download_info->filename = g_strdup (filename);
download_info->uri = g_strdup (uri);
download_info->parent = error_dlg_parent;
download_info->was_error = FALSE;
+ g_free (filename);
+
/* it frees all on the error, so do not free it twice */
if (!download_to_local_path (download_info, ex))
return NULL;
@@ -573,23 +693,27 @@ e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, cons
void
-e_attachment_build_remote_file (const char *file_name, EAttachment *attachment, const char *disposition, CamelException *ex)
+e_attachment_build_remote_file (const gchar *filename,
+ EAttachment *attachment,
+ CamelException *ex)
{
CamelMimePart *part;
CamelDataWrapper *wrapper;
CamelStream *stream;
struct stat statbuf;
- char *mime_type;
- char *filename;
+ const gchar *description;
+ const gchar *disposition;
+ gchar *mime_type;
+ gchar *basename;
CamelURL *url;
- g_return_if_fail (file_name != NULL);
+ g_return_if_fail (filename != NULL);
- if (g_stat (file_name, &statbuf) == -1) {
+ if (g_stat (filename, &statbuf) == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
- g_message ("Cannot attach file %s: %s\n", file_name, g_strerror (errno));
+ filename, g_strerror (errno));
+ g_message ("Cannot attach file %s: %s\n", filename, g_strerror (errno));
return;
}
@@ -597,19 +721,19 @@ e_attachment_build_remote_file (const char *file_name, EAttachment *attachment,
if (!S_ISREG (statbuf.st_mode)) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot attach file %s: not a regular file"),
- file_name);
- g_message ("Cannot attach file %s: not a regular file", file_name);
+ filename);
+ g_message ("Cannot attach file %s: not a regular file", filename);
return;
}
- if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
+ if (!(stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0))) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
+ filename, g_strerror (errno));
return;
}
- if ((mime_type = attachment_guess_mime_type (file_name))) {
+ if ((mime_type = attachment_guess_mime_type (filename))) {
if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
wrapper = (CamelDataWrapper *) camel_mime_message_new ();
} else {
@@ -631,36 +755,34 @@ e_attachment_build_remote_file (const char *file_name, EAttachment *attachment,
camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
camel_object_unref (wrapper);
- if (attachment->disposition)
- camel_mime_part_set_disposition (part, "inline");
- else
- camel_mime_part_set_disposition (part, "attachment");
+ disposition = e_attachment_get_disposition (attachment);
+ camel_mime_part_set_disposition (part, disposition);
- if (!attachment->file_name)
- filename = g_path_get_basename (file_name);
+ if (e_attachment_get_filename (attachment) == NULL)
+ basename = g_path_get_basename (filename);
else
- filename = g_path_get_basename (attachment->file_name);
+ basename = g_path_get_basename (e_attachment_get_filename (attachment));
camel_mime_part_set_filename (part, filename);
- if (attachment->description) {
- camel_mime_part_set_description (part, attachment->description);
- g_free (attachment->description);
- attachment->description = NULL;
+ description = e_attachment_get_description (attachment);
+ if (description != NULL) {
+ camel_mime_part_set_description (part, description);
+ e_attachment_set_description (attachment, NULL);
}
- attachment->editor_gui = NULL;
- attachment->body = part;
+ attachment->priv->mime_part = part;
attachment->size = statbuf.st_size;
attachment->guessed_type = TRUE;
- g_free (attachment->file_name);
- attachment->file_name = filename;
+
+ e_attachment_set_filename (attachment, basename);
url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, file_name);
+ camel_url_set_path (url, filename);
attachment->store_uri = camel_url_to_string (url, 0);
camel_url_free (url);
+ g_free (basename);
}
@@ -674,210 +796,231 @@ EAttachment *
e_attachment_new_from_mime_part (CamelMimePart *part)
{
EAttachment *new;
+ const gchar *filename;
g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
- new = g_object_new (E_TYPE_ATTACHMENT, NULL);
- new->editor_gui = NULL;
+ filename = camel_mime_part_get_filename (part);
+
+ new = g_object_new (E_TYPE_ATTACHMENT, "filename", filename, NULL);
camel_object_ref (part);
- new->body = part;
+ new->priv->mime_part = part;
new->guessed_type = FALSE;
new->is_available_local = TRUE;
new->size = camel_mime_part_get_content_size (part);
- new->file_name = g_strdup (camel_mime_part_get_filename(part));
return new;
}
-
-/* The attachment property dialog. */
-
-typedef struct {
+void
+e_attachment_edit (EAttachment *attachment,
+ GtkWindow *parent)
+{
GtkWidget *dialog;
- GtkEntry *file_name_entry;
- GtkEntry *description_entry;
- GtkEntry *mime_type_entry;
- GtkToggleButton *disposition_checkbox;
- EAttachment *attachment;
-} DialogData;
-static void
-destroy_dialog_data (DialogData *data)
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ dialog = e_attachment_dialog_new (parent, attachment);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+const gchar *
+e_attachment_get_description (EAttachment *attachment)
{
- g_free (data);
+ CamelMimePart *mime_part;
+ const gchar *description;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part != NULL)
+ description = camel_mime_part_get_description (mime_part);
+ else
+ description = attachment->priv->description;
+
+ return description;
}
-/*
- * fixme: I am converting EVERYTHING to/from UTF-8, although mime types
- * are in ASCII. This is not strictly necessary, but we want to be
- * consistent and possibly check for errors somewhere.
- */
+void
+e_attachment_set_description (EAttachment *attachment,
+ const gchar *description)
+{
+ CamelMimePart *mime_part;
-static void
-set_entry (GladeXML *xml, const char *widget_name, const char *value)
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_free (attachment->priv->description);
+ attachment->priv->description = g_strdup (description);
+
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part != NULL)
+ camel_mime_part_set_description (mime_part, description);
+
+ g_object_notify (G_OBJECT (attachment), "description");
+}
+
+const gchar *
+e_attachment_get_disposition (EAttachment *attachment)
{
- GtkEntry *entry;
+ CamelMimePart *mime_part;
+ const gchar *disposition;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- entry = GTK_ENTRY (glade_xml_get_widget (xml, widget_name));
- if (entry == NULL)
- g_warning ("Entry for `%s' not found.", widget_name);
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part != NULL)
+ disposition = camel_mime_part_get_disposition (mime_part);
else
- gtk_entry_set_text (entry, value ? value : "");
+ disposition = attachment->priv->disposition;
+
+ return disposition;
}
-static void
-connect_widget (GladeXML *gui, const char *name, const char *signal_name,
- GCallback func, gpointer data)
+void
+e_attachment_set_disposition (EAttachment *attachment,
+ const gchar *disposition)
{
- GtkWidget *widget;
+ CamelMimePart *mime_part;
- widget = glade_xml_get_widget (gui, name);
- g_signal_connect (widget, signal_name, func, data);
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_free (attachment->priv->disposition);
+ attachment->priv->disposition = g_strdup (disposition);
+
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part != NULL)
+ camel_mime_part_set_disposition (mime_part, disposition);
+
+ g_object_notify (G_OBJECT (attachment), "disposition");
}
-static void
-close_cb (GtkWidget *widget, gpointer data)
+const gchar *
+e_attachment_get_filename (EAttachment *attachment)
{
- EAttachment *attachment;
- DialogData *dialog_data;
+ CamelMimePart *mime_part;
+ const gchar *filename;
- dialog_data = (DialogData *) data;
- attachment = dialog_data->attachment;
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
- gtk_widget_destroy (dialog_data->dialog);
- g_object_unref (attachment->editor_gui);
- attachment->editor_gui = NULL;
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part != NULL)
+ filename = camel_mime_part_get_filename (mime_part);
+ else
+ filename = attachment->priv->filename;
- destroy_dialog_data (dialog_data);
+ return filename;
}
-static void
-ok_cb (GtkWidget *widget, gpointer data)
+void
+e_attachment_set_filename (EAttachment *attachment,
+ const gchar *filename)
{
- DialogData *dialog_data;
- EAttachment *attachment;
- const char *str;
+ CamelMimePart *mime_part;
- dialog_data = (DialogData *) data;
- attachment = dialog_data->attachment;
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
- str = gtk_entry_get_text (dialog_data->file_name_entry);
- if (attachment->is_available_local)
- camel_mime_part_set_filename (attachment->body, str);
- g_free (attachment->file_name);
- attachment->file_name = g_strdup (str);
+ g_free (attachment->priv->filename);
+ attachment->priv->filename = g_strdup (filename);
- str = gtk_entry_get_text (dialog_data->description_entry);
- if (attachment->is_available_local) {
- camel_mime_part_set_description (attachment->body, str);
- } else {
- g_free (attachment->description);
- attachment->description = g_strdup (str);
- }
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part != NULL)
+ camel_mime_part_set_filename (mime_part, filename);
- str = gtk_entry_get_text (dialog_data->mime_type_entry);
- if (attachment->is_available_local) {
- camel_mime_part_set_content_type (attachment->body, str);
- camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str);
- }
+ g_object_notify (G_OBJECT (attachment), "filename");
+}
- if (attachment->is_available_local) {
- switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) {
- case 0:
- camel_mime_part_set_disposition (attachment->body, "attachment");
- break;
- case 1:
- camel_mime_part_set_disposition (attachment->body, "inline");
- break;
- default:
- /* Hmmmm? */
- break;
- }
- } else {
- attachment->disposition = gtk_toggle_button_get_active (dialog_data->disposition_checkbox);
+CamelMimePart *
+e_attachment_get_mime_part (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->mime_part;
+}
+
+const gchar *
+e_attachment_get_mime_type (EAttachment *attachment)
+{
+ CamelContentType *content_type;
+ CamelMimePart *mime_part;
+ const gchar *filename;
+ gchar *mime_type;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ if (attachment->priv->mime_type != NULL)
+ goto exit;
+
+ mime_part = e_attachment_get_mime_part (attachment);
+ filename = e_attachment_get_filename (attachment);
+ content_type = camel_mime_part_get_content_type (mime_part);
+
+ if (mime_part == NULL)
+ mime_type = attachment_guess_mime_type (filename);
+ else {
+ content_type = camel_mime_part_get_content_type (mime_part);
+ mime_type = camel_content_type_simple (content_type);
}
- changed (attachment);
- close_cb (widget, data);
+ attachment->priv->mime_type = mime_type;
+
+exit:
+ return attachment->priv->mime_type;
}
-static void
-response_cb (GtkWidget *widget, gint response, gpointer data)
+GdkPixbuf *
+e_attachment_get_thumbnail (EAttachment *attachment)
{
- if (response == GTK_RESPONSE_OK)
- ok_cb (widget, data);
- else
- close_cb (widget, data);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->thumbnail;
}
void
-e_attachment_edit (EAttachment *attachment, GtkWidget *parent)
+e_attachment_set_thumbnail (EAttachment *attachment,
+ GdkPixbuf *thumbnail)
{
- CamelContentType *content_type;
- const char *disposition;
- DialogData *dialog_data;
- GladeXML *editor_gui;
- GtkWidget *window;
- char *type;
- char *filename;
-
g_return_if_fail (E_IS_ATTACHMENT (attachment));
- if (attachment->editor_gui != NULL) {
- window = glade_xml_get_widget (attachment->editor_gui, "dialog");
- gdk_window_show (window->window);
- return;
+ if (thumbnail != NULL) {
+ g_return_if_fail (GDK_IS_PIXBUF (thumbnail));
+ g_object_ref (thumbnail);
}
- filename = g_build_filename (EVOLUTION_GLADEDIR, "e-attachment.glade", NULL);
- editor_gui = glade_xml_new (filename, NULL, NULL);
- g_free (filename);
+ if (attachment->priv->thumbnail != NULL)
+ g_object_unref (attachment->priv->thumbnail);
- if (editor_gui == NULL) {
- g_warning ("Cannot load `e-attachment.glade'");
- return;
- }
+ attachment->priv->thumbnail = thumbnail;
- attachment->editor_gui = editor_gui;
-
- gtk_window_set_transient_for (GTK_WINDOW (glade_xml_get_widget (editor_gui, "dialog")),
- GTK_WINDOW (gtk_widget_get_toplevel (parent)));
-
- dialog_data = g_new (DialogData, 1);
- dialog_data->attachment = attachment;
- dialog_data->dialog = glade_xml_get_widget (editor_gui, "dialog");
- dialog_data->file_name_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "file_name_entry"));
- dialog_data->description_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "description_entry"));
- dialog_data->mime_type_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "mime_type_entry"));
- dialog_data->disposition_checkbox = GTK_TOGGLE_BUTTON (glade_xml_get_widget (editor_gui, "disposition_checkbox"));
-
- if (attachment->is_available_local && attachment->body) {
- set_entry (editor_gui, "file_name_entry", camel_mime_part_get_filename (attachment->body));
- set_entry (editor_gui, "description_entry", camel_mime_part_get_description (attachment->body));
- content_type = camel_mime_part_get_content_type (attachment->body);
- type = camel_content_type_simple (content_type);
- set_entry (editor_gui, "mime_type_entry", type);
- g_free (type);
-
- disposition = camel_mime_part_get_disposition (attachment->body);
- gtk_toggle_button_set_active (dialog_data->disposition_checkbox,
- disposition && !g_ascii_strcasecmp (disposition, "inline"));
- } else {
- set_entry (editor_gui, "file_name_entry", attachment->file_name);
- set_entry (editor_gui, "description_entry", attachment->description);
- if ((type = attachment_guess_mime_type (attachment->file_name))) {
- set_entry (editor_gui, "mime_type_entry", type);
- g_free (type);
- } else {
- set_entry (editor_gui, "mime_type_entry", "");
- }
+ g_object_notify (G_OBJECT (attachment), "thumbnail");
+}
- gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition);
- }
+gboolean
+e_attachment_is_image (EAttachment *attachment)
+{
+ CamelContentType *content_type;
+ CamelMimePart *mime_part;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part == NULL)
+ return FALSE;
+
+ content_type = camel_mime_part_get_content_type (mime_part);
+
+ return camel_content_type_is (content_type, "image", "*");
+}
+
+gboolean
+e_attachment_is_inline (EAttachment *attachment)
+{
+ const gchar *disposition;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
- connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data);
+ disposition = e_attachment_get_disposition (attachment);
+ g_return_val_if_fail (disposition != NULL, FALSE);
- /* make sure that when the parent gets hidden/closed that our windows also close */
- parent = gtk_widget_get_toplevel (parent);
- gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_data->dialog), TRUE);
+ return (g_ascii_strcasecmp (disposition, "inline") == 0);
}
diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h
index 7b45f24ae5..c69189c189 100644
--- a/widgets/misc/e-attachment.h
+++ b/widgets/misc/e-attachment.h
@@ -15,14 +15,14 @@
*
* Authors:
* Ettore Perazzoli <ettore@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
+ * Srinivasa Ragavan <sragavan@novell.com>
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
-#ifndef __E_ATTACHMENT_H__
-#define __E_ATTACHMENT_H__
+#ifndef E_ATTACHMENT_H
+#define E_ATTACHMENT_H
#include <gio/gio.h>
#include <gtk/gtk.h>
@@ -31,73 +31,91 @@
#include <camel/camel-exception.h>
#include <camel/camel-cipher-context.h>
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define E_TYPE_ATTACHMENT (e_attachment_get_type ())
-#define E_ATTACHMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT, EAttachment))
-#define E_ATTACHMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT, EAttachmentClass))
-#define E_IS_ATTACHMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT))
-#define E_IS_ATTACHMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT))
-
-
-typedef struct _EAttachment EAttachment;
-typedef struct _EAttachmentClass EAttachmentClass;
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT \
+ (e_attachment_get_type ())
+#define E_ATTACHMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT, EAttachment))
+#define E_ATTACHMENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT, EAttachmentClass))
+#define E_IS_ATTACHMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT))
+#define E_IS_ATTACHMENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((obj), E_TYPE_ATTACHMENT))
+#define E_ATTACHMENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT, EAttachmentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachment EAttachment;
+typedef struct _EAttachmentClass EAttachmentClass;
+typedef struct _EAttachmentPrivate EAttachmentPrivate;
struct _EAttachment {
GObject parent;
- GladeXML *editor_gui;
-
- CamelMimePart *body;
gboolean guessed_type;
gulong size;
- GdkPixbuf *pixbuf_cache;
-
GCancellable *cancellable;
gboolean is_available_local;
int percentage;
- char *file_name;
- char *description;
- gboolean disposition;
int index;
char *store_uri;
/* Status of signed/encrypted attachments */
camel_cipher_validity_sign_t sign;
camel_cipher_validity_encrypt_t encrypt;
+
+ EAttachmentPrivate *priv;
};
struct _EAttachmentClass {
GObjectClass parent_class;
- void (*changed) (EAttachment *attachment);
- void (*update) (EAttachment *attachment, char *msg);
+ void (*changed) (EAttachment *attachment);
+ void (*update) (EAttachment *attachment,
+ gchar *message);
};
-GType e_attachment_get_type (void);
-EAttachment *e_attachment_new (const char *file_name,
- const char *disposition,
- CamelException *ex);
-EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent,
- const char *url,
- const char *disposition,
- const char *path,
- CamelException *ex);
-void e_attachment_build_remote_file (const char *filename,
- EAttachment *attachment,
- const char *disposition,
- CamelException *ex);
-EAttachment *e_attachment_new_from_mime_part (CamelMimePart *part);
-void e_attachment_edit (EAttachment *attachment,
- GtkWidget *parent);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __E_ATTACHMENT_H__ */
+GType e_attachment_get_type (void);
+EAttachment * e_attachment_new (const gchar *filename,
+ const gchar *disposition,
+ CamelException *ex);
+EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent,
+ const gchar *url,
+ const gchar *disposition,
+ const gchar *path,
+ CamelException *ex);
+void e_attachment_build_remote_file (const gchar *filename,
+ EAttachment *attachment,
+ CamelException *ex);
+EAttachment * e_attachment_new_from_mime_part (CamelMimePart *part);
+void e_attachment_edit (EAttachment *attachment,
+ GtkWindow *parent);
+const gchar * e_attachment_get_description (EAttachment *attachment);
+void e_attachment_set_description (EAttachment *attachment,
+ const gchar *description);
+const gchar * e_attachment_get_disposition (EAttachment *attachment);
+void e_attachment_set_disposition (EAttachment *attachment,
+ const gchar *disposition);
+const gchar * e_attachment_get_filename (EAttachment *attachment);
+void e_attachment_set_filename (EAttachment *attachment,
+ const gchar *filename);
+CamelMimePart * e_attachment_get_mime_part (EAttachment *attachment);
+const gchar * e_attachment_get_mime_type (EAttachment *attachment);
+GdkPixbuf * e_attachment_get_thumbnail (EAttachment *attachment);
+void e_attachment_set_thumbnail (EAttachment *attachment,
+ GdkPixbuf *pixbuf);
+gboolean e_attachment_is_image (EAttachment *attachment);
+gboolean e_attachment_is_inline (EAttachment *attachment);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_H */
diff --git a/widgets/misc/e-mime-part-utils.c b/widgets/misc/e-mime-part-utils.c
new file mode 100644
index 0000000000..3238ca93f5
--- /dev/null
+++ b/widgets/misc/e-mime-part-utils.c
@@ -0,0 +1,223 @@
+/*
+ * e-mime-part-utils.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-mime-part-utils.h"
+
+#include <errno.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+#include <camel/camel-stream-vfs.h>
+
+#include "e-util/e-util.h"
+
+static void
+mime_part_utils_open_in_cb (GtkAction *action,
+ CamelMimePart *mime_part)
+{
+ GtkWindow *parent;
+ GFile *file;
+ gchar *path;
+ gchar *uri;
+ gint fd;
+ GError *error = NULL;
+
+ parent = g_object_get_data (G_OBJECT (action), "parent-window");
+
+ fd = e_file_open_tmp (&path, &error);
+ if (error != NULL)
+ goto fail;
+
+ close (fd);
+
+ file = g_file_new_for_path (path);
+ e_mime_part_utils_save_to_file (mime_part, file, &error);
+ g_free (path);
+
+ if (error != NULL) {
+ g_object_unref (file);
+ goto fail;
+ }
+
+ uri = g_file_get_uri (file);
+ e_show_uri (parent, uri);
+ g_free (uri);
+
+ g_object_unref (file);
+
+ return;
+
+fail:
+ g_warning ("%s", error->message);
+ g_error_free (error);
+}
+
+GList *
+e_mime_part_utils_get_apps (CamelMimePart *mime_part)
+{
+ GList *app_info_list;
+ const gchar *filename;
+ gchar *content_type;
+ gchar *mime_type;
+ gchar *cp;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
+
+ filename = camel_mime_part_get_filename (mime_part);
+ mime_type = camel_content_type_simple (
+ camel_mime_part_get_content_type (mime_part));
+ g_return_val_if_fail (mime_type != NULL, NULL);
+
+ /* GIO expects lowercase MIME types. */
+ for (cp = mime_type; *cp != '\0'; cp++)
+ *cp = g_ascii_tolower (*cp);
+
+ content_type = g_content_type_from_mime_type (mime_type);
+ if (content_type != NULL)
+ app_info_list = g_app_info_get_all_for_type (content_type);
+ else
+ app_info_list = g_app_info_get_all_for_type (mime_type);
+ g_free (content_type);
+
+ if (app_info_list != NULL || filename == NULL)
+ goto exit;
+
+ if (strcmp (mime_type, "application/octet-stream") != 0)
+ goto exit;
+
+ content_type = g_content_type_guess (filename, NULL, 0, NULL);
+ app_info_list = g_app_info_get_all_for_type (content_type);
+ g_free (content_type);
+
+exit:
+ g_free (mime_type);
+
+ return app_info_list;
+}
+
+gboolean
+e_mime_part_utils_save_to_file (CamelMimePart *mime_part,
+ GFile *file,
+ GError **error)
+{
+ GFileOutputStream *output_stream;
+ CamelDataWrapper *content;
+ CamelStream *stream;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+ output_stream = g_file_replace (
+ file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
+ if (output_stream == NULL)
+ return FALSE;
+
+ /* The CamelStream takes ownership of the GFileOutputStream. */
+ content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+ stream = camel_stream_vfs_new_with_stream (G_OBJECT (output_stream));
+
+ /* XXX Camel's streams are synchronous only, so we have to write
+ * the whole thing in one shot and hope it doesn't block the
+ * main loop for too long. */
+ if (camel_data_wrapper_decode_to_stream (content, stream) < 0)
+ goto file_error;
+
+ if (camel_stream_flush (stream) < 0)
+ goto file_error;
+
+ camel_object_unref (stream);
+
+ return TRUE;
+
+file_error:
+ g_set_error (
+ error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s", g_strerror (errno));
+
+ camel_object_unref (stream);
+
+ return FALSE;
+}
+
+void
+e_mime_part_utils_add_open_actions (CamelMimePart *mime_part,
+ GtkUIManager *ui_manager,
+ GtkActionGroup *action_group,
+ const gchar *widget_path,
+ GtkWindow *parent,
+ guint merge_id)
+{
+ GList *app_info_list;
+ GList *iter;
+
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager));
+ g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
+ g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+ g_return_if_fail (widget_path != NULL);
+
+ app_info_list = e_mime_part_utils_get_apps (mime_part);
+
+ for (iter = app_info_list; iter != NULL; iter = iter->next) {
+ GAppInfo *app_info = iter->data;
+ GtkAction *action;
+ const gchar *app_executable;
+ const gchar *app_name;
+ gchar *action_tooltip;
+ gchar *action_label;
+ gchar *action_name;
+
+ if (!g_app_info_should_show (app_info))
+ continue;
+
+ app_executable = g_app_info_get_executable (app_info);
+ app_name = g_app_info_get_name (app_info);
+
+ action_name = g_strdup_printf ("open-in-%s", app_executable);
+ action_label = g_strdup_printf (_("Open in %s..."), app_name);
+
+ action_tooltip = g_strdup_printf (
+ _("Open this attachment in %s"), app_name);
+
+ action = gtk_action_new (
+ action_name, action_label, action_tooltip, NULL);
+
+ g_object_set_data (
+ G_OBJECT (action), "parent-window", parent);
+
+ g_signal_connect (
+ action, "activate",
+ G_CALLBACK (mime_part_utils_open_in_cb), mime_part);
+
+ gtk_action_group_add_action (action_group, action);
+
+ gtk_ui_manager_add_ui (
+ ui_manager, merge_id, widget_path, action_name,
+ action_name, GTK_UI_MANAGER_AUTO, FALSE);
+
+ g_free (action_name);
+ g_free (action_label);
+ g_free (action_tooltip);
+ }
+
+ g_list_foreach (app_info_list, (GFunc) g_object_unref, NULL);
+ g_list_free (app_info_list);
+}
diff --git a/widgets/misc/e-mime-part-utils.h b/widgets/misc/e-mime-part-utils.h
new file mode 100644
index 0000000000..e923e07c8d
--- /dev/null
+++ b/widgets/misc/e-mime-part-utils.h
@@ -0,0 +1,46 @@
+/*
+ * e-mime-part-utils.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_MIME_PART_UTILS_H
+#define E_MIME_PART_UTILS_H
+
+#include <gtk/gtk.h>
+#include <camel/camel-mime-part.h>
+#include <shell/e-shell-window.h>
+
+G_BEGIN_DECLS
+
+GList * e_mime_part_utils_get_apps (CamelMimePart *mime_part);
+gboolean e_mime_part_utils_save_to_file (CamelMimePart *mime_part,
+ GFile *file,
+ GError **error);
+
+void e_mime_part_utils_add_open_actions
+ (CamelMimePart *mime_part,
+ GtkUIManager *ui_manager,
+ GtkActionGroup *action_group,
+ const gchar *widget_path,
+ GtkWindow *parent,
+ guint merge_id);
+
+G_END_DECLS
+
+#endif /* E_MIME_PART_UTILS_H */
diff --git a/widgets/misc/e-timeout-activity.c b/widgets/misc/e-timeout-activity.c
new file mode 100644
index 0000000000..d02bcf96d2
--- /dev/null
+++ b/widgets/misc/e-timeout-activity.c
@@ -0,0 +1,180 @@
+/*
+ * e-timeout-activity.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-timeout-activity.h"
+
+#define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate))
+
+struct _ETimeoutActivityPrivate {
+ guint timeout_id;
+};
+
+enum {
+ TIMEOUT,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static gulong signals[LAST_SIGNAL];
+
+static gboolean
+timeout_activity_cb (ETimeoutActivity *timeout_activity)
+{
+ g_signal_emit (timeout_activity, signals[TIMEOUT], 0);
+
+ return FALSE;
+}
+
+static void
+timeout_activity_finalize (GObject *object)
+{
+ ETimeoutActivityPrivate *priv;
+
+ priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (object);
+
+ if (priv->timeout_id > 0)
+ g_source_remove (priv->timeout_id);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+timeout_activity_cancelled (EActivity *activity)
+{
+ ETimeoutActivityPrivate *priv;
+
+ priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
+
+ if (priv->timeout_id > 0) {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+
+ /* Chain up to parent's cancelled() method. */
+ E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
+}
+
+static void
+timeout_activity_completed (EActivity *activity)
+{
+ ETimeoutActivityPrivate *priv;
+
+ priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
+
+ if (priv->timeout_id > 0) {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+
+ /* Chain up to parent's completed() method. */
+ E_ACTIVITY_CLASS (parent_class)->completed (activity);
+}
+
+static void
+timeout_activity_timeout (ETimeoutActivity *timeout_activity)
+{
+ /* Allow subclasses to safely chain up. */
+}
+
+static void
+timeout_activity_class_init (ETimeoutActivityClass *class)
+{
+ GObjectClass *object_class;
+ EActivityClass *activity_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETimeoutActivityPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = timeout_activity_finalize;
+
+ activity_class = E_ACTIVITY_CLASS (class);
+ activity_class->cancelled = timeout_activity_cancelled;
+ activity_class->completed = timeout_activity_completed;
+
+ class->timeout = timeout_activity_timeout;
+
+ signals[TIMEOUT] = g_signal_new (
+ "timeout",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ETimeoutActivityClass, timeout),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+timeout_activity_init (ETimeoutActivity *timeout_activity)
+{
+ timeout_activity->priv =
+ E_TIMEOUT_ACTIVITY_GET_PRIVATE (timeout_activity);
+}
+
+GType
+e_timeout_activity_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ETimeoutActivityClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) timeout_activity_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETimeoutActivity),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) timeout_activity_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_ACTIVITY, "ETimeoutActivity", &type_info, 0);
+ }
+
+ return type;
+}
+
+EActivity *
+e_timeout_activity_new (const gchar *primary_text)
+{
+ return g_object_new (
+ E_TYPE_TIMEOUT_ACTIVITY,
+ "primary-text", primary_text, NULL);
+}
+
+void
+e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
+ guint seconds)
+{
+ g_return_if_fail (E_IS_TIMEOUT_ACTIVITY (timeout_activity));
+
+ if (timeout_activity->priv->timeout_id > 0)
+ e_activity_cancel (E_ACTIVITY (timeout_activity));
+
+ timeout_activity->priv->timeout_id = g_timeout_add_seconds (
+ seconds, (GSourceFunc) timeout_activity_cb, timeout_activity);
+}
diff --git a/widgets/misc/e-timeout-activity.h b/widgets/misc/e-timeout-activity.h
new file mode 100644
index 0000000000..70aaee7dcb
--- /dev/null
+++ b/widgets/misc/e-timeout-activity.h
@@ -0,0 +1,71 @@
+/*
+ * e-timeout-activity.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_TIMEOUT_ACTIVITY_H
+#define E_TIMEOUT_ACTIVITY_H
+
+#include <e-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TIMEOUT_ACTIVITY \
+ (e_timeout_activity_get_type ())
+#define E_TIMEOUT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivity))
+#define E_TIMEOUT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
+#define E_IS_TIMEOUT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY))
+#define E_IS_TIMEOUT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TIMEOUT_ACTIVITY))
+#define E_TIMEOUT_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETimeoutActivity ETimeoutActivity;
+typedef struct _ETimeoutActivityClass ETimeoutActivityClass;
+typedef struct _ETimeoutActivityPrivate ETimeoutActivityPrivate;
+
+struct _ETimeoutActivity {
+ EActivity parent;
+ ETimeoutActivityPrivate *priv;
+};
+
+struct _ETimeoutActivityClass {
+ EActivityClass parent_class;
+
+ /* Signals */
+ void (*timeout) (ETimeoutActivity *timeout_activity);
+};
+
+GType e_timeout_activity_get_type (void);
+EActivity * e_timeout_activity_new (const gchar *primary_text);
+void e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
+ guint seconds);
+
+G_END_DECLS
+
+#endif /* E_TIMEOUT_ACTIVITY_H */