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

article-toolbar.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 <config.h>

#include <string.h>

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

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

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

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

static void fire_user_changed_filter (void);

static GtkWidget * _filter_phrase_entry = NULL;

/*
 * FIXME: these should be made threadsafe is we're to allow 
 * multiple group switches in parallel (see switch_mutex in articlelist)
 */

static PString _filter_phrase;

static PhraseKeyType _phrase_key_type = PHRASE_KEY_SUBJECT;
static Filter* _filter = NULL;
static Filter* _raw_filter = NULL;

extern GtkTooltips * ttips;

/**
***
***   PHRASE FILTER
***
**/

static gboolean
update_filter_phrase (void)
{
      gboolean changed;
      PString new_phrase;

      new_phrase = pstring_shallow (gtk_entry_get_text (GTK_ENTRY (_filter_phrase_entry)), -1);
      new_phrase = pstring_strstrip_shallow (&new_phrase);

      changed = !pstring_equal (&_filter_phrase, &new_phrase);

      if (changed)
            pstring_copy (&_filter_phrase, &new_phrase);

      return changed;
}

static PhraseKeyType
get_phrase_key_type (void)
{
      return _phrase_key_type;
}


static Filter*
merge_filter_with_phrase (Filter * filter)
{
      Filter * retval = NULL;

      if (!_filter_phrase.len)
            retval = filter;
      else /* add the phrase filter to `filter' */
      {
            char * key = g_strndup (_filter_phrase.str, _filter_phrase.len);
            Filter * phrase_filter = filter_phrase_new ();
            Filter * children[2];

            children[0] = filter;
            children[1] = phrase_filter;

            filter_phrase_set (FILTER_PHRASE(phrase_filter),
                               PHRASE_MATCH_CONTAINS,
                               get_phrase_key_type(),
                               key,
                               FALSE);

            retval = filter_aggregate_new ();
            filter_aggregate_add (FILTER_AGGREGATE(retval), children, G_N_ELEMENTS(children));

            /* cleanup */
            pan_object_unref (PAN_OBJECT(children[0]));
            pan_object_unref (PAN_OBJECT(children[1]));
            g_free (key);
      }

      return retval;
}

/***
****
****   FILTERS
**** 
***/

static void
rebuild_filters (void)
{
      gulong bits;
      FilterShow show;
      Filter * old;

      /* update the raw value */
      old = _raw_filter;
      filter_mediator_get_bits (&bits, &show);
      _raw_filter = filter_mediator_get_filter (bits, FALSE);
      pan_object_unref (PAN_OBJECT(old));

      /* update the main filter */
      old = _filter;
      _filter = merge_filter_with_phrase (filter_dup(_raw_filter));
      pan_object_unref (PAN_OBJECT(old));
}

static void 
filter_changed_cb (gpointer call_obj, gpointer call_arg, gpointer user_data);

void
article_toolbar_set_group (const Group * group)
{
      g_return_if_fail (group_is_valid (group));

      pan_callback_remove (filter_mediator_get_change_callback(), filter_changed_cb, NULL);
      filter_mediator_set_bits (group->filter_bits, group->filter_show);
      pan_callback_add (filter_mediator_get_change_callback(), filter_changed_cb, NULL);

      rebuild_filters ();
}

void
article_toolbar_set_group_filter (Group * group)
{
      gulong bits;
      FilterShow show;
      g_return_if_fail (group_is_valid (group));

      filter_mediator_get_bits (&bits, &show);
      group->filter_bits = bits;
      group->filter_show = show;
      group_set_dirty (group);
}

void
article_toolbar_get_filter (Filter     ** newme_filter,
                            FilterShow  * show_setme)
{
      g_return_if_fail (newme_filter!=NULL);
      g_return_if_fail (show_setme!=NULL);

      *newme_filter = filter_dup (_filter);
      filter_mediator_get_bits (NULL,  show_setme);
}

static gboolean
grab_focus_idle (gpointer w)
{
      pan_lock ();
      gtk_widget_grab_focus (GTK_WIDGET(w));
      pan_unlock ();
      return FALSE;
}

static gboolean
article_phrase_activate_cb (void)
{
      if (update_filter_phrase ())
      {
            rebuild_filters ();
            fire_user_changed_filter ();
            gui_queue_add (grab_focus_idle, Pan.article_ctree);
      }
      return FALSE;
}

static void
set_key_type_cb (GtkMenuItem * item, gpointer data)
{
      PhraseKeyType key_type = GPOINTER_TO_INT(data);
      
      if (key_type != _phrase_key_type)
      {
            _phrase_key_type = key_type;
            rebuild_filters ();
            fire_user_changed_filter ();
      }
}

/***
****
****   FILTER DIALOG
**** 
***/


