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

score-view-ui.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2003  Charles Kerr <charles@rebelbase.com>
 *
 * 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; version 2 of the License.
 *
 * 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
 */

/*********************
**********************  Includes
*********************/

#include <config.h>

#include <stdlib.h>
#include <string.h>

#include <glib.h>
#include <gtk/gtk.h>

#include <pan/base/argset.h>
#include <pan/base/debug.h>
#include <pan/base/log.h>
#include <pan/base/pan-i18n.h>
#include <pan/base/pan-glib-extensions.h>

#include <pan/filters/filter-phrase.h>
#include <pan/filters/score.h>

#include <pan/score-add-ui.h>
#include <pan/score-view-ui.h>
#include <pan/prefs.h>
#include <pan/util.h>

/*********************
**********************  Defines / Enumerated types
*********************/

enum
{
      COLUMN_SCORE_DELTA,
      COLUMN_SCORE_VALUE,
      COLUMN_CRITERIA,
      COLUMN_DATA,
      COLUMN_QTY
};

/*********************
**********************  Macros
*********************/

/*********************
**********************  Structures / Typedefs
*********************/

typedef struct
{
      Article * article;
      GPtrArray * items;
      GStringChunk * string_chunk;

      GtkWidget * tree_view;
      GtkWidget * dialog;
      GtkListStore * store;
      GtkWidget * remove_button;
      GtkWidget * edit_button;
      GtkWidget * add_button;
}
ScoreViewDialog;

/*********************
**********************  Private Function Prototypes
*********************/

/*********************
**********************  Variables
*********************/

/***********
************  Extern
***********/

/***********
************  Public
***********/

/***********
************  Private
***********/

/*********************
**********************  BEGINNING OF SOURCE
*********************/

/***
****  Utility
***/

static ScoreViewItem*
get_selected_item (ScoreViewDialog * d)
{
      ScoreViewItem * retval = NULL;
      GtkTreeSelection * selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d->tree_view));
      GtkTreeIter iter;
      GtkTreeModel * model;

      if (gtk_tree_selection_get_selected (selection, &model, &iter))
            gtk_tree_model_get (model, &iter, COLUMN_DATA, &retval, -1);

      return retval;
}

static void
button_refresh (ScoreViewDialog * d)
{
      const gboolean have_sel = (get_selected_item (d) != NULL);

      gtk_widget_set_sensitive (d->remove_button, have_sel);
}

static void
tree_view_refresh (ScoreViewDialog * d)
{
      GString * criteria = g_string_sized_new (512);
      GtkTreeSelection * selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d->tree_view));
      gboolean found_selected = FALSE;
      GtkTreeIter selected_iter;
      ScoreViewItem * selected_item = get_selected_item (d);
      GPtrArray * a = d->items;
      int i;
      int score;

      gtk_list_store_clear (d->store);

      for (score=i=0; i<a->len; ++i)
      {
            GtkTreeIter iter;
            const ScoreViewItem * item = (const ScoreViewItem*) g_ptr_array_index (a, i);
            char delta_str[32];
            char value_str[32];

            /* build the delta column*/
            if (item->value_assign_flag)
                  g_snprintf (delta_str, sizeof(delta_str), "=%d", item->value);
            else
                  g_snprintf (delta_str, sizeof(delta_str), "%c%d", (item->value<0?'-':'+'), abs(item->value));

            /* build the score column */
            if (item->value_assign_flag)
                  score = item->value;
            else
                  score += item->value;
            g_snprintf (value_str, sizeof(value_str), "%d", score);

            /* build the criteria column: file & line numbers, optional name, criteria */
            g_string_printf (criteria, "file %s, lines %d - %d\n", item->filename, item->begin_line, item->end_line);
            if (is_nonempty_string (item->score_name))
                  g_string_append_printf (criteria, "name: \"%s\"\n", item->score_name);
            g_string_append_printf (criteria, "%s", item->filter_string);
            if (criteria->str[criteria->len-1] == '\n')
                  g_string_erase (criteria, criteria->len-1, 1);

            /* add the new row to the model */
            gtk_list_store_append (d->store, &iter);
            gtk_list_store_set (d->store, &iter, 
                                COLUMN_SCORE_DELTA, g_string_chunk_insert (d->string_chunk, delta_str),
                                COLUMN_SCORE_VALUE, g_string_chunk_insert (d->string_chunk, value_str),
                                COLUMN_CRITERIA, g_string_chunk_insert (d->string_chunk, criteria->str),
                                COLUMN_DATA, item,
                            -1);

            if (item == selected_item) {
                  found_selected = TRUE;
                  selected_iter = iter;
            }

      }

      if (found_selected)
            gtk_tree_selection_select_iter (selection, &selected_iter);

      /* cleanup */
      g_string_free (criteria, TRUE);
}

