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

filter-mediator.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
 */

#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkradiomenuitem.h>
#include <gtk/gtktogglebutton.h>
#include <pan/base/group.h>

#include <pan/base/debug.h>

#include <pan/filters/filter.h>
#include <pan/filters/filter-manager.h>
#include <pan/filters/filter-aggregate.h>
#include <pan/filters/filter-binary.h>
#include <pan/filters/filter-cached.h>
#include <pan/filters/filter-manager.h>
#include <pan/filters/filter-mine.h>
#include <pan/filters/filter-new.h>
#include <pan/filters/filter-phrase.h>
#include <pan/filters/filter-top.h>
#include <pan/filters/filter-score.h>
#include <pan/filters/filter-manager.h>

#include <pan/filter-mediator.h>
#include <pan/util.h>


#define DEFAULT_FILTER_SHOW FILTER_SHOW_MATCHES
#define SCORE_ALL_BUT_IGNORED (~(gulong)STATE_FILTER_SCORE_IGNORED)

static FilterCurrentMediatorCtor _buttons;
static gulong _filter_bits = SCORE_ALL_BUT_IGNORED;
static FilterShow _filter_show = DEFAULT_FILTER_SHOW;
static void fire_user_changed_filter (void);

static int _mute_feedback = 0;

const static gulong NEW_MASK = STATE_FILTER_NEW | STATE_FILTER_UNREAD | STATE_FILTER_READ;
const static gulong MINE_MASK = STATE_FILTER_MINE | STATE_FILTER_NOT_MINE;
const static gulong BIN_MASK = STATE_FILTER_COMPLETE_BINARIES | STATE_FILTER_INCOMPLETE_BINARIES | STATE_FILTER_NONBINARIES;
const static gulong CACHED_MASK = STATE_FILTER_CACHED | STATE_FILTER_NOT_CACHED;

/**
 * Holds the state of the new/unread/read menu buttons before the user
 * clicks on the `only new' button in the toolbar, so that when they
 * click it off we can set the menu buttons back to their old values.
 */
static gulong _new_bits_memento = 0ul;

/**
 * Holds the state of the score menu buttons before the user clicks on the
 * `only watched' button in the toolbar, so that when they click it off we
 * can set the menu buttons back to their old values.
 */
static gulong _score_bits_memento = 0ul;


static void
set_memento (gulong    * setme_bits,
             gulong      new_value,
             gulong      mask,
             gulong      set_to_mask_if_new_value_is_this)
{
      /* constrain the new value & compare value into the mask */
      new_value &= mask;
      set_to_mask_if_new_value_is_this &= mask;

      /* update *setme_bits */
      if (new_value == set_to_mask_if_new_value_is_this)
            *setme_bits = mask;
      else
            *setme_bits = new_value;      
}

/**
***  REFRESH
**/

/**
 * Updates the Filter menu buttons to reflect the current state of the filter.
 */
