[pan2: 133/268] nearly complete support for filtering actions based on score



commit 9148e3ea66857d8915d2d648cce107f7b6a9d0dc
Author: Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
Date:   Tue Jul 19 12:03:50 2011 +0200

    nearly complete support for filtering actions based on score

 pan/data-impl/data-impl.h       |   22 +++++--
 pan/data-impl/headers.cc        |    9 ++-
 pan/data-impl/my-tree.cc        |  121 ++++++++++++++++++++++----------------
 pan/data-impl/rules-filter.cc   |   75 +++++++++++++++++-------
 pan/data-impl/rules-filter.h    |   16 ++++-
 pan/data/data.h                 |   13 ++++-
 pan/gui/actions.cc              |   13 +++-
 pan/gui/gui.cc                  |   94 +++++++-----------------------
 pan/gui/gui.h                   |    1 +
 pan/gui/header-pane.cc          |   97 ++++++++++++++++++++-----------
 pan/gui/header-pane.h           |    5 +-
 pan/gui/pan-ui.h                |    2 +
 pan/gui/pan.ui.h                |    2 +
 pan/gui/prefs-ui.cc             |    7 +-
 pan/gui/prefs.h                 |    1 +
 pan/gui/save-ui.cc              |    2 +-
 pan/tasks/task-article.h        |    2 +
 pan/tasks/task-xover.cc         |   10 ---
 pan/usenet-utils/filter-info.cc |    1 +
 pan/usenet-utils/filter-info.h  |    2 +-
 pan/usenet-utils/rules-info.cc  |   44 +++++++++++++-
 pan/usenet-utils/rules-info.h   |   16 ++++--
 22 files changed, 332 insertions(+), 223 deletions(-)
---
diff --git a/pan/data-impl/data-impl.h b/pan/data-impl/data-impl.h
index ab00f7d..655cca0 100644
--- a/pan/data-impl/data-impl.h
+++ b/pan/data-impl/data-impl.h
@@ -431,7 +431,9 @@ namespace pan
           MyTree (DataImpl              & data_impl,
                   const Quark           & group,
                   const Data::ShowType    show_type,
-                  const FilterInfo      * filter_info);
+                  const FilterInfo      * filter_info=0,
+                  const RulesInfo       * rules=0,
+                        Queue           * queue=0);
           virtual ~MyTree ();
 
         public: // from ArticleTree
@@ -441,7 +443,8 @@ namespace pan
           virtual size_t size () const;
           virtual void set_filter (const ShowType      show_type = SHOW_ARTICLES,
                                    const FilterInfo  * criteria  = 0);
-          virtual void set_rules (const RulesInfo * criteria = 0);
+          virtual void set_rules  (const ShowType      show_type = SHOW_ARTICLES,
+                                   const RulesInfo   * rules  = 0);
 
         public:
           void articles_changed (const quarks_t& mids, bool do_refilter);
@@ -464,9 +467,15 @@ namespace pan
           void accumulate_descendants (unique_nodes_t&, const ArticleNode*) const;
           void add_articles (const const_nodes_v&);
           void apply_filter (const const_nodes_v&);
-          void apply_rules (const const_nodes_v& candidates);
+          void apply_rules  (const_nodes_v& candidates);
+
+        private:
+          void cache_articles (std::set<const Article*> s);
+          void download_articles (std::set<const Article*> s);
       };
 
+
+
       std::set<MyTree*> _trees;
       void on_articles_removed (const quarks_t& mids) const;
       void on_articles_added (const Quark& group, const quarks_t& mids);
@@ -474,14 +483,15 @@ namespace pan
       void remove_articles_from_tree (MyTree*, const quarks_t& mids) const;
       void add_articles_to_tree (MyTree*, const quarks_t& mids);
 
-
     public:  // Data interface
 
       virtual void delete_articles             (const unique_articles_t&);
 
       virtual ArticleTree* group_get_articles  (const Quark        & group,
                                                 const ShowType      show_type = SHOW_ARTICLES,
-                                                const FilterInfo   * criteria=0) const;
+                                                const FilterInfo   * criteria=0,
+                                                const RulesInfo    * rules=0,
+                                                      Queue        * queue=0) const;
 
       virtual void group_clear_articles        (const Quark        & group);
 
@@ -625,7 +635,7 @@ namespace pan
     public:
 
       const ArticleFilter _article_filter;
-      const RulesFilter   _rules_filter;
+      RulesFilter   _rules_filter;
 
     private:
       guint newsrc_autosave_id;
