Logo Search packages:      
Sourcecode: uget version File versions  Download package

uget.c

/*
 *
 *   Copyright (C) 2005-2009 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  This library 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.1 of the License, or (at your option) any later version.
 *
 *  This library 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 this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include <string.h>

#include <ug_utils.h>
#include <ug_list_view.h>
#include <ug_data_app.h>
#include <ug_item.h>
#include <ug_utils.h>
#include <ug_url.h>
#include <uget.h>

#include <glib/gi18n.h>

extern void uget_init_gui (Uget* app);          // uget-gui.c
static void ug_string_list_in_markup (GList** string_list, GMarkupParseContext* context);
static void ug_string_list_to_markup (GList** string_list, UgMarkup* markup);
static void uget_category_store_in_markup (Uget* app, GMarkupParseContext* context);
static void uget_category_store_to_markup (Uget* app, UgMarkup* markup);
static void uget_parser_start_element (GMarkupParseContext* context, const gchar*   element_name,
                                       const gchar**  attr_names,  const gchar**    attr_values,
                                       Uget*                app,         GError**         error);

// Uget*  user_data
static GMarkupParser    uget_parser =
{
      (gpointer) uget_parser_start_element,
      (gpointer) g_markup_parse_context_pop,
      NULL, NULL, NULL
};

static      UgDataEntry       uget_data_entry[] =
{
      {"Visible",                   G_STRUCT_OFFSET (Uget, visible),                      UG_DATA_TYPE_CUSTOM,    (UgInMarkupFunc) ug_data_in_markup,             (UgToMarkupFunc) ug_data_to_markup},
      {"WindowX",                   G_STRUCT_OFFSET (Uget, window_x),                     UG_DATA_TYPE_INT,       NULL,       NULL},
      {"WindowY",                   G_STRUCT_OFFSET (Uget, window_y),                     UG_DATA_TYPE_INT,       NULL,       NULL},
      {"WindowWidth",               G_STRUCT_OFFSET (Uget, window_width),                 UG_DATA_TYPE_INT,       NULL,       NULL},
      {"WindowHeight",        G_STRUCT_OFFSET (Uget, window_height),                UG_DATA_TYPE_INT,       NULL,       NULL},
      {"WindowMaximized",           G_STRUCT_OFFSET (Uget, window_maximized),       UG_DATA_TYPE_INT,       NULL,       NULL},
      {"WindowCloseConfirmation",   G_STRUCT_OFFSET (Uget, window_close_confirmation),    UG_DATA_TYPE_INT,       NULL,       NULL},
      {"WindowCloseSetting",        G_STRUCT_OFFSET (Uget, window_close_setting),         UG_DATA_TYPE_INT,       NULL,       NULL},

      {"FolderList",                G_STRUCT_OFFSET (Uget, folder_list),                  UG_DATA_TYPE_CUSTOM,    (UgInMarkupFunc) ug_string_list_in_markup,      (UgToMarkupFunc) ug_string_list_to_markup},
      {"ClipboardMonitor",    G_STRUCT_OFFSET (Uget, clipboard_monitor),            UG_DATA_TYPE_INT,       NULL,       NULL},
      {"ClipboardPattern",    G_STRUCT_OFFSET (Uget, clipboard_pattern),            UG_DATA_TYPE_STRING,    NULL,       NULL},
      {"LaunchApp",                 G_STRUCT_OFFSET (Uget, launch_app),                   UG_DATA_TYPE_INT,       NULL,       NULL},
      {"LaunchAppTypes",            G_STRUCT_OFFSET (Uget, launch_app_types),       UG_DATA_TYPE_STRING,    NULL,       NULL},
      {"AutoSave",                  G_STRUCT_OFFSET (Uget, auto_save),                    UG_DATA_TYPE_INT,       NULL,       NULL},
      {"AutoSaveInterval",    G_STRUCT_OFFSET (Uget, auto_save_interval),           UG_DATA_TYPE_INT,       NULL,       NULL},
      {"CategoryDefault",           G_STRUCT_OFFSET (Uget, category_default),       UG_DATA_TYPE_CUSTOM,    (UgInMarkupFunc) ug_category_in_markup,         (UgToMarkupFunc) ug_category_to_markup},
      {"CategoryStore",       0,                                                                      UG_DATA_TYPE_CUSTOM,    (UgInMarkupFunc) uget_category_store_in_markup, (UgToMarkupFunc) uget_category_store_to_markup},
      {NULL},
};

static      UgDataEntry       visible_setting_data_entry[] =
{
      {"Toolbar",             G_STRUCT_OFFSET (UgetVisibleSetting, toolbar),              UG_DATA_TYPE_INT, NULL, NULL},
      {"Statusbar",           G_STRUCT_OFFSET (UgetVisibleSetting, statusbar),            UG_DATA_TYPE_INT, NULL, NULL},
      {"TotalList",           G_STRUCT_OFFSET (UgetVisibleSetting, total_list),           UG_DATA_TYPE_INT, NULL, NULL},
      {"CategoryTree",  G_STRUCT_OFFSET (UgetVisibleSetting, category_tree),  UG_DATA_TYPE_INT, NULL, NULL},
      {NULL},
};

static      UgDataClass       uget_data_class =
{
      "Uget",
      NULL,
      sizeof (Uget),
      uget_data_entry,

      (UgInitFunc)            NULL,
      (UgFinalizeFunc)  NULL,
      (UgAssignFunc)          NULL,
};

static      UgDataClass       visible_setting_data_class =
{
      "UgetVisibleSetting",
      NULL,
      sizeof (UgetVisibleSetting),
      visible_setting_data_entry,

      (UgInitFunc)            NULL,
      (UgFinalizeFunc)  NULL,
      (UgAssignFunc)          NULL,
};

Uget* uget_new (UgIpc* ipc)
{
      Uget*                   app;

      app = g_malloc0 (sizeof (Uget));
      app->data_class = &uget_data_class; // for UgMarkup input/output

      // initialize UgetVisibleView
      app->visible.data_class       = &visible_setting_data_class;      // for UgMarkup input/output
      app->visible.toolbar          = TRUE;
      app->visible.statusbar        = TRUE;
      app->visible.total_list       = TRUE;
      app->visible.category_tree    = TRUE;

      // Category store --- start ---
      app->total_list         = gtk_list_store_new (1, G_TYPE_POINTER);
      app->category_list      = gtk_list_store_new (1, G_TYPE_POINTER);
      app->category_tree      = gtk_tree_store_new (1, G_TYPE_POINTER);
      // Category - Queuing
      app->queuing  = ug_category_new (UG_CATEGORY_QUEUING_NAME, NULL);
      app->queuing->list_icon = UG_LIST_ICON_RUNNING;
      app->queuing->visible_column.category  = TRUE;
      gtk_list_store_append (app->total_list, &app->queuing->list_iter);
      gtk_list_store_set (app->total_list, &app->queuing->list_iter, 0, app->queuing, -1);
      // Category - Completed
      app->completed = app->queuing->completed;
      app->completed->visible_column.category  = TRUE;
      gtk_list_store_append (app->total_list, &app->completed->list_iter);
      gtk_list_store_set (app->total_list, &app->completed->list_iter, 0, app->completed, -1);
      // Category - Recycled
      app->recycled  = app->queuing->recycled;
      app->recycled->visible_column.category  = TRUE;
      gtk_list_store_append (app->total_list, &app->recycled->list_iter);
      gtk_list_store_set (app->total_list, &app->recycled->list_iter, 0, app->recycled, -1);
      // Category store --- end ---
      app->category_default = ug_category_new (NULL, app->queuing);
      app->summary_store = gtk_list_store_new (1, G_TYPE_POINTER);

      // dialog
      app->dialog_clipboard_no_url = NULL;
      app->dialog_close_confirmation = NULL;
      app->dialog_settings = NULL;

      // initialize clipboard
      app->clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
      app->clipboard_pattern = g_strdup ("ZIP|BIN|GZ|Z|TAR|TGZ|BZ2|A[0-9]?|LZH|MP3|RPM|DEB|EXE|RAR|R[0-9][0-9]");
      app->clipboard_monitor = TRUE;
      // create GRegex after loading data
//    app->clipboard_regex = g_regex_new (app->clipboard_pattern, G_REGEX_CASELESS, 0, NULL);

      // launch default application for downloaded file.
      app->launch_app = TRUE;
      app->launch_app_types = g_strdup ("torrent");
      // create GRegex after loading data
//    app->launch_app_regex = g_regex_new (app->launch_app_types, G_REGEX_CASELESS, 0, NULL);

      // auto save
      app->auto_save = TRUE;
      app->auto_save_interval = 6;  // minutes

      // window setting
      app->window_close_confirmation = TRUE;
      app->window_close_setting = 0;      // Let user decide

      // ipc
      app->ipc = ipc;
      app->ipc->argument_func = (UgIpcArgFunc) uget_parse_option;
      app->ipc->argument_data = app;

      return app;
}

// call this function after uget_load()
static void uget_check_config (Uget* app)
{
      UgCategory*       category;
      UgDataCommon*     common;
      GtkTreeModel*     model;
      GtkTreeIter       iter;
      gboolean          valid;

      // update visible download columns for total list
      ug_category_apply_visible (app->queuing);
      // check/reset setting for category tree
      model = GTK_TREE_MODEL (app->category_list);
      valid = gtk_tree_model_get_iter_first (model, &iter);
      // If no category, create default one.
      if (valid == FALSE) {
            category = ug_category_new (_("Home"), app->queuing);
            common = UG_DATASET_COMMON (category->download_default);
            ug_str_set (&common->folder, g_get_home_dir (), -1);
            uget_append_category (app, category);
            return;
      }

      // check and reset all setting from markup
      while (valid) {
            gtk_tree_model_get (model, &iter, 0, &category, -1);
            valid = gtk_tree_model_iter_next (model, &iter);
            // reset string to current language.
            ug_str_set (&category->completed->name, UG_CATEGORY_COMPLETED_NAME, -1);
            ug_str_set (&category->recycled->name,  UG_CATEGORY_RECYCLED_NAME,  -1);
            // reset visible download columns
            ug_category_apply_visible (category);
            // clear running state in queuing of category.
            ug_category_clear_running_state (category);
      }
}

void  uget_run (Uget* app)
{
      GtkTreeSelection* selection;
      GtkTreePath*            tree_path;

      // load config
      ug_data_class_register (UgDataAppClass);
      uget_load (app);
      // check config
      uget_check_config (app);
      // create regex after loading config
      app->clipboard_regex  = g_regex_new (app->clipboard_pattern, G_REGEX_CASELESS, 0, NULL);
      app->launch_app_regex = g_regex_new (app->launch_app_types,  G_REGEX_CASELESS, 0, NULL);

      // initialize GUI (uget-gui.c)
      uget_init_gui (app);
      // set position, size, and maximized state
      if (app->window_x < gdk_screen_width ()   && app->window_y < gdk_screen_height ()   &&
          app->window_x + app->window_width > 0 && app->window_y + app->window_height > 0 &&
          app->window_width > 0                 && app->window_height > 0)
      {
            gtk_window_move (app->window, app->window_x, app->window_y);
            gtk_window_resize (app->window, app->window_width, app->window_height);
      }
      if (app->window_maximized)
            gtk_window_maximize (app->window);

      selection = gtk_tree_view_get_selection (app->total_list_view);
//    selection = gtk_tree_view_get_selection (app->category_tree_view);
      tree_path = gtk_tree_path_new_from_indices (0, -1);
      gtk_tree_selection_select_path (selection, tree_path);
      gtk_tree_path_free (tree_path);

      uget_update_menu_move_to (app, TRUE);
      uget_apply_visible (app);
      uget_update_category_sensitive (app);
      gtk_check_menu_item_set_active ((GtkCheckMenuItem*) app->menubar.edit.clipboard_monitor, app->clipboard_monitor);

      g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 1000, (GSourceFunc) uget_on_timer, app, NULL);
}

void  uget_switch_category (Uget* app, UgCategory* category)
{
      GtkTreeSelection* download_selection;
      UgCategory*             selected;

      if (category == app->current)
            return;

      if (app->current) {
            selected = app->current;
            g_object_ref (selected->download_scroll);
            gtk_container_remove (GTK_CONTAINER (app->vpaned), (GtkWidget*) selected->download_scroll);
            download_selection = gtk_tree_view_get_selection (selected->download_view);
            g_signal_handler_disconnect (download_selection, app->download_changed_signal);
            g_signal_handler_disconnect (selected->download_view, app->download_button_signal);
            g_signal_handler_disconnect (selected->download_view, app->download_key_signal);
      }

      if (category) {
            if (gtk_paned_get_child1 (app->vpaned) == app->label_no_selected) {
                  g_object_ref (app->label_no_selected);
                  gtk_container_remove (GTK_CONTAINER (app->vpaned), app->label_no_selected);
            }
            app->current = category;
            gtk_paned_pack1 (app->vpaned, GTK_WIDGET (category->download_scroll), TRUE, FALSE);
            download_selection = gtk_tree_view_get_selection (category->download_view);
            app->download_changed_signal = g_signal_connect (download_selection, "changed", G_CALLBACK (uget_on_queue_selection_changed), app);
            app->download_button_signal  = g_signal_connect (category->download_view, "button-press-event", G_CALLBACK (uget_on_right_button_press), app);
            app->download_key_signal     = g_signal_connect (category->download_view, "key-press-event", G_CALLBACK (uget_on_download_key_press_event), app);
      }
      else {
            app->current = NULL;
            app->download_button_signal  = 0;
            app->download_changed_signal = 0;
            // do it in callback function
//          gtk_paned_pack1 (app->vpaned, app->label_no_selected, TRUE, FALSE);
      }
}

void  uget_append_category (Uget* app, UgCategory* category)
{
      GtkTreeIter iter;

      category = category->queuing; // get top level category in treeview
      ug_category_apply_visible (category);

      // add category (queuing) in list
      gtk_list_store_append (app->category_list, &category->list_iter);
      gtk_list_store_set (app->category_list, &category->list_iter, 0, category, -1);
      // add category (queuing) in tree
      gtk_tree_store_append (app->category_tree, &category->tree_iter, NULL);
      gtk_tree_store_set (app->category_tree, &category->tree_iter, 0, category, -1);
      // add child (completed)
      gtk_tree_store_append (app->category_tree, &iter, &category->tree_iter);
      gtk_tree_store_set (app->category_tree, &iter, 0, category->completed, -1);
      // add child (recycled)
      gtk_tree_store_append (app->category_tree, &iter, &category->tree_iter);
      gtk_tree_store_set (app->category_tree, &iter, 0, category->recycled, -1);
}

void  uget_apply_visible (Uget* app)
{
      // toolbar
      gtk_check_menu_item_set_active ((GtkCheckMenuItem*) app->menubar.view.toolbar, app->visible.toolbar);
/*
      if (app->visible.toolbar)
            gtk_widget_show (app->toolbar.self);
      else
            gtk_widget_hide (app->toolbar.self);
*/
      // status bar
      gtk_check_menu_item_set_active ((GtkCheckMenuItem*) app->menubar.view.statusbar, app->visible.statusbar);