static void
refresh (void)
{
      GtkCheckMenuItem * ckm;
      GtkToggleButton * tb;
      gboolean model;

      pan_lock ();
      ++_mute_feedback;

      /* new, old, read */

      model = (_filter_bits & NEW_MASK) == STATE_FILTER_NEW;
      tb = GTK_TOGGLE_BUTTON(_buttons._match_only_new_tb);
      gtk_toggle_button_set_active (tb, model);

      model = _filter_bits & STATE_FILTER_NEW;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_new_ckm);
      gtk_check_menu_item_set_active (ckm, model);

      model = _filter_bits & STATE_FILTER_UNREAD;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_unread_ckm);
      gtk_check_menu_item_set_active (ckm, model);

      model = _filter_bits & STATE_FILTER_READ;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_read_ckm);
      gtk_check_menu_item_set_active (ckm, model);

      /* binaries */

      model = (_filter_bits & BIN_MASK) == STATE_FILTER_COMPLETE_BINARIES;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_complete_ckm);
      gtk_check_menu_item_set_active (ckm, model);
      tb = GTK_TOGGLE_BUTTON(_buttons._match_only_complete_tb);
      gtk_toggle_button_set_active (tb, model);

      /* text */

      model = (_filter_bits & BIN_MASK) == STATE_FILTER_NONBINARIES;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_text_ckm);
      gtk_check_menu_item_set_active (ckm, model);

      /* cached */

      model = (_filter_bits & CACHED_MASK) == STATE_FILTER_CACHED;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_cached_ckm);
      gtk_check_menu_item_set_active (ckm, model);
      tb = GTK_TOGGLE_BUTTON(_buttons._match_only_cached_tb);
      gtk_toggle_button_set_active (tb, model);

      /* author */

      model = (_filter_bits & MINE_MASK) == STATE_FILTER_MINE;
      ckm = GTK_CHECK_MENU_ITEM(_buttons._match_only_mine_ckm);
      gtk_check_menu_item_set_active (ckm, model);
      tb = GTK_TOGGLE_BUTTON(_buttons._match_only_mine_tb);
      gtk_toggle_button_set_active (tb, model);

      /* score */

      model = (_filter_bits & STATE_FILTER_SCORE_MASK) == STATE_FILTER_SCORE_WATCHED;
      tb = GTK_TOGGLE_BUTTON(_buttons._match_only_watched_tb);
      gtk_toggle_button_set_active (tb, model);

      model = (_filter_bits & STATE_FILTER_SCORE_WATCHED);
      ckm = GTK_CHECK_MENU_ITEM (_buttons._match_only_watched_rmi);
      gtk_check_menu_item_set_active (ckm, model);

      model = (_filter_bits & STATE_FILTER_SCORE_HIGH);
      ckm = GTK_CHECK_MENU_ITEM (_buttons._match_only_high_rmi);
      gtk_check_menu_item_set_active (ckm, model);

      model = (_filter_bits & STATE_FILTER_SCORE_MEDIUM);
      ckm = GTK_CHECK_MENU_ITEM (_buttons._match_only_medium_rmi);
      gtk_check_menu_item_set_active (ckm, model);

      model = (_filter_bits & STATE_FILTER_SCORE_ZERO);
      ckm = GTK_CHECK_MENU_ITEM (_buttons._match_only_zero_rmi);
      gtk_check_menu_item_set_active (ckm, model);

      model = (_filter_bits & STATE_FILTER_SCORE_LOW);
      ckm = GTK_CHECK_MENU_ITEM (_buttons._match_only_low_rmi);
      gtk_check_menu_item_set_active (ckm, model);

      model = (_filter_bits & STATE_FILTER_SCORE_IGNORED);
      ckm = GTK_CHECK_MENU_ITEM (_buttons._match_only_ignored_rmi);
      gtk_check_menu_item_set_active (ckm, model);


      /* show */

      if (_filter_show == FILTER_SHOW_THREAD)
            ckm = GTK_CHECK_MENU_ITEM(_buttons._show_threads_rmi);
      else if (_filter_show == FILTER_SHOW_SUBTHREADS)
            ckm = GTK_CHECK_MENU_ITEM(_buttons._show_subthreads_rmi);
      else
            ckm = GTK_CHECK_MENU_ITEM(_buttons._show_articles_rmi);
      if (!ckm->active)
            gtk_check_menu_item_set_active (ckm, TRUE);

      --_mute_feedback;
      pan_unlock ();
}

/**
 * Calls refresh in an idle thread.
 */
static int
refresh_idle (gpointer unused)
{
      refresh ();
      return 0;
}

/**
 * Sets the current filter state and updates the menu to reflect the new state.
 */
static void
set (gulong bits, FilterShow show)
{
      if (_mute_feedback == 0)
      {
            ++_mute_feedback;

            if (_filter_bits!=bits || _filter_show!=show)
            {
                  _filter_show = show;
                  _filter_bits = bits;

                  gui_queue_add (refresh_idle, NULL);
                  fire_user_changed_filter ();
            }

            --_mute_feedback;
      }
}

/**
 * Set the current filter's bit bits (ie, what it matches)
 */
static void
set_bits (gulong bits)
{
      set (bits, _filter_show);
}

