/* * 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 #include #include #include #include #include #include #include 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); }