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

score-add-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/debug.h>
#include <pan/base/pan-i18n.h>
#include <pan/base/pan-glib-extensions.h>
#include <pan/base/pan-config.h>

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

#include <pan/articlelist.h>
#include <pan/grouplist.h>
#include <pan/score-add-ui.h>

#include <pan/util.h>

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

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

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

typedef struct
{
      gboolean new_score;

      GtkWidget * dialog;

      GtkWidget * section_menu;
      GtkWidget * section_entry;

      GtkWidget * subject_tb;
      GtkWidget * subject_menu;
      GtkWidget * subject_entry;
      GtkWidget * author_tb;
      GtkWidget * author_menu;
      GtkWidget * author_entry;
      GtkWidget * lines_tb;
      GtkWidget * lines_menu;
      GtkObject * lines_adj;
      GtkWidget * refs_tb;
      GtkWidget * refs_menu;
      GtkWidget * refs_entry;

      GtkWidget * score_tb;
      GtkWidget * score_menu;
      GtkObject * score_adj;
      GtkWidget * ignore_tb;
      GtkWidget * watch_tb;

      GtkWidget * expire_tb;
      GtkObject * expire_adj;
      GtkWidget * expire_never_tb;

      char * group_string;
      char * xref_string;
      char * message_id;
      char * top_message_id;
}
ScoreEditDialog;

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

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

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

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

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

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

/**
***  Utility - FilterPhrase's MatchType option menu
**/

static GtkWidget*
match_type_option_menu_new (void)
{
      int i;
      GtkWidget * om;
      GtkWidget * m;
      GHashTable * hash;
      struct {
            int type;
            const char * str;
      } items[] = {
            { PHRASE_MATCH_CONTAINS,     N_("contains")},
            {-PHRASE_MATCH_CONTAINS,     N_("does not contain")},
            { PHRASE_MATCH_IS,           N_("is")},
            {-PHRASE_MATCH_IS,           N_("is not")},
            { PHRASE_MATCH_STARTS_WITH,  N_("starts with")}, 
            {-PHRASE_MATCH_STARTS_WITH,  N_("does not start with")},
            { PHRASE_MATCH_ENDS_WITH,    N_("ends with")},
            {-PHRASE_MATCH_ENDS_WITH,    N_("does not end with")},
            { PHRASE_MATCH_REGEX,        N_("matches regular expression")}, 
            {-PHRASE_MATCH_REGEX,        N_("does not match regular expression")}
      };

      om = gtk_option_menu_new ();
      m = gtk_menu_new (); 
      hash = g_hash_table_new (g_direct_hash, g_direct_equal);
      g_object_set_data_full (G_OBJECT(om), "match_type_hash", hash, (GDestroyNotify)g_hash_table_destroy);
      for (i=0; i<G_N_ELEMENTS(items); ++i) {
            GtkWidget * tmp = gtk_menu_item_new_with_label (items[i].str);
            gpointer user_data = GINT_TO_POINTER (items[i].type);
            gtk_object_set_user_data (GTK_OBJECT(tmp), user_data);
            gtk_widget_show (tmp);
            gtk_menu_shell_append (GTK_MENU_SHELL(m), tmp);
            g_hash_table_insert (hash, user_data, GINT_TO_POINTER(i));
      }
      gtk_option_menu_set_menu (GTK_OPTION_MENU(om), m);

      return om;
}

static void
match_type_option_menu_get (GtkWidget * om, int * type, gboolean * negate)
{
      GtkWidget * m = gtk_option_menu_get_menu (GTK_OPTION_MENU(om));
      GtkWidget * active = gtk_menu_get_active (GTK_MENU(m));
      const int match_type = GPOINTER_TO_INT(gtk_object_get_user_data (GTK_OBJECT(active)));
      *type = abs(match_type);
      *negate = match_type < 0;
}

static void
match_type_option_menu_set (GtkWidget * om, int match_type, gboolean negate)
{
      const int type = negate ? -match_type : match_type;
      gpointer user_data = GINT_TO_POINTER(type);
      GHashTable * hash = g_object_get_data (G_OBJECT(om), "match_type_hash");
      const int index = GPOINTER_TO_INT (g_hash_table_lookup (hash, user_data));
      gtk_option_menu_set_history (GTK_OPTION_MENU(om), index);
}

