Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-links-dialog.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  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 "kz-links-dialog.h"

#include <stdio.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>

#include "gobject-utils.h"
#include "kz-bookmark-filter.h"
#include "kz-icons.h"

enum {
      PROP_0,
      PROP_KZ_WINDOW,
      PROP_KZ_EMBED,
      PROP_SELECTED_ONLY
};

enum {
      RESPONSE_SAVE
};

enum {
      TERMINATOR = -1,
      COLUMN_TITLE,
      COLUMN_URI,
      COLUMN_SAVE,
      N_COLUMNS
};

static void     kz_links_dialog_class_init         (KzLinksDialogClass *klass);
static void     kz_links_dialog_init               (KzLinksDialog  *kzlinks);
static GObject *kz_links_dialog_constructor        (GType           type,
                                        guint           n_props,
                                        GObjectConstructParam *props);
static void     kz_links_dialog_dispose            (GObject        *object);
static void     kz_links_dialog_set_property       (GObject       *object,
                                        guint          prop_id,
                                        const GValue  *value,
                                        GParamSpec    *pspec);
static void     kz_links_dialog_get_property       (GObject       *object,
                                        guint          prop_id,
                                        GValue        *value,
                                        GParamSpec    *pspec);
static void     kz_links_dialog_response           (GtkDialog      *dialog,
                                        gint            arg);

static void     cb_parent_destroy                  (GtkWidget      *widget,
                                        KzLinksDialog  *kzlinks);
static void     tree_sel_open_selected             (GtkTreeModel   *model,
                                        GtkTreePath    *path,
                                        GtkTreeIter    *iter,
                                        gpointer        data);
static gboolean cb_tree_view_key_press             (GtkWidget      *widget,
                                        GdkEventKey    *event,
                                        KzLinksDialog  *kzlinks);
static gboolean cb_tree_view_button_press          (GtkWidget      *widget,
                                        GdkEventButton *event,
                                        KzLinksDialog  *kzlinks);
static void     cb_save_toggled                    (GtkCellRendererToggle *cell,
                                        gchar          *path_str,
                                        KzLinksDialog  *kzlinks);

static GtkDialogClass *parent_class = NULL;


KZ_OBJECT_GET_TYPE(kz_links_dialog, "KzLinksDialog", KzLinksDialog,
               kz_links_dialog_class_init, kz_links_dialog_init,
               GTK_TYPE_DIALOG)

static void
kz_links_dialog_class_init (KzLinksDialogClass *klass)
{
      GObjectClass *gobject_class;
      GtkDialogClass *dialog_class;

      parent_class = g_type_class_peek_parent (klass);

      gobject_class = (GObjectClass *) klass;
      dialog_class  = (GtkDialogClass *) klass;

      /* GtkObject signals */
      gobject_class->constructor  = kz_links_dialog_constructor;
      gobject_class->dispose      = kz_links_dialog_dispose;
      gobject_class->set_property = kz_links_dialog_set_property;
      gobject_class->get_property = kz_links_dialog_get_property;

      /* GtkDialog signals */
      dialog_class->response = kz_links_dialog_response;

      g_object_class_install_property
            (gobject_class,
             PROP_KZ_WINDOW,
             g_param_spec_object("kz-window",
                              _("KzWindow"),
                             _("The parent kazehakase window"),
                             KZ_TYPE_WINDOW,
                             G_PARAM_READWRITE |
                             G_PARAM_CONSTRUCT_ONLY));
      g_object_class_install_property
            (gobject_class,
             PROP_KZ_EMBED,
             g_param_spec_object("kz-embed",
                             _("KzEmbed"),
                             _("The embed widget to extract links"),
                             KZ_TYPE_EMBED,
                             G_PARAM_READWRITE |
                             G_PARAM_CONSTRUCT_ONLY));
      g_object_class_install_property
            (gobject_class,
             PROP_SELECTED_ONLY,
             g_param_spec_boolean("selected-only",
                              _("Selected Only"),
                              _("Whether extract only selected links or not"),
                              FALSE,
                              G_PARAM_READWRITE |
                              G_PARAM_CONSTRUCT_ONLY));
}