static void
refresh_all (ScoreViewDialog * d)
{
      g_return_if_fail (d!=NULL);

      score_invalidate (FALSE);
      score_view_free (d->items);
      d->items = score_view_article (d->article);
      tree_view_refresh (d);
      button_refresh (d);
}

/***
****  Remove
***/

static void
remove_button_clicked_cb (GtkButton * button, gpointer data)
{
      ScoreViewDialog * d = (ScoreViewDialog*) data;
      ScoreViewItem * selected_item = get_selected_item (d);

      if (selected_item != NULL)
      {
            /* remove the score */
            score_remove_score (selected_item->filename,
                                selected_item->begin_line,
                                selected_item->end_line,
                                FALSE);

            refresh_all (d);
      }
}

/***
****  Add
***/

static void
add_dialog_destroy_cb (GtkWidget * w, gpointer user_data)
{
      if (GTK_IS_WIDGET (user_data))
      {
            refresh_all ((ScoreViewDialog*) g_object_get_data (G_OBJECT(user_data), "dialog"));
      }
}
static void
add_button_clicked_cb (GtkButton * button, gpointer user_data)
{
      ScoreViewDialog * d = (ScoreViewDialog*) user_data;
      GtkWidget * add_dialog = score_add_dialog (d->dialog, d->article, SCORE_ADD);
      g_signal_connect (add_dialog, "destroy", G_CALLBACK(add_dialog_destroy_cb), d->dialog);
      gtk_widget_show_all (add_dialog);
}

/***
****  Edit
***/

static int
after_external_editor (gpointer data)
{
      ArgSet * args = (ArgSet*) data;
      ScoreViewDialog * dialog = (ScoreViewDialog*) argset_get (args, 1);

      pan_lock ();
      refresh_all (dialog);
      pan_unlock ();

      /* cleanup */
      argset_free (args);
      return 0;
}

static void*
run_external_editor (void * argset_voidp)
{
      ArgSet * args = (ArgSet*) argset_voidp;
      ScoreViewItem * item = (ScoreViewItem*) argset_get (args, 0);
      launch_external_editor (score_editor_command,
                              (item ? item->filename : score_get_main_scorefile_filename()),
                              (item ? item->begin_line : 0),
                              after_external_editor, args);
      return NULL;
}

static void
edit_button_clicked_cb (GtkButton * button, gpointer user_data)
{
      GtkWidget * list_dialog = GTK_WIDGET (user_data);
      ScoreViewDialog * d = (ScoreViewDialog*) g_object_get_data (G_OBJECT(list_dialog), "dialog"); 
      ScoreViewItem * selected_item = get_selected_item (d);

      run_in_worker_thread (run_external_editor, argset_new2 (selected_item, d));
}