/*
      if (app->visible.statusbar)
            gtk_widget_show ((GtkWidget*) app->statusbar);
      else
            gtk_widget_hide ((GtkWidget*) app->statusbar);
*/

      // total list
      gtk_check_menu_item_set_active ((GtkCheckMenuItem*) app->menubar.view.total_list, app->visible.total_list);
/*
      if (app->visible.total_list) {
            gtk_widget_show ((GtkWidget*) app->total_list_view);
            gtk_widget_show ((GtkWidget*) app->total_list_label);
      }
      else {
            gtk_widget_hide ((GtkWidget*) app->total_list_view);
            gtk_widget_hide ((GtkWidget*) app->total_list_label);
      }
*/
      // category tree
      gtk_check_menu_item_set_active ((GtkCheckMenuItem*) app->menubar.view.category_tree, app->visible.category_tree);
/*
      if (app->visible.category_tree) {
            gtk_widget_show ((GtkWidget*) app->category_tree_scroll);
            gtk_widget_show ((GtkWidget*) app->category_tree_label);
      }
      else {
            gtk_widget_hide ((GtkWidget*) app->category_tree_scroll);
            gtk_widget_hide ((GtkWidget*) app->category_tree_label);
      }
      // left side vbox contain total list and category tree
      if (app->visible.total_list || app->visible.category_tree)
            gtk_widget_show ((GtkWidget*) app->left_vbox);
      else
            gtk_widget_hide ((GtkWidget*) app->left_vbox);
*/
}