static void
kz_links_dialog_init (KzLinksDialog *kzlinks)
{
      GtkWidget *main_vbox, *scrwin, *tree_view;
      GtkListStore *store;
      GtkCellRenderer *cell;
      GtkTreeViewColumn *col;
      GtkTreeSelection *selection;

      kzlinks->kz            = NULL;
      kzlinks->kzembed       = NULL;
      kzlinks->selected_only = FALSE;

      main_vbox = GTK_DIALOG(kzlinks)->vbox;
      gtk_window_set_default_size(GTK_WINDOW(kzlinks), 600, 450);
      gtk_window_set_icon(GTK_WINDOW(kzlinks), kz_icon);

      gtk_dialog_add_buttons(GTK_DIALOG(kzlinks),
                         GTK_STOCK_OPEN,  GTK_RESPONSE_YES,
                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                         GTK_STOCK_SAVE,  RESPONSE_SAVE,
                         NULL);

      /* scrolled window */
      scrwin = gtk_scrolled_window_new(NULL, NULL);
      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
                               GTK_POLICY_AUTOMATIC,
                               GTK_POLICY_AUTOMATIC);
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrwin),
                                  GTK_SHADOW_IN);
      gtk_box_pack_start(GTK_BOX(main_vbox), scrwin, TRUE, TRUE, 0);
      gtk_widget_show(scrwin);

      /* tree view */
      store = gtk_list_store_new(N_COLUMNS,
                           G_TYPE_STRING,
                           G_TYPE_STRING,
                           G_TYPE_BOOLEAN);
      tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
      gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
      gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);

      /* save column */
      cell = gtk_cell_renderer_toggle_new();
      col = gtk_tree_view_column_new_with_attributes
                  (_("Save"), cell, "active", COLUMN_SAVE, NULL);
      g_signal_connect(cell, "toggled",
                   G_CALLBACK(cb_save_toggled), kzlinks);
      gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);

      /* title column */
      cell = gtk_cell_renderer_text_new();
      col = gtk_tree_view_column_new_with_attributes
                  (_("Title"), cell, "text", COLUMN_TITLE, NULL);
      gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
      gtk_tree_view_column_set_fixed_width (col, 200);
      gtk_tree_view_column_set_resizable(col, TRUE);
      gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);

      /* uri column */
      cell = gtk_cell_renderer_text_new();
      col = gtk_tree_view_column_new_with_attributes
                  (_("URI"), cell, "text", COLUMN_URI, NULL);
      gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
      gtk_tree_view_column_set_fixed_width (col, 400);
      gtk_tree_view_column_set_resizable(col, TRUE);
      gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);

      g_signal_connect(tree_view, "key-press-event",
                   G_CALLBACK(cb_tree_view_key_press), kzlinks);
      g_signal_connect(tree_view, "button-press-event",
                   G_CALLBACK(cb_tree_view_button_press), kzlinks);

      gtk_container_add(GTK_CONTAINER(scrwin), tree_view);
      gtk_widget_show(tree_view);

      kzlinks->scrolled_window = scrwin;
      kzlinks->tree_view       = GTK_TREE_VIEW(tree_view);
      kzlinks->list_store      = store;
}


static GObject*
kz_links_dialog_constructor (GType                  type,
                       guint                  n_props,
                       GObjectConstructParam *props)
{
      GtkWidget *widget;
      KzLinksDialog *kzlinks;
      GObject *object;
      GObjectClass *klass = G_OBJECT_CLASS(parent_class);
      GList *list = NULL, *node;
      gboolean result;
      gchar buf[256];

      object = klass->constructor(type, n_props, props);

      kzlinks = KZ_LINKS_DIALOG(object);
      widget = GTK_WIDGET(kzlinks);

      g_signal_connect(kzlinks->kz, "destroy",
                   G_CALLBACK(cb_parent_destroy), kzlinks);
      g_signal_connect(kzlinks->kzembed, "destroy",
                   G_CALLBACK(cb_parent_destroy), kzlinks);

      g_snprintf(buf, sizeof(buf), _("Extracted links  - %s"),
               kz_embed_get_title(kzlinks->kzembed));
      gtk_window_set_title(GTK_WINDOW(kzlinks), buf);

      result = kz_embed_get_links(kzlinks->kzembed, &list,
                            kzlinks->selected_only);
      if (!result || !list) return object;

      for (node = list; node; node = g_list_next(node))
      {
            KzBookmark *link = node->data;
            GtkTreeIter iter;
            const gchar *title = kz_bookmark_get_title(link);
            const gchar *uri = kz_bookmark_get_link(link);

            if (!uri || !*uri) continue;

            if (kz_bookmark_filter_out(link)) continue;

            gtk_list_store_append(kzlinks->list_store, &iter);
            gtk_list_store_set(kzlinks->list_store, &iter,
                           COLUMN_TITLE, title,
                           COLUMN_URI,   uri,
                           COLUMN_SAVE,  TRUE,
                           TERMINATOR);
      }

      g_list_foreach(list, (GFunc) g_object_unref, NULL);
      g_list_free(list);

      return object;
}