/**
 * Set the current filter's show bits (ie, the FilterShow apply to the matched articles)
 */
static void
set_show (FilterShow show)
{
      set (_filter_bits, show);
}


/**
***  MENU BUTTON CALLBACKS
**/

static void
set_mask_bits (gulong mask, gulong value)
{
      gulong bits;

      g_assert (!(value & ~mask)); /* make sure everything in new_value is in mask */

      bits = _filter_bits;
      bits &= ~mask; /* turn off everything in the mask */
      bits |= value;

      set_bits (bits);
}

static void
show_only_new_tb_cb (GtkToggleButton * tb, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = gtk_toggle_button_get_active (tb);

            if (active)
                  set_memento (&_new_bits_memento, _filter_bits, NEW_MASK, STATE_FILTER_NEW);

            set_mask_bits (NEW_MASK, active ? STATE_FILTER_NEW : _new_bits_memento);
      }
}

static void
show_only_complete_ckm_cb (GtkCheckMenuItem * item, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = item->active;
            set_mask_bits (BIN_MASK, active ? STATE_FILTER_COMPLETE_BINARIES  : BIN_MASK);
      }
}

static void
show_only_complete_tb_cb (GtkToggleButton * tb, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = gtk_toggle_button_get_active (tb);
            set_mask_bits (BIN_MASK, active ? STATE_FILTER_COMPLETE_BINARIES  : BIN_MASK);
      }
}

static void
show_only_text_ckm_cb (GtkCheckMenuItem * item, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = item->active;
            set_mask_bits (BIN_MASK, active ? STATE_FILTER_NONBINARIES  : BIN_MASK);
      }
}

static void
show_only_cached_ckm_cb (GtkCheckMenuItem * item, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = item->active;
            set_mask_bits (CACHED_MASK, active ? STATE_FILTER_CACHED  : CACHED_MASK);
      }
}

static void
show_only_cached_tb_cb (GtkToggleButton * tb, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = gtk_toggle_button_get_active (tb);
            set_mask_bits (CACHED_MASK, active ? STATE_FILTER_CACHED  : CACHED_MASK);
      }
}

static void
show_only_mine_ckm_cb (GtkCheckMenuItem * item, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = item->active;
            set_mask_bits (MINE_MASK, active ? STATE_FILTER_MINE  : MINE_MASK);
      }
}

static void
show_only_mine_tb_cb (GtkToggleButton * tb, gpointer user_data)
{
      if (!_mute_feedback)
      {
            const gboolean active = gtk_toggle_button_get_active (tb);
            set_mask_bits (MINE_MASK, active ? STATE_FILTER_MINE  : MINE_MASK);
      }
}

static void
match_score_is_watched_tb_cb (GtkToggleButton * tb, gpointer unused)
{
      if (!_mute_feedback)
      {
            const gboolean active = gtk_toggle_button_get_active (tb);

            if (active)
                  set_memento (&_score_bits_memento, _filter_bits, STATE_FILTER_SCORE_MASK, SCORE_ALL_BUT_IGNORED);

            set_mask_bits (STATE_FILTER_SCORE_MASK, active ? STATE_FILTER_SCORE_WATCHED : _score_bits_memento);
      }
}

static void
new_toggled_cb (GtkCheckMenuItem * item, gpointer bit_gpointer)
{
      if (!_mute_feedback)
      {
            const gboolean active = item->active;
            const gulong bit = GPOINTER_TO_UINT(bit_gpointer);
            set_memento (&_new_bits_memento, _filter_bits, NEW_MASK, STATE_FILTER_NEW);
            set_mask_bits (bit, active ? bit : 0);
      }
}

static void
score_toggled_cb (GtkCheckMenuItem * item, gpointer bit_gpointer)
{
      if (!_mute_feedback)
      {
            const gboolean active = item->active;
            const gulong bit = GPOINTER_TO_UINT(bit_gpointer);
            set_memento (&_score_bits_memento, _filter_bits, STATE_FILTER_SCORE_MASK, SCORE_ALL_BUT_IGNORED);
            set_mask_bits (bit, active ? bit : 0);
      }
}

