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

filter-edit-ui.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2002  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 <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/filters/filter.h>
#include <pan/filters/filter-aggregate.h>
#include <pan/filters/filter-binary.h>
#include <pan/filters/filter-cached.h>
#include <pan/filters/filter-crosspost.h>
#include <pan/filters/filter-mine.h>
#include <pan/filters/filter-date.h>
#include <pan/filters/filter-linecount.h>
#include <pan/filters/filter-new.h>
#include <pan/filters/filter-phrase.h>
#include <pan/filters/filter-score.h>

#include <pan/filter-edit-ui.h>
#include <pan/util.h>

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

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

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

typedef struct
{
      GtkWidget * dialog;
      GtkWidget * filter_name_entry;
      GtkWidget * show_in_menu_checkbutton;
      GtkWidget * view_clist;

      GtkWidget * phrase_rb;
      GtkWidget * phrase_key_menu;
      GtkWidget * phrase_match_menu;
      GtkWidget * phrase_key_entry;
      GtkWidget * lines_rb;
      GtkWidget * lines_sb;
      GtkWidget * xpost_rb;
      GtkWidget * xpost_sb;
      GtkWidget * age_rb;
      GtkWidget * age_sb;
      GtkWidget * score_rb;
#if 0
      GtkWidget * score_combo;
#else
      GtkWidget * score_menu;
#endif
      GtkWidget * thread_rb;
      GtkWidget * thread_menu;
      GtkWidget * attach_rb;
      GtkWidget * attach_menu;

      GtkWidget * article_is_rb;
      GtkWidget * article_is_menu;

      Filter * top;
}
FilterEditDialog;

typedef enum
{
      ARTICLE_IS_MINE,
      ARTICLE_IS_CACHED,
      ARTICLE_IS_NEW,
      ARTICLE_IS_UNREAD,
      ARTICLE_IS_READ
}
ArticleIs;

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

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

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

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

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

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

/************
*************  PRIVATE
***********/

/*****
******  Rendering a Rule to ascii strings
*****/

typedef struct
{
      Filter * filter;
      char * string;
}
FilterView;

static void
indent_to_depth (GString * str, int depth)
{
      int i;
      for (i=0; i<depth; ++i)
            g_string_append (str, "          ");
}
static void
get_filter_view_impl (GPtrArray * a, Filter * filter, int depth)
{
      const gboolean is_aggregate = filter_isa (filter, FILTER_AGGREGATE_CLASS_ID);

      /* add this item */
      if (1)
      {
            char * s;
            GString * str = g_string_new (NULL);
            FilterView * view;

            /* indent */
            indent_to_depth (str, depth);

            /* add filter text */
            s = filter_to_string (filter);
            g_string_append (str, s);
            g_free (s);

            /* maybe add empty notice */
            if (is_aggregate) {
                  int children = filter_aggregate_child_size (FILTER_AGGREGATE(filter));
                  if (children==0) {
                        if (filter->negate)
                              g_string_append (str, _("  (No conditions -- no articles will match)"));
                        else
                              g_string_append (str, _("  (No conditions -- all articles will match)"));
                  }
            }

                  view = g_new (FilterView, 1);
            view->filter = filter;
            view->string = g_string_free (str, FALSE);
            g_ptr_array_add (a, view);
      }

      /* add children */
      if (is_aggregate) {
            guint i;
            FilterAggregate * fa = FILTER_AGGREGATE (filter);
            for (i=0; i<fa->children->len; ++i) {
                  Filter * child = FILTER(g_ptr_array_index(fa->children,i));
                  get_filter_view_impl (a, child, depth+1);
            }
      }
            
}
static GPtrArray*
get_filter_view (Filter * filter)
{
      GPtrArray * a = g_ptr_array_new ();
      get_filter_view_impl (a, filter, 0);
      return a;
}

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

static Filter*
get_parent (FilterEditDialog * d, Filter * f)
{
      int i;
      GtkCList * clist;
      Filter * retval = NULL;

      g_return_val_if_fail (d!=NULL, NULL);
      g_return_val_if_fail (f!=NULL, NULL);

      /* find the selected filter */
      clist = GTK_CLIST(d->view_clist);
      for (i=gtk_clist_find_row_from_data(clist, f)-1; retval==NULL && i>=0; --i) {
            Filter * test = FILTER(gtk_clist_get_row_data (clist, i));
            if (filter_isa (test, FILTER_AGGREGATE_CLASS_ID) &&
                filter_aggregate_has_child(FILTER_AGGREGATE(test), f))
                  retval = test;
      }

      return retval;
}

