[pan2: 132/268] fixed threading segfault
- From: Heinrich MÃller <henmull src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pan2: 132/268] fixed threading segfault
- Date: Mon, 2 Jan 2012 15:49:05 +0000 (UTC)
commit 11f3a9b5c15f51ca7255d892f721e3fd02f774ac
Author: Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
Date: Mon Jul 18 15:34:19 2011 +0200
fixed threading segfault
pan.cbp | 5 ++-
pan/data-impl/Makefile.am | 2 +
pan/data-impl/article-filter.h | 1 +
pan/data-impl/data-impl.h | 5 ++
pan/data-impl/my-tree.cc | 105 ++++++++++++++++++++++++++++++++++++++--
pan/data-impl/rules-filter.cc | 77 +++++++++++++++++++++++++++++
pan/data-impl/rules-filter.h | 50 +++++++++++++++++++
pan/data/data.h | 3 +
pan/gui/gui.cc | 69 ++++++++++++++++++++++++++
pan/gui/gui.h | 4 +-
pan/gui/header-pane.cc | 52 ++++++++++++++++++--
pan/gui/header-pane.h | 4 ++
pan/gui/prefs-ui.cc | 71 +++++++++++++++++++++++++++
pan/gui/prefs-ui.h | 4 +-
pan/gui/prefs.h | 5 ++-
pan/icons/icon_read_group.png | Bin 541 -> 1230 bytes
pan/tasks/task-upload.cc | 10 ++--
pan/usenet-utils/Makefile.am | 2 +
pan/usenet-utils/rules-info.cc | 77 +++++++++++++++++++++++++++++
pan/usenet-utils/rules-info.h | 85 ++++++++++++++++++++++++++++++++
20 files changed, 612 insertions(+), 19 deletions(-)
---
diff --git a/pan.cbp b/pan.cbp
index 4c546b9..5e43ecb 100644
--- a/pan.cbp
+++ b/pan.cbp
@@ -55,6 +55,8 @@
<Unit filename="pan/data-impl/my-tree.cc" />
<Unit filename="pan/data-impl/profiles.cc" />
<Unit filename="pan/data-impl/profiles.h" />
+ <Unit filename="pan/data-impl/rules-filter.cc" />
+ <Unit filename="pan/data-impl/rules-filter.h" />
<Unit filename="pan/data-impl/server.cc" />
<Unit filename="pan/data-impl/speed-test-load-group.cc" />
<Unit filename="pan/data-impl/task-archive.cc" />
@@ -255,8 +257,9 @@
<Unit filename="pan/usenet-utils/numbers-test.cc" />
<Unit filename="pan/usenet-utils/numbers.cc" />
<Unit filename="pan/usenet-utils/numbers.h" />
- <Unit filename="pan/usenet-utils/rng.cc" />
<Unit filename="pan/usenet-utils/rng.h" />
+ <Unit filename="pan/usenet-utils/rules-info.cc" />
+ <Unit filename="pan/usenet-utils/rules-info.h" />
<Unit filename="pan/usenet-utils/scorefile-test.cc" />
<Unit filename="pan/usenet-utils/scorefile.cc" />
<Unit filename="pan/usenet-utils/scorefile.h" />
diff --git a/pan/data-impl/Makefile.am b/pan/data-impl/Makefile.am
index ed09bd2..fbd513b 100644
--- a/pan/data-impl/Makefile.am
+++ b/pan/data-impl/Makefile.am
@@ -4,6 +4,7 @@ noinst_LIBRARIES = libpandata.a
libpandata_a_SOURCES = \
article-filter.cc \
+ rules-filter.cc \
data-io.cc \
data-impl.cc \
groups.cc \
@@ -16,6 +17,7 @@ libpandata_a_SOURCES = \
noinst_HEADERS = \
article-filter.h \
+ rules-filter.h \
data-impl.h \
data-io.h \
defgroup.h \
diff --git a/pan/data-impl/article-filter.h b/pan/data-impl/article-filter.h
index 9b6eec2..3a740ee 100644
--- a/pan/data-impl/article-filter.h
+++ b/pan/data-impl/article-filter.h
@@ -22,6 +22,7 @@
#include <pan/general/quark.h>
#include <pan/usenet-utils/filter-info.h>
+#include <pan/usenet-utils/rules-info.h>
#include <pan/usenet-utils/scorefile.h>
#include <pan/data/article.h>
#include <pan/data/data.h>
diff --git a/pan/data-impl/data-impl.h b/pan/data-impl/data-impl.h
index b5b1ad6..ab00f7d 100644
--- a/pan/data-impl/data-impl.h
+++ b/pan/data-impl/data-impl.h
@@ -40,6 +40,7 @@
#include <pan/tasks/queue.h>
#include <pan/data-impl/data-io.h>
#include <pan/data-impl/article-filter.h>
+#include <pan/data-impl/rules-filter.h>
#include <pan/data-impl/profiles.h>
#include <pan/data-impl/memchunk.h>
@@ -440,6 +441,7 @@ 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);
public:
void articles_changed (const quarks_t& mids, bool do_refilter);
@@ -452,6 +454,7 @@ namespace pan
nodes_t _nodes;
MemChunk<ArticleNode> _node_chunk;
FilterInfo _filter;
+ RulesInfo _rules;
Data::ShowType _show_type;
struct NodeMidCompare;
struct TwoNodes;
@@ -461,6 +464,7 @@ 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);
};
std::set<MyTree*> _trees;
@@ -621,6 +625,7 @@ namespace pan
public:
const ArticleFilter _article_filter;
+ const RulesFilter _rules_filter;
private:
guint newsrc_autosave_id;
diff --git a/pan/data-impl/my-tree.cc b/pan/data-impl/my-tree.cc
index fa0e3cc..ebe1caf 100644
--- a/pan/data-impl/my-tree.cc
+++ b/pan/data-impl/my-tree.cc
@@ -78,19 +78,28 @@ DataImpl :: MyTree :: get_article (const Quark& mid) const
}
size_t
-DataImpl :: MyTree :: size () const
+DataImpl :: MyTree :: size () const
{
return _nodes.size();
}
void
+DataImpl :: MyTree :: set_rules (const RulesInfo * criteria )
+{
+ if (criteria)
+ _rules = *criteria;
+ else
+ _rules.clear ();
+}
+
+void
DataImpl :: MyTree :: set_filter (const Data::ShowType show_type,
const FilterInfo * criteria)
{
// set the filter...
if (criteria)
_filter = *criteria;
- else
+ else
_filter.clear ();
_show_type = show_type;
@@ -122,6 +131,7 @@ DataImpl :: MyTree :: MyTree (DataImpl & data_impl,
_data.ref_group (_group);
_data._trees.insert (this);
set_filter (show_type, filter);
+ // set_rules (rules)
}
DataImpl :: MyTree :: ~MyTree ()
@@ -132,7 +142,7 @@ DataImpl :: MyTree :: ~MyTree ()
}
/****
-*****
+*****
****/
struct
@@ -154,6 +164,89 @@ DataImpl :: MyTree :: NodeMidCompare
{ return a->_mid < b; }
};
+void
+DataImpl :: MyTree :: apply_rules (const 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) {
+ if (!(*it)->_article)
+ continue;
+ else 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";
+
+ // maybe include threads or subthreads...
+ if (_show_type == Data::SHOW_THREADS)
+ {
+ foreach (const_nodes_v, pass, it) {
+ const ArticleNode *& n (*it);
+ while (n->_parent)
+ n = n->_parent;
+ }
+ std::sort (pass.begin(), pass.end(), compare);
+ pass.erase (std::unique (pass.begin(), pass.end()), pass.end());
+ //std::cerr << LINE_ID << " reduces to " << pass.size() << " threads\n";
+ }
+
+ if (_show_type == Data::SHOW_THREADS || _show_type == Data::SHOW_SUBTHREADS)
+ {
+ unique_nodes_t d;
+ foreach_const (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
+ }
+
+ // 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";
+ }
+
+
+ // 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);
+
+}
+
// candidates holds GroupHeader's ArticleNodes pointers
// candidates are sorted by Mid (see NodeMidCompare)
@@ -219,7 +312,7 @@ DataImpl :: MyTree :: apply_filter (const const_nodes_v& candidates)
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(),
@@ -227,7 +320,7 @@ DataImpl :: MyTree :: apply_filter (const const_nodes_v& candidates)
inserter (tmp, tmp.begin()), compare);
fail.swap (tmp);
//std::cerr << LINE_ID << ' ' << pass.size() << " of "
- // << (pass.size() + fail.size())
+ // << (pass.size() + fail.size())
// << " make it past the show-thread block\n";
}
@@ -331,6 +424,7 @@ DataImpl :: MyTree :: articles_changed (const quarks_t& mids, bool do_refilter)
const_nodes_v nodes;
_data.find_nodes (mids, _data.get_group_headers(_group)->_nodes, nodes);
apply_filter (nodes);
+ apply_rules (nodes);
}
// fire an update event for any of those mids in our tree...
@@ -350,6 +444,7 @@ 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);
}
diff --git a/pan/data-impl/rules-filter.cc b/pan/data-impl/rules-filter.cc
new file mode 100644
index 0000000..05ca5c2
--- /dev/null
+++ b/pan/data-impl/rules-filter.cc
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 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 <cassert>
+#include <pan/general/debug.h>
+#include <pan/general/macros.h>
+#include <pan/data/data.h>
+#include <gmime/gmime.h>
+#include <glib/gprintf.h>
+#include "rules-filter.h"
+
+using namespace pan;
+
+bool
+RulesFilter :: test_article (const Data & data,
+ const RulesInfo & rules,
+ const Quark & group,
+ const Article & article) const
+{
+ bool pass (false);
+ const ArticleCache& cache(data.get_cache());
+
+ 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;
+ }
+ }
+ break;
+
+ case RulesInfo::AGGREGATE_OR:
+ if (rules._aggregates.empty())
+ 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;
+ }
+ }
+ }
+ break;
+
+ case RulesInfo::MARK_READ:
+ pass = article.score == Article::COMPLETE;
+ break;
+ }
+
+ return pass;
+}
+
diff --git a/pan/data-impl/rules-filter.h b/pan/data-impl/rules-filter.h
new file mode 100644
index 0000000..c0f4b40
--- /dev/null
+++ b/pan/data-impl/rules-filter.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 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
+ */
+
+#ifndef __RulesFilter_h__
+#define __RulesFilter_h__
+
+#include <pan/general/quark.h>
+#include <pan/usenet-utils/filter-info.h>
+#include <pan/usenet-utils/rules-info.h>
+#include <pan/usenet-utils/scorefile.h>
+#include <pan/data/article.h>
+#include <pan/data/data.h>
+
+namespace pan
+{
+ /**
+ * @ingroup data_impl
+ */
+ class RulesFilter
+ {
+
+ public:
+
+ RulesFilter() { }
+
+ bool test_article (const Data& data,
+ const RulesInfo & rules,
+ const Quark& group,
+ const Article& article) const;
+
+ };
+}
+
+#endif
diff --git a/pan/data/data.h b/pan/data/data.h
index 28c16e1..e2db9be 100644
--- a/pan/data/data.h
+++ b/pan/data/data.h
@@ -37,6 +37,7 @@
namespace pan
{
class FilterInfo;
+ class RulesInfo;
/**
* Data Interface class for seeing the mapping between groups and servers.
@@ -468,6 +469,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;
};
/**
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index cc22eb3..fb1aa0a 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -904,6 +904,7 @@ void GUI :: do_select_article_body ()
void GUI :: do_show_preferences_dialog ()
{
PrefsDialog * dialog = new PrefsDialog (_prefs, get_window(_root));
+ g_signal_connect (dialog->root(), "destroy", G_CALLBACK(prefs_dialog_destroyed_cb), this);
gtk_widget_show (dialog->root());
}
void GUI :: do_show_group_preferences_dialog ()
@@ -1066,6 +1067,74 @@ void GUI :: server_list_dialog_destroyed (GtkWidget *)
}
}
+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 *)
+{
+
+ const Quark& group (_header_pane->get_group());
+ if (!group.empty() && _prefs._rules_changed)
+ {
+ _prefs._rules_changed = !_prefs._rules_changed;
+ std::string text;
+ int no(0);
+ _header_pane->rules(no);
+ }
+// // 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
+// }
+// }
+}
+
+
void GUI :: do_show_servers_dialog ()
{
GtkWidget * w = server_list_dialog_new (_data, _queue, get_window(_root));
diff --git a/pan/gui/gui.h b/pan/gui/gui.h
index 5470a09..542aa13 100644
--- a/pan/gui/gui.h
+++ b/pan/gui/gui.h
@@ -244,7 +244,9 @@ namespace pan
static void add_widget (GtkUIManager*, GtkWidget*, gpointer);
static void server_list_dialog_destroyed_cb (GtkWidget*, gpointer);
void server_list_dialog_destroyed (GtkWidget*);
-
+ static void prefs_dialog_destroyed_cb (GtkWidget * w, gpointer self);
+ void prefs_dialog_destroyed (GtkWidget* w);
+ int score_int_from_string(std::string val, const char* rules[]);
};
}
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index 6f2b330..3e54483 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -131,7 +131,7 @@ namespace
const Quark & message_id)
{
int offset (ICON_EMPTY);
-
+
if (queue.contains (message_id))
offset = ICON_QUEUED;
else if (cache.contains (message_id))
@@ -319,7 +319,7 @@ HeaderPane :: create_row (const EvolutionDateMaker & e,
std::pair<mid_to_row_t::iterator,bool> result (_mid_to_row.insert (row));
g_assert (result.second);
-
+
return row;
}
@@ -684,7 +684,7 @@ HeaderPane :: on_tree_change (const Data::ArticleTree::Diffs& diffs)
}
_tree_store->insert_sorted (tmp);
}
-
+
// reparent...
if (do_thread && !diffs.reparented.empty()) {
PanTreeStore::parent_to_children_t tmp;
@@ -916,7 +916,7 @@ HeaderPane :: on_button_pressed (GtkWidget * treeview, GdkEventButton *event, gp
GtkTreeSelection * selection = gtk_tree_view_get_selection(tv);
GtkTreePath *path;
if (gtk_tree_view_get_path_at_pos (tv,
- (gint) event->x,
+ (gint) event->x,
(gint) event->y,
&path, NULL, NULL, NULL))
{
@@ -1024,6 +1024,34 @@ namespace
AUTHOR,
MESSAGE_ID
};
+
+ enum
+ {
+ RULES_MARK_READ,
+ RULES_MARK_UNREAD,
+ RULES_AUTOCACHE,
+ RULES_AUTODL,
+ RULES_DELETE
+ };
+}
+
+void
+HeaderPane :: rebuild_rules (int mode)
+{
+
+ RulesInfo &f (_rules);
+ f.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);
+// }
+
}
void
@@ -1036,6 +1064,7 @@ HeaderPane :: rebuild_filter (const std::string& text, int mode)
d.text = text;
FilterInfo &f (_filter);
+
f.set_type_aggregate_and ();
// entry field filter...
@@ -1174,6 +1203,19 @@ HeaderPane :: filter (const std::string& text, int mode)
}
}
+void
+HeaderPane :: rules(int mode)
+{
+ if (_prefs.get_string("rules-mark-read-value","never") != "never")
+ rebuild_rules(RULES_MARK_READ);
+
+ if (_rules._aggregates.empty())
+ _atree->set_rules();
+ else
+ _atree->set_rules(&_rules);
+
+}
+
namespace
{
// the text typed by the user.
@@ -1869,7 +1911,7 @@ namespace
}
/**
-***
+***
**/
void
diff --git a/pan/gui/header-pane.h b/pan/gui/header-pane.h
index 70de04c..532226d 100644
--- a/pan/gui/header-pane.h
+++ b/pan/gui/header-pane.h
@@ -26,6 +26,7 @@
#include <pan/data/article-cache.h>
#include <pan/data/data.h>
#include <pan/usenet-utils/filter-info.h>
+#include <pan/usenet-utils/rules-info.h>
#include <pan/usenet-utils/gnksa.h>
#include <pan/tasks/queue.h>
#include <pan/gui/action-manager.h>
@@ -297,15 +298,18 @@ namespace pan
GtkWidget * _tree_view;
PanTreeStore * _tree_store;
FilterInfo _filter;
+ RulesInfo _rules;
Data::ShowType _show_type;
guint _selection_changed_idle_tag;
private:
void rebuild_filter (const std::string&, int);
+ void rebuild_rules (int mode);
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);
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/prefs-ui.cc b/pan/gui/prefs-ui.cc
index d9fbc2c..3144e34 100644
--- a/pan/gui/prefs-ui.cc
+++ b/pan/gui/prefs-ui.cc
@@ -96,6 +96,7 @@ namespace
Prefs *prefs = static_cast<Prefs*>(data);
prefs->set_int(key, gtk_spin_button_get_value_as_int(spin));
}
+
GtkWidget* new_spin_button (const char *key, int low, int high, Prefs &prefs)
{
guint tm = prefs.get_int(key, 5 );
@@ -177,6 +178,7 @@ namespace
{
Prefs * prefs (static_cast<Prefs*>(user_data));
const char * key = (const char*) g_object_get_data (G_OBJECT(c), PREFS_KEY);
+ prefs->_rules_changed = strcmp(key,"rules-");
const int column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(c), "column"));
const int row (gtk_combo_box_get_active (c));
GtkTreeModel * m = gtk_combo_box_get_model (c);
@@ -212,6 +214,7 @@ namespace
if (mode == strings[i][1])
sel_index = i;
}
+
GtkWidget * c = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
GtkCellRenderer * renderer (gtk_cell_renderer_text_new ());
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (c), renderer, true);
@@ -239,6 +242,48 @@ namespace
return h;
}
+/*
+ Scores:
+ "Scores of 9999 or more:"
+ "Scores from 5000 to 9998:"
+ "Scores from 1 to 4999:"
+ "Scores from -9998 to -1:" */
+ GtkWidget* score_handler_new (Prefs& prefs,
+ const char * mode_key,
+ const char * mode_fallback,
+ GtkWidget *& setme_mnemonic_target)
+ {
+ // 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" },
+ { N_("9999 or more"), "watched" },
+ { N_("5000 to 9998"), "high" },
+ { N_("1 to 4999"), "medium" },
+ { N_("-9998 to -1"), "low" },
+ { N_("-9999 or less"),"ignored" }};
+ int sel_index (0);
+ for (size_t i=0; i<G_N_ELEMENTS(strings); ++i) {
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _(strings[i][0]), 1, strings[i][1], -1);
+ if (mode == strings[i][1])
+ sel_index = i;
+ }
+
+ GtkWidget * c = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
+ GtkCellRenderer * renderer (gtk_cell_renderer_text_new ());
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (c), renderer, true);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (c), renderer, "text", 0, NULL);
+ gtk_combo_box_set_active (GTK_COMBO_BOX(c), sel_index);
+ g_object_set_data_full (G_OBJECT(c), PREFS_KEY, g_strdup(mode_key), g_free);
+ g_object_set_data (G_OBJECT(c), "column", GINT_TO_POINTER(1));
+ g_signal_connect (c, "changed", G_CALLBACK(set_prefs_string_from_combobox), &prefs);
+
+ setme_mnemonic_target = c;
+ return c;
+ }
+
void font_set_cb (GtkFontButton* b, gpointer prefs_gpointer)
{
const char * key = (const char*) g_object_get_data (G_OBJECT(b), PREFS_KEY);
@@ -442,6 +487,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
g_signal_connect_swapped (dialog, "destroy", G_CALLBACK(delete_prefs_dialog), this);
GtkWidget * notebook = gtk_notebook_new ();
+ // Behaviour
int row (0);
GtkWidget *h, *w, *l, *b, *t;
t = HIG :: workarea_create ();
@@ -489,6 +535,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
HIG :: workarea_finish (t, &row);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("_Behavior")));
+ // Layout
row = 0;
t = HIG :: workarea_create ();
HIG :: workarea_add_section_title (t, &row, _("Pane Layout"));
@@ -525,6 +572,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
HIG :: workarea_finish (t, &row);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("_Layout")));
+ // Headers
row = 0;
t = HIG :: workarea_create ();
HIG :: workarea_add_section_title (t, &row, _("Header Pane Columns"));
@@ -535,6 +583,26 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
row = 0;
t = HIG :: workarea_create ();
+
+ 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);
+ 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);
+ HIG :: workarea_add_row (t, &row, _("Download _attachments of Posts scoring at: "), w);
+
+ HIG :: workarea_finish (t, &row);
+ gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("_Actions")));
+
+ // Fonts
+ row = 0;
+ t = HIG :: workarea_create ();
HIG :: workarea_add_section_title (t, &row, _("Fonts"));
HIG :: workarea_add_section_spacer (t, row, 4);
l = new_check_button (_("Use custom font in Group Pane:"), "group-pane-font-enabled", false, prefs);
@@ -558,6 +626,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
HIG :: workarea_finish (t, &row);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("_Fonts")));
+ // Colors
row = 0;
t = HIG :: workarea_create ();
HIG :: workarea_add_section_title (t, &row, _("Header Pane"));
@@ -605,6 +674,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
HIG :: workarea_finish (t, &row);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("_Colors")));
+ // Applications
row = 0;
t = HIG :: workarea_create ();
HIG :: workarea_add_section_title (t, &row, _("Preferred Applications"));
@@ -620,6 +690,7 @@ PrefsDialog :: PrefsDialog (Prefs& prefs, GtkWindow* parent):
HIG :: workarea_finish (t, &row);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook), t, gtk_label_new_with_mnemonic(_("A_pplications")));
+ // Upload Options
row = 0;
t = HIG :: workarea_create ();
HIG :: workarea_add_section_title (t, &row, _("Encoding Options"));
diff --git a/pan/gui/prefs-ui.h b/pan/gui/prefs-ui.h
index ad32711..449e113 100644
--- a/pan/gui/prefs-ui.h
+++ b/pan/gui/prefs-ui.h
@@ -28,8 +28,8 @@ namespace pan
class PrefsDialog
{
public:
- PrefsDialog (Prefs&, GtkWindow*);
- ~PrefsDialog () {}
+ PrefsDialog (Prefs&, GtkWindow*) ;
+ ~PrefsDialog () { }
GtkWidget* root() { return _root; }
private:
diff --git a/pan/gui/prefs.h b/pan/gui/prefs.h
index 0969fca..a4527d3 100644
--- a/pan/gui/prefs.h
+++ b/pan/gui/prefs.h
@@ -101,7 +101,7 @@ namespace pan
bool get_geometry (const StringView&, int&, int&, int&, int&) const;
public:
- Prefs () {}
+ Prefs () { _rules_changed = false; }
virtual void save () const {}
virtual ~Prefs () {}
@@ -128,6 +128,9 @@ namespace pan
mutable colors_t _colors;
typedef std::map<std::string,int> ints_t;
mutable ints_t _ints;
+
+ public:
+ bool _rules_changed;
};
}
diff --git a/pan/icons/icon_read_group.png b/pan/icons/icon_read_group.png
index afe2b09..32e7035 100644
Binary files a/pan/icons/icon_read_group.png and b/pan/icons/icon_read_group.png differ
diff --git a/pan/tasks/task-upload.cc b/pan/tasks/task-upload.cc
index 6d16951..dc2d927 100644
--- a/pan/tasks/task-upload.cc
+++ b/pan/tasks/task-upload.cc
@@ -162,7 +162,7 @@ TaskUpload :: update_work (NNTP* checkin_pending)
{
_state.set_working();
}
- else if ((_encoder_has_run && !_needed.empty()))
+ else if (_encoder_has_run && !_needed.empty())
{
_state.set_need_nntp(_server);
}
@@ -264,6 +264,7 @@ TaskUpload :: on_nntp_done (NNTP * nntp,
tmp.date = time(NULL);
tmp.is_child = true;
bool found(false);
+ bool post_ok(false);
needed_t::iterator it;
for (it=_needed.begin(); it!=_needed.end(); ++it)
@@ -274,13 +275,14 @@ TaskUpload :: on_nntp_done (NNTP * nntp,
if (!found) return;
- bool post_ok(false);
+ if (_queue_pos == -1) { _needed.erase(it); goto _end; }
+
switch (health)
{
case OK:
std::cerr<<"OK "<<_queue_pos<<std::endl;
-// increment_step(it->second.bytes);
-// _needed.erase (it);
+ increment_step(it->second.bytes);
+ _needed.erase (it);
post_ok = true;
break;
case ERR_NETWORK:
diff --git a/pan/usenet-utils/Makefile.am b/pan/usenet-utils/Makefile.am
index 73e833a..081e894 100644
--- a/pan/usenet-utils/Makefile.am
+++ b/pan/usenet-utils/Makefile.am
@@ -4,6 +4,7 @@ noinst_LIBRARIES = libusenetutils.a
libusenetutils_a_SOURCES = \
filter-info.cc \
+ rules-info.cc \
gnksa.cc \
message-check.cc \
mime-utils.cc \
@@ -15,6 +16,7 @@ libusenetutils_a_SOURCES = \
noinst_HEADERS = \
defgroup.h \
filter-info.h \
+ rules-info.h \
gnksa.h \
message-check.h \
mime-utils.h \
diff --git a/pan/usenet-utils/rules-info.cc b/pan/usenet-utils/rules-info.cc
new file mode 100644
index 0000000..e6d2ec2
--- /dev/null
+++ b/pan/usenet-utils/rules-info.cc
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 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>
+extern "C" {
+ #include <glib.h>
+ #include <glib/gi18n.h>
+}
+#include <pan/general/macros.h>
+#include "rules-info.h"
+
+using namespace pan;
+
+/***
+****
+***/
+
+void
+RulesInfo :: clear ()
+{
+ _type = RulesInfo::TYPE_ERR;
+ _aggregates.clear ();
+ _negate = false;
+ _needs_body = false;
+}
+
+void
+RulesInfo :: set_type_is (Type type) {
+ clear ();
+ _type = type;
+}
+
+void
+RulesInfo :: set_type_le (Type type, unsigned long le) {
+ clear ();
+ _type = type;
+ _negate = true;
+}
+
+void
+RulesInfo :: set_type_aggregate_and () {
+ clear ();
+ _type = AGGREGATE_AND;
+}
+void
+RulesInfo :: set_type_aggregate_or () {
+ clear ();
+ _type = AGGREGATE_OR;
+}
+
+/****
+*****
+****/
+
+
+void
+RulesInfo :: set_type_mark_read ()
+{
+ set_type_is (MARK_READ);
+}
+
diff --git a/pan/usenet-utils/rules-info.h b/pan/usenet-utils/rules-info.h
new file mode 100644
index 0000000..3165c82
--- /dev/null
+++ b/pan/usenet-utils/rules-info.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006 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
+ */
+
+#ifndef __Rules_Info_h__
+#define __Rules_Info_h__
+
+#include <deque>
+#include <pan/general/quark.h>
+#include <pan/general/string-view.h>
+#include <pan/general/text-match.h>
+
+namespace pan
+{
+ /**
+ * Interface class describing a filter that can be applied to a set of articles.
+ * @ingroup usenet_utils
+ */
+ class RulesInfo
+ {
+ public:
+
+ /** The different type of filters we support. */
+ enum Type {
+ TYPE_ERR,
+ AGGREGATE_AND,
+ AGGREGATE_OR,
+ MARK_READ,
+ MARK_UNREAD,
+ AUTOCACHE,
+ AUTODOWNLOAD,
+ DELETE
+ };
+
+ public:
+ bool empty() const { return _type == TYPE_ERR; }
+ RulesInfo () { clear(); }
+ virtual ~RulesInfo () { }
+
+ public:
+
+ /** Defines what type of filter this is. */
+ Type _type;
+
+ /** Convenience typedef. */
+ typedef std::deque<RulesInfo> aggregates_t;
+
+ /** When `_type' is AGGREGATE_OR or AGGREGATE_AND,
+ these are the filters being or'ed or and'ed together. */
+ aggregates_t _aggregates;
+
+ /** 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);
+
+ public:
+ void clear ();
+ void set_type_aggregate_and ();
+ void set_type_aggregate_or ();
+ void set_type_mark_read ();
+ };
+}
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]