diff options
Diffstat (limited to 'embed/downloader-view.c')
-rw-r--r-- | embed/downloader-view.c | 1100 |
1 files changed, 1100 insertions, 0 deletions
diff --git a/embed/downloader-view.c b/embed/downloader-view.c new file mode 100644 index 000000000..97e05a613 --- /dev/null +++ b/embed/downloader-view.c @@ -0,0 +1,1100 @@ +/* + * Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "downloader-view.h" +#include "eel-gconf-extensions.h" +#include "ephy-gui.h" +#include "ephy-prefs.h" +#include "ephy-ellipsizing-label.h" +#include "ephy-embed-utils.h" +#include "ephy-file-helpers.h" + +#include <gtk/gtktreeview.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtktreeviewcolumn.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomeui/gnome-dialog-util.h> +#include <libgnomeui/gnome-dialog.h> +#include <gtk/gtkprogressbar.h> +#include <libgnomevfs/gnome-vfs-mime-handlers.h> + +enum +{ + DOWNLOAD_REMOVE, + DOWNLOAD_PAUSE, + DOWNLOAD_RESUME, + LAST_SIGNAL +}; + +enum +{ + COL_PERCENT, + COL_FILENAME, + COL_SIZE, + COL_REMAINING, + COL_PERSIST_OBJECT +}; + +struct DownloaderViewPrivate +{ + GHashTable *details_hash; + GtkTreeModel *model; + gboolean show_details; + + /* Widgets */ + GtkWidget *treeview; + GtkWidget *details_file; + GtkWidget *details_location; + GtkWidget *details_status; + GtkWidget *details_elapsed; + GtkWidget *details_remaining; + GtkWidget *details_progress; + GtkWidget *details_button; + GtkWidget *keep_open_check; + GtkWidget *pause_button; + GtkWidget *resume_button; + GtkWidget *abort_button; + GtkWidget *open_button; +}; + +typedef struct +{ + glong elapsed; + glong remaining; + gfloat speed; + gint size_total; + gint size_done; + gfloat progress; + gboolean can_pause; + gchar *filename; + gchar *source; + gchar *dest; + DownloadStatus status; + + GtkTreeRowReference *ref; +} DownloadDetails; + +typedef struct +{ + gboolean can_resume; + gboolean can_pause; + gboolean can_abort; + gboolean can_open; + DownloaderViewPrivate *priv; +} ControlsInfo; + +enum +{ + PROP_TREEVIEW, + PROP_KEEP_OPEN, + PROP_DETAILS_FRAME, + PROP_DETAILS_SEPARATOR, + PROP_DETAILS_TABLE, + PROP_DETAILS_STATUS, + PROP_DETAILS_ELAPSED, + PROP_DETAILS_REMAINING, + PROP_DETAILS_PROGRESS, + PROP_PAUSE_BUTTON, + PROP_RESUME_BUTTON, + PROP_ABORT_BUTTON, + PROP_OPEN_BUTTON, + PROP_DETAILS_BUTTON +}; + +static const +EphyDialogProperty properties [] = +{ + { PROP_TREEVIEW, "clist", NULL, PT_NORMAL, NULL }, + { PROP_KEEP_OPEN, "keep_open_check", CONF_DOWNLOADING_KEEP_OPEN, PT_NORMAL, NULL }, + { PROP_DETAILS_FRAME, "details_frame", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_SEPARATOR, "details_separator", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_TABLE, "details_table", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_STATUS, "details_status", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_ELAPSED, "details_elapsed", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_REMAINING, "details_remaining", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_PROGRESS, "details_progress", NULL, PT_NORMAL, NULL }, + { PROP_PAUSE_BUTTON, "pause_button", NULL, PT_NORMAL, NULL }, + { PROP_RESUME_BUTTON, "resume_button", NULL, PT_NORMAL, NULL }, + { PROP_ABORT_BUTTON, "abort_button", NULL, PT_NORMAL, NULL }, + { PROP_OPEN_BUTTON, "open_button", NULL, PT_NORMAL, NULL }, + { PROP_DETAILS_BUTTON, "details_togglebutton", CONF_DOWNLOADING_SHOW_DETAILS, PT_NORMAL, NULL }, + + { -1, NULL, NULL } +}; + +static void +downloader_view_build_ui (DownloaderView *dv); +static void +downloader_view_class_init (DownloaderViewClass *klass); +static void +downloader_view_finalize (GObject *object); +static void +downloader_view_init (DownloaderView *dv); + +/* Callbacks */ +void +download_dialog_resume_cb (GtkButton *button, DownloaderView *dv); +void +download_dialog_pause_cb (GtkButton *button, DownloaderView *dv); +void +download_dialog_abort_cb (GtkButton *button, DownloaderView *dv); +static void +downloader_treeview_selection_changed_cb (GtkTreeSelection *selection, + DownloaderView *dv); +gboolean +download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event, + DownloaderView *dv); +void +download_dialog_details_cb (GtkToggleButton *button, + DownloaderView *dv); +void +download_dialog_open_cb (GtkWidget *button, + DownloaderView *dv); + +static GObjectClass *parent_class = NULL; +static guint downloader_view_signals[LAST_SIGNAL] = { 0 }; + +GType +downloader_view_get_type (void) +{ + static GType downloader_view_type = 0; + + if (downloader_view_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (DownloaderViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) downloader_view_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (DownloaderView), + 0, /* n_preallocs */ + (GInstanceInitFunc) downloader_view_init + }; + + downloader_view_type = g_type_register_static (EPHY_DIALOG_TYPE, + "DownloaderView", + &our_info, 0); + } + + return downloader_view_type; +} + +static void +format_time (gchar *buffer, glong time) +{ + gint secs, hours, mins; + + secs = (gint)(time + .5); + hours = secs / 3600; + secs -= hours * 3600; + mins = secs / 60; + secs -= mins * 60; + + if (hours) + { + sprintf (buffer, "%u:%02u.%02u", hours, mins, secs); + } + else + { + sprintf (buffer, "%02u.%02u", mins, secs); + } +} + +static void +downloader_view_class_init (DownloaderViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EphyDialogClass *ephy_dialog_class; + + parent_class = g_type_class_peek_parent (klass); + ephy_dialog_class = EPHY_DIALOG_CLASS (klass); + + object_class->finalize = downloader_view_finalize; + + /* init signals */ + downloader_view_signals[DOWNLOAD_REMOVE] = + g_signal_new ("download_remove", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DownloaderViewClass, download_remove), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + downloader_view_signals[DOWNLOAD_PAUSE] = + g_signal_new ("download_pause", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DownloaderViewClass, download_pause), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + downloader_view_signals[DOWNLOAD_RESUME] = + g_signal_new ("download_resume", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DownloaderViewClass, download_resume), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + +} + +static void +destroy_details_cb (DownloadDetails *details) +{ + g_free (details->filename); + g_free (details->source); + g_free (details->dest); + g_free (details); +} + +static void +downloader_view_init (DownloaderView *dv) +{ + dv->priv = g_new0 (DownloaderViewPrivate, 1); + dv->priv->details_hash = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify)destroy_details_cb); + + downloader_view_build_ui (dv); +} + +static void +downloader_view_finalize (GObject *object) +{ + DownloaderView *dv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_DOWNLOADER_VIEW (object)); + + dv = DOWNLOADER_VIEW (object); + + g_return_if_fail (dv->priv != NULL); + + g_hash_table_destroy (dv->priv->details_hash); + + g_free (dv->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +DownloaderView * +downloader_view_new (void) +{ + return DOWNLOADER_VIEW (g_object_new + (DOWNLOADER_VIEW_TYPE, NULL)); +} + +static void +controls_info_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + ControlsInfo *info) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer persist_object; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (info->priv->details_hash, + persist_object); + + info->can_pause |= details->can_pause; + info->can_resume |= (details->status == DOWNLOAD_STATUS_PAUSED); + info->can_abort |= (details->status != DOWNLOAD_STATUS_COMPLETED); + info->can_open |= (details->status == DOWNLOAD_STATUS_COMPLETED); +} + +static void +downloader_view_update_controls (DownloaderViewPrivate *priv) +{ + GtkTreeSelection *selection; + ControlsInfo *info; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview)); + + info = g_new0 (ControlsInfo, 1); + info->priv = priv; + + /* initial conditions */ + info->can_pause = info->can_resume = info->can_abort + = info->can_open = FALSE; + + if (selection) + { + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)controls_info_foreach, + info); + } + + /* setup buttons */ + gtk_widget_set_sensitive (priv->pause_button, info->can_pause); + gtk_widget_set_sensitive (priv->resume_button, info->can_resume); + gtk_widget_set_sensitive (priv->abort_button, info->can_abort); + gtk_widget_set_sensitive (priv->open_button, info->can_open); + + g_free (info); +} + +static void +downloader_view_update_details (DownloaderViewPrivate *priv, + DownloadDetails *details) +{ + gchar buffer[50]; + + ephy_ellipsizing_label_set_text + (EPHY_ELLIPSIZING_LABEL (priv->details_location), + details->source); + ephy_ellipsizing_label_set_text + (EPHY_ELLIPSIZING_LABEL (priv->details_file), + details->filename); + + if (details->size_total >= 10000) + { + sprintf (buffer, _("%.1f of %.1f MB"), + details->size_done / 1024.0, + details->size_total / 1024.0); + } + else if (details->size_total > 0) + { + sprintf (buffer, _("%d of %d KB"), + details->size_done, + details->size_total); + } + else + { + sprintf (buffer, _("%d KB"), + details->size_done); + } + + if (details->speed > 0) + { + sprintf (buffer, "%s at %.1f KB/s", buffer, details->speed); + } + gtk_label_set_text (GTK_LABEL (priv->details_status), + buffer); + + format_time (buffer, details->elapsed/1000000); + gtk_label_set_text (GTK_LABEL (priv->details_elapsed), + buffer); + + format_time (buffer, details->remaining); + gtk_label_set_text (GTK_LABEL (priv->details_remaining), + buffer); + + if (details->progress >= 0) + { + gtk_progress_bar_set_fraction + (GTK_PROGRESS_BAR (priv->details_progress), + details->progress); + } + else + { + gtk_progress_bar_pulse + (GTK_PROGRESS_BAR (priv->details_progress)); + } +} + +static gboolean +get_selected_row (DownloaderViewPrivate *priv, GtkTreeIter *iter) +{ + GList *l; + GtkTreePath *node; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview)); + l = gtk_tree_selection_get_selected_rows (selection, &model); + + if (l == NULL) return FALSE; + + node = l->data; + gtk_tree_model_get_iter (model, iter, node); + + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + + return TRUE; +} + +static void +downloader_view_set_download_info (DownloaderViewPrivate *priv, + DownloadDetails *details, + GtkTreeIter *iter) +{ + gchar buffer[50]; + GtkTreePath *path; + GtkTreePath *selected_path = NULL; + GtkTreeIter selected_iter; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(priv->treeview)); + + if (get_selected_row (priv, &selected_iter)) + { + selected_path = gtk_tree_model_get_path + (priv->model, &selected_iter); + } + + path = gtk_tree_row_reference_get_path (details->ref); + + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_FILENAME, details->filename, + -1); + + /* Progress */ + if (details->status == DOWNLOAD_STATUS_COMPLETED) + details->progress = 1; + sprintf (buffer, "%.1f%%", + details->progress > 0 ? + details->progress * 100.0 : + 0); + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_PERCENT, buffer, + -1); + + /* Total */ + if (details->size_total >= 10000) + { + sprintf (buffer, "%.2f MB", details->size_total / 1024.0); + } + else if (details->size_total > 0) + { + sprintf (buffer, "%d KB", details->size_total); + } + else + { + sprintf (buffer, _("Unknown")); + } + + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_SIZE, buffer, + -1); + + /* Remaining */ + if (details->remaining >= 0) + { + format_time (buffer, details->remaining); + } + else + { + sprintf (buffer, _("Unknown")); + } + gtk_list_store_set (GTK_LIST_STORE (priv->model), + iter, + COL_REMAINING, buffer, + -1); + + if (gtk_tree_path_compare (path, selected_path) == 0) + { + downloader_view_update_details (priv, details); + } +} + +static void +ensure_selected_row (DownloaderView *dv) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + + g_return_if_fail (IS_DOWNLOADER_VIEW(dv)); + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(dv->priv->treeview)); + if (get_selected_row (dv->priv, &iter)) + { + /* there is already a selection */ + return; + } + + if (gtk_tree_model_get_iter_first (dv->priv->model, &iter)) + { + gtk_tree_selection_select_iter (selection, &iter); + } +} + +void +downloader_view_add_download (DownloaderView *dv, + gchar *filename, + gchar *source, + gchar *dest, + gpointer persist_object) +{ + GtkTreeIter iter; + DownloadDetails *details; + GtkTreeSelection *selection; + + details = g_new0 (DownloadDetails, 1); + details->filename = g_strdup (filename); + details->source = g_strdup (source); + details->dest = g_strdup (dest); + details->elapsed = -1; + details->remaining = -1; + details->speed = -1; + details->size_total = -1; + details->size_done = -1; + details->progress = -1; + dv->priv->show_details = FALSE; + + g_hash_table_insert (dv->priv->details_hash, + persist_object, + details); + + gtk_list_store_append (GTK_LIST_STORE (dv->priv->model), + &iter); + + details->ref = gtk_tree_row_reference_new + (GTK_TREE_MODEL (dv->priv->model), + gtk_tree_model_get_path + (GTK_TREE_MODEL (dv->priv->model), &iter)); + + gtk_list_store_set (GTK_LIST_STORE (dv->priv->model), + &iter, + COL_PERSIST_OBJECT, persist_object, + -1); + + selection = gtk_tree_view_get_selection + (GTK_TREE_VIEW(dv->priv->treeview)); + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_iter (selection, &iter); + + downloader_view_set_download_info (dv->priv, details, &iter); + + ephy_dialog_show (EPHY_DIALOG(dv)); +} + +void +downloader_view_remove_download (DownloaderView *dv, + gpointer persist_object) +{ + DownloadDetails *details; + GtkTreeIter iter; + GValue keep_open = {0, }; + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), + &iter, + gtk_tree_row_reference_get_path (details->ref)); + + gtk_list_store_remove (GTK_LIST_STORE (dv->priv->model), &iter); + + g_hash_table_remove (dv->priv->details_hash, + persist_object); + + ephy_dialog_get_value (EPHY_DIALOG(dv), PROP_KEEP_OPEN, &keep_open); + + if (!g_value_get_boolean (&keep_open) && + g_hash_table_size (dv->priv->details_hash) == 0) + { + g_object_unref (dv); + } + else + { + ensure_selected_row (dv); + } +} + +void +downloader_view_set_download_progress (DownloaderView *dv, + glong elapsed, + glong remaining, + gfloat speed, + gint size_total, + gint size_done, + gfloat progress, + gboolean can_pause, + gpointer persist_object) +{ + DownloadDetails *details; + GtkTreeIter iter; + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + details->elapsed = elapsed; + details->remaining = remaining; + details->speed = speed; + details->size_total = size_total; + details->size_done = size_done; + details->can_pause = can_pause; + details->progress = progress; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), + &iter, + gtk_tree_row_reference_get_path (details->ref)); + + downloader_view_set_download_info (dv->priv, details, &iter); +} + +void +downloader_view_set_download_status (DownloaderView *dv, + DownloadStatus status, + gpointer persist_object) +{ + DownloadDetails *details; + GtkTreeIter iter; + GValue keep_open = {0, }; + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + details->status = status; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), + &iter, + gtk_tree_row_reference_get_path (details->ref)); + + downloader_view_set_download_info (dv->priv, details, &iter); + downloader_view_update_controls (dv->priv); + + ephy_dialog_get_value (EPHY_DIALOG(dv), PROP_KEEP_OPEN, &keep_open); + + if (status == DOWNLOAD_STATUS_COMPLETED && + !g_value_get_boolean (&keep_open)) + { + downloader_view_remove_download (dv, persist_object); + } +} + +static void +downloader_view_build_ui (DownloaderView *dv) +{ + DownloaderViewPrivate *priv = dv->priv; + GtkListStore *liststore; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GtkWidget *details_table; + EphyDialog *d = EPHY_DIALOG (dv); + + ephy_dialog_construct (d, + properties, + "epiphany.glade", + "download_manager_dialog"); + + /* lookup needed widgets */ + priv->treeview = ephy_dialog_get_control (d, PROP_TREEVIEW); + priv->details_status = ephy_dialog_get_control (d, PROP_DETAILS_STATUS); + priv->details_elapsed = ephy_dialog_get_control (d, PROP_DETAILS_ELAPSED); + priv->details_remaining = ephy_dialog_get_control (d, PROP_DETAILS_REMAINING); + priv->details_progress = ephy_dialog_get_control (d, PROP_DETAILS_PROGRESS); + priv->keep_open_check = ephy_dialog_get_control (d, PROP_KEEP_OPEN); + priv->details_button = ephy_dialog_get_control (d, PROP_DETAILS_BUTTON); + priv->pause_button = ephy_dialog_get_control (d, PROP_PAUSE_BUTTON); + priv->resume_button = ephy_dialog_get_control (d, PROP_RESUME_BUTTON); + priv->abort_button = ephy_dialog_get_control (d, PROP_ABORT_BUTTON); + priv->open_button = ephy_dialog_get_control (d, PROP_OPEN_BUTTON); + details_table = ephy_dialog_get_control (d, PROP_DETAILS_TABLE); + + /* create file and location details labels */ + priv->details_location = ephy_ellipsizing_label_new (""); + priv->details_file = ephy_ellipsizing_label_new (""); + gtk_table_attach_defaults (GTK_TABLE(details_table), priv->details_location, + 1, 2, 0, 1); + gtk_table_attach_defaults (GTK_TABLE(details_table), priv->details_file, + 1, 2, 1, 2); + gtk_misc_set_alignment (GTK_MISC(priv->details_location), 0, 0); + gtk_misc_set_alignment (GTK_MISC(priv->details_file), 0, 0); + gtk_label_set_selectable (GTK_LABEL(priv->details_location), TRUE); + gtk_label_set_selectable (GTK_LABEL(priv->details_file), TRUE); + gtk_widget_show (priv->details_location); + gtk_widget_show (priv->details_file); + + liststore = gtk_list_store_new (5, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER); + + gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), + GTK_TREE_MODEL (liststore)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(priv->treeview), + TRUE); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + 0, _("%"), + renderer, + "text", 0, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), 0); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_PERCENT); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + COL_FILENAME, _("Filename"), + renderer, + "text", COL_FILENAME, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), + COL_FILENAME); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_FILENAME); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + COL_SIZE, _("Size"), + renderer, + "text", COL_SIZE, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), + COL_SIZE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_SIZE); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), + COL_REMAINING, _("Remaining"), + renderer, + "text", COL_REMAINING, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW(priv->treeview), + COL_REMAINING); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_reorderable (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, COL_REMAINING); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (downloader_treeview_selection_changed_cb), dv); + + priv->model = GTK_TREE_MODEL (liststore); +} + +static void +resume_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + DownloaderView *dv) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer *persist_object; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + if (details->status == DOWNLOAD_STATUS_COMPLETED) return; + + downloader_view_set_download_status (dv, DOWNLOAD_STATUS_RESUMING, persist_object); + + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_RESUME], 0); +} + +void +download_dialog_resume_cb (GtkButton *button, DownloaderView *dv) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)resume_selection_foreach, + (gpointer)dv); +} + +static void +pause_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + DownloaderView *dv) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer *persist_object; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + if (details->status == DOWNLOAD_STATUS_COMPLETED) return; + + downloader_view_set_download_status (dv, DOWNLOAD_STATUS_PAUSED, persist_object); + + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_PAUSE], 0); +} + +void +download_dialog_pause_cb (GtkButton *button, DownloaderView *dv) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)pause_selection_foreach, + (gpointer)dv); +} + +void +download_dialog_abort_cb (GtkButton *button, DownloaderView *dv) +{ + GList *l, *r = NULL; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + l = gtk_tree_selection_get_selected_rows (selection, &model); + for (;l != NULL; l = l->next) + { + r = g_list_append (r, gtk_tree_row_reference_new + (model, (GtkTreePath *)l->data)); + } + + for (; r != NULL; r = g_list_next (r)) + { + GtkTreeRowReference *node = r->data; + GValue val = {0, }; + gpointer *persist_object; + GtkTreeIter iter; + DownloadDetails *details; + + gtk_tree_model_get_iter (model, &iter, + gtk_tree_row_reference_get_path (node)); + + gtk_tree_model_get_value (model, &iter, + COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_REMOVE], 0); + + downloader_view_remove_download (dv, persist_object); + + gtk_tree_row_reference_free (node); + } + + l = g_list_first (l); + g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); + g_list_free (l); + g_list_free (r); +} + +static void +downloader_treeview_selection_changed_cb (GtkTreeSelection *selection, + DownloaderView *dv) +{ + GtkTreeIter iter; + GValue val = {0, }; + gpointer *persist_object; + DownloadDetails *details = NULL; + GtkWidget *details_frame; + DownloaderViewPrivate *priv= dv->priv; + + details_frame = ephy_dialog_get_control (EPHY_DIALOG(dv), + PROP_DETAILS_FRAME); + + if (get_selected_row (priv, &iter)) + { + gtk_tree_model_get_value (priv->model, &iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (priv->details_hash, + persist_object); + g_return_if_fail (details); + + gtk_widget_set_sensitive (details_frame, TRUE); + + downloader_view_update_details (priv, details); + downloader_view_update_controls (priv); + } + else + { + gtk_label_set_text (GTK_LABEL (priv->details_location), ""); + gtk_label_set_text (GTK_LABEL (priv->details_file), ""); + gtk_label_set_text (GTK_LABEL (priv->details_status), ""); + gtk_label_set_text (GTK_LABEL (priv->details_elapsed), ""); + gtk_label_set_text (GTK_LABEL (priv->details_remaining), ""); + gtk_progress_bar_set_fraction + (GTK_PROGRESS_BAR (priv->details_progress), + 0); + + gtk_widget_set_sensitive (details_frame, FALSE); + } +} + +static void +alive_download_foreach (gpointer persist_object, + DownloadDetails *details, + gboolean *alive) +{ + if (details->status != DOWNLOAD_STATUS_COMPLETED) + { + *alive = TRUE; + } +} + +static gboolean +delete_pending_foreach (gpointer persist_object, + DownloadDetails *details, + DownloaderView *dv) +{ + g_signal_emit (G_OBJECT (dv), downloader_view_signals[DOWNLOAD_REMOVE], + 0, persist_object); + + return TRUE; +} + +gboolean +download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event, + DownloaderView *dv) +{ + GtkWidget *dialog; + gboolean choice; + gboolean alive_download = FALSE; + + g_hash_table_foreach (dv->priv->details_hash, + (GHFunc)alive_download_foreach, + &alive_download); + + if (!alive_download) return FALSE; + + /* build question dialog */ + dialog = gtk_message_dialog_new ( + GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_YES_NO, + _("Cancel all pending downloads?")); + + /* run it */ + choice = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + /* do the appropriate thing */ + if (choice == GTK_RESPONSE_YES) + { + g_hash_table_foreach_remove (dv->priv->details_hash, + (GHRFunc)delete_pending_foreach, + dv); + return FALSE; + } + + return TRUE; +} + +void +download_dialog_details_cb (GtkToggleButton *button, + DownloaderView *dv) +{ + GtkWidget *details_frame; + GtkWidget *details_separator; + + details_frame = ephy_dialog_get_control (EPHY_DIALOG(dv), + PROP_DETAILS_FRAME); + details_separator = ephy_dialog_get_control (EPHY_DIALOG(dv), + PROP_DETAILS_SEPARATOR); + + if (gtk_toggle_button_get_active (button)) + { + gtk_widget_show (GTK_WIDGET (details_frame)); + gtk_widget_show (GTK_WIDGET (details_separator)); + dv->priv->show_details = TRUE; + } + else + { + gtk_widget_hide (GTK_WIDGET (details_frame)); + gtk_widget_hide (GTK_WIDGET (details_separator)); + dv->priv->show_details = FALSE; + } + +} + +static void +open_selection_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + DownloaderView *dv) +{ + DownloadDetails *details; + GValue val = {0, }; + gpointer *persist_object; + GnomeVFSMimeApplication *app; + char *mime; + + gtk_tree_model_get_value (model, iter, COL_PERSIST_OBJECT, &val); + persist_object = g_value_get_pointer (&val); + + details = g_hash_table_lookup (dv->priv->details_hash, + persist_object); + g_return_if_fail (details); + + if (details->status != DOWNLOAD_STATUS_COMPLETED) return; + + mime = gnome_vfs_get_mime_type (details->dest); + g_return_if_fail (mime != NULL); + + app = gnome_vfs_mime_get_default_application (mime); + if (app) + { + ephy_file_launch_application (app->command, + details->dest, + app->requires_terminal); + } + else + { + GtkWidget *parent; + parent = gtk_widget_get_toplevel (dv->priv->open_button); + ephy_embed_utils_nohandler_dialog_run (parent); + } + + g_free(mime); +} + +void +download_dialog_open_cb (GtkWidget *button, + DownloaderView *dv) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); + + gtk_tree_selection_selected_foreach + (selection, + (GtkTreeSelectionForeachFunc)open_selection_foreach, + (gpointer)dv); +} |