// update menu.view
void  uget_update_menu_view (Uget* app)
{
      GtkCheckMenuItem* item;
      UgCategory*             category;
      gboolean                visible;

      category = app->current;
      if (category == NULL)
            return;

      // Download Columns -------------------------
      // rules_hint
      item  = (GtkCheckMenuItem*) app->menubar.view.rules_hint;
      visible     = category->visible_column.rules_hint;
      gtk_check_menu_item_set_active (item, visible);
      // completed
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.completed;
      visible     = category->visible_column.completed;
      gtk_check_menu_item_set_active (item, visible);
      // total
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.total;
      visible     = category->visible_column.total;
      gtk_check_menu_item_set_active (item, visible);
      // percent
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.percent;
      visible     = category->visible_column.percent;
      gtk_check_menu_item_set_active (item, visible);
      // elapsed
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.elapsed;
      visible     = category->visible_column.elapsed;
      gtk_check_menu_item_set_active (item, visible);
      // left
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.left;
      visible     = category->visible_column.left;
      gtk_check_menu_item_set_active (item, visible);
      // speed
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.speed;
      visible     = category->visible_column.speed;
      gtk_check_menu_item_set_active (item, visible);
      // retry
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.retry;
      visible     = category->visible_column.retry;
      gtk_check_menu_item_set_active (item, visible);
      // category
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.category;
      visible     = category->visible_column.category;
      gtk_check_menu_item_set_active (item, visible);
      // url
      item  = (GtkCheckMenuItem*) app->menubar.view.columns.url;
      visible     = category->visible_column.url;
      gtk_check_menu_item_set_active (item, visible);

      // Summary ----------------------------------
      item  = (GtkCheckMenuItem*) app->menubar.view.summary;
      visible     = category->visible_summary.self;
      gtk_check_menu_item_set_active (item, visible);
      if (visible)
            gtk_widget_show (app->summary_scroll);
      else
            gtk_widget_hide (app->summary_scroll);
      // name
      item  = (GtkCheckMenuItem*) app->menubar.view.summary_items.name;
      visible     = category->visible_summary.name;
      gtk_check_menu_item_set_active (item, visible);
      // folder
      item  = (GtkCheckMenuItem*) app->menubar.view.summary_items.folder;
      visible     = category->visible_summary.folder;
      gtk_check_menu_item_set_active (item, visible);
      // category
      item  = (GtkCheckMenuItem*) app->menubar.view.summary_items.category;
      visible     = category->visible_summary.category;
      gtk_check_menu_item_set_active (item, visible);
      // elapsed
//    item  = (GtkCheckMenuItem*) app->menubar.view.summary_items.elapsed;
//    visible     = category->visible_summary.elapsed;
//    gtk_check_menu_item_set_active (item, visible);
      // url
      item  = (GtkCheckMenuItem*) app->menubar.view.summary_items.url;
      visible     = category->visible_summary.url;
      gtk_check_menu_item_set_active (item, visible);
      // message
      item  = (GtkCheckMenuItem*) app->menubar.view.summary_items.message;
      visible     = category->visible_summary.message;
      gtk_check_menu_item_set_active (item, visible);
}