static void
show_toggled_cb (GtkCheckMenuItem * check, gpointer user_data)
{
      if (!_mute_feedback)
      {
            g_return_if_fail (GTK_IS_CHECK_MENU_ITEM(check));

            if (check->active)
                  set_show (GPOINTER_TO_SIZE(user_data));
      }
}

/***
****
****  Custom Filter Menu
****
***/

static GStaticMutex _custom_filter_entries_mutex = G_STATIC_MUTEX_INIT;
static GtkItemFactoryEntry * _custom_filter_entries = NULL;
static int _custom_filter_entry_qty = 0;

static void
custom_filter_selected_cb (gpointer user_data, int unused, GtkWidget * w)
{
      fire_user_changed_filter ();
}

extern GtkItemFactory * _main_menu_factory;

static void
rebuild_custom_filter_menu_with_filters (GPtrArray * filters)
{
      int i;

      pan_lock ();
      g_static_mutex_lock (&_custom_filter_entries_mutex);

      /* remove any old filter buttons */
      if (_custom_filter_entries != NULL) {
            gtk_item_factory_delete_entries (_main_menu_factory, _custom_filter_entry_qty, _custom_filter_entries);
            for (i=0; i<_custom_filter_entry_qty; ++i)
                  g_free (_custom_filter_entries[i].path);
            g_free (_custom_filter_entries);
            _custom_filter_entries = NULL;
            _custom_filter_entry_qty = 0;
      }

      /* build the new filter buttons */
      if (filters->len)
      {
            int j;

            _custom_filter_entries = g_new0 (GtkItemFactoryEntry, filters->len+1);

            /* add the separator */
            _custom_filter_entries[_custom_filter_entry_qty=0].path = g_strdup_printf ("/Filter/---");
            _custom_filter_entries[_custom_filter_entry_qty].item_type = "<Separator>";
            _custom_filter_entries[_custom_filter_entry_qty++].callback = NULL;

            /* add the custom filters */
            for (i=0; i<filters->len; ++i)
            {
                  const FilterTop * top = FILTER_TOP(g_ptr_array_index(filters,i));
                  if (top->is_visible)
                  {
                        char * underscore_escaped_path = pan_substitute (top->name, "_", "__");

                        /* build an entry */
                        _custom_filter_entries[_custom_filter_entry_qty].path = g_strdup_printf ("/Filter/%s", underscore_escaped_path);
                        _custom_filter_entries[_custom_filter_entry_qty].item_type = "<ToggleItem>";
                        _custom_filter_entries[_custom_filter_entry_qty++].callback = custom_filter_selected_cb;

                        g_free (underscore_escaped_path);
                  }
            }

            /* add the filters to the menu */
            gtk_item_factory_create_items (_main_menu_factory, _custom_filter_entry_qty, _custom_filter_entries, NULL);

            /* add the filter name as data item in the menu buttons.
             * This is used by custom_filter_selected_cb() callback to
             * get a FilterTop* from the GtkMenuToggleButton.
             * j starts at 1 because _custom_filter_entries[0] is
             * the menu separator  */
            for (i=0, j=1; i<filters->len; ++i)
            {
                  const FilterTop * top = FILTER_TOP(g_ptr_array_index(filters,i));

                  if (top->is_visible)
                  {
                        GtkWidget * w;
                        char path[1024];

                        g_snprintf (path, sizeof(path), "/Filter/%s", top->name);
                        w = gtk_item_factory_get_widget (_main_menu_factory, path);
                        g_object_set_data_full (G_OBJECT(w), "filter_name", g_strdup(top->name), g_free);
                        _custom_filter_entries[j++].extra_data = w;
                  }
            }
      }

      g_static_mutex_unlock (&_custom_filter_entries_mutex);
      pan_unlock ();
}

static void
rebuild_custom_filter_menu (void)
{
      GPtrArray * a = g_ptr_array_sized_new (64);
      filter_manager_get_filters (a);
      rebuild_custom_filter_menu_with_filters (a);
      pan_g_ptr_array_foreach (a, (GFunc)pan_object_unref, NULL);
      g_ptr_array_free (a, TRUE);
}