static void
kz_links_dialog_dispose (GObject *object)
{
      KzLinksDialog *kzlinks = KZ_LINKS_DIALOG(object);

      if (kzlinks->kz)
      {
            g_signal_handlers_disconnect_by_func
                  (kzlinks->kz,
                   G_CALLBACK(cb_parent_destroy),
                   kzlinks);
            g_object_unref(kzlinks->kz);
            kzlinks->kz = NULL;
      }

      if (kzlinks->kzembed)
      {
            g_signal_handlers_disconnect_by_func
                  (kzlinks->kzembed,
                   G_CALLBACK(cb_parent_destroy),
                   kzlinks);
            g_object_unref(kzlinks->kzembed);
            kzlinks->kzembed = NULL;
      }

      if (kzlinks->list_store)
      {
            g_object_unref(kzlinks->list_store);
            kzlinks->list_store= NULL;
      }

      if (G_OBJECT_CLASS (parent_class)->dispose)
            G_OBJECT_CLASS (parent_class)->dispose(object);
}


static void
kz_links_dialog_set_property (GObject         *object,
                        guint            prop_id,
                        const GValue    *value,
                        GParamSpec      *pspec)
{
      KzLinksDialog *kzlinks = KZ_LINKS_DIALOG(object);
  
      switch (prop_id)
      {
      case PROP_KZ_WINDOW:
            kzlinks->kz = g_object_ref(g_value_get_object(value));
            break;
      case PROP_KZ_EMBED:
            kzlinks->kzembed = g_object_ref(g_value_get_object(value));
            break;
      case PROP_SELECTED_ONLY:
            kzlinks->selected_only = g_value_get_boolean(value);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}


static void
kz_links_dialog_get_property (GObject         *object,
                        guint            prop_id,
                        GValue          *value,
                        GParamSpec      *pspec)
{
      KzLinksDialog *kzlinks = KZ_LINKS_DIALOG(object);

      switch (prop_id)
      {
      case PROP_KZ_WINDOW:
            g_value_set_object(value, kzlinks->kz);
            break;
      case PROP_KZ_EMBED:
            g_value_set_object(value, kzlinks->kzembed);
            break;
      case PROP_SELECTED_ONLY:
            g_value_set_boolean(value, kzlinks->selected_only);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}


GtkWidget *
kz_links_dialog_new (KzWindow *kz, KzEmbed *kzembed, gboolean selected_only)
{
      GtkWidget *widget;

      widget = GTK_WIDGET(g_object_new(KZ_TYPE_LINKS_DIALOG,
                               "kz-window",     kz,
                               "kz-embed",      kzembed,
                               "selected-only", selected_only,
                               NULL));

      return widget;
}


static gchar *last_saved_file = NULL;


static gboolean
kz_links_dialog_save (KzLinksDialog *kzlinks, const gchar *filename)
{
      FILE *fp;
      GtkTreeModel *model = GTK_TREE_MODEL(kzlinks->list_store);
      GtkTreeIter iter;
      gboolean exist;

      fp = fopen(filename, "wt");
      if (!fp)
      {
            GtkWidget *dialog;

            dialog = gtk_message_dialog_new(GTK_WINDOW(kzlinks),
                                    GTK_DIALOG_MODAL,
                                    GTK_MESSAGE_ERROR,
                                    GTK_BUTTONS_OK,
                                    _("Can't open %s for write!"),
                                    filename);
            gtk_dialog_run(GTK_DIALOG(dialog));
            gtk_widget_destroy(dialog);

            return FALSE;
      }

      exist = gtk_tree_model_get_iter_first(model, &iter);
      for (; exist; exist = gtk_tree_model_iter_next(model, &iter))
      {
            gchar *url = NULL;
            gboolean save = TRUE;

            gtk_tree_model_get(model, &iter,
                           COLUMN_URI,  &url,
                           COLUMN_SAVE, &save,
                           TERMINATOR);
            if (!url) continue;
            if (!*url || !save)
            {
                  g_free(url);
                  continue;
            }

            fputs(url, fp);
            fputc('\n', fp);
            g_free(url);
      }

      fclose(fp);

      return TRUE;
}


static void
cb_filedialog_response (GtkDialog *dialog, gint arg, KzLinksDialog *kzlinks)
{
      GtkFileChooserDialog *filedialog = GTK_FILE_CHOOSER_DIALOG(dialog);
      gchar *file = NULL;
      gboolean close = TRUE;

      file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filedialog));

      switch (arg) {
      case GTK_RESPONSE_OK:
            if (file && *file)
                  close = kz_links_dialog_save(kzlinks, file);
      case GTK_RESPONSE_CANCEL:
            if (file && *file)
                  g_free(last_saved_file);
            last_saved_file = g_strdup(file);
            if (close)
                  gtk_widget_destroy(GTK_WIDGET(dialog));
            break;
      default:
            break;
      }

      if (file)
            g_free(file);
}