static int
get_selected_index (FilterEditDialog * d)
{
      int sel;
      GtkCList * clist;

      /* find the selected filter */
      clist = GTK_CLIST(d->view_clist);
      sel = -1;
        if (clist->selection != NULL)
                sel = GPOINTER_TO_INT(clist->selection->data);

      return sel;
}

static Filter*
get_filter_at (FilterEditDialog * d, int index)
{
      return FILTER(gtk_clist_get_row_data (GTK_CLIST(d->view_clist), index));
}
      
static Filter*
get_selected_filter (FilterEditDialog * d)
{
      int sel = get_selected_index (d);
      if (sel == -1)
            sel = 0;

      return get_filter_at (d, sel);
}

static Filter*
get_selected_aggregate (FilterEditDialog * d)
{
      Filter * f = get_selected_filter (d);

      if (!filter_isa (f, FILTER_AGGREGATE_CLASS_ID))
            f = get_parent (d, f);

      return f;
}

static void
update_clist_move_sel (FilterEditDialog * d, int move_sel)
{
      int sel;
      guint i;
      Filter * f;
      GPtrArray * a;
      GtkCList * clist;

      f = d->top;
      a = get_filter_view (f);

      /* update the UI */
      clist = GTK_CLIST(d->view_clist);
      gtk_clist_freeze (clist);
      sel = -1;
        if (clist->selection != NULL)
                sel = GPOINTER_TO_INT(clist->selection->data);
      gtk_clist_clear (clist);
      for (i=0; i<a->len; ++i) {
            int row;
            FilterView * view = (FilterView*) g_ptr_array_index (a, i);
            row = gtk_clist_insert (clist, -1, (char**)&view->string);
            gtk_clist_set_row_data (clist, row, view->filter);
            g_free (view->string);
            g_free (view);
      }
      gtk_clist_select_row (clist, sel+move_sel, 0);
      gtk_clist_thaw (clist);

      g_ptr_array_free (a, TRUE);
}

static void
update_clist (FilterEditDialog * d)
{
      update_clist_move_sel (d, 0);
}


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

static Filter*
get_new_filter (FilterEditDialog * d)
{
      Filter * f = NULL;
      debug_enter ("get_new_filter");

      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->phrase_rb)))
      {
            GtkWidget * active;
            PhraseKeyType key_type;
            int match_type;
            char * key;
            gboolean negate = FALSE;

            active = gtk_menu_get_active (GTK_MENU(d->phrase_match_menu));
            match_type = GPOINTER_TO_INT(gtk_object_get_user_data (GTK_OBJECT(active)));
            if (match_type < 0) {
                  match_type = -match_type;
                  negate = TRUE;
            }

            active = gtk_menu_get_active (GTK_MENU(d->phrase_key_menu));
            key_type = GPOINTER_TO_INT(gtk_object_get_user_data (GTK_OBJECT(active)));

            key = gtk_editable_get_chars (GTK_EDITABLE(d->phrase_key_entry), 0, -1);
                g_strstrip (key);
            if (is_nonempty_string(key))
            {
                  f = filter_phrase_new ();
                  filter_phrase_set (FILTER_PHRASE(f), match_type, key_type, key, FALSE);
                  if (negate)
                        filter_negate (f);
            }
            g_free (key);
      }
      else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->lines_rb)))
      {
            f = filter_line_count_new ();
            FILTER_LINE_COUNT(f)->minimum_line_count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->lines_sb));
      }
      else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->xpost_rb)))
      {
            f = filter_crosspost_new ();
            FILTER_CROSSPOST(f)->minimum_crosspost_count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->xpost_sb));
      }
      else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->age_rb)))
      {
            f = filter_date_new ();
            FILTER_DATE(f)->minimum_days_old = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->age_sb));
      }
      else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->score_rb)))
      {
            GtkWidget * active = gtk_menu_get_active (GTK_MENU(d->score_menu));
            const FilterScoreMode menu_mode = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (active)));
            FilterScoreMode mode = 0;

            switch (menu_mode) /* note fall-through to build "greater than or equal" bitmask */
            {
                  case SCORE_IGNORED:
                        mode |= SCORE_IGNORED;
                  case SCORE_LOW:
                        mode |= SCORE_LOW;
                  case SCORE_ZERO:
                        mode |= SCORE_ZERO;
                  case SCORE_MEDIUM:
                        mode |= SCORE_MEDIUM;
                  case SCORE_HIGH:
                        mode |= SCORE_HIGH;
                  case SCORE_WATCHED:
                        mode |= SCORE_WATCHED;
                  default:
                        break;
            }

            f = filter_score_new (mode);
      }
      else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->attach_rb)))
      {
            GtkWidget * active = gtk_menu_get_active (GTK_MENU(d->attach_menu));
            gpointer state = gtk_object_get_user_data (GTK_OBJECT(active));
            f = filter_binary_new ();
            filter_binary_set_state (FILTER_BINARY(f), GPOINTER_TO_INT(state));
      }
      else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->article_is_rb)))
      {
            GtkWidget * active = gtk_menu_get_active (GTK_MENU(d->article_is_menu));
            const ArticleIs state = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT(active)));
            switch (state)
            {
                  case ARTICLE_IS_MINE:
                        f = filter_mine_new ();
                        break;
                  case ARTICLE_IS_CACHED:
                        f = filter_cached_new ();
                        break;
                  case ARTICLE_IS_NEW:
                        f = filter_new_article_new (FILTER_NEW_NEW);
                        break;
                  case ARTICLE_IS_UNREAD:
                        f = filter_new_article_new (FILTER_NEW_UNREAD);
                        break;
                  case ARTICLE_IS_READ:
                        f = filter_new_article_new (FILTER_NEW_READ);
                        break;
                  default:
                        pan_warn_if_reached ();
            }
      }

      debug_exit ("get_new_filter");
      return f;
}

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