static int
filter_manager_filters_changed_idle (gpointer unused)
{
      rebuild_custom_filter_menu ();
      fire_user_changed_filter ();
      return 0;
}

static void
filter_manager_filters_changed_callback (gpointer call_obj, gpointer call_arg, gpointer user_data)
{
      gui_queue_add (filter_manager_filters_changed_idle, NULL);
}



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

void
filter_mediator_init (FilterCurrentMediatorCtor * ctor)
{
      _buttons = *ctor;

      /* New / Read / Unread */

      g_signal_connect (G_OBJECT(_buttons._match_only_new_ckm),    "toggled", G_CALLBACK(new_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_NEW));
      g_signal_connect (G_OBJECT(_buttons._match_only_unread_ckm), "toggled", G_CALLBACK(new_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_UNREAD));
      g_signal_connect (G_OBJECT(_buttons._match_only_read_ckm),   "toggled", G_CALLBACK(new_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_READ));
      g_signal_connect (G_OBJECT(_buttons._match_only_new_tb),     "toggled", G_CALLBACK(show_only_new_tb_cb), NULL);

      /* Text / Complete / Incomplete */

      g_signal_connect (G_OBJECT(_buttons._match_only_complete_ckm), "toggled", G_CALLBACK(show_only_complete_ckm_cb), NULL);
      g_signal_connect (G_OBJECT(_buttons._match_only_text_ckm),     "toggled", G_CALLBACK(show_only_text_ckm_cb), NULL);
      g_signal_connect (G_OBJECT(_buttons._match_only_complete_tb),  "toggled", G_CALLBACK(show_only_complete_tb_cb), NULL);

      /* Cached */

      g_signal_connect (G_OBJECT(_buttons._match_only_cached_ckm), "toggled", G_CALLBACK(show_only_cached_ckm_cb), NULL);
      g_signal_connect (G_OBJECT(_buttons._match_only_cached_tb),  "toggled", G_CALLBACK(show_only_cached_tb_cb), NULL);

      /* Author */

      g_signal_connect (G_OBJECT(_buttons._match_only_mine_ckm), "toggled", G_CALLBACK(show_only_mine_ckm_cb), NULL);
      g_signal_connect (G_OBJECT(_buttons._match_only_mine_tb),  "toggled", G_CALLBACK(show_only_mine_tb_cb),  NULL);

      /* Score */

      g_signal_connect (G_OBJECT(_buttons._match_only_watched_tb),  "toggled", G_CALLBACK(match_score_is_watched_tb_cb), NULL);
      g_signal_connect (G_OBJECT(_buttons._match_only_watched_rmi), "toggled", G_CALLBACK(score_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_SCORE_WATCHED));
      g_signal_connect (G_OBJECT(_buttons._match_only_high_rmi),    "toggled", G_CALLBACK(score_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_SCORE_HIGH));
      g_signal_connect (G_OBJECT(_buttons._match_only_medium_rmi),  "toggled", G_CALLBACK(score_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_SCORE_MEDIUM));
      g_signal_connect (G_OBJECT(_buttons._match_only_zero_rmi),    "toggled", G_CALLBACK(score_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_SCORE_ZERO));
      g_signal_connect (G_OBJECT(_buttons._match_only_low_rmi),     "toggled", G_CALLBACK(score_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_SCORE_LOW));
      g_signal_connect (G_OBJECT(_buttons._match_only_ignored_rmi), "toggled", G_CALLBACK(score_toggled_cb), GUINT_TO_POINTER(STATE_FILTER_SCORE_IGNORED));

      /* show */

      g_signal_connect (G_OBJECT(_buttons._show_articles_rmi), "toggled",
                        G_CALLBACK(show_toggled_cb), GSIZE_TO_POINTER(FILTER_SHOW_MATCHES));
      g_signal_connect (G_OBJECT(_buttons._show_subthreads_rmi), "toggled",
                        G_CALLBACK(show_toggled_cb), GSIZE_TO_POINTER(FILTER_SHOW_SUBTHREADS));
      g_signal_connect (G_OBJECT(_buttons._show_threads_rmi), "toggled",
                        G_CALLBACK(show_toggled_cb), GSIZE_TO_POINTER(FILTER_SHOW_THREAD));

      pan_callback_add (filter_manager_get_filters_changed_callback(), filter_manager_filters_changed_callback, NULL);
      rebuild_custom_filter_menu ();

      refresh ();
}