diff --git a/pan/data-impl/headers.cc b/pan/data-impl/headers.cc
index 3430352..a81dc3d 100644
--- a/pan/data-impl/headers.cc
+++ b/pan/data-impl/headers.cc
@@ -922,6 +922,7 @@ DataImpl :: get_article_scores (const Quark         & group,
 void
 DataImpl :: rescore_articles (const Quark& group, const quarks_t mids)
 {
+
   GroupHeaders * gh (get_group_headers (group));
   if (!gh) // group isn't loaded
     return;
@@ -1075,6 +1076,7 @@ DataImpl :: group_clear_articles (const Quark& group)
 void
 DataImpl :: delete_articles (const unique_articles_t& articles)
 {
+
   quarks_t all_mids;
 
   // info we need to batch these deletions per group...
@@ -1136,6 +1138,7 @@ DataImpl :: on_articles_changed (const Quark& group, const quarks_t& mids, bool
 void
 DataImpl :: on_articles_added (const Quark& group, const quarks_t& mids)
 {
+
   if (!mids.empty())
   {
     Log::add_info_va (_("Added %lu articles to %s."),
@@ -1192,8 +1195,10 @@ DataImpl :: find_closest_ancestor (const ArticleNode             * node,
 Data::ArticleTree*
 DataImpl :: group_get_articles (const Quark       & group,
                                 const ShowType      show_type,
-                                const FilterInfo  * filter) const
+                                const FilterInfo  * filter,
+                                const RulesInfo   * rules,
+                                      Queue       * queue) const
 {
   // cast const away for group_ref()... consider _groups mutable
-  return new MyTree (*const_cast<DataImpl*>(this), group, show_type, filter);
+  return new MyTree (*const_cast<DataImpl*>(this), group, show_type, filter, rules,queue);
 }
diff --git a/pan/data-impl/my-tree.cc b/pan/data-impl/my-tree.cc
index ebe1caf..a52a539 100644
--- a/pan/data-impl/my-tree.cc
+++ b/pan/data-impl/my-tree.cc
@@ -84,12 +84,27 @@ DataImpl :: MyTree :: size () const
 }
 
 void
-DataImpl :: MyTree :: set_rules (const RulesInfo * criteria )
+DataImpl :: MyTree :: set_rules (const Data::ShowType    show_type,
+                                 const RulesInfo * rules )
 {
-  if (criteria)
-    _rules = *criteria;
+
+  if (rules)
+    _rules = *rules;
   else
     _rules.clear ();
+  _show_type = show_type;
+
+  const GroupHeaders * h (_data.get_group_headers (_group));
+  g_assert (h != 0);
+  const_nodes_v candidates;
+  candidates.reserve (h->_nodes.size());
+  foreach_const (nodes_t, h->_nodes, it) {
+    const ArticleNode * node (it->second);
+    if (node->_article)
+      candidates.push_back ((ArticleNode*)node);
+  }
+
+  apply_rules(candidates);
 }
 
 void
@@ -124,14 +139,19 @@ DataImpl :: MyTree :: set_filter (const Data::ShowType    show_type,
 DataImpl :: MyTree :: MyTree (DataImpl              & data_impl,
                               const Quark           & group,
                               const Data::ShowType    show_type,
-                              const FilterInfo      * filter):
+                              const FilterInfo      * filter,
+                              const RulesInfo       * rules,
+                                    Queue           * queue):
   _group (group),
   _data (data_impl)
 {
+
+  _data.set_queue(queue);
   _data.ref_group (_group);
   _data._trees.insert (this);
+
   set_filter (show_type, filter);
-  // set_rules (rules)
+  set_rules (show_type, rules);
 }
 
 DataImpl :: MyTree :: ~MyTree ()
@@ -165,23 +185,21 @@ DataImpl :: MyTree :: NodeMidCompare
 };
 
 void
-DataImpl :: MyTree :: apply_rules (const const_nodes_v& candidates)
+DataImpl :: MyTree :: apply_rules (const_nodes_v& candidates)
 {
+
   NodeMidCompare compare;
   const_nodes_v pass;
-  const_nodes_v fail;
   pass.reserve (candidates.size());
-  fail.reserve (candidates.size());
 
   // apply the rules to the whole tree
-  foreach_const (const_nodes_v, candidates, it) {
+  foreach (const_nodes_v, candidates, it) {
     if (!(*it)->_article)
       continue;
-    else if (_data._rules_filter.test_article (_data, _rules, _group, *(*it)->_article))
+    if (_data._rules_filter.test_article (_data, _rules, _group, *(*it)->_article))
       pass.push_back (*it);
-    else
-      fail.push_back (*it);
   }
+
   //std::cerr << LINE_ID << " " << pass.size() << " of "
   //          << (pass.size() + fail.size()) << " articles pass\n";
 
@@ -201,50 +219,46 @@ DataImpl :: MyTree :: apply_rules (const const_nodes_v& candidates)
   if (_show_type == Data::SHOW_THREADS || _show_type == Data::SHOW_SUBTHREADS)
   {
     unique_nodes_t d;
-    foreach_const (const_nodes_v, pass, it)
+    foreach (const_nodes_v, pass, it)
       accumulate_descendants (d, *it);
     //std::cerr << LINE_ID << " expands into " << d.size() << " articles\n";
 
     const_nodes_v fail2;
     pass.clear ();
-    foreach_const (unique_nodes_t, d, it) {
-      const Article * a ((*it)->_article);
-      if (a->score > -9999 || _data._rules_filter.test_article (_data, _rules, _group, *a))
-        pass.push_back (*it); // pass is now sorted by mid because d was too
-      else
-        fail2.push_back (*it); // fail2 is sorted by mid because d was too
+    foreach (unique_nodes_t, d, it) {
+      Article * a ((*it)->_article);
+      _data._rules_filter.test_article (_data, _rules, _group, *a);
     }
-
-    // fail cleanup: add fail2 and remove duplicates.
-    // both are sorted by mid, so set_union will do the job
-    const_nodes_v tmp;
-    tmp.reserve (fail.size() + fail2.size());
-    std::set_union (fail.begin(), fail.end(),
-                    fail2.begin(), fail2.end(),
-                    inserter (tmp, tmp.begin()), compare);
-    fail.swap (tmp);
-
-    // fail cleanup: remove newly-passing articles
-    tmp.clear ();
-    std::set_difference (fail.begin(), fail.end(),
-                         pass.begin(), pass.end(),
-                         inserter (tmp, tmp.begin()), compare);
-    fail.swap (tmp);
-    //std::cerr << LINE_ID << ' ' << pass.size() << " of "
-    //          << (pass.size() + fail.size())
-    //          << " make it past the show-thread block\n";
   }
+  cache_articles(_data._rules_filter._cached);
+  download_articles(_data._rules_filter._downloaded);
+  _data._rules_filter.finalize(_data);
+}
 
+void
+DataImpl :: MyTree :: cache_articles (std::set<const Article*> s)
+{
+  if (!_data._queue) return;
+
+  Queue::tasks_t tasks;
+  ArticleCache& cache(_data.get_cache());
+  foreach_const (std::set<const Article*>, s, it)
+    tasks.push_back (new TaskArticle (_data, _data, **it, cache, _data));
+  if (!tasks.empty())
+    _data._queue->add_tasks (tasks, Queue::TOP);
+}
 
-  // passing articles not in the tree should be added...
-  add_articles (pass);
-
-  // failing articles in the tree should be removed...
-  quarks_t mids;
-  foreach_const (const_nodes_v, fail, it)
-    mids.insert (mids.end(), (*it)->_mid);
-  remove_articles (mids);
-
+void
+DataImpl :: MyTree :: download_articles (std::set<const Article*> s)
+{
+  if (!_data._queue) return;
+
+  Queue::tasks_t tasks;
+  ArticleCache& cache(_data.get_cache());
+  foreach_const (std::set<const Article*>, s, it)
+    tasks.push_back (new TaskArticle (_data, _data, **it, cache, _data));
+  if (!tasks.empty())
+    _data._queue->add_tasks (tasks, Queue::TOP);
 }
 
 
@@ -419,17 +433,21 @@ DataImpl :: MyTree :: accumulate_descendants (unique_nodes_t& descendants,
 void
 DataImpl :: MyTree :: articles_changed (const quarks_t& mids, bool do_refilter)
 {
-  if (do_refilter) {
-    // refilter... this may cause articles to be shown or hidden
+
+  if (do_refilter)
+  {
     const_nodes_v nodes;
     _data.find_nodes (mids, _data.get_group_headers(_group)->_nodes, nodes);
-    apply_filter (nodes);
     apply_rules (nodes);
+     // refilter... this may cause articles to be shown or hidden
+    apply_filter (nodes);
   }
 
+
   // fire an update event for any of those mids in our tree...
   nodes_v my_nodes;
   _data.find_nodes (mids, _nodes, my_nodes);
+
   if (!my_nodes.empty()) {
     ArticleTree::Diffs diffs;
     foreach_const (nodes_v, my_nodes, it)
@@ -443,8 +461,9 @@ DataImpl :: MyTree :: add_articles (const quarks_t& mids)
 {
   const_nodes_v nodes;
   _data.find_nodes (mids, _data.get_group_headers(_group)->_nodes, nodes);
-  apply_filter (nodes);
   apply_rules (nodes);
+  apply_filter (nodes);
+
 }
 
 
diff --git a/pan/data-impl/rules-filter.cc b/pan/data-impl/rules-filter.cc
index 05ca5c2..b7598cb 100644
--- a/pan/data-impl/rules-filter.cc
+++ b/pan/data-impl/rules-filter.cc
@@ -28,27 +28,36 @@
 
 using namespace pan;
 
+void
+RulesFilter :: finalize (Data& data)
+{
+
+  data.delete_articles (_delete);
+  _delete.clear();
+
+  const std::vector<const Article*> tmp (_mark_read.begin(), _mark_read.end());
+  data.mark_read ((const Article**)&tmp.front(), tmp.size());
+  _mark_read.clear();
+
+  _cached.clear();
+  _downloaded.clear();
+}
+
 bool
-RulesFilter :: test_article (const Data        & data,
-                             const RulesInfo   & rules,
-                             const Quark       & group,
-                             const Article     & article) const
+RulesFilter :: test_article ( Data        & data,
+                              RulesInfo   & rules,
+                              const Quark & group,
+                              Article     & article)
 {
-  bool pass (false);
-  const ArticleCache& cache(data.get_cache());
+
+  bool pass (article.score >= rules._lb && article.score <= rules._hb);
 
   switch (rules._type)
   {
     case RulesInfo::AGGREGATE_AND:
       pass = true;
-      foreach_const (RulesInfo::aggregates_t, rules._aggregates, it) {
-        // assume test passes if test needs body but article not cached
-        if (!it->_needs_body || cache.contains(article.message_id) )
-          if (!test_article (data, *it, group, article)) {
-            pass = false;
-            break;
-          }
-      }
+      foreach (RulesInfo::aggregates_t, rules._aggregates, it)
+        test_article (data, *it, group, article);
       break;
 
     case RulesInfo::AGGREGATE_OR:
@@ -56,20 +65,40 @@ RulesFilter :: test_article (const Data        & data,
         pass = true;
       else {
         pass = false;
-        foreach_const (RulesInfo::aggregates_t, rules._aggregates, it) {
-          // assume test fails if test needs body but article not cached
-          if (!it->_needs_body || cache.contains(article.message_id) )
-            if (test_article (data, *it, group, article)) {
-              pass = true;
-              break;
-            }
+        foreach (RulesInfo::aggregates_t, rules._aggregates, it) {
+          if (test_article (data, *it, group, article)) {
+            pass = true;
+            break;
+          }
         }
       }
       break;
 
     case RulesInfo::MARK_READ:
-      pass = article.score == Article::COMPLETE;
-    break;
+
+      if (pass)
+        _mark_read.insert(&article);
+      break;
+
+    case RulesInfo::AUTOCACHE:
+      if (pass)
+        _cached.insert (&article);
+      break;
+
+    case RulesInfo::AUTODOWNLOAD:
+      if (pass)
+        _downloaded.insert (&article);
+      break;
+
+    case RulesInfo::DELETE:
+      if (pass)
+         _delete.insert (&article);
+      break;
+
+    default:
+     debug("error : unknown rules type "<<rules._type);
+     return true;
+     break;
   }
 
   return pass;
diff --git a/pan/data-impl/rules-filter.h b/pan/data-impl/rules-filter.h
index c0f4b40..2913fb6 100644
--- a/pan/data-impl/rules-filter.h
+++ b/pan/data-impl/rules-filter.h
@@ -21,6 +21,7 @@
 #define __RulesFilter_h__
 
 #include <pan/general/quark.h>
+#include <pan/tasks/queue.h>
 #include <pan/usenet-utils/filter-info.h>
 #include <pan/usenet-utils/rules-info.h>
 #include <pan/usenet-utils/scorefile.h>
@@ -39,11 +40,20 @@ namespace pan
 
       RulesFilter() {  }
 
-      bool test_article (const Data& data,
-                         const RulesInfo   & rules,
+      bool test_article (Data        & data,
+                         RulesInfo   & rules,
                          const Quark& group,
-                         const Article& article) const;
+                         Article& article);
 
+      private:
+        std::set<const Article*> _mark_read;
+        std::set<const Article*> _delete;
+
+      public:
+
+        std::set<const Article*> _cached;
+        std::set<const Article*> _downloaded;
+        void finalize (Data& data) ;
   };
 }
 
diff --git a/pan/data/data.h b/pan/data/data.h
index e2db9be..e33a096 100644
--- a/pan/data/data.h
+++ b/pan/data/data.h
@@ -38,6 +38,7 @@ namespace pan
 {
   class FilterInfo;
   class RulesInfo;
+  class Queue;
 
   /**
    * Data Interface class for seeing the mapping between groups and servers.
@@ -470,7 +471,8 @@ namespace pan
           virtual void set_filter (const ShowType     show_type = SHOW_ARTICLES,
                                    const FilterInfo * filter_or_null_to_reset = 0) = 0;
 
-          virtual void set_rules (const RulesInfo * filterme = 0) = 0;
+          virtual void set_rules (const ShowType     show_type = SHOW_ARTICLES,
+                                   const RulesInfo * filter_or_null_to_reset = 0) = 0;
       };
 
        /**
@@ -478,7 +480,9 @@ namespace pan
         */
        virtual ArticleTree* group_get_articles (const Quark       & group,
                                                 const ShowType      show_type = SHOW_ARTICLES,
-                                                const FilterInfo  * criteria = 0) const=0;
+                                                const FilterInfo  * criteria = 0,
+                                                const RulesInfo   * rules    = 0,
+                                                      Queue       * queue = 0) const=0;
 
        virtual void group_clear_articles (const Quark& group) = 0;
 
@@ -506,6 +510,11 @@ namespace pan
 
         virtual void rescore () = 0;
 
+    ///TODO private!
+    public:
+      Queue * _queue;
+      void set_queue (Queue* q) { _queue = q; }
+
 
 
     /*****************************************************************
diff --git a/pan/gui/actions.cc b/pan/gui/actions.cc
index 04411af..eb00c95 100644
--- a/pan/gui/actions.cc
+++ b/pan/gui/actions.cc
@@ -82,9 +82,6 @@ namespace
       GtkIconSet * icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
       gtk_icon_factory_add (factory, my_builtin_icons[i].name, icon_set);
       g_object_unref (pixbuf);
-
-      //std::cerr << "registered icon " << my_builtin_icons[i].name << std::endl;
-
       g_object_unref (pixbuf);
       gtk_icon_set_unref (icon_set);
     }
@@ -230,6 +227,12 @@ namespace
     set_new_match_on_score_state (new_state);
   }
 
+  void do_toggle_rules  (GtkToggleAction * a)
+  {
+    prefs->_rules_enabled = gtk_toggle_action_get_active (a);
+    pan_ui->do_enable_toggle_rules(prefs->_rules_enabled);
+  }
+
   void do_match_only_watched_articles (GtkToggleAction * a)   { set_new_match_on_score_state (gtk_toggle_action_get_active(a) ? MATCH_WATCHED : prev_score_state); }
   void do_match_watched_articles (GtkToggleAction * a)        { set_score_state_bit_from_toggle (a, MATCH_WATCHED); }
   void do_match_high_scoring_articles (GtkToggleAction * a)   { set_score_state_bit_from_toggle (a, MATCH_HIGH_SCORING); }
@@ -645,7 +648,9 @@ namespace
     { "match-medium-scoring-articles", NULL, N_("Match Scores of 1...4999 (Me_dium)"), NULL, NULL, G_CALLBACK(do_match_medium_scoring_articles), true },
     { "match-normal-scoring-articles", NULL, N_("Match Scores of 0 (_Normal)"), NULL, NULL, G_CALLBACK(do_match_normal_scoring_articles), true },
     { "match-low-scoring-articles", NULL, N_("Match Scores of -9998...-1 (_Low)"), NULL, NULL, G_CALLBACK(do_match_low_scoring_articles), true },
-    { "match-ignored-articles", NULL, N_("Match Scores of -9999 (_Ignored)"), NULL, NULL, G_CALLBACK(do_match_ignored_articles), false }
+    { "match-ignored-articles", NULL, N_("Match Scores of -9999 (_Ignored)"), NULL, NULL, G_CALLBACK(do_match_ignored_articles), false },
+
+    { "enable-rules", NULL, N_("Enable/Disable all _Rules"), "R", NULL, G_CALLBACK(do_toggle_rules), true    }
   };
 
   const guint n_toggle_entries (G_N_ELEMENTS(toggle_entries));
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index fb1aa0a..421ae02 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -588,6 +588,7 @@ GUI :: prompt_user_for_filename (GtkWindow * parent, const Prefs& prefs)
   return file;
 }
 
+/// TODO drag-n-drop of nzb files
 gboolean GUI ::dragged(GtkWidget *wgt, GdkDragContext *context, int x, int y,
               GtkSelectionData *seldata, guint info, guint time,
               gpointer userdata)
@@ -597,8 +598,6 @@ gboolean GUI ::dragged(GtkWidget *wgt, GdkDragContext *context, int x, int y,
 
   GUI * p(static_cast<GUI*>(userdata));
 
-  std::cerr<<"dragged\n";
-
   GdkAtom target_type;
 
   /* If the source offers a target */
@@ -621,25 +620,23 @@ void GUI ::dragged_rcvd(GtkWidget *wgt, GdkDragContext *context, int x, int y,
 
   gtk_drag_finish (context, true, true, time);
 
-  std::cerr<<"dragged rcvd\n";
-
-  GUI * p(static_cast<GUI*>(userdata));
-
-  GtkWidget * header_pane;
-  GtkTreeIter   iter;
-
-  header_pane = GTK_WIDGET(userdata);
-  std::cerr<<"data : "<<(gchar*)seldata->data<<std::endl;
-  Article a;
-  a.message_id = Quark((gchar*)seldata->data);
-  a.xref.insert ("2", "alt.binaries.test", 0);
-  a.set_part_count (1);
-  a.is_binary = true;
-  std::vector<Article> v;
-  v.push_back(a);
-  SaveDialog * dialog = new SaveDialog (p->_prefs, p->_group_prefs, p->_data, p->_data,
-                                        p->_cache, p->_data, p->_queue, get_window(p->_root), p->_header_pane->get_group(), v);
-  gtk_widget_show (dialog->root());
+//  GUI * p(static_cast<GUI*>(userdata));
+//
+//  GtkWidget * header_pane;
+//  GtkTreeIter   iter;
+//
+//  header_pane = GTK_WIDGET(userdata);
+////  std::cerr<<"data : "<<(gchar*)seldata->data<<std::endl;
+//  Article a;
+//  a.message_id = Quark((gchar*)seldata->data);
+//  a.xref.insert ("2", "alt.binaries.test", 0);
+//  a.set_part_count (1);
+//  a.is_binary = true;
+//  std::vector<Article> v;
+//  v.push_back(a);
+//  SaveDialog * dialog = new SaveDialog (p->_prefs, p->_group_prefs, p->_data, p->_data,
+//                                        p->_cache, p->_data, p->_queue, get_window(p->_root), p->_header_pane->get_group(), v);
+//  gtk_widget_show (dialog->root());
 
   gtk_drag_finish (context, true, false, time);
 
@@ -1072,26 +1069,6 @@ void GUI ::  prefs_dialog_destroyed_cb (GtkWidget * w, gpointer self)
   static_cast<GUI*>(self)->prefs_dialog_destroyed (w);
 }
 
-/*
-    w = score_handler_new (prefs, "rules-delete-score-value", "never", b);
-    w = score_handler_new (prefs, "rules-mark-read-value", "never", b);
-    w = score_handler_new (prefs, "rules-mark-unread-value", "never", b);
-    w = score_handler_new (prefs, "rules-autocache-value", "never", b);
-    w = score_handler_new (prefs, "rules-auto-dl-value", "never", b);
-*/
-
-#define NUM_RULES 6
-
-//int GUI :: score_int_from_string(std::string val, const char* rules[])
-//{
-//  const char* tmp (val.c_str());
-//  int res(-1);
-//  for (int i=0;i<NUM_RULES;++i) {
-//    if (!strcmp(rules[i],tmp)) { res = i; break; }
-//  }
-//  return res;
-//}
-
 void GUI :: prefs_dialog_destroyed (GtkWidget *)
 {
 
@@ -1099,39 +1076,9 @@ void GUI :: prefs_dialog_destroyed (GtkWidget *)
   if (!group.empty() && _prefs._rules_changed)
   {
     _prefs._rules_changed = !_prefs._rules_changed;
-    std::string text;
-    int no(0);
-    _header_pane->rules(no);
+    _header_pane->rules(_prefs._rules_enabled);
   }
-//  // apply filters
-//  if (_prefs._rules_changed && !group.empty())
-//  {
-//    _prefs._rules_changed = !_prefs._rules_changed;
-//    std::map<int, const char*> rules_map;
-//
-//    const char* rules [NUM_RULES] = { "never",
-//                              "watched",
-//                              "high" ,
-//                              "medium",
-//                              "low" ,
-//                              "ignored" };
-//    for (int i=0;i<NUM_RULES;++i)
-//      rules_map.insert(std::pair<int,const char*>(i,rules[i]));
-//    int val_delete(score_int_from_string(_prefs.get_string("rules-delete-score-value", "never"),rules));
-//    int val_read(score_int_from_string(_prefs.get_string("rules-mark-read-value", "never"),rules));
-//    int val_unread(score_int_from_string(_prefs.get_string("rules-mark-unread-value", "never"),rules));
-//    int val_cache(score_int_from_string(_prefs.get_string("rules-autocache-value", "never"),rules));
-//    int val_dl(score_int_from_string(_prefs.get_string("rules-auto-dl-value", "never"),rules));
-//
-//    std::cerr<<val_delete<<" "<<val_read<<std::endl;
-//
-//    std::vector<const Article*> articles_v (_header_pane->get_full_selection_v());
-//
-//    foreach (std::vector<const Article*>, articles_v, vit)
-//    {
-////      foreach
-//    }
-//  }
+
 }
 
 
@@ -1654,6 +1601,7 @@ void GUI :: do_match_only_cached_articles (bool) { _header_pane->refilter (); }
 void GUI :: do_match_only_binary_articles (bool) { _header_pane->refilter (); }
 void GUI :: do_match_only_my_articles     (bool) { _header_pane->refilter (); }
 void GUI :: do_match_on_score_state       (int)  { _header_pane->refilter (); }
+void GUI :: do_enable_toggle_rules        (bool enable) { _header_pane -> rules (enable); }
 
 void GUI :: do_show_matches (const Data::ShowType show_type)
 {
diff --git a/pan/gui/gui.h b/pan/gui/gui.h
index 542aa13..7cdfe80 100644
--- a/pan/gui/gui.h
+++ b/pan/gui/gui.h
@@ -144,6 +144,7 @@ namespace pan
       virtual void do_match_only_binary_articles (bool);
       virtual void do_match_only_my_articles (bool);
       virtual void do_match_only_unread_articles (bool);
+      virtual void do_enable_toggle_rules (bool enable);
       virtual void do_match_on_score_state (int);
       virtual void do_show_matches (const Data::ShowType);
       virtual void do_read_selected_group ();
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index 3e54483..1c7bd50 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -362,8 +362,6 @@ HeaderPane :: column_compare_func (GtkTreeModel  * model,
 {
   int ret (0);
   const PanTreeStore * store (reinterpret_cast<PanTreeStore*>(model));
-  //const Row& row_a (*dynamic_cast<const Row*>(store->get_row (iter_a)));
-  //const Row& row_b (*dynamic_cast<const Row*>(store->get_row (iter_b)));
   const Row& row_a (*static_cast<const Row*>(store->get_row (iter_a)));
   const Row& row_b (*static_cast<const Row*>(store->get_row (iter_b)));
 
@@ -542,7 +540,7 @@ HeaderPane :: set_group (const Quark& new_group)
 
     if (!_group.empty())
     {
-      _atree = _data.group_get_articles (new_group, _show_type, &_filter);
+      _atree = _data.group_get_articles (new_group, _show_type, &_filter,&_rules,&_queue);
       _atree->add_listener (this);
 
       rebuild ();
@@ -1025,38 +1023,63 @@ namespace
     MESSAGE_ID
   };
 
-  enum
-  {
-    RULES_MARK_READ,
-    RULES_MARK_UNREAD,
-    RULES_AUTOCACHE,
-    RULES_AUTODL,
-    RULES_DELETE
-  };
+}
+
+#define RANGE 4998
+int
+HeaderPane :: get_int_from_rules_str(std::string val)
+{
+  if (val == "new") return 0;
+  if (val == "never") return 9999+RANGE+1;
+  if (val == "watched") return 9999;
+  if (val == "high") return 5000;
+  if (val == "medium") return 1;
+  if (val == "low") return -4999;
+  if (val == "ignored") return -9999;
 }
 
 void
-HeaderPane :: rebuild_rules (int mode)
+HeaderPane :: rebuild_rules (bool enable)
 {
 
-  RulesInfo &f (_rules);
-  f.set_type_aggregate_and ();
+  if (!enable)
+  {
+    _rules.clear();
+    return;
+  }
+
+  RulesInfo &r (_rules);
+  r.set_type_aggregate_and ();
   RulesInfo tmp;
 
-  if (mode == RULES_MARK_READ) {
-    tmp.set_type_mark_read ();
-    f._aggregates.push_back (tmp);
-  }
-//   if (mode == RULES_MARK_UNREAD) {
-//    tmp.set_type_mark_unread ();
-//    f._aggregates.push_back (tmp);
-//  }
+  int backup (get_int_from_rules_str("never"));
+  int val_mark_read(get_int_from_rules_str(_prefs.get_string("rules-mark-read-value", "never")));
+  if (!enable) val_mark_read = backup;
+  int val_delete(get_int_from_rules_str(_prefs.get_string("rules-delete-value", "never")));
+  if (!enable) val_delete = backup;
+  int val_cache(get_int_from_rules_str(_prefs.get_string("rules-autocache-value", "never")));
+  if (!enable) val_cache = backup;
+  int val_dl(get_int_from_rules_str(_prefs.get_string("rules-auto-dl-value", "never")));
+  if (!enable) val_dl = backup;
+
+  tmp.set_type_mark_read_b (val_mark_read, val_mark_read == 0 ? 0 : val_mark_read+RANGE);
+  r._aggregates.push_back (tmp);
+
+  tmp.set_type_delete_b (val_delete, val_delete == 0 ? 0 : val_delete+RANGE);
+  r._aggregates.push_back (tmp);
+
+  tmp.set_type_autocache_b (val_cache, val_cache == 0 ? 0 : val_cache+RANGE);
+  r._aggregates.push_back (tmp);
+
+  tmp.set_type_dl_b (val_dl, val_dl == 0 ? 0 : val_dl+RANGE);
+  r._aggregates.push_back (tmp);
 
 }
 
 void
 HeaderPane :: rebuild_filter (const std::string& text, int mode)
 {
+
   TextMatch::Description d;
   d.negate = false;
   d.case_sensitive = false;
@@ -1204,16 +1227,22 @@ HeaderPane :: filter (const std::string& text, int mode)
 }
 
 void
-HeaderPane :: rules(int mode)
+HeaderPane :: rules(bool enable)
 {
-  if (_prefs.get_string("rules-mark-read-value","never") != "never")
-    rebuild_rules(RULES_MARK_READ);
+  rebuild_rules(enable);
 
-  if (_rules._aggregates.empty())
-    _atree->set_rules();
-  else
-    _atree->set_rules(&_rules);
+  if (_atree)
+  {
+    _wait.watch_cursor_on ();
 
+    if (_rules._aggregates.empty()) {
+      _atree->set_rules();
+    }
+    else
+      _atree->set_rules(_show_type, &_rules);
+
+    _wait.watch_cursor_off ();
+  }
 }
 
 namespace
@@ -1691,6 +1720,7 @@ HeaderPane :: HeaderPane (ActionManager       & action_manager,
   _root = scroll;
 
   search_activate (this); // calls rebuild_filter
+  rules();
 
   _data.add_listener (this);
   _prefs.add_listener (this);
@@ -2113,10 +2143,11 @@ HeaderPane :: on_queue_task_removed (Queue&, Task& task, int)
 void
 HeaderPane :: on_cache_added (const Quark& message_id)
 {
-  quarks_t q;
-  q.insert(message_id);
-  _data.rescore_articles ( _group, q );
-  rebuild_article_action (message_id);
+    /// SLOOOOW!
+//  quarks_t q;
+//  q.insert(message_id);
+//  _data.rescore_articles ( _group, q );
+//  rebuild_article_action (message_id);
 }
 void
 HeaderPane :: on_cache_removed (const quarks_t& message_ids)
diff --git a/pan/gui/header-pane.h b/pan/gui/header-pane.h
index 532226d..37ccfcb 100644
--- a/pan/gui/header-pane.h
+++ b/pan/gui/header-pane.h
@@ -304,12 +304,13 @@ namespace pan
 
     private:
       void rebuild_filter (const std::string&, int);
-      void rebuild_rules (int mode);
+      void rebuild_rules (bool enable=false);
+      int get_int_from_rules_str(std::string val);
       void refresh_font ();
 
     public: // public so that anonymous namespace can reach -- don't call
       void filter (const std::string& text, int mode);
-      void rules (int mode);
+      void rules (bool enable=false);
       static void do_popup_menu (GtkWidget*, GdkEventButton*, gpointer);
       static void on_row_activated (GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer);
       static gboolean on_button_pressed (GtkWidget*, GdkEventButton*, gpointer);
diff --git a/pan/gui/pan-ui.h b/pan/gui/pan-ui.h
index 47c7ab5..8c56d35 100644
--- a/pan/gui/pan-ui.h
+++ b/pan/gui/pan-ui.h
@@ -116,6 +116,8 @@ namespace pan
     virtual void do_match_only_my_articles (bool) = 0;
     virtual void do_show_matches (const Data::ShowType) = 0;
 
+    virtual void do_enable_toggle_rules (bool enable) = 0;
+
 #define MATCH_IGNORED         (1<<0)
 #define MATCH_LOW_SCORING     (1<<1)
 #define MATCH_NORMAL_SCORING  (1<<2)
diff --git a/pan/gui/pan.ui.h b/pan/gui/pan.ui.h
index b2f8479..b2da2b7 100644
--- a/pan/gui/pan.ui.h
+++ b/pan/gui/pan.ui.h
@@ -42,6 +42,8 @@ const char * fallback_ui_file =
 "      <menu action='view-header-pane-menu'>\n"
 "        <menuitem action='thread-headers' />\n"
 "        <separator />\n"
+"        <menuitem action='enable-rules' />\n"
+"        <separator />\n"
 "        <menuitem action='show-matching-articles' />\n"
 "        <menuitem action='show-matching-threads' />\n"
 "        <menuitem action='show-matching-subthreads' />\n"
diff --git a/pan/gui/prefs-ui.cc b/pan/gui/prefs-ui.cc
index 3144e34..cdeeb52 100644
--- a/pan/gui/prefs-ui.cc
+++ b/pan/gui/prefs-ui.cc
@@ -256,7 +256,8 @@ namespace
     // build the combo box...
     const std::string mode (prefs.get_string (mode_key, mode_fallback));
     GtkListStore * store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
-    const char* strings[6][2] = { { N_("Disabled"),"never" },
+    const char* strings[7][2] = { { N_("Disabled"),"never" },
+                                  { N_("Only new (Score == 0)"),"new" },
                                   { N_("9999 or more"), "watched" },
                                   { N_("5000 to 9998"), "high" },
                                   { N_("1 to 4999"),    "medium" },
@@ -586,12 +587,10 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
 
     gtk_widget_set_tooltip_text (t, _("This menu lets you configure Pan to take certain actions on your behalf automatically, based on a post's score."));
 
-    w = score_handler_new (prefs, "rules-delete-score-value", "never", b);
+    w = score_handler_new (prefs, "rules-delete-value", "never", b);
     HIG :: workarea_add_row (t, &row, _("_Delete Posts scoring at: "), w);
     w = score_handler_new (prefs, "rules-mark-read-value", "never", b);
     HIG :: workarea_add_row (t, &row, _("Mark Posts _read scoring at: "), w);
-    w = score_handler_new (prefs, "rules-mark-unread-value", "never", b);
-    HIG :: workarea_add_row (t, &row, _("Mark Posts _unread scoring at: "), w);
     w = score_handler_new (prefs, "rules-autocache-value", "never", b);
     HIG :: workarea_add_row (t, &row, _("_Cache Posts scoring at: "), w);
     w = score_handler_new (prefs, "rules-auto-dl-value", "never", b);
diff --git a/pan/gui/prefs.h b/pan/gui/prefs.h
index a4527d3..a3215a7 100644
--- a/pan/gui/prefs.h
+++ b/pan/gui/prefs.h
@@ -131,6 +131,7 @@ namespace pan
 
     public:
       bool _rules_changed;
+      bool _rules_enabled;
   };
 }
 
diff --git a/pan/gui/save-ui.cc b/pan/gui/save-ui.cc
index 339aa41..21a4cf3 100644
--- a/pan/gui/save-ui.cc
+++ b/pan/gui/save-ui.cc
@@ -141,7 +141,7 @@ SaveDialog :: response_cb (GtkDialog * dialog,
 
     std::string sep( self->_prefs.get_string("save-subj-seperator", "-") );
 
-    // make the tasks... 
+    // make the tasks...
     Queue::tasks_t tasks;
     foreach_const (std::vector<Article>, self->_articles, it)
     {
diff --git a/pan/tasks/task-article.h b/pan/tasks/task-article.h
index 37298a8..73befae 100644
--- a/pan/tasks/task-article.h
+++ b/pan/tasks/task-article.h
@@ -27,6 +27,7 @@
 #include <pan/general/worker-pool.h>
 #include <pan/data/article.h>
 #include <pan/data/article-cache.h>
+#include <pan/data/server-info.h>
 #include <pan/data/data.h>
 #include <pan/data/xref.h>
 #include <pan/tasks/nntp.h>
@@ -35,6 +36,7 @@
 namespace pan
 {
   struct Decoder;
+  class Data;
 
   /**
    * Task for downloading, and optionally decoding, articles
diff --git a/pan/tasks/task-xover.cc b/pan/tasks/task-xover.cc
index a027d89..46ce503 100644
--- a/pan/tasks/task-xover.cc
+++ b/pan/tasks/task-xover.cc
@@ -85,16 +85,6 @@ namespace
   }
 }
 
-namespace
-{
-  char* build_cachename (char* buf, size_t len, const char* name)
-  {
-    const char * home(file::get_pan_home().c_str());
-    g_snprintf(buf,len,"%s%c%s%c%s",home, G_DIR_SEPARATOR, "encode-cache", G_DIR_SEPARATOR, name);
-    return buf;
-  }
-}
-
 TaskXOver :: TaskXOver (Data         & data,
                         const Quark  & group,
                         Mode           mode,
diff --git a/pan/usenet-utils/filter-info.cc b/pan/usenet-utils/filter-info.cc
index 2e25835..f83b939 100644
--- a/pan/usenet-utils/filter-info.cc
+++ b/pan/usenet-utils/filter-info.cc
@@ -54,6 +54,7 @@ FilterInfo :: set_type_ge (Type type, unsigned long ge) {
   _type = type;
   _ge = ge;
 }
+
 void
 FilterInfo :: set_type_le (Type type, unsigned long le) {
   clear ();
diff --git a/pan/usenet-utils/filter-info.h b/pan/usenet-utils/filter-info.h
index 13e53ac..408b6ae 100644
--- a/pan/usenet-utils/filter-info.h
+++ b/pan/usenet-utils/filter-info.h
@@ -29,7 +29,7 @@ namespace pan
 {
   /**
    * Interface class describing a filter that can be applied to a set of articles.
-   * @ingroup usenet_utils 
+   * @ingroup usenet_utils
    */
   class FilterInfo
   {
diff --git a/pan/usenet-utils/rules-info.cc b/pan/usenet-utils/rules-info.cc
index e6d2ec2..bb3c2a3 100644
--- a/pan/usenet-utils/rules-info.cc
+++ b/pan/usenet-utils/rules-info.cc
@@ -17,6 +17,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <iostream>
+#include <pan/general/debug.h>
+#include <pan/tasks/queue.h>
+
 #include <config.h>
 extern "C" {
   #include <glib.h>
@@ -36,8 +40,9 @@ RulesInfo :: clear ()
 {
   _type = RulesInfo::TYPE_ERR;
   _aggregates.clear ();
+  _lb = _hb = 0;
+  _ge = 0;
   _negate = false;
-  _needs_body = false;
 }
 
 void
@@ -47,10 +52,26 @@ RulesInfo :: set_type_is (Type type) {
 }
 
 void
+RulesInfo :: set_type_ge (Type type, unsigned long ge) {
+  clear ();
+  _type = type;
+  _ge = ge;
+}
+
+void
 RulesInfo :: set_type_le (Type type, unsigned long le) {
   clear ();
   _type = type;
   _negate = true;
+  _ge = le+1;  // le N == !ge N+1
+}
+
+void
+RulesInfo :: set_type_bounds (Type type, int low, int high)
+{
+  clear ();
+  _type = type;
+  _lb = low; _hb = high;
 }
 
 void
@@ -70,8 +91,25 @@ RulesInfo :: set_type_aggregate_or () {
 
 
 void
-RulesInfo :: set_type_mark_read ()
+RulesInfo :: set_type_mark_read_b (int lb, int hb)
 {
-   set_type_is (MARK_READ);
+   set_type_bounds (MARK_READ, lb, hb);
 }
 
+void
+RulesInfo :: set_type_autocache_b (int lb, int hb)
+{
+   set_type_bounds (AUTOCACHE, lb, hb);
+}
+
+void
+RulesInfo :: set_type_dl_b  (int lb, int hb)
+{
+   set_type_bounds (AUTODOWNLOAD, lb, hb);
+}
+
+void
+RulesInfo :: set_type_delete_b  (int lb, int hb)
+{
+   set_type_bounds (DELETE, lb, hb);
+}
diff --git a/pan/usenet-utils/rules-info.h b/pan/usenet-utils/rules-info.h
index 3165c82..ebc71d8 100644
--- a/pan/usenet-utils/rules-info.h
+++ b/pan/usenet-utils/rules-info.h
@@ -41,7 +41,6 @@ namespace pan
         AGGREGATE_AND,
         AGGREGATE_OR,
         MARK_READ,
-        MARK_UNREAD,
         AUTOCACHE,
         AUTODOWNLOAD,
         DELETE
@@ -67,18 +66,25 @@ namespace pan
       /** When this is true, the results of the test should be negated. */
       bool _negate;
 
-      /** When this is true the test needs the article body. */
-      bool _needs_body;
-
     private:
       void set_type_is (Type type);
       void set_type_le (Type type, unsigned long le);
+      void set_type_ge (Type type, unsigned long ge);
+      void set_type_bounds (Type type, int low, int high);
+
 
     public:
+
+      unsigned long _ge;
+      int _lb, _hb;
+
       void clear ();
       void set_type_aggregate_and ();
       void set_type_aggregate_or ();
-      void set_type_mark_read ();
+      void set_type_mark_read_b (int lb, int hb);
+      void set_type_autocache_b (int lb, int hb);
+      void set_type_dl_b (int lb, int hb);
+      void set_type_delete_b (int lb, int hb);
   };
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]