// update menu.download.move_to
void  uget_update_menu_move_to (Uget* app, gboolean reset_item)
{
      GtkTreeModel*     model;
      GtkTreeIter       iter;
      GtkWidget*        widget;
      GPtrArray*        array;
      UgCategory*       category;
      gboolean          valid;
      gchar*                  string;
      gchar*                  category_name;
      guint             index;

      array = app->menubar.download.move_to.array;
      model = GTK_TREE_MODEL (app->category_tree);

      if (reset_item) {
            for (index = 3*2;  index < array->len;  index += 2) {
                  widget   = g_ptr_array_index (array, index);
                  gtk_container_remove ((GtkContainer*) app->menubar.download.move_to.menu, widget);
            }
            g_ptr_array_set_size (array, 3*2);

            valid = gtk_tree_model_get_iter_first (model, &iter);
            while (valid) {
                  gtk_tree_model_get (model, &iter, 0, &category, -1);
                  // queuing
                  category_name = category->name;
                  widget  = gtk_image_menu_item_new_with_label (category_name);
                  gtk_image_menu_item_set_image ((GtkImageMenuItem*) widget, gtk_image_new_from_stock (UG_CATEGORY_STOCK, GTK_ICON_SIZE_MENU));
                  gtk_menu_shell_append ((GtkMenuShell*) app->menubar.download.move_to.menu, widget);
                  g_signal_connect (widget, "activate", G_CALLBACK (uget_on_move_download), app);
                  g_ptr_array_add (array, widget);
                  g_ptr_array_add (array, category);
                  // completed
                  category = category->completed;
                  string = g_strconcat (category_name, " - ", UG_CATEGORY_COMPLETED_NAME, NULL);
                  widget  = gtk_image_menu_item_new_with_label (string);
                  g_free (string);
//                gtk_image_menu_item_set_image ((GtkImageMenuItem*) widget, gtk_image_new_from_stock (UG_CATEGORY_COMPLETED_STOCK, GTK_ICON_SIZE_MENU));
                  gtk_menu_shell_append ((GtkMenuShell*) app->menubar.download.move_to.menu, widget);
                  g_signal_connect (widget, "activate", G_CALLBACK (uget_on_move_download), app);
                  g_ptr_array_add (array, widget);
                  g_ptr_array_add (array, category);
                  // recycled
                  category = category->recycled;
                  string = g_strconcat (category_name, " - ", UG_CATEGORY_RECYCLED_NAME, NULL);
                  widget  = gtk_image_menu_item_new_with_label (string);
                  g_free (string);
//                gtk_image_menu_item_set_image ((GtkImageMenuItem*) widget, gtk_image_new_from_stock (UG_CATEGORY_RECYCLED_STOCK, GTK_ICON_SIZE_MENU));
                  gtk_menu_shell_append ((GtkMenuShell*) app->menubar.download.move_to.menu, widget);
                  g_signal_connect (widget, "activate", G_CALLBACK (uget_on_move_download), app);
                  g_ptr_array_add (array, widget);
                  g_ptr_array_add (array, category);

//                gtk_menu_shell_append ((GtkMenuShell*) app->menubar.download.move_to.menu, gtk_separator_menu_item_new() );
                  valid = gtk_tree_model_iter_next (model, &iter);
            }
            gtk_widget_show_all (app->menubar.download.move_to.menu);
      }

      valid = TRUE;     // "total list" is visible by default.
      for (index = 0;  index < array->len;  index += 2) {
            widget   = g_ptr_array_index (array, index);
            category = g_ptr_array_index (array, index + 1);
            if (category == app->current) {
                  valid = (index < 3*2) ? TRUE : FALSE;
                  gtk_widget_set_sensitive (widget, FALSE);
            }
            else
                  gtk_widget_set_sensitive (widget, TRUE);
      }
      // If current category is in "total list", show "total list" menu item.
      // If current category is in "category tree", show "category tree" menu item.
      for (index = 0;  index < array->len;  index += 2) {
            if (index == 3*2) // begin index of category tree is 3*2
                  valid = !valid;
            if (valid)
                  gtk_widget_show (array->pdata[index]);
            else
                  gtk_widget_hide (array->pdata[index]);
      }
}