static void
kz_links_dialog_save_dialog (KzLinksDialog *kzlinks)
{
      GtkWidget *filedialog;

      filedialog = gtk_file_chooser_dialog_new (_("Save to file"),
                                      GTK_WINDOW(kzlinks),
                                      GTK_FILE_CHOOSER_ACTION_SAVE,
                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                      GTK_STOCK_OK, GTK_RESPONSE_OK,
                                      NULL);
      gtk_dialog_set_default_response(GTK_DIALOG(filedialog),
                              GTK_RESPONSE_OK);
      if (last_saved_file)
      {
            gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filedialog),
                                      last_saved_file);
      }
      g_signal_connect(filedialog, "response",
                   G_CALLBACK(cb_filedialog_response), kzlinks);
      g_signal_connect(filedialog, "destroy",
                   G_CALLBACK(gtk_main_quit), NULL);
      gtk_grab_add(GTK_WIDGET(filedialog));
      gtk_widget_show(filedialog);
      gtk_main();
}


static void
kz_links_dialog_response (GtkDialog *dialog, gint arg)
{
      KzLinksDialog *kzlinks;
      GtkTreeSelection *selection;

      g_return_if_fail (KZ_IS_LINKS_DIALOG(dialog));

      kzlinks = KZ_LINKS_DIALOG(dialog);
      if (!kzlinks->kz || !kzlinks->kzembed) return;

      switch (arg) {
      case GTK_RESPONSE_YES:
            selection = gtk_tree_view_get_selection(kzlinks->tree_view);
            gtk_tree_selection_selected_foreach
                  (selection, tree_sel_open_selected, kzlinks);
            break;
      case GTK_RESPONSE_CLOSE:
            gtk_widget_destroy(GTK_WIDGET(dialog));
            break;
      case RESPONSE_SAVE:
            kz_links_dialog_save_dialog(kzlinks);
            break;
      default:
            break;
      }
}


static void
cb_parent_destroy(GtkWidget *widget, KzLinksDialog *kzlinks)
{
      g_return_if_fail (KZ_IS_LINKS_DIALOG(kzlinks));
      gtk_widget_destroy(GTK_WIDGET(kzlinks));
}


static void
tree_sel_open_selected (GtkTreeModel *model,
                  GtkTreePath *path, GtkTreeIter *iter,
                  gpointer data)
{
      KzLinksDialog *kzlinks = data;
      gchar *url;

      g_return_if_fail(KZ_IS_LINKS_DIALOG(kzlinks));

      gtk_tree_model_get(GTK_TREE_MODEL(kzlinks->list_store),
                     iter, 1, &url, -1);

      if (url && *url)
            kz_window_open_new_tab_with_parent(kzlinks->kz, url,
                                       GTK_WIDGET(kzlinks->kzembed));

      g_free(url);
}


static gboolean
cb_tree_view_button_press (GtkWidget *widget, GdkEventButton *event,
                     KzLinksDialog *kzlinks)
{
      GtkTreeSelection *selection;

      g_return_val_if_fail(KZ_IS_LINKS_DIALOG(kzlinks), FALSE);

      if (event->type == GDK_2BUTTON_PRESS)
      {
            selection = gtk_tree_view_get_selection(kzlinks->tree_view);
            gtk_tree_selection_selected_foreach
                  (selection, tree_sel_open_selected, kzlinks);
            return TRUE;
      }

      return FALSE;
}


static gboolean
cb_tree_view_key_press (GtkWidget *widget, GdkEventKey *event,
                  KzLinksDialog *kzlinks)
{
      GtkTreeSelection *selection;

      g_return_val_if_fail(KZ_IS_LINKS_DIALOG(kzlinks), FALSE);

      switch (event->keyval) {
      case GDK_Return:
      case GDK_space:
            selection = gtk_tree_view_get_selection(kzlinks->tree_view);
            gtk_tree_selection_selected_foreach
                  (selection, tree_sel_open_selected, kzlinks);
            return TRUE;
            break;
      default:
            break;
      }

      return FALSE;
}


static void
cb_save_toggled (GtkCellRendererToggle *cell, gchar *path_str,
             KzLinksDialog *kzlinks)
{
        GtkTreeView *treeview;
        GtkTreeModel *model;
        GtkTreePath *path;
        GtkTreeIter iter;
      gboolean active;

      g_return_if_fail(KZ_IS_LINKS_DIALOG(kzlinks));

      treeview = GTK_TREE_VIEW(kzlinks->tree_view);
      model = gtk_tree_view_get_model(treeview);
      path = gtk_tree_path_new_from_string(path_str);

      active = gtk_cell_renderer_toggle_get_active(cell);

        gtk_tree_model_get_iter(model, &iter, path);
        gtk_list_store_set(GTK_LIST_STORE(model), &iter,
                     COLUMN_SAVE, !active,
                     TERMINATOR);

        gtk_tree_path_free (path);
}

Generated by  Doxygen 1.6.0   Back to index