/* * 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. * * $Id$ */ #ifdef HAVE_CONFIG_H #include #endif #include "downloader-view.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 "ephy-embed-shell.h" #include "ephy-cell-renderer-progress.h" #include "ephy-stock-icons.h" #include #include #include #include #include #include #include #include #define CONF_DOWNLOADING_SHOW_DETAILS "/apps/epiphany/dialogs/downloader_show_details" enum { COL_PERCENT, COL_FILENAME, COL_SIZE, COL_REMAINING, COL_DOWNLOAD_OBJECT }; #define EPHY_DOWNLOADER_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_DOWNLOADER_VIEW, DownloaderViewPrivate)) struct DownloaderViewPrivate { GtkTreeModel *model; GHashTable *downloads_hash; /* Widgets */ GtkWidget *window; GtkWidget *treeview; GtkWidget *pause_button; GtkWidget *abort_button; }; typedef struct { gboolean is_paused; gboolean can_abort; DownloaderViewPrivate *priv; } ControlsInfo; enum { PROP_WINDOW, PROP_TREEVIEW, PROP_PAUSE_BUTTON, PROP_ABORT_BUTTON, PROP_DETAILS_BUTTON }; static const EphyDialogProperty properties [] = { { PROP_WINDOW, "download_manager_dialog", NULL, PT_NORMAL, NULL}, { PROP_TREEVIEW, "clist", NULL, PT_NORMAL, NULL }, { PROP_PAUSE_BUTTON, "pause_button", NULL, PT_NORMAL, NULL }, { PROP_ABORT_BUTTON, "abort_button", NULL, 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_pause_cb (GtkButton *button, DownloaderView *dv); void download_dialog_abort_cb (GtkButton *button, DownloaderView *dv); gboolean download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event, DownloaderView *dv); static GObjectClass *parent_class = NULL; 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_TYPE_DIALOG, "DownloaderView", &our_info, 0); } return downloader_view_type; } static void downloader_view_class_init (DownloaderViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = downloader_view_finalize; g_type_class_add_private (object_class, sizeof(DownloaderViewPrivate)); } static void downloader_view_init (DownloaderView *dv) { dv->priv = EPHY_DOWNLOADER_VIEW_GET_PRIVATE (dv); dv->priv->downloads_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)gtk_tree_row_reference_free); downloader_view_build_ui (dv); g_object_ref (embed_shell); } static void downloader_view_finalize (GObject *object) { DownloaderView *dv = EPHY_DOWNLOADER_VIEW (object); g_hash_table_destroy (dv->priv->downloads_hash); g_object_unref (embed_shell); G_OBJECT_CLASS (parent_class)->finalize (object); } DownloaderView * downloader_view_new (void) { return EPHY_DOWNLOADER_VIEW (g_object_new (EPHY_TYPE_DOWNLOADER_VIEW, NULL)); } static char * format_interval (long interval) { int secs, hours, mins; secs = (int)(interval + .5); hours = secs / 3600; secs -= hours * 3600; mins = secs / 60; secs -= mins * 60; if (hours) { return g_strdup_printf (_("%u:%02u.%02u"), hours, mins, secs); } else { return g_strdup_printf (_("%02u.%02u"), mins, secs); } } static GtkTreeRowReference * get_row_from_download (DownloaderView *dv, EphyDownload *download) { return g_hash_table_lookup (dv->priv->downloads_hash, download); } static void download_changed_cb (EphyDownload *download, DownloaderView *dv) { GtkTreeRowReference *row_ref; GtkTreePath *path; GtkTreeIter iter; EphyDownloadState state; int percent; long total; long remaining_secs; char *remaining; char *size; struct tm; row_ref = get_row_from_download (dv, download); g_return_if_fail (row_ref != NULL); total = ephy_download_get_total_progress (download) / 1024; /* State special casing */ state = ephy_download_get_state (download); switch (state) { case EPHY_DOWNLOAD_FAILED: percent = -2; remaining_secs = 0; break; case EPHY_DOWNLOAD_COMPLETED: downloader_view_remove_download (dv, download); return; case EPHY_DOWNLOAD_DOWNLOADING: case EPHY_DOWNLOAD_PAUSED: percent = ephy_download_get_percent (download); remaining_secs = ephy_download_get_remaining_time (download); break; default: percent = 0; remaining_secs = 0; break; } size = g_strdup_printf ("%ld kB", total); remaining = format_interval (remaining_secs); path = gtk_tree_row_reference_get_path (row_ref); gtk_tree_model_get_iter (dv->priv->model, &iter, path); gtk_list_store_set (GTK_LIST_STORE (dv->priv->model), &iter, COL_PERCENT, percent, COL_SIZE, size, COL_REMAINING, remaining, -1); gtk_tree_path_free (path); g_free (size); g_free (remaining); } void downloader_view_add_download (DownloaderView *dv, EphyDownload *download) { GtkTreeRowReference *row_ref; GtkTreeIter iter; GtkTreeSelection *selection; GtkTreePath *path; char *name; gtk_list_store_append (GTK_LIST_STORE (dv->priv->model), &iter); path = gtk_tree_model_get_path (GTK_TREE_MODEL (dv->priv->model), &iter); row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (dv->priv->model), path); gtk_tree_path_free (path); g_hash_table_insert (dv->priv->downloads_hash, download, row_ref); name = ephy_download_get_name (download); gtk_list_store_set (GTK_LIST_STORE (dv->priv->model), &iter, COL_FILENAME, name, COL_DOWNLOAD_OBJECT, download, -1); g_free (name); 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); g_signal_connect_object (download, "changed", G_CALLBACK (download_changed_cb), dv, 0); ephy_dialog_show (EPHY_DIALOG (dv)); } static void downloader_view_build_ui (DownloaderView *dv) { DownloaderViewPrivate *priv = dv->priv; GtkListStore *liststore; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkTreeSelection *selection; GdkPixbuf *icon; EphyDialog *d = EPHY_DIALOG (dv); ephy_dialog_construct (d, properties, "epiphany.glade", "download_manager_dialog"); /* lookup needed widgets */ priv->window = ephy_dialog_get_control(d, PROP_WINDOW); priv->treeview = ephy_dialog_get_control (d, PROP_TREEVIEW); priv->pause_button = ephy_dialog_get_control (d, PROP_PAUSE_BUTTON); priv->abort_button = ephy_dialog_get_control (d, PROP_ABORT_BUTTON); gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)), GTK_SELECTION_SINGLE); liststore = gtk_list_store_new (5, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT); gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL (liststore)); g_object_unref (liststore); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(priv->treeview), TRUE); renderer = ephy_cell_renderer_progress_new (); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(priv->treeview), 0, _("%"), renderer, "value", 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); renderer = gtk_cell_renderer_text_new (); 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_SINGLE); priv->model = GTK_TREE_MODEL (liststore); icon = gtk_widget_render_icon (GTK_WIDGET (priv->window), EPHY_STOCK_DOWNLOAD, GTK_ICON_SIZE_MENU, NULL); gtk_window_set_icon (GTK_WINDOW(priv->window), icon); } void download_dialog_pause_cb (GtkButton *button, DownloaderView *dv) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; GValue val = {0, }; EphyDownload *download; EphyDownloadState state; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; gtk_tree_model_get_value (model, &iter, COL_DOWNLOAD_OBJECT, &val); download = g_value_get_object (&val); g_value_unset (&val); state = ephy_download_get_state (download); if (state == EPHY_DOWNLOAD_DOWNLOADING) { ephy_download_pause (download); } else if (state == EPHY_DOWNLOAD_PAUSED) { ephy_download_resume (download); } } void downloader_view_remove_download (DownloaderView *dv, EphyDownload *download) { GtkTreeRowReference *row_ref; GtkTreePath *path = NULL; GtkTreeIter iter; row_ref = get_row_from_download (dv, download); g_return_if_fail (row_ref); path = gtk_tree_row_reference_get_path (row_ref); gtk_tree_model_get_iter (GTK_TREE_MODEL (dv->priv->model), &iter, path); gtk_list_store_remove (GTK_LIST_STORE (dv->priv->model), &iter); /* FIXME: smart selection */ g_hash_table_remove (dv->priv->downloads_hash, download); gtk_tree_path_free (path); if (!g_hash_table_size (dv->priv->downloads_hash)) g_object_unref (G_OBJECT (dv)); } void download_dialog_abort_cb (GtkButton *button, DownloaderView *dv) { GValue val = {0, }; GtkTreeSelection *selection; GtkTreeIter iter; GtkTreeModel *model; gpointer download; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(dv->priv->treeview)); gtk_tree_selection_get_selected (selection, &model, &iter); gtk_tree_model_get_value (model, &iter, COL_DOWNLOAD_OBJECT, &val); download = g_value_get_object (&val); g_value_unset (&val); g_return_if_fail (download != NULL); ephy_download_cancel ((EphyDownload*)download); downloader_view_remove_download (dv, download); } gboolean download_dialog_delete_cb (GtkWidget *window, GdkEventAny *event, DownloaderView *dv) { return TRUE; }