void  uget_update_category_sensitive (Uget* app)
{
      static gboolean         last_sensitive = TRUE;
      gboolean                sensitive;

      if (app->current)
            sensitive = TRUE;
      else
            sensitive = FALSE;

      if (last_sensitive != sensitive) {
            last_sensitive = sensitive;
//          gtk_widget_set_sensitive (app->menubar.category.delete, sensitive);
            gtk_widget_set_sensitive (app->menubar.category.properties, sensitive);
            gtk_widget_set_sensitive (app->menubar.view.columns.self, sensitive);
            gtk_widget_set_sensitive (app->menubar.view.rules_hint, sensitive);
      }
      if (app->current == app->queuing || app->current == app->completed || app->current == app->recycled) {
            gtk_widget_set_sensitive (app->menubar.category.delete, FALSE);
            gtk_widget_set_sensitive (app->menubar.category.properties, FALSE);
      }
      else {
            gtk_widget_set_sensitive (app->menubar.category.delete, sensitive);
            gtk_widget_set_sensitive (app->menubar.category.properties, sensitive);
      }

      uget_update_download_sensitive (app);
}

void  uget_update_download_sensitive (Uget* app)
{
      GtkTreeSelection* download_selection;
      static gboolean         last_sensitive = TRUE;
      gboolean                sensitive = FALSE;

      if (app->current) {
            download_selection = gtk_tree_view_get_selection (app->current->download_view);
            if (gtk_tree_selection_count_selected_rows (download_selection) > 0)
                  sensitive = TRUE;
      }
      // Move Up/Down/Top/Bottom functions need reset sensitive when selection changed.
      // These need by  uget_on_move_download_xxx()  series.
      gtk_widget_set_sensitive (app->menubar.download.move_up, sensitive);
      gtk_widget_set_sensitive (app->menubar.download.move_down, sensitive);
      gtk_widget_set_sensitive (app->menubar.download.move_top, sensitive);
      gtk_widget_set_sensitive (app->menubar.download.move_bottom, sensitive);
      gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.move_up, sensitive);
      gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.move_down, sensitive);
      gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.move_top, sensitive);
      gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.move_bottom, sensitive);
      // change sensitive after select/unselect
      if (last_sensitive != sensitive) {
            last_sensitive = sensitive;
            gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.runnable, sensitive);
            gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.pause, sensitive);
            gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.properties, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.open, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.open_folder, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.delete, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.delete_file, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.runnable, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.pause, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.move_to.self, sensitive);
            gtk_widget_set_sensitive (app->menubar.download.properties, sensitive);
      }
}

void  uget_update_statusbar (Uget* app)
{
      GtkTreeSelection* download_selection;
      static guint            last_id=0;
      guint n_selected;
      gchar*      string;

      if (last_id) {
            gtk_statusbar_pop (app->statusbar, last_id);
            last_id = 0;
      }

      if (app->current) {
            download_selection = gtk_tree_view_get_selection (app->current->download_view);
            n_selected = gtk_tree_selection_count_selected_rows (download_selection);
            string = g_strdup_printf (_("Selected %d items"), n_selected);
            last_id = gtk_statusbar_get_context_id (app->statusbar, string);
            gtk_statusbar_push (app->statusbar, last_id, string);
            g_free (string);
      }
}