static void
tree_view_row_activated_cb (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
{
      edit_button_clicked_cb (NULL, user_data);
}

static void
tree_view_selection_changed_cb (GtkTreeSelection * selection, gpointer user_data)
{
      button_refresh ((ScoreViewDialog*)user_data);
}


/***
****
***/

static void                                          
response_cb (GtkDialog * dialog, int response, gpointer user_data)
{
      if (response == GTK_RESPONSE_APPLY)
            score_invalidate (TRUE);

      gtk_widget_destroy (GTK_WIDGET(dialog));     
}

static void
dialog_free (gpointer dialog_gpointer)
{
      ScoreViewDialog * d = (ScoreViewDialog*) dialog_gpointer;

      g_string_chunk_free (d->string_chunk);
      group_unref_articles (d->article->group, NULL);
      score_view_free (d->items);
      g_free (d);
}

GtkWidget*
score_view_dialog (GtkWidget * parent, Article * article)
{
      GtkWidget * w;
      GtkWidget * bbox;
      GtkWidget * hbox;
      ScoreViewDialog * d;
      GtkTreeViewColumn * column;
      GtkTreeSelection * selection;
      GtkCellRenderer * renderer;
      GtkTooltips * tips = gtk_tooltips_new ();

      /* sanity clause */
      g_return_val_if_fail (GTK_IS_WINDOW(parent), NULL);
      g_return_val_if_fail (article_is_valid(article), NULL);
      g_return_val_if_fail (GTK_IS_WINDOW(parent), NULL);

      group_ref_articles (article->group, NULL);

      /* create our struct */
      d = g_new0 (ScoreViewDialog, 1);
      d->article = article;
      d->items = score_view_article (d->article);
      d->string_chunk = g_string_chunk_new (1024);
      d->dialog = w = gtk_dialog_new_with_buttons (_("Pan: View Article Scores"),
                                                   GTK_WINDOW(parent),
                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
                                                   GTK_STOCK_CLOSE, GTK_RESPONSE_OK,
                                                   NULL);

      {
            GtkWidget *label, *image, *image2, *button, *hbox, *align;

            button = gtk_button_new ();
            label = gtk_label_new_with_mnemonic (_("Close and Re_score"));
            gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
                        
            image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON);
            image2 = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON);
            hbox = gtk_hbox_new (FALSE, 2);

            align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
                                      
            gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
            gtk_box_pack_start (GTK_BOX (hbox), image2, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);

            gtk_container_add (GTK_CONTAINER (button), align);
            gtk_container_add (GTK_CONTAINER (align), hbox);
            gtk_widget_show_all (align);
            gtk_dialog_add_action_widget (GTK_DIALOG(d->dialog), button, GTK_RESPONSE_APPLY);
      }

      gtk_window_set_policy (GTK_WINDOW(w), TRUE, TRUE, TRUE);
      g_signal_connect (GTK_OBJECT(w), "response", G_CALLBACK(response_cb), d);
      g_object_set_data_full (G_OBJECT(w), "dialog", d, dialog_free);

      /* workarea */
      hbox = gtk_hbox_new (FALSE, GUI_PAD);
      gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
      gtk_box_pack_start (GTK_BOX(GTK_DIALOG(w)->vbox), hbox, TRUE, TRUE, 0);

      /* create the list store */
      d->store = gtk_list_store_new (COLUMN_QTY, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);

      /* create the tree_view */
      d->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (d->store));
      gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(d->tree_view), TRUE);

      /* add COLUMN_SCORE_DELTA */
      renderer = gtk_cell_renderer_text_new ();
      column = gtk_tree_view_column_new_with_attributes (_("Change"), renderer, "text", COLUMN_SCORE_DELTA, NULL);
      gtk_tree_view_append_column (GTK_TREE_VIEW(d->tree_view), column);

      /* add COLUMN_SCORE_VALUE */
      renderer = gtk_cell_renderer_text_new ();
      column = gtk_tree_view_column_new_with_attributes (_("New Score"), renderer, "text", COLUMN_SCORE_VALUE, NULL);
      gtk_tree_view_append_column (GTK_TREE_VIEW(d->tree_view), column);

      /* add COLUMN_CRITERIA */
      renderer = gtk_cell_renderer_text_new ();
      column = gtk_tree_view_column_new_with_attributes (_("Criteria"), renderer, "text", COLUMN_CRITERIA, NULL);
      gtk_tree_view_append_column (GTK_TREE_VIEW(d->tree_view), column);

      /* set the selection mode */
      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d->tree_view));
      gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);

      /* add callbacks */
      g_signal_connect (G_OBJECT(d->tree_view), "row-activated",
                        G_CALLBACK (tree_view_row_activated_cb), d->dialog);
      g_signal_connect (G_OBJECT(selection), "changed",
                        G_CALLBACK (tree_view_selection_changed_cb), d);

      w = gtk_scrolled_window_new (NULL, NULL);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
      gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(w), GTK_SHADOW_IN);
      gtk_container_add (GTK_CONTAINER(w), d->tree_view);
      gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
      gtk_widget_set_usize (w, 500, 300);

      /* button box */
      bbox = gtk_vbox_new (FALSE, GUI_PAD_SMALL);
      gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);

      /* add button */
      w = gtk_button_new_from_stock (GTK_STOCK_ADD);
      gtk_box_pack_start (GTK_BOX (bbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Add a new score"), NULL);
      g_signal_connect (w, "clicked", G_CALLBACK(add_button_clicked_cb), d);

      /* edit button */
      w = gtk_button_new_from_stock (GTK_STOCK_OPEN);
      gtk_box_pack_start (GTK_BOX (bbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Edit the selected score"), NULL);
      g_signal_connect (w, "clicked", G_CALLBACK(edit_button_clicked_cb), d->dialog);
      d->edit_button = w;

      /* remove button */
      w = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
      gtk_box_pack_start (GTK_BOX (bbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Remove the selected score"), NULL);
      g_signal_connect (w, "clicked", G_CALLBACK(remove_button_clicked_cb), d);
      d->remove_button = w;

      tree_view_refresh (d);
      button_refresh (d);

      return d->dialog;
}

Generated by  Doxygen 1.6.0   Back to index