static void
dialog_close_cb (GtkDialog * dialog, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      pan_object_unref (PAN_OBJECT(d->top));
      g_free (d);
}

static void
up_button_cb (GtkButton * button, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      Filter * f = get_selected_filter (d);
      FilterAggregate * p = FILTER_AGGREGATE(get_parent (d, f));
      int move_sel = 0;

      if (p != NULL)
      {
            int index = filter_aggregate_child_index (p, f);
            if (index > 0)
            {
                  Filter * sib = filter_aggregate_get_child_at (p, index-1);
                  pan_object_ref (PAN_OBJECT(f));
                  filter_aggregate_remove (p, &f, 1);
                  if (filter_isa (sib, FILTER_AGGREGATE_CLASS_ID)) {
                        filter_aggregate_add (FILTER_AGGREGATE(sib), &f, 1);
                  } else {
                        move_sel = -1;
                        filter_aggregate_insert (p, &f, 1, index-1);
                  }
                  pan_object_unref (PAN_OBJECT(f));
            }
            else /* up and out */
            {
                  Filter * p2 = get_parent (d, FILTER(p));
                  if (p2 != NULL)
                  {
                        int index = filter_aggregate_child_index (FILTER_AGGREGATE(p2), FILTER(p));
                        pan_object_ref (PAN_OBJECT(f));
                        filter_aggregate_remove (p, &f, 1);
                        filter_aggregate_insert (FILTER_AGGREGATE(p2), &f, 1, index);
                        pan_object_unref (PAN_OBJECT(f));
                        move_sel = -1;
                  }
            }
      }

      update_clist_move_sel (d, move_sel);
}

static void
down_button_cb (GtkButton * button, gpointer data)
{
      int move_sel = 0;
      FilterEditDialog * d = (FilterEditDialog*) data;
      Filter * f = get_selected_filter (d);
      FilterAggregate * p = FILTER_AGGREGATE(get_parent (d, f));

      if (p != NULL)
      {
            int index = filter_aggregate_child_index (p, f);
            int size = filter_aggregate_child_size (p);
            if (index < size-1) /* down */
            {
                  Filter * sib = filter_aggregate_get_child_at (p, index+1);
                  pan_object_ref (PAN_OBJECT(f));
                  filter_aggregate_remove (p, &f, 1);
                  move_sel = 1;
                  if (filter_isa (sib, FILTER_AGGREGATE_CLASS_ID))
                        filter_aggregate_insert (FILTER_AGGREGATE(sib), &f, 1, 0);
                  else
                        filter_aggregate_insert (p, &f, 1, index+1);
                  pan_object_unref (PAN_OBJECT(f));
            }
            else /* down and out */
            {
                  Filter * p2 = get_parent (d, FILTER(p));
                  if (p2 != NULL)
                  {
                        int index = filter_aggregate_child_index (FILTER_AGGREGATE(p2), FILTER(p));
                        pan_object_ref (PAN_OBJECT(f));
                        filter_aggregate_remove (p, &f, 1);
                        filter_aggregate_insert (FILTER_AGGREGATE(p2), &f, 1, index+1);
                        pan_object_unref (PAN_OBJECT(f));
                  }
            }
            
      }

      update_clist_move_sel (d, move_sel);
}