void  uget_update_summary (Uget* app)
{
      UgItem*                 item;
      UgCategory*       category;
      UgDataset*        dataset;
      UgDataCommon*     common;
      GtkTreeIter       iter;

      // Is any category selected ?
      category = app->current;
      if (category == NULL) {
            ug_item_store_clear_after (app->summary_store, NULL);
            return;
      }
      dataset = ug_category_get_cursor (category);
      // Is any download selected ?
      if (dataset == NULL) {
            ug_item_store_clear_after (app->summary_store, NULL);
            return;
      }
      common = UG_DATASET_COMMON (dataset);

      // clear iter for ug_item_store_realloc_next()
      memset (&iter, 0, sizeof (GtkTreeIter));
      // Summary Name
      if (category->visible_summary.name) {
            item = ug_item_store_realloc_next (app->summary_store, &iter);
            if (common->name) {
                  g_free (item->name);
                  item->name = g_strconcat (_("Name"), ":", NULL);
                  ug_str_set (&item->value, common->name, -1);
            }
            else {
                  g_free (item->name);
                  item->name = g_strconcat (_("File"), ":", NULL);
                  ug_str_set (&item->value, common->file, -1);
            }
            item->list_icon = UG_LIST_ICON_FILE;
      }
      // Summary Folder
      if (category->visible_summary.folder) {
            item = ug_item_store_realloc_next (app->summary_store, &iter);
            item->list_icon = UG_LIST_ICON_FOLDER;
            g_free (item->name);
            item->name = g_strconcat (_("Folder"), ":", NULL);
            ug_str_set (&item->value, common->folder, -1);
      }
      // Summary Category
      if (category->visible_summary.category) {
            item = ug_item_store_realloc_next (app->summary_store, &iter);
            item->list_icon = UG_LIST_ICON_CATEGORY;
            g_free (item->name);
            item->name = g_strconcat (_("Category"), ":", NULL);
            ug_str_set (&item->value, UG_DATASET_APP (dataset)->category_name, -1);
      }
      // Summary Elapsed
//    if (category->visible_summary.elapsed) {
//          item = ug_item_store_realloc_next (app->summary_store, &iter, FALSE);
//          item->list_icon = UG_LIST_ICON_REFRESH;
//          g_free (item->name);
//          item->name = g_strconcat (_("Elapsed"), ":", NULL);
//          g_free (item->value);
//          if (dataset->progress)
//                item->value = ug_str_from_time ((guint) dataset->progress->consume_time, TRUE);
//          else
//                item->value = NULL;
//    }
      // Summary URL
      if (category->visible_summary.url) {
            item = ug_item_store_realloc_next (app->summary_store, &iter);
            item->list_icon = UG_LIST_ICON_NETWORK;
            g_free (item->name);
            item->name = g_strconcat (_("URL"), ":", NULL);
            ug_str_set (&item->value, common->url, -1);
      }
      // Summary Message
      if (category->visible_summary.message) {
            UgDataApp*  appdata = UG_DATASET_APP (dataset);

            item = ug_item_store_realloc_next (app->summary_store, &iter);
            switch (appdata->message_type) {
            case UG_MESSAGE_ERROR:
                  item->list_icon = UG_LIST_ICON_ERROR;
                  break;
            case UG_MESSAGE_WARNING:
                  item->list_icon = UG_LIST_ICON_WARNING;
                  break;
            default:
                  item->list_icon = UG_LIST_ICON_INFO;
                  break;
            }
            g_free (item->name);
            item->name = g_strconcat (_("Message"), ":", NULL);
            ug_str_set (&item->value, appdata->message, -1);
      }
      // clear
      ug_item_store_clear_after (app->summary_store, &iter);
      gtk_widget_queue_draw ((GtkWidget*) app->summary_view);
}

GList*      uget_clipboard_get_url (Uget* app, gint n_url_limit)
{
      UgUrlPart*  urlpart;
      GList*            list;
      gchar*            text;
      guint       text_len;
      guint       line_len;
      guint       offset;

      if (gtk_clipboard_wait_is_text_available (app->clipboard) == FALSE)
            return NULL;
      text = gtk_clipboard_wait_for_text (app->clipboard);
      if (text == NULL)
            return NULL;
      text_len = strlen (text);
      list = NULL;
      urlpart = g_malloc (sizeof (UgUrlPart));
      for (offset = 0;  offset < text_len && n_url_limit;  offset += line_len+1) {
            line_len = ug_str_line_len (text, text_len, offset);
            ug_url_part (urlpart, text+offset, line_len);
            if (urlpart->url_scheme_len == 0)
                  continue;
            list = g_list_prepend (list, g_strndup (text+offset, line_len));
            if (n_url_limit > 0)
                  n_url_limit--;
      }
      g_free (urlpart);
      g_free (text);
      return list;
}

GList*      uget_regex_get_url (Uget* app, const gchar* text, gint text_len)
{
      UgUrlPart*  urlpart;
      GList*            list;
      guint       line_len;
      guint       offset;

      if (text_len == -1)
            text_len = strlen (text);
      list = NULL;
      urlpart = g_malloc (sizeof (UgUrlPart));
      for (offset = 0;  offset < (guint)text_len;  offset += line_len+1) {
            line_len = ug_str_line_len (text, text_len, offset);
            ug_url_part (urlpart, text+offset, line_len);
            if (urlpart->url_scheme_len == 0 || urlpart->file_ext_len == 0)
                  continue;
            if (urlpart->url_scheme_len == 4 && strncmp (urlpart->url, "file", 4) == 0)
                  continue;
            if (g_regex_match_full (app->clipboard_regex, urlpart->file_ext, urlpart->file_ext_len, 0, 0, NULL, NULL))
                  list = g_list_prepend (list, g_strndup (text+offset, line_len));
      }
      g_free (urlpart);
      return list;
}