PanCallback*
filter_mediator_get_change_callback (void)
{
      static PanCallback * cb = NULL;
      if (cb==NULL) cb = pan_callback_new ();
      return cb;
}

static void
fire_user_changed_filter (void)
{
      pan_callback_call (filter_mediator_get_change_callback(), GSIZE_TO_POINTER(_filter_bits), NULL);
}

void
filter_mediator_get_bits (gulong      * setme_bits,
                          FilterShow  * setme_show)
{
      if (setme_bits != NULL)
            *setme_bits = _filter_bits;
      if (setme_show != NULL)
            *setme_show = _filter_show;
}

void
filter_mediator_set_bits (gulong        bits,
                          FilterShow    show)
{
      set_memento (&_new_bits_memento, bits, NEW_MASK, STATE_FILTER_NEW);
      set_memento (&_score_bits_memento, bits, STATE_FILTER_SCORE_MASK, SCORE_ALL_BUT_IGNORED);
      set (bits, show);
}

Filter*
filter_mediator_get_filter  (gulong        bits,
                             gboolean      negate)
{
      int i;
      int n;
      Filter * retval;
      FilterAggregate * top;
      const gulong l = bits;
      const gboolean show_new = (l & STATE_FILTER_NEW) != 0;
      const gboolean show_unread = (l & STATE_FILTER_UNREAD) != 0;
      const gboolean show_read = (l & STATE_FILTER_READ) != 0;
      const gboolean show_bin = (l & STATE_FILTER_COMPLETE_BINARIES) != 0;
      const gboolean show_inc_bin = (l & STATE_FILTER_INCOMPLETE_BINARIES) != 0;
      const gboolean show_nonbinary = (l & STATE_FILTER_NONBINARIES) != 0;
      const gboolean show_cached = (l & STATE_FILTER_CACHED) != 0;
      const gboolean show_non_cached = (l & STATE_FILTER_NOT_CACHED) != 0;
      const gboolean show_by_me = (l & STATE_FILTER_MINE) != 0;
      const gboolean show_by_others = (l & STATE_FILTER_NOT_MINE) != 0;

      const gboolean show_score_watched = (l & STATE_FILTER_SCORE_WATCHED) != 0;
      const gboolean show_score_high    = (l & STATE_FILTER_SCORE_HIGH) != 0;
      const gboolean show_score_medium  = (l & STATE_FILTER_SCORE_MEDIUM) != 0;
      const gboolean show_score_zero    = (l & STATE_FILTER_SCORE_ZERO) != 0;
      const gboolean show_score_low     = (l & STATE_FILTER_SCORE_LOW) != 0;
      const gboolean show_score_ignored = (l & STATE_FILTER_SCORE_IGNORED) != 0;

      /* top */
      top = FILTER_AGGREGATE(filter_aggregate_new ());
      filter_aggregate_set_type (top, AGGREGATE_TYPE_AND);

      /* new/unread/read */
      n = 0;
      if (show_new) ++n;
      if (show_unread) ++n;
      if (show_read) ++n;
      if (n==1 || n==2) {
            Filter * filter = filter_new_article_new (FILTER_NEW_NEW);
            if (n==1) {
                  if (show_new)
                        filter_new_set_state (FILTER_NEW(filter), FILTER_NEW_NEW);
                  else if (show_unread)
                        filter_new_set_state (FILTER_NEW(filter), FILTER_NEW_UNREAD);
                  else if (show_read)
                        filter_new_set_state (FILTER_NEW(filter), FILTER_NEW_READ);
            } else {
                  if (!show_new)
                        filter_new_set_state (FILTER_NEW(filter), FILTER_NEW_NEW);
                  else if (!show_unread)
                        filter_new_set_state (FILTER_NEW(filter), FILTER_NEW_UNREAD);
                  else if (!show_read)
                        filter_new_set_state (FILTER_NEW(filter), FILTER_NEW_READ);
                  filter_negate (filter);
            }
            filter_aggregate_add (top, &filter, 1);
            pan_object_unref (PAN_OBJECT(filter));
      }

      /* attachments */
      n = 0;
      if (show_bin) ++n;
      if (show_inc_bin) ++n;
      if (show_nonbinary) ++n;
      if (n==1 || n==2) {
            Filter * filter = filter_binary_new ();
            if (n==1) {
                  if (show_bin)
                        filter_binary_set_state (FILTER_BINARY(filter), FILTER_BINARY_COMPLETE);
                  else if (show_inc_bin)
                        filter_binary_set_state (FILTER_BINARY(filter), FILTER_BINARY_INCOMPLETE);
                  else if (show_nonbinary)
                        filter_binary_set_state (FILTER_BINARY(filter), FILTER_BINARY_NONBINARY);
            } else {
                  if (!show_bin)
                        filter_binary_set_state (FILTER_BINARY(filter), FILTER_BINARY_COMPLETE);
                  else if (!show_inc_bin)
                        filter_binary_set_state (FILTER_BINARY(filter), FILTER_BINARY_INCOMPLETE);
                  else if (!show_nonbinary)
                        filter_binary_set_state (FILTER_BINARY(filter), FILTER_BINARY_NONBINARY);
                  filter_negate (filter);
            }
            filter_aggregate_add (top, &filter, 1);
            pan_object_unref (PAN_OBJECT(filter));
      }

      /* cached */
      n = 0;
      if (show_cached) ++n;
      if (show_non_cached) ++n;
      if (n == 1) {
            Filter * filter = filter_cached_new ();
            if (show_non_cached)
                  filter_negate (filter);
            filter_aggregate_add (top, &filter, 1);
            pan_object_unref (PAN_OBJECT(filter));
      }

      /* by me / others */
      n = 0;
      if (show_by_me) ++n;
      if (show_by_others) ++n;

      if (n == 1) {
            Filter * filter = filter_mine_new ();
            if (show_by_others)
                  filter_negate (filter);
            filter_aggregate_add (top, &filter, 1);
            pan_object_unref (PAN_OBJECT(filter));
      }

      /* score */
      {
            FilterScoreMode mode = 0;
            if (show_score_watched)  mode |= SCORE_WATCHED;
            if (show_score_high)     mode |= SCORE_HIGH;
            if (show_score_medium)   mode |= SCORE_MEDIUM;
            if (show_score_zero)     mode |= SCORE_ZERO;
            if (show_score_low)      mode |= SCORE_LOW;
            if (show_score_ignored)  mode |= SCORE_IGNORED;
            if (mode != 0)
            {
                  Filter * filter = filter_score_new (mode);
                  filter_aggregate_add (top, &filter, 1);
                  pan_object_unref (PAN_OBJECT(filter));
            }
      }

      /* custom filters */
      for (i=1; i<_custom_filter_entry_qty; ++i) {
            GtkWidget * w = GTK_WIDGET (_custom_filter_entries[i].extra_data);
            const char * name = (const char*) g_object_get_data (G_OBJECT(w), "filter_name");
            const gboolean active = GTK_CHECK_MENU_ITEM(w)->active;
            if (active) {
                  Filter * filter = filter_manager_get_named_filter (name);
                  if (filter != NULL)
                        filter_aggregate_add (top, &filter, 1);
            }
      }

      /* retval */
      if (filter_aggregate_child_size(top) != 1)
            retval = FILTER(top);
      else {
            retval = filter_aggregate_get_child_at (top, 0);
            pan_object_ref (PAN_OBJECT(retval));
            pan_object_unref (PAN_OBJECT(top)); /* remove previous filter */
      }

      /* negate */
      if (negate)
            filter_negate (retval);

      return retval;
}

Generated by  Doxygen 1.6.0   Back to index