static void
negate_button_cb (GtkButton * button, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      Filter * f = get_selected_filter (d);
      if (f != NULL) {
            filter_negate (f);
            update_clist (d);
      }
}

static void
aggregate_action (FilterEditDialog * d, FilterAggregateType type)
{
      Filter * f = get_selected_filter (d);

      if (filter_isa (f, FILTER_AGGREGATE_CLASS_ID)) /* set selected aggregate state */
      {
            filter_aggregate_set_type (FILTER_AGGREGATE(f), type);
            update_clist (d);
      }
      else /* add a new aggregate */
      {
            Filter * p = get_parent (d, f);
            Filter * a = filter_aggregate_new ();
            int index = filter_aggregate_child_index (FILTER_AGGREGATE(p), f);
            filter_aggregate_set_type (FILTER_AGGREGATE(a), type);
            filter_aggregate_insert (FILTER_AGGREGATE(p), &a, 1, index+1);
            pan_object_unref (PAN_OBJECT(a));
            update_clist_move_sel (d, 1);
      }
}
static void
and_button_cb (GtkButton * button, gpointer data)
{
      aggregate_action ((FilterEditDialog*)data, AGGREGATE_TYPE_AND);
}
static void
or_button_cb (GtkButton * button, gpointer data)
{
      aggregate_action ((FilterEditDialog*)data, AGGREGATE_TYPE_OR);
}

static void
delete_button_cb (GtkButton * button, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      Filter * f = get_selected_filter (d);
      if (f != d->top)
      {
            FilterAggregate * p = FILTER_AGGREGATE(get_parent(d,f));

            if (filter_isa (f, FILTER_AGGREGATE_CLASS_ID))
            {
                  GPtrArray * a = filter_aggregate_get_children (FILTER_AGGREGATE(f));
                  filter_aggregate_remove (FILTER_AGGREGATE(f), (Filter**)a->pdata, a->len);
                  filter_aggregate_add (p, (Filter**)a->pdata, a->len);
                  filter_aggregate_clear_child_array (a);
            }

            filter_aggregate_remove (p, &f, 1);
            update_clist (d);
      }
}

static void
add_button_cb (GtkButton * button, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      Filter * f = get_new_filter (d);
      if (f != NULL)
      {
            Filter * parent = get_selected_aggregate (d);
            filter_aggregate_add (FILTER_AGGREGATE(parent), &f, 1);
            pan_object_unref (PAN_OBJECT(f));
            update_clist (d);
      }
}

static void
name_editable_changed_cb (GtkEditable * editable, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      char * pch = gtk_editable_get_chars (editable, 0, -1);
      filter_top_set_name (FILTER_TOP(d->top), pch);
      g_free (pch);
}

static void
in_menu_togglebutton_toggled_cb (GtkToggleButton * tb, gpointer data)
{
      FilterEditDialog * d = (FilterEditDialog*) data;
      filter_top_set_visible (FILTER_TOP(d->top), gtk_toggle_button_get_active (tb));
}

/************
*************  PROTECTED
************/

/************
*************  PUBLIC
************/

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