/**
***
**/

static void
tb_activate (GtkToggleButton * tb)
{
      gtk_toggle_button_set_active (tb, TRUE);
}

static void
menu_add_item (GtkWidget * m, GtkWidget * radiobutton, gpointer user_data, const char * str)
{
      GtkWidget * tmp;

      /* sanity clause */
      g_return_if_fail (GTK_IS_WIDGET(m));
      g_return_if_fail (radiobutton==NULL || GTK_IS_WIDGET(radiobutton));
      g_return_if_fail (is_nonempty_string (str));

      /* build the menu button */
      tmp = gtk_menu_item_new_with_label (str);
      gtk_object_set_user_data (GTK_OBJECT(tmp), user_data);
      if (radiobutton != NULL)
            g_signal_connect_swapped (G_OBJECT(tmp), "activate", G_CALLBACK(tb_activate), G_OBJECT(radiobutton));
      gtk_widget_show (tmp);
      gtk_menu_shell_append (GTK_MENU_SHELL(m), tmp);
}

/************
*************  EDIT DIALOG
************/

static char*
get_value_for_match_type_from_str (const char * in, GtkWidget * om, gboolean * negate)
{
      int match_type;
      match_type_option_menu_get (om, &match_type, negate);
      return filter_phrase_create_regex (in, match_type);
}

static char*
get_value_for_match_type (GtkWidget * entry, GtkWidget * om, gboolean * negate)
{
      return get_value_for_match_type_from_str (gtk_entry_get_text (GTK_ENTRY(entry)), om, negate);
}


static char*
add_this_to_scorefile (ScoreEditDialog * d, gboolean do_rescore_all)
{
      gboolean value_assign_flag;
      gboolean on;
      GString * str;
      int value;
      int lifespan_days;
      int item_qty = 0;
      int i;
      char * retval = NULL;
      char * section;
      gboolean section_negate;
      ScoreAddItem items[16];
      GtkWidget * active;

      /* section */

      section_negate = FALSE;
      section = get_value_for_match_type (d->section_entry, d->section_menu, &section_negate);
      if (!is_nonempty_string (section))
            replace_gstr (&section, g_strdup ("*"));
      if (section_negate)
            replace_gstr (&section, g_strdup_printf ("~%s", section));

      /* value */

      value_assign_flag = TRUE;
      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->ignore_tb)))
            value = -9999;
      else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->watch_tb)))
            value = 9999;
      else {
            value = (int) gtk_adjustment_get_value (GTK_ADJUSTMENT(d->score_adj));
            active = gtk_menu_get_active (GTK_MENU(d->score_menu));
            switch (GPOINTER_TO_INT(gtk_object_get_user_data (GTK_OBJECT(active)))) {
                  case 0: value_assign_flag = FALSE; break; /* add */
                  case 1: value_assign_flag = FALSE; value = -value; break; /* subtract */
            }
      }

      lifespan_days = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->expire_never_tb))
            ? 0
            : (int) gtk_adjustment_get_value (GTK_ADJUSTMENT(d->expire_adj));

      items[item_qty].key = "Subject";
      items[item_qty].on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->subject_tb));
      items[item_qty].value = get_value_for_match_type (d->subject_entry, d->subject_menu, &items[item_qty].negate);
      ++item_qty;

      items[item_qty].key = "From";
      items[item_qty].on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->author_tb));
      items[item_qty].value = get_value_for_match_type (d->author_entry, d->author_menu, &items[item_qty].negate);
      ++item_qty;

      items[item_qty].key = "References";
      items[item_qty].on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->refs_tb));
      items[item_qty].value = get_value_for_match_type (d->refs_entry, d->refs_menu, &items[item_qty].negate);
      ++item_qty;

      /* add this in to make life easier when editing scorefiles by hand */
      if (is_nonempty_string (d->xref_string)) {
            items[item_qty].key = "Xref";
            items[item_qty].value = g_strdup (d->xref_string);
            items[item_qty].on = FALSE;
            items[item_qty].negate = FALSE;
            ++item_qty;
      }

      items[item_qty].key = "Lines";
      active = gtk_menu_get_active (GTK_MENU(d->lines_menu));
      items[item_qty].on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->lines_tb));
      items[item_qty].negate = gtk_object_get_user_data (GTK_OBJECT(active)) != NULL;
      items[item_qty].value = g_strdup_printf ("%d", (int)gtk_adjustment_get_value(GTK_ADJUSTMENT(d->lines_adj)));
      ++item_qty;

      /**
      ***  Sanity checks
      **/

      on = FALSE;
      str = g_string_new (NULL);
      for (i=0; i<item_qty; ++i) {
            on = on || items[i].on;
            if (items[i].on)
            {
                  if (!is_nonempty_string(items[i].value))
                  {
                        g_string_append_printf (str, _("Criterion \"%s\" is selected, but empty."), items[i].key);
                        g_string_append_c (str, '\n');
                  }
                  else
                  {
                        char * regex_errmsg = filter_phrase_validate_pattern (items[i].value);
                        if (regex_errmsg != NULL) {
                              g_string_append_printf (str, _("Can't use regular expression \"%s\": %s"), items[i].value, regex_errmsg);
                              g_string_append_c (str, '\n');
                              g_free (regex_errmsg);
                        }
                  }
            }
      }
      if (!on) {
            g_string_append (str, _("No criteria are selected."));
            g_string_append_c (str, '\n');
      }
      if (!str->len)
            g_string_free (str, TRUE);
      else {
            g_string_truncate (str, str->len-1); /* remove trailing \n */
            retval = g_string_free (str, FALSE);
      }

      /* if no errors in the user's in put, add the score. */
      if (!retval)
            score_add (NULL, section, value, value_assign_flag, lifespan_days, AGGREGATE_TYPE_AND, items, item_qty, do_rescore_all);

      /* cleanup */
      g_free (section);
      for (i=0; i<item_qty; ++i)
            g_free (items[i].value);

      return retval;
}