static int
filter_changed_idle (gpointer unused)
{
      rebuild_filters ();
      fire_user_changed_filter ();
      return 0;
}
static void 
filter_changed_cb (gpointer call_obj, gpointer call_arg, gpointer user_data)
{
      gui_queue_add (filter_changed_idle, NULL);
}

extern GtkAccelGroup * _main_accel_group;

static gboolean
entry_focus_in_cb (GtkWidget * w, GdkEventKey * event, gpointer unused) {
      g_object_ref (_main_accel_group);
      gtk_window_remove_accel_group (GTK_WINDOW(Pan.window), _main_accel_group);
      return FALSE;
}
static gboolean
entry_focus_out_cb (GtkWidget * w, GdkEventKey * event, gpointer unused) {
      gtk_window_add_accel_group (GTK_WINDOW(Pan.window), _main_accel_group);
      g_object_unref (_main_accel_group);
      return FALSE;
}

/****
*****
*****  BUILDING THE TOOLBAR
*****
****/

typedef struct
{
      const char * name;
      PhraseKeyType state;
}
ArticleToolbarOptionMenuStruct;

GtkWidget*
article_toolbar_new (void)
{
      gulong bits;
      FilterShow show;
      GtkWidget * w;
      GtkWidget * toolbar;

      /**
      ***  One-time initialization of local fields
      **/

      bits = ~(gulong)(STATE_FILTER_SCORE_IGNORED);

      show = FILTER_SHOW_MATCHES;

      filter_mediator_set_bits (bits, show);

      _raw_filter = filter_mediator_get_filter (bits, FALSE);

      _filter = filter_dup (_raw_filter);

      pan_callback_add (filter_mediator_get_change_callback(), filter_changed_cb, NULL);

      /**
      ***  Create the GUI
      **/

      toolbar = gtk_hbox_new (FALSE, GUI_PAD);

      /* filter by phrase */
      if (1) {
            GtkWidget * option_menu = gtk_option_menu_new ();
            GtkWidget *menu = gtk_menu_new ();
            int index = 0;
            int i;
            ArticleToolbarOptionMenuStruct foo[] = {
                  {NULL, PHRASE_KEY_SUBJECT},
                  {NULL, PHRASE_KEY_AUTHOR},
                  {NULL, PHRASE_KEY_MESSAGE_ID}
            };
            const int row_qty = G_N_ELEMENTS (foo);
            foo[0].name = _("Subject");
            foo[1].name = _("Author");
            foo[2].name = _("Message-ID");
            for (i=0; i<row_qty; ++i) {
                  GtkWidget * item = gtk_menu_item_new_with_label (foo[i].name);
                  gtk_signal_connect (GTK_OBJECT(item), "activate",
                                      GTK_SIGNAL_FUNC(set_key_type_cb), GINT_TO_POINTER(foo[i].state));
                  gtk_menu_append (GTK_MENU(menu), item);
                  gtk_widget_show (item);
            }
            gtk_menu_set_active (GTK_MENU(menu), index);
            gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
            gtk_widget_show_all (GTK_WIDGET(option_menu));
            w = option_menu;
      }
      gtk_box_pack_start (GTK_BOX(toolbar), w, FALSE, FALSE, 0);

      w = gtk_label_new_with_mnemonic (_("Fin_d:"));
      gtk_box_pack_start (GTK_BOX(toolbar), w, FALSE, FALSE, 0);

      _filter_phrase = PSTRING_INIT;
      _filter_phrase_entry = gtk_entry_new ();
      gtk_label_set_mnemonic_widget (GTK_LABEL(w), _filter_phrase_entry);
      w = _filter_phrase_entry;
      g_signal_connect (w, "focus_in_event", G_CALLBACK(entry_focus_in_cb), NULL);
      g_signal_connect (w, "focus_out_event", G_CALLBACK(entry_focus_out_cb), NULL);
      g_signal_connect (w, "focus_out_event", G_CALLBACK(article_phrase_activate_cb), NULL);
      g_signal_connect (w, "activate", G_CALLBACK(article_phrase_activate_cb), NULL);
      gtk_tooltips_set_tip (GTK_TOOLTIPS(ttips), w,
              _("Type in a search string and press ENTER.\nWildcards are allowed."), NULL);
      gtk_box_pack_start (GTK_BOX(toolbar), w, TRUE, TRUE, 0);

      /* return the toolbar widget */
      gtk_widget_show_all (toolbar);
      return toolbar;
}

/***
****  Events
***/

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

static void
fire_user_changed_filter (void)
{
      FilterShow show;
      ArticleToolbarCallbackStruct cbs;
      debug_enter ("fire_filter_changed");
      filter_mediator_get_bits (NULL, &show);
      cbs.filter = _filter;
      cbs.filter_show = show;
      pan_callback_call (article_toolbar_get_user_changed_filter_callback (), &cbs, NULL);

      debug_exit ("fire_filter_changed");
}

Generated by  Doxygen 1.6.0   Back to index