GtkWidget*
filter_edit_dialog_new (GtkWindow * window, const FilterTop * top)
{
      const int ROWS = 2;
      const int COLS = 10;
      int row;
      int col;
      GtkWidget * w;
      GtkWidget * w2;
      GtkWidget * tmp;
      GtkWidget * table;
      GtkWidget * hbox;
      GtkWidget * vbox;
      GtkWidget * vbox_main;
      GtkObject * adj;
      GtkTooltips * tips = gtk_tooltips_new ();
      GSList * rb_group = NULL;
      FilterEditDialog * d;

      d = g_new0 (FilterEditDialog, 1);
      d->top = top!=NULL ? filter_dup(FILTER(top)) : filter_top_new ();

      /* dialog */
      w = d->dialog = gtk_dialog_new_with_buttons (_("Pan: Edit Filter"),
                                                   GTK_WINDOW(window),
                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
                                                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                                   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
                                                   GTK_STOCK_OK, GTK_RESPONSE_OK,
                                                   NULL);
      vbox_main = GTK_DIALOG(w)->vbox;
      gtk_box_set_spacing (GTK_BOX(vbox_main), GUI_PAD);
      gtk_container_set_border_width (GTK_CONTAINER(vbox_main), GUI_PAD);
      gtk_window_set_policy (GTK_WINDOW(w), TRUE, TRUE, TRUE);
      g_signal_connect (GTK_OBJECT(w), "destroy", G_CALLBACK(dialog_close_cb), d);

      /* top row: filter name, show in filter menu */
      hbox = gtk_hbox_new (FALSE, GUI_PAD);
      gtk_box_pack_start (GTK_BOX(vbox_main), hbox, FALSE, TRUE, 1);
      w = gtk_label_new (_("Filter name: "));
      gtk_box_pack_start (GTK_BOX(hbox), w, FALSE, FALSE, 0);
      w = d->filter_name_entry = gtk_entry_new ();
      pan_gtk_entry_set_text (w, FILTER_TOP(d->top)->name);
      g_signal_connect (GTK_OBJECT(w), "changed",
                          G_CALLBACK(name_editable_changed_cb), d);
      gtk_box_pack_start (GTK_BOX(hbox), w, TRUE, TRUE, 0);
      w = d->show_in_menu_checkbutton = gtk_check_button_new_with_label (_("Show in Filter Menu"));
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), FILTER_TOP(d->top)->is_visible);
      g_signal_connect (GTK_OBJECT(w), "toggled",
                          G_CALLBACK(in_menu_togglebutton_toggled_cb), d);
      gtk_box_pack_end (GTK_BOX(hbox), w, FALSE, FALSE, 0);

      /* separator */
      w = gtk_hseparator_new ();
      gtk_box_pack_start (GTK_BOX(vbox_main), w, FALSE, FALSE, 10);

      /* rules clist + its buttons */
      hbox = gtk_hbox_new (FALSE, GUI_PAD);
      gtk_box_pack_start (GTK_BOX(vbox_main), hbox, TRUE, TRUE, 0);
      w = gtk_scrolled_window_new (NULL, NULL);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
      gtk_box_pack_start (GTK_BOX(hbox), w, TRUE, TRUE, 0);
      w2 = w;
      w = d->view_clist = gtk_clist_new (1);
      gtk_clist_set_selection_mode (GTK_CLIST(w), GTK_SELECTION_BROWSE);
      gtk_container_add (GTK_CONTAINER(w2), w);
      vbox = gtk_vbox_new (FALSE, 0);
      gtk_box_pack_start (GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
      w = gtk_button_new_from_stock (GTK_STOCK_GO_UP);
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(up_button_cb), d);
      gtk_box_pack_start (GTK_BOX(vbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Move the selected line up one line"), NULL);
      w = gtk_button_new_from_stock (GTK_STOCK_GO_DOWN);
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(down_button_cb), d);
      gtk_box_pack_start (GTK_BOX(vbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Move the selected line down one line"), NULL);
      w = gtk_button_new_with_label (_("Invert"));
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(negate_button_cb), d);
      gtk_box_pack_start (GTK_BOX(vbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Invert the selected line"), NULL);
      w = gtk_button_new_with_label (_("All Of"));
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(and_button_cb), d);
      gtk_box_pack_start (GTK_BOX(vbox), w, FALSE, FALSE, 0);
      w = gtk_button_new_with_label (_("Any Of"));
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(or_button_cb), d);
      gtk_box_pack_start (GTK_BOX(vbox), w, FALSE, FALSE, 0);
      w = gtk_button_new_from_stock (GTK_STOCK_DELETE);
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(delete_button_cb), d);
      gtk_box_pack_end (GTK_BOX(vbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Delete the selected line"), NULL);

      /* add-condition button */
      hbox = gtk_hbutton_box_new ();
      gtk_box_pack_start (GTK_BOX(vbox_main), hbox, FALSE, FALSE, 0);
      w = gtk_button_new_with_mnemonic (_("Add New Line to the Filter"));
      g_signal_connect (GTK_OBJECT(w), "clicked", G_CALLBACK(add_button_cb), d);
      gtk_container_add (GTK_CONTAINER(hbox), w);

      /* hoo-boy, the conditions */
      w = gtk_frame_new (_("New Filter Line"));
      gtk_box_pack_end (GTK_BOX(vbox_main), w, FALSE, FALSE, 0);
      table = gtk_table_new (ROWS, COLS, FALSE);
      gtk_container_add (GTK_CONTAINER(w), table);
      gtk_table_set_col_spacings (GTK_TABLE(table), 0);
      gtk_container_set_border_width (GTK_CONTAINER(table), 0);
      row = col = 0;

      /* phrase */
      hbox = gtk_hbox_new (FALSE, GUI_PAD);
      gtk_table_attach (GTK_TABLE(table), hbox, 0, COLS, row, row+1, GTK_FILL, GTK_FILL, 0, 0);
      w = d->phrase_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("_Article"));
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      gtk_box_pack_start (GTK_BOX(hbox), w, FALSE, FALSE, 0);

#define add_menu_item(str, callback_int, radiobutton) \
      tmp = gtk_menu_item_new_with_label (str); \
      gtk_object_set_user_data (GTK_OBJECT(tmp), GINT_TO_POINTER(callback_int)); \
      g_signal_connect_swapped (GTK_OBJECT(tmp), "activate", G_CALLBACK(tb_activate), GTK_OBJECT(radiobutton)); \
      gtk_widget_show (tmp); \
      gtk_menu_append (GTK_MENU(w2), tmp); \

      w = gtk_option_menu_new ();
      gtk_box_pack_start (GTK_BOX(hbox), w, FALSE, FALSE, 0);
      w2 = d->phrase_key_menu = gtk_menu_new ();
      add_menu_item (_("Subject"), PHRASE_KEY_SUBJECT, d->phrase_rb)
      add_menu_item (_("Author"), PHRASE_KEY_AUTHOR, d->phrase_rb)
      add_menu_item (_("Message-ID"), PHRASE_KEY_MESSAGE_ID, d->phrase_rb)
      gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);

      w = gtk_option_menu_new ();
      gtk_box_pack_start (GTK_BOX(hbox), w, FALSE, FALSE, 0);
      w2 = d->phrase_match_menu = gtk_menu_new ();
      add_menu_item (_("contains"), PHRASE_MATCH_CONTAINS, d->phrase_rb)
      add_menu_item (_("does not contain"), -PHRASE_MATCH_CONTAINS, d->phrase_rb)
      add_menu_item (_("is"), PHRASE_MATCH_IS, d->phrase_rb)
      add_menu_item (_("is not"), -PHRASE_MATCH_IS, d->phrase_rb)
      add_menu_item (_("starts with"), PHRASE_MATCH_STARTS_WITH, d->phrase_rb)
      add_menu_item (_("does not start with"), -PHRASE_MATCH_STARTS_WITH, d->phrase_rb)
      add_menu_item (_("ends with"), PHRASE_MATCH_ENDS_WITH, d->phrase_rb)
      add_menu_item (_("does not end with"), -PHRASE_MATCH_ENDS_WITH, d->phrase_rb)
      add_menu_item (_("matches regular expression"), PHRASE_MATCH_REGEX, d->phrase_rb)
      add_menu_item (_("does not match regular expression"), -PHRASE_MATCH_REGEX, d->phrase_rb)
      gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);

      w = d->phrase_key_entry = gtk_entry_new ();
      g_signal_connect_swapped (GTK_OBJECT(w), "focus_in_event", G_CALLBACK(tb_activate), GTK_OBJECT(d->phrase_rb));
      gtk_box_pack_start (GTK_BOX(hbox), w, TRUE, TRUE, 0);

      /* attachment */
      ++row;
      w = d->attach_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("Article h_as"));
      gtk_table_attach (GTK_TABLE(table), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0);
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      w = gtk_option_menu_new ();
      gtk_table_attach (GTK_TABLE(table), w, col+1, col+2, row, row+1, GTK_FILL, 0, 0, 0);
      w2 = d->attach_menu = gtk_menu_new ();
      add_menu_item (_("Attachments"), FILTER_BINARY_COMPLETE, d->attach_rb)
      add_menu_item (_("Incomplete Attachments"), FILTER_BINARY_INCOMPLETE, d->attach_rb)
      add_menu_item (_("No Attachments"), FILTER_BINARY_NONBINARY, d->attach_rb)
      gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);

      /* read, cached, new, posted-by-me */
      ++row;
      w = d->article_is_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("Article _is"));
      gtk_table_attach (GTK_TABLE(table), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0);
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      w = gtk_option_menu_new ();
      gtk_table_attach (GTK_TABLE(table), w, col+1, col+2, row, row+1, GTK_FILL, 0, 0, 0);
      w2 = d->article_is_menu = gtk_menu_new ();
      add_menu_item (_("New"), ARTICLE_IS_NEW, d->article_is_rb)
      add_menu_item (_("Unread"), ARTICLE_IS_UNREAD, d->article_is_rb)
      add_menu_item (_("Read"), ARTICLE_IS_READ, d->article_is_rb)
      add_menu_item (_("Cached"), ARTICLE_IS_CACHED, d->article_is_rb)
      add_menu_item (_("Posted by Me"), ARTICLE_IS_MINE, d->article_is_rb)
      gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);

      /* lines */
      ++row;
      w = d->lines_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("Article has at _least N lines:"));
      gtk_table_attach (GTK_TABLE(table), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0);
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      adj = gtk_adjustment_new (1, 0, 300000, 1, 10, 10);
      w = d->lines_sb = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1, 0);
      g_signal_connect_swapped (GTK_OBJECT(w), "focus_in_event", G_CALLBACK(tb_activate), GTK_OBJECT(d->lines_rb));
      gtk_table_attach (GTK_TABLE(table), w, col+1, col+2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);

      /* crosspost */
      ++row;
      w = d->xpost_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("Article was _posted to at least N groups:"));
      gtk_table_attach (GTK_TABLE(table), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0);
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      adj = gtk_adjustment_new (1, 0, 300000, 1, 10, 10);
      w = d->xpost_sb = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1, 0);
      g_signal_connect_swapped (GTK_OBJECT(w), "focus_in_event", G_CALLBACK(tb_activate), GTK_OBJECT(d->xpost_rb));
      gtk_table_attach (GTK_TABLE(table), w, col+1, col+2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);

      /* age */
      ++row;
      w = d->age_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("Article is at least N days _old"));
      gtk_table_attach (GTK_TABLE(table), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0);
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      adj = gtk_adjustment_new (1, 0, 300000, 1, 10, 10);
      w = d->age_sb = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1, 0);
      g_signal_connect_swapped (GTK_OBJECT(w), "focus_in_event", G_CALLBACK(tb_activate), GTK_OBJECT(d->age_rb));
      gtk_table_attach (GTK_TABLE(table), w, col+1, col+2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);

      /* score */
      ++row;
      w = d->score_rb = gtk_radio_button_new_with_mnemonic (rb_group, _("Article _score is at least"));
      gtk_table_attach (GTK_TABLE(table), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0);
      rb_group = gtk_radio_button_group (GTK_RADIO_BUTTON(w));
      w = gtk_option_menu_new ();
      gtk_table_attach (GTK_TABLE(table), w, col+1, col+2, row, row+1, GTK_FILL, 0, 0, 0);
      w2 = d->score_menu = gtk_menu_new ();
      add_menu_item (_("Watched"), SCORE_WATCHED, d->score_rb)
      add_menu_item (_("High"),    SCORE_HIGH,    d->score_rb)
      add_menu_item (_("Medium"),  SCORE_MEDIUM,  d->score_rb)
      add_menu_item (_("Zero"),    SCORE_ZERO,    d->score_rb)
      add_menu_item (_("Low"),     SCORE_LOW,     d->score_rb)
      add_menu_item (_("Ignored"), SCORE_IGNORED, d->score_rb)
      gtk_option_menu_set_menu (GTK_OPTION_MENU(w), w2);

      /* prepare the ui state */
      update_clist (d);

      gtk_object_set_user_data (GTK_OBJECT(d->dialog), d);
      return d->dialog;
}

const FilterTop*
filter_edit_dialog_get_filter (GtkWidget * w)
{
      FilterEditDialog * d = (FilterEditDialog*) gtk_object_get_user_data (GTK_OBJECT(w));
      return FILTER_TOP(d->top);
}

Generated by  Doxygen 1.6.0   Back to index