static void
score_edit_response_cb (GtkDialog * w, int response, gpointer user_data)
{
      ScoreEditDialog * d = (ScoreEditDialog*) user_data;
      gboolean do_close = TRUE;

      if (response == GTK_RESPONSE_APPLY || response == GTK_RESPONSE_OK)
      {
            char * error_message = add_this_to_scorefile (d, response==GTK_RESPONSE_APPLY);
            if (error_message != NULL)
            {
                  GtkWidget * dialog = gtk_message_dialog_new (GTK_WINDOW(w),
                        GTK_DIALOG_DESTROY_WITH_PARENT,
                        GTK_MESSAGE_ERROR,
                        GTK_BUTTONS_CLOSE, "%s", error_message);
                  g_signal_connect_swapped (G_OBJECT(dialog), "response",
                                            G_CALLBACK (gtk_widget_destroy), dialog);
                  gtk_widget_show_all (dialog);
                  g_free (error_message);
                  do_close = FALSE;
            }
      }
      if (response == GTK_RESPONSE_HELP)
      {
            g_message ("FIXME: help");
            do_close = FALSE;
      }
      if (do_close)
      {
            g_free (d->message_id);
            g_free (d->top_message_id);
            g_free (d->group_string);
            g_free (d->xref_string);
            g_object_set_data (G_OBJECT(w), "response", GINT_TO_POINTER(response));
            gtk_widget_destroy (GTK_WIDGET(w));
      }
}