void  uget_quit (Uget* app)
{
      UgCategory*       category;
      GtkTreeModel*     model;
      GtkTreeIter       iter;
      gboolean          valid;
      gboolean          updated = FALSE;

      model = GTK_TREE_MODEL (app->category_list);
      valid = gtk_tree_model_get_iter_first (model, &iter);
      while (valid) {
            gtk_tree_model_get (model, &iter, 0, &category, -1);
            valid = gtk_tree_model_iter_next (model, &iter);
            if (ug_category_stop_running (category))
                  updated = TRUE;
      }

      uget_save (app);
      ug_ipc_finalize (app->ipc);
      // hide icon in system tray before quit
      gtk_status_icon_set_visible (app->status_icon, FALSE);
      gtk_widget_hide ((GtkWidget*) app->window);

      if (updated)
            g_usleep (2 * 1000000);
      gtk_main_quit ();
}

gboolean uget_load (Uget* app)
{
      gchar*            config_file;
      gboolean    result;

      config_file = g_build_filename (g_get_home_dir (), ".Uget-data.xml", NULL);
      if (g_file_test (config_file, G_FILE_TEST_EXISTS)) {
            // load setting from home dir
            result = ug_markup_input (config_file, &uget_parser, app);
            ug_unlink (config_file);
            g_free (config_file);
            uget_save (app);
      }
      else {
            g_free (config_file);
            // load setting from user config dir
            config_file = g_build_filename (g_get_user_config_dir (), UGET_DATA_FOLDER, UGET_DATA_FILE, NULL);
            result = ug_markup_input (config_file, &uget_parser, app);
            g_free (config_file);
      }

      // copy visible setting to total_list
      if (result)
            ug_category_assign_visible (app->queuing, app->category_default);
      return result;
}

void  uget_save (Uget* app)
{
      UgMarkup*   markup;
      gchar*            config_file;

      // get position, size, and maximzied state
      if (gdk_window_get_state (GTK_WIDGET (app->window)->window) & GDK_WINDOW_STATE_MAXIMIZED)
            app->window_maximized = TRUE;
      else
            app->window_maximized = FALSE;
      if (app->window_maximized == FALSE && GTK_WIDGET_VISIBLE (app->window) == TRUE) {
            gtk_window_get_position (app->window, &app->window_x, &app->window_y);
            gtk_window_get_size (app->window, &app->window_width, &app->window_height);
      }

      // copy visible setting to category_default
      ug_category_assign_visible (app->category_default, app->queuing);
      // create folder
      config_file = g_build_filename (g_get_user_config_dir (), UGET_DATA_FOLDER, NULL);
      ug_create_dir (config_file);
      g_free (config_file);
      // output
      config_file = g_build_filename (g_get_user_config_dir (), UGET_DATA_FOLDER, UGET_DATA_FILE, NULL);
      markup = ug_markup_new ();
      ug_markup_output_start (markup, config_file, TRUE);
      ug_markup_output_element_start      (markup, "Uget version='1.1'");
      ug_data_to_markup ((UgData*) app, markup);
      ug_markup_output_element_end  (markup, "Uget");
      ug_markup_output_end (markup);
      g_free (config_file);
}

gboolean    uget_parse_option (Uget* app, int argc, char** argv)
{
      UgOptionMainData* option_data;
      UgCategory*       category;
      UgDataset*        dataset;
      UgDataCommon*     common;
      GtkTreeModel*     model;
      GtkTreeIter       iter;
      gint              index;

      // If no argument, program presents main window to the user.
      if (argc == 1) {
            if (GTK_WIDGET_VISIBLE (app->window) == FALSE)
                  gtk_window_deiconify (app->window);
            gtk_window_present (app->window);
            return TRUE;
      }

      ug_option_init_data (UgOptionMain);
      g_option_context_parse (app->option_context, &argc, &argv, NULL);

      dataset = ug_dataset_new_app ();
      ug_option_get_dataset (UgOptionMain, dataset);
      common = UG_DATASET_COMMON (dataset);

      for (index=1;  index < argc;  index++) {
            if (*(argv[index]) == '-')
                  continue;
            ug_str_set (&common->url, argv[index], -1);
            break;
      }

      option_data = UgOptionMain->option_data;
      // select category
      model = GTK_TREE_MODEL (app->category_list);
      if (option_data->category_index > 0 && gtk_tree_model_iter_n_children (model, NULL) > option_data->category_index) {
            gtk_tree_model_iter_nth_child (model, &iter, NULL, option_data->category_index);
            gtk_tree_model_get (model, &iter, 0, &category, -1);
      }
      else if (app->current)
            category = app->current->queuing;
      else if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 0))
            gtk_tree_model_get (model, &iter, 0, &category, -1);
      else
            category = NULL;

      // complete filename from URL
      if (common->file == NULL) {
            if (common->url) {
                  UgUrlPart*  urlpart = ug_url_part_new (common->url, -1);
                  if (urlpart->file_len)
                        common->file = ug_url_unescape_to_utf8 (urlpart->file, urlpart->file_len);
                  ug_url_part_free (urlpart);
            }
            if (common->file == NULL)
                  ug_str_set (&common->file, "index.htm", -1);
      }

      // apply settings if need
      if (category && category->download_default) {
            UgDataHttp  *http, *http_default;

            http         = ug_dataset_get (dataset, UgDataHttpClass, 0);
            http_default = ug_dataset_get (category->download_default, UgDataHttpClass, 0);
            if (http_default) {
                  if (http == NULL) {
                        http = ug_dataset_realloc (dataset, UgDataHttpClass, 0);
                        ug_data_assign (http, http_default);
                  }
                  else if (http->referer == NULL)
                        ug_str_set (&http->referer, http_default->referer, -1);
            }

            if (common->user == NULL && common->password == NULL) {
                  ug_str_set (&common->user,     UG_DATASET_COMMON (category->download_default)->user,     -1);
                  ug_str_set (&common->password, UG_DATASET_COMMON (category->download_default)->password, -1);
            }
            if (common->folder == NULL)
                  ug_str_set (&common->folder, UG_DATASET_COMMON (category->download_default)->folder, -1);
            if (UG_DATASET_PROXY (dataset) == NULL)
                  ug_dataset_copy_list (dataset, UgDataProxyClass, UG_DATASET_PROXY (category->download_default));

            common->retry_limit = UG_DATASET_COMMON (category->download_default)->retry_limit;
            common->retry_delay = UG_DATASET_COMMON (category->download_default)->retry_delay;
            UG_DATASET_APP (dataset)->list_icon = UG_DATASET_APP (category->download_default)->list_icon;
      }

      if (option_data->input_file) {
            uget_import_list_file (app, option_data->input_file, option_data->quiet);
            return TRUE;
      }
      if (common->url == NULL) {
            ug_data_free (dataset);
            return FALSE;
      }
      // add download to category
      if (option_data->quiet == FALSE)
            uget_on_create_download_from_ipc (app, dataset, category);
      else if (category)
            ug_category_append (category, dataset);

      return TRUE;
}


// ----------------------------------------------------------------------------
// markup input/output

static void uget_parser_start_element (GMarkupParseContext* context,
                                       const gchar*         element_name,
                                       const gchar**  attr_names,
                                       const gchar**  attr_values,
                                       Uget*                app,
                                       GError**             error)
{
      guint index;

      if (strcmp (element_name, "Uget") != 0) {
            g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "Unknow element");
            return;
      }

      for (index=0; attr_names[index]; index++) {
            if (strcmp (attr_names[index], "version") != 0)
                  continue;
            if (strcmp (attr_values[index], "1.0") == 0 || strcmp (attr_values[index], "1.1") == 0) {
                  g_markup_parse_context_push (context, &ug_data_parser, app);
                  return;
            }
      }

      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "Unknow element");
}

// ----------------------------------------------
// markup input/output for string_list (GList*)

static void ug_string_list_start_element (GMarkupParseContext*    context,
                                          const gchar*            element_name,
                                          const gchar**           attr_names,
                                          const gchar**           attr_values,
                                          GList**                 string_list,
                                          GError**                error)
{
      guint index;

      for (index=0; attr_names[index]; index++) {
            if (strcmp (attr_names[index], "value") == 0)
                  *string_list = g_list_prepend (*string_list, g_strdup (attr_values[index]));
      }

      // skip end_element() one times.
      g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (0));
}

// GList**  user_data
static GMarkupParser    ug_string_list_parser =
{
      (gpointer) ug_string_list_start_element,
      (gpointer) g_markup_parse_context_pop,
      NULL, NULL, NULL
};

static void ug_string_list_in_markup (GList** string_list, GMarkupParseContext* context)
{
      g_markup_parse_context_push (context, &ug_string_list_parser, string_list);
}

static void ug_string_list_to_markup (GList** string_list, UgMarkup* markup)
{
      GList*      link;

      for (link = g_list_last (*string_list);  link;  link = link->prev) {
            ug_markup_output_element_start      (markup, "string value='%s'", link->data);
            ug_markup_output_element_end  (markup, "string");
      }
}


// ----------------------------------------------
// markup input/output for category_store

static void       uget_category_store_start_element (GMarkupParseContext*     context,
                                                   const gchar*         element_name,
                                                   const gchar**  attr_names,
                                                   const gchar**  attr_values,
                                                   Uget*                app,
                                                   GError**             error)
{
      UgCategory*       category;

      if (strcmp (element_name, "category") == 0) {
            category = ug_category_new (NULL, app->queuing);
            uget_append_category (app, category);
            ug_category_in_markup (&category, context);
      }
      else {
            // Skip this element, don't parse anything.
            g_markup_parse_context_push (context, &ug_markup_skip_parser, GINT_TO_POINTER (6));
      }
}

// Uget*  user_data
static GMarkupParser    uget_category_store_parser =
{
      (gpointer) uget_category_store_start_element,
      (gpointer) g_markup_parse_context_pop,
      NULL, NULL, NULL
};

static void uget_category_store_in_markup (Uget* app, GMarkupParseContext* context)
{
      g_markup_parse_context_push (context, &uget_category_store_parser, app);
}

static void uget_category_store_to_markup (Uget* app, UgMarkup* markup)
{
      GtkTreeModel*     model;
      GtkTreeIter       iter;
      UgCategory*       category;
      gboolean          valid;

      model = GTK_TREE_MODEL (app->category_list);
      valid = gtk_tree_model_get_iter_first (model, &iter);
      while (valid) {
            gtk_tree_model_get (model, &iter, 0, &category, -1);
            valid = gtk_tree_model_iter_next (model, &iter);
            // output markup
            ug_markup_output_element_start (markup, "category");
            ug_category_to_markup (&category, markup);
            ug_markup_output_element_end (markup, "category");
      }
}


Generated by  Doxygen 1.6.0   Back to index