static void
dialog_populate (ScoreEditDialog * d, const Article * a, ScoreAddMode mode)
{
      Group * group;
      char buf[512];
      int match_type;

      /* populate the dialog's article fields */
      d->message_id = a ? g_strdup (article_get_message_id (a)) : NULL;
      d->top_message_id = a ? article_get_thread_message_id (a) : NULL;
      d->group_string = a ? g_strdup (group_get_name (a->group)) : NULL;
      d->xref_string = a ? g_memdup (a->xref.str, a->xref.len+1) : NULL;

      /* section */
      /* FIXME: this is awkward, and gui.c's menu refresh does it too.
       * we need a canonical way of getting the current group. */
      group = NULL;
      if (a != NULL)
            group = a->group;
      if (group == NULL)
            group = articlelist_get_group ();
      if (group == NULL)
            group = grouplist_get_selected_group ();
      if (group != NULL) {
            gtk_entry_set_text (GTK_ENTRY(d->section_entry), group_get_name(group));
            match_type_option_menu_set (d->section_menu, PHRASE_MATCH_IS, FALSE);
      } else {
            gtk_entry_set_text (GTK_ENTRY(d->section_entry), "*");
            match_type_option_menu_set (d->section_menu, PHRASE_MATCH_REGEX, FALSE);
      }

      /* criteria */
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->subject_tb), FALSE);
      gtk_entry_set_text (GTK_ENTRY(d->subject_entry), a ? article_get_subject(a): "");
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->author_tb), mode==SCORE_ADD_PLONK);
      *buf = '\0';
      if (a != NULL)
            article_get_author_str (a, buf, sizeof(buf));
      if (mode == SCORE_ADD_PLONK)
            match_type_option_menu_set (d->author_menu, PHRASE_MATCH_IS, FALSE);
      gtk_entry_set_text (GTK_ENTRY(d->author_entry), buf);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->lines_tb), FALSE);
      gtk_adjustment_set_value (GTK_ADJUSTMENT(d->lines_adj), a ? a->linecount : 0);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->refs_tb),
               mode==SCORE_ADD_WATCH_SUBTHREAD
            || mode==SCORE_ADD_IGNORE_SUBTHREAD);
      switch (mode) {
            case SCORE_ADD_WATCH_SUBTHREAD:
            case SCORE_ADD_IGNORE_SUBTHREAD:
                  match_type = PHRASE_MATCH_CONTAINS;
                  break;
            case SCORE_ADD_PLONK:
            case SCORE_ADD:
                  match_type = PHRASE_MATCH_IS;
                  break;
      }
      match_type_option_menu_set (d->author_menu, match_type, FALSE);
      gtk_entry_set_text (GTK_ENTRY(d->refs_entry), a ? article_get_message_id(a) : "");

      /* score */
      switch (mode) {
            case SCORE_ADD_WATCH_SUBTHREAD:
                  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->watch_tb), TRUE);
                  break;
            case SCORE_ADD_PLONK:
            case SCORE_ADD_IGNORE_SUBTHREAD:
                  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->ignore_tb), TRUE);
                  break;
            case SCORE_ADD:
                  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->score_tb), TRUE);
                  break;
      }

      /* lifespan */
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->expire_tb), TRUE);
      gtk_adjustment_set_value (GTK_ADJUSTMENT(d->expire_adj), 30);
}

#define SENSITIVE_LIST "sensitive_list"

static void
refresh_enabled_states (GtkToggleButton * tb)
{
      GSList * l;
      GSList * s = (GSList*) g_object_get_data (G_OBJECT(tb), SENSITIVE_LIST);
      const gboolean active = gtk_toggle_button_get_active (tb);

      for (l=s; l!=NULL; l=l->next)
            gtk_widget_set_sensitive (GTK_WIDGET(l->data), active);
}

static void
toggled_cb (GtkToggleButton * tb, gpointer user_data)
{
      refresh_enabled_states (tb);
}


#define ENTRY_WIDTH_CHARS 40
#define ROWS 17
#define COLUMNS 6
#define CHECK_L 1
#define CHECK_R 2
#define CONTROL1_L 3
#define CONTROL1_R 4
#define CONTROL2_L 5
#define CONTROL2_R 6

GtkWidget*
score_add_dialog (GtkWidget * window, Article * article, ScoreAddMode mode)
{
      GtkObject * a;
      GtkWidget * dialog;
      GtkWidget * w;
      GtkWidget * w2;
      GtkWidget * t;
      GtkWidget * l;
      GSList * s = NULL;
      int row;
      ScoreEditDialog * d;

      /* create the dialog */
      dialog = gtk_dialog_new_with_buttons (_("Pan: Add to Scorefile"),
                                            GTK_WINDOW(window),
                                            GTK_DIALOG_DESTROY_WITH_PARENT,
                                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                            GTK_STOCK_HELP, GTK_RESPONSE_HELP,
                                            GTK_STOCK_ADD, GTK_RESPONSE_OK,
                                            NULL);

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

            button = gtk_button_new ();
            label = gtk_label_new_with_mnemonic (_("Add and Re_score"));
            gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
                        
            image = gtk_image_new_from_stock (GTK_STOCK_ADD, 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(dialog), button, GTK_RESPONSE_APPLY);
      }

      d = g_new0 (ScoreEditDialog, 1);
      d->dialog = dialog;
      g_object_set_data_full (G_OBJECT(dialog), "dialog", d, g_free);
      g_signal_connect (dialog, "response", G_CALLBACK(score_edit_response_cb), d);

      /**
      ***  workarea
      **/

      row = 0;
      t = pan_hig_workarea_create ();
      gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), t, TRUE, TRUE, 0);

      /**
      ***  Spacers
      **/

      /* offset the checkboxes a little bit from the section titles */
      w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
      gtk_widget_set_usize (w, 18u, 0u);
      gtk_table_attach (GTK_TABLE(t), w, 0, 1, 0, ROWS, 0, 0, 0, 0);

      /* spacer between the checkboxes and their controls */
      w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
      gtk_widget_set_usize (w, 12u, 0u);
      gtk_table_attach (GTK_TABLE(t), w, 2, 3, 0, ROWS, 0, 0, 0, 0);

      /* spacer between a checkboxes' first and second controls */
      w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
      gtk_widget_set_usize (w, 6u, 0u);
      gtk_table_attach (GTK_TABLE(t), w, 4, 5, 0, ROWS, 0, 0, 0, 0);

      /**
      ***  Section
      **/

      pan_hig_workarea_add_section_title (t, &row, _("Newsgroups"));

            /* section */

            l = pan_hig_workarea_add_label (t, row, _("Group"));

            w = d->section_menu = match_type_option_menu_new ();
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            match_type_option_menu_set (w, PHRASE_MATCH_IS, FALSE);

            w = d->section_entry = gtk_entry_new ();
            gtk_entry_set_width_chars (GTK_ENTRY(w), ENTRY_WIDTH_CHARS);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL2_L, CONTROL2_R, row, row+1);
            ++row;

      /**
      ***  Criteria
      **/

      pan_hig_workarea_add_section_divider (t, &row);
      pan_hig_workarea_add_section_title (t,  &row, _("Criteria"));

            /* subject */
            l = d->subject_tb = gtk_check_button_new_with_mnemonic (_("Su_bject:"));
            g_signal_connect (l, "toggled", G_CALLBACK(toggled_cb), NULL);
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            w = d->subject_menu = match_type_option_menu_new ();
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            w = d->subject_entry = gtk_entry_new ();
            s = g_slist_prepend (s, w);
            gtk_entry_set_width_chars (GTK_ENTRY(w), ENTRY_WIDTH_CHARS);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL2_L, CONTROL2_R, row, row+1);
            g_object_set_data_full (G_OBJECT(l), SENSITIVE_LIST, s, (GDestroyNotify)g_slist_free);
            s = NULL;
            refresh_enabled_states (GTK_TOGGLE_BUTTON(l));
            ++row;

            /* from */
            l = d->author_tb = gtk_check_button_new_with_mnemonic (_("A_uthor:"));
            g_signal_connect (l, "toggled", G_CALLBACK(toggled_cb), NULL);
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            w = d->author_menu = match_type_option_menu_new ();
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            w = d->author_entry = gtk_entry_new ();
            s = g_slist_prepend (s, w);
            gtk_entry_set_width_chars (GTK_ENTRY(w), ENTRY_WIDTH_CHARS);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL2_L, CONTROL2_R, row, row+1);
            g_object_set_data_full (G_OBJECT(l), SENSITIVE_LIST, s, (GDestroyNotify)g_slist_free);
            s = NULL;
            refresh_enabled_states (GTK_TOGGLE_BUTTON(l));
            ++row;

            /* references */
            l = d->refs_tb = gtk_check_button_new_with_mnemonic (_("_References:"));
            g_signal_connect (l, "toggled", G_CALLBACK(toggled_cb), NULL);
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            w = d->refs_menu = match_type_option_menu_new ();
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            w = d->refs_entry = gtk_entry_new ();
            s = g_slist_prepend (s, w);
            gtk_entry_set_width_chars (GTK_ENTRY(w), ENTRY_WIDTH_CHARS);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL2_L, CONTROL2_R, row, row+1);
            g_object_set_data_full (G_OBJECT(l), SENSITIVE_LIST, s, (GDestroyNotify)g_slist_free);
            s = NULL;
            refresh_enabled_states (GTK_TOGGLE_BUTTON(l));
            ++row;

            /* lines */
            l = d->lines_tb = gtk_check_button_new_with_mnemonic (_("_Lines:"));
            g_signal_connect (l, "toggled", G_CALLBACK(toggled_cb), NULL);
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            w = gtk_option_menu_new ();
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            w2 = d->lines_menu = gtk_menu_new (); 
            menu_add_item (w2, l, GINT_TO_POINTER(0), _("at least N lines long"));
            menu_add_item (w2, l, GINT_TO_POINTER(1), _("less than N lines long"));
            gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);
            a = d->lines_adj = gtk_adjustment_new (10.0, 0.0, ULONG_MAX, 1.0, 1.0, 1.0);
            w = gtk_spin_button_new (GTK_ADJUSTMENT(a), 100.0, 0u);
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL2_L, CONTROL2_R, row, row+1);
            g_object_set_data_full (G_OBJECT(l), SENSITIVE_LIST, s, (GDestroyNotify)g_slist_free);
            s = NULL;
            refresh_enabled_states (GTK_TOGGLE_BUTTON(l));
            ++row;

      pan_hig_workarea_add_section_divider (t, &row);
      pan_hig_workarea_add_section_title (t,  &row, _("Score"));

            /* Numeric */
            l = d->score_tb = gtk_radio_button_new_with_mnemonic (NULL, _("Chan_ge Score:"));
            g_signal_connect (l, "toggled", G_CALLBACK(toggled_cb), NULL);
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            w = gtk_option_menu_new ();
            s = g_slist_prepend (s, w);
            w2 = d->score_menu = gtk_menu_new (); 
            menu_add_item (w2, l, GINT_TO_POINTER(0), _("add"));
            menu_add_item (w2, l, GINT_TO_POINTER(1), _("subtract"));
            menu_add_item (w2, l, GINT_TO_POINTER(2), _("set score to"));
            gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            a = d->score_adj = gtk_adjustment_new (100.0, 1.0, 9999.0, 1.0, 1.0, 1.0);
            w = gtk_spin_button_new (GTK_ADJUSTMENT(a), 100.0, 0u);
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL2_L, CONTROL2_R, row, row+1);
            g_object_set_data_full (G_OBJECT(l), SENSITIVE_LIST, s, (GDestroyNotify)g_slist_free);
            s = NULL;
            refresh_enabled_states (GTK_TOGGLE_BUTTON(l));
            ++row;

            /* Ignore */
            l = d->ignore_tb = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(l), _("_Ignore (set score to -9999)"));
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            ++row;

            /* Watch */
            l = d->watch_tb = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(l), _("_Watch (set score to 9999)"));
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            ++row;

      pan_hig_workarea_add_section_divider (t, &row);
      pan_hig_workarea_add_section_title (t,  &row, _("Score"));

            /* expire in N days */
            l = d->expire_tb = gtk_radio_button_new_with_mnemonic (NULL, _("Expire in N _days:"));
            g_signal_connect (l, "toggled", G_CALLBACK(toggled_cb), NULL);
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);

                a = d->expire_adj = gtk_adjustment_new (31.0, 1.0, ULONG_MAX, 1.0, 1.0, 1.0);
            w = gtk_spin_button_new (GTK_ADJUSTMENT(a), 1.0, 0u);
            s = g_slist_prepend (s, w);
            gtk_table_attach_defaults (GTK_TABLE(t), w, CONTROL1_L, CONTROL1_R, row, row+1);
            g_object_set_data_full (G_OBJECT(l), SENSITIVE_LIST, s, (GDestroyNotify)g_slist_free);
            s = NULL;
            refresh_enabled_states (GTK_TOGGLE_BUTTON(l));
            ++row;

            /* never expire */
            l = d->expire_never_tb = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(l), _("Ne_ver Expire"));
            gtk_table_attach_defaults (GTK_TABLE(t), l, CHECK_L, CHECK_R, row, row+1);
            ++row;

      g_assert (row == ROWS);
      dialog_populate (d, article, mode);

      return dialog;
}

Generated by  Doxygen 1.6.0   Back to index