#include "gtkutils.h"
#include "alertpanel.h"
#include "folder.h"
+#include "description_window.h"
#include "matcher_parser.h"
#include "colorlabel.h"
+/*!
+ *\brief UI data for matcher dialog
+ */
static struct Matcher {
GtkWidget *window;
GtkWidget *criteria_table;
- /* selected criteria in combobox */
- gint selected_criteria;
+ gint selected_criteria; /*!< selected criteria in combobox */
} matcher;
-/* choice in the list */
-
+/*!
+ *\brief Conditions with a negate counterpart (like unread and ~unread)
+ * have the same CRITERIA_XXX id). I.e. both unread and ~unread
+ * have criteria id CRITERIA_UNREAD. This id is passed as the
+ * first parameter to #matcherprop_new and #matcherprop_unquote_new.
+ *
+ *\warning Currently the enum constants should have the same order as the
+ * #criteria_text
+ */
enum {
CRITERIA_ALL = 0,
CRITERIA_SCORE_LOWER = 25,
CRITERIA_SCORE_EQUAL = 26,
- CRITERIA_EXECUTE = 27,
+ CRITERIA_TEST = 27,
CRITERIA_SIZE_GREATER = 28,
CRITERIA_SIZE_SMALLER = 29,
CRITERIA_SIZE_EQUAL = 30
};
+/*!
+ *\brief Descriptive text for conditions
+ */
+static const gchar *criteria_text [] = {
+ N_("All messages"), N_("Subject"),
+ N_("From"), N_("To"), N_("Cc"), N_("To or Cc"),
+ N_("Newsgroups"), N_("In reply to"), N_("References"),
+ N_("Age greater than"), N_("Age lower than"),
+ N_("Header"), N_("Headers part"),
+ N_("Body part"), N_("Whole message"),
+ N_("Unread flag"), N_("New flag"),
+ N_("Marked flag"), N_("Deleted flag"),
+ N_("Replied flag"), N_("Forwarded flag"),
+ N_("Locked flag"),
+ N_("Color label"),
+ N_("Ignore thread"),
+ N_("Score greater than"), N_("Score lower than"),
+ N_("Score equal to"),
+ N_("Execute"),
+ N_("Size greater than"),
+ N_("Size smaller than"),
+ N_("Size exactly")
+};
+
+/*!
+ *\brief Boolean / predicate constants
+ *
+ *\warning Same order as #bool_op_text!
+ */
enum {
BOOL_OP_OR = 0,
BOOL_OP_AND = 1
};
-static gchar *bool_op_text [] = {
+/*!
+ *\brief Descriptive text in UI
+ */
+static const gchar *bool_op_text [] = {
N_("or"), N_("and")
};
+/*!
+ *\brief Contains predicate
+ *
+ *\warning Same order as in #predicate_text
+ */
enum {
PREDICATE_CONTAINS = 0,
PREDICATE_DOES_NOT_CONTAIN = 1
};
-static gchar *predicate_text [] = {
+/*!
+ *\brief Descriptive text in UI for predicate
+ */
+static const gchar *predicate_text [] = {
N_("contains"), N_("does not contain")
};
+/*!
+ *\brief Enabled predicate
+ *
+ *\warning Same order as in #predicate_flag_text
+ */
enum {
PREDICATE_FLAG_ENABLED = 0,
PREDICATE_FLAG_DISABLED = 1
};
-static gchar *predicate_flag_text [] = {
+/*!
+ *\brief Descriptive text in UI for enabled flag
+ */
+static const gchar *predicate_flag_text [] = {
N_("yes"), N_("no")
};
-static gchar *criteria_text [] = {
- N_("All messages"), N_("Subject"),
- N_("From"), N_("To"), N_("Cc"), N_("To or Cc"),
- N_("Newsgroups"), N_("In reply to"), N_("References"),
- N_("Age greater than"), N_("Age lower than"),
- N_("Header"), N_("Headers part"),
- N_("Body part"), N_("Whole message"),
- N_("Unread flag"), N_("New flag"),
- N_("Marked flag"), N_("Deleted flag"),
- N_("Replied flag"), N_("Forwarded flag"),
- N_("Locked flag"),
- N_("Color label"),
- N_("Ignore thread"),
- N_("Score greater than"), N_("Score lower than"),
- N_("Score equal to"),
- N_("Execute"),
- N_("Size greater than"),
- N_("Size smaller than"),
- N_("Size exactly")
-};
-
-static PrefsMatcherSignal * matchers_callback;
+/*!
+ *\brief Hooks
+ */
+static PrefsMatcherSignal *matchers_callback;
/* widget creating functions */
static void prefs_matcher_create (void);
gint row,
gint column,
GdkEvent *event);
-static void prefs_matcher_key_pressed (GtkWidget *widget,
+static gboolean prefs_matcher_key_pressed(GtkWidget *widget,
GdkEventKey *event,
gpointer data);
static void prefs_matcher_ok (void);
static void prefs_matcher_criteria_select (GtkList *list,
GtkWidget *widget,
gpointer user_data);
-static MatcherList * prefs_matcher_get_list (void);
-static void prefs_matcher_exec_info_create (void);
+static MatcherList *prefs_matcher_get_list (void);
-static gint get_sel_from_list(GtkList * list)
+
+/*!
+ *\brief Find index of list selection
+ *
+ *\param list GTK list widget
+ *
+ *\return gint Selection index
+ */
+static gint get_sel_from_list(GtkList *list)
{
gint row = 0;
void * sel;
return row;
}
+/*!
+ *\brief Opens the matcher dialog with a list of conditions
+ *
+ *\param matchers List of conditions
+ *\param cb Callback
+ *
+ */
void prefs_matcher_open(MatcherList *matchers, PrefsMatcherSignal *cb)
{
inc_lock();
gtk_widget_show(matcher.window);
}
+/*!
+ *\brief Create the matcher dialog
+ */
static void prefs_matcher_create(void)
{
GtkWidget *window;
matcher.cond_clist = cond_clist;
}
+/*!
+ *\brief Set the contents of a row
+ *
+ *\param row Index of row to set
+ *\param prop Condition to set
+ *
+ *\return gint Row index \a prop has been added
+ */
static gint prefs_matcher_clist_set_row(gint row, MatcherProp *prop)
{
GtkCList *clist = GTK_CLIST(matcher.cond_clist);
return row;
}
+/*!
+ *\brief Clears a condition in the list widget
+ */
static void prefs_matcher_reset_condition(void)
{
gtk_list_select_item(GTK_LIST(matcher.criteria_list), 0);
gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), "");
}
+/*!
+ *\brief Update scrollbar
+ */
static void prefs_matcher_update_hscrollbar(void)
{
gint optwidth = gtk_clist_optimal_column_width(GTK_CLIST(matcher.cond_clist), 0);
gtk_clist_set_column_width(GTK_CLIST(matcher.cond_clist), 0, optwidth);
}
+/*!
+ *\brief Initializes dialog with a set of conditions
+ *
+ *\param matchers List of conditions
+ */
static void prefs_matcher_set_dialog(MatcherList *matchers)
{
GtkCList *clist = GTK_CLIST(matcher.cond_clist);
prefs_matcher_reset_condition();
}
+/*!
+ *\brief Converts current conditions in list box in
+ * a matcher list used by the matcher.
+ *
+ *\return MatcherList * List of conditions.
+ */
static MatcherList *prefs_matcher_get_list(void)
{
gchar *matcher_str;
return matchers;
}
+/*!
+ *\brief Maps a keyword id (see #get_matchparser_tab_id) to a
+ * criteria type (see first parameter of #matcherprop_new
+ * or #matcherprop_unquote_new)
+ *
+ *\param matching_id Id returned by the matcher parser.
+ *
+ *\return gint One of the CRITERIA_xxx constants.
+ */
static gint prefs_matcher_get_criteria_from_matching(gint matching_id)
{
switch(matching_id) {
return CRITERIA_SCORE_LOWER;
case MATCHCRITERIA_SCORE_EQUAL:
return CRITERIA_SCORE_EQUAL;
- case MATCHCRITERIA_NOT_EXECUTE:
- case MATCHCRITERIA_EXECUTE:
- return CRITERIA_EXECUTE;
+ case MATCHCRITERIA_NOT_TEST:
+ case MATCHCRITERIA_TEST:
+ return CRITERIA_TEST;
case MATCHCRITERIA_SIZE_GREATER:
return CRITERIA_SIZE_GREATER;
case MATCHCRITERIA_SIZE_SMALLER:
}
}
+/*!
+ *\brief Returns the matcher keyword id from a criteria id
+ *
+ *\param criteria_id Criteria id (should not be the negate
+ * one)
+ *
+ *\return gint A matcher keyword id. See #get_matchparser_tab_id.
+ */
static gint prefs_matcher_get_matching_from_criteria(gint criteria_id)
{
switch (criteria_id) {
return MATCHCRITERIA_BODY_PART;
case CRITERIA_MESSAGE:
return MATCHCRITERIA_MESSAGE;
- case CRITERIA_EXECUTE:
- return MATCHCRITERIA_EXECUTE;
+ case CRITERIA_TEST:
+ return MATCHCRITERIA_TEST;
case CRITERIA_SIZE_GREATER:
return MATCHCRITERIA_SIZE_GREATER;
case CRITERIA_SIZE_SMALLER:
}
}
+/*!
+ *\brief Returns the negate matcher keyword id from a matcher keyword
+ * id.
+ *
+ *\param matcher_criteria Matcher keyword id.
+ *
+ *\return gint A matcher keyword id. See #get_matchparser_tab_id.
+ */
static gint prefs_matcher_not_criteria(gint matcher_criteria)
{
switch(matcher_criteria) {
return MATCHCRITERIA_NOT_HEADERS_PART;
case MATCHCRITERIA_MESSAGE:
return MATCHCRITERIA_NOT_MESSAGE;
- case MATCHCRITERIA_EXECUTE:
- return MATCHCRITERIA_NOT_EXECUTE;
+ case MATCHCRITERIA_TEST:
+ return MATCHCRITERIA_NOT_TEST;
case MATCHCRITERIA_BODY_PART:
return MATCHCRITERIA_NOT_BODY_PART;
default:
}
}
+/*!
+ *\brief Converts the text in the selected row to a
+ * matcher structure
+ *
+ *\return MatcherProp * Newly allocated matcher structure.
+ */
static MatcherProp *prefs_matcher_dialog_to_matcher(void)
{
MatcherProp *matcherprop;
case CRITERIA_REPLIED:
case CRITERIA_FORWARDED:
case CRITERIA_LOCKED:
- case CRITERIA_EXECUTE:
+ case CRITERIA_TEST:
case CRITERIA_COLORLABEL:
case CRITERIA_IGNORE_THREAD:
if (value_pred_flag == PREDICATE_FLAG_DISABLED)
case CRITERIA_HEADERS_PART:
case CRITERIA_BODY_PART:
case CRITERIA_MESSAGE:
- case CRITERIA_EXECUTE:
+ case CRITERIA_TEST:
expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
break;
return matcherprop;
}
+/*!
+ *\brief Signal handler for register button
+ */
static void prefs_matcher_register_cb(void)
{
MatcherProp *matcherprop;
prefs_matcher_update_hscrollbar();
}
+/*!
+ *\brief Signal handler for substitute button
+ */
static void prefs_matcher_substitute_cb(void)
{
GtkCList *clist = GTK_CLIST(matcher.cond_clist);
gint row;
MatcherProp *matcherprop;
+ if (!clist->selection) return;
row = GPOINTER_TO_INT(clist->selection->data);
if (row == 0)
return;
prefs_matcher_update_hscrollbar();
}
+/*!
+ *\brief Signal handler for delete button
+ */
static void prefs_matcher_delete_cb(void)
{
GtkCList *clist = GTK_CLIST(matcher.cond_clist);
return;
gtk_clist_remove(clist, row);
-
+
+ prefs_matcher_reset_condition();
+
prefs_matcher_update_hscrollbar();
}
+/*!
+ *\brief Signal handler for 'move up' button
+ */
static void prefs_matcher_up(void)
{
GtkCList *clist = GTK_CLIST(matcher.cond_clist);
}
}
+/*!
+ *\brief Signal handler for 'move down' button
+ */
static void prefs_matcher_down(void)
{
GtkCList *clist = GTK_CLIST(matcher.cond_clist);
}
}
+/*!
+ *\brief Signal handler for select row.
+ *
+ *\param clist List widget
+ *\param row Selected row
+ *\param column Selected column
+ *\param event Event information
+ */
static void prefs_matcher_select(GtkCList *clist, gint row, gint column,
GdkEvent *event)
{
case MATCHCRITERIA_HEADERS_PART:
case MATCHCRITERIA_BODY_PART:
case MATCHCRITERIA_MESSAGE:
+ case MATCHCRITERIA_TEST:
gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), prop->expr);
break;
}
}
+/*!
+ *\brief Helper function that allows us to replace the 'Value' entry box
+ * by another widget.
+ *
+ *\param old_widget Widget that needs to be removed.
+ *\param new_widget Replacement widget
+ */
static void prefs_matcher_set_value_widget(GtkWidget *old_widget,
GtkWidget *new_widget)
{
- /* TODO: find out why the following spews harmless
- * "parent errors" */
+ /* TODO: find out why the following spews harmless "parent errors" */
+
+ /* NOTE: we first need to bump up the refcount of the old_widget,
+ * because the gtkut_container_remove() will otherwise destroy it */
gtk_widget_ref(old_widget);
gtkut_container_remove(GTK_CONTAINER(matcher.criteria_table), old_widget);
gtk_widget_show(new_widget);
0, 0, 0);
}
+/*!
+ *\brief Change widgets depending on the selected condition
+ *
+ *\param list List widget
+ *\param widget Not used
+ *\param user_data Not used
+ */
static void prefs_matcher_criteria_select(GtkList *list,
GtkWidget *widget,
gpointer user_data)
gtk_widget_set_sensitive(matcher.exec_btn, FALSE);
break;
- case CRITERIA_EXECUTE:
+ case CRITERIA_TEST:
gtk_widget_set_sensitive(matcher.header_combo, FALSE);
gtk_widget_set_sensitive(matcher.header_label, FALSE);
gtk_widget_set_sensitive(matcher.value_label, TRUE);
}
}
-static void prefs_matcher_key_pressed(GtkWidget *widget, GdkEventKey *event,
+/*!
+ *\brief Handle key press
+ *
+ *\param widget Widget receiving key press
+ *\param event Key event
+ *\param data User data
+ */
+static gboolean prefs_matcher_key_pressed(GtkWidget *widget, GdkEventKey *event,
gpointer data)
{
if (event && event->keyval == GDK_Escape)
prefs_matcher_cancel();
+ return TRUE;
}
+/*!
+ *\brief Cancel matcher dialog
+ */
static void prefs_matcher_cancel(void)
{
gtk_widget_hide(matcher.window);
inc_unlock();
}
+/*!
+ *\brief Accept current matchers
+ */
static void prefs_matcher_ok(void)
{
MatcherList *matchers;
MatcherProp *matcherprop;
AlertValue val;
- gint criteria;
- gint value_criteria;
gchar *matcher_str;
gchar *str;
gint row = 1;
if (strcmp(matcher_str, str) == 0) break;
row++;
}
+
if (strcmp(matcher_str, str) != 0) {
- val = alertpanel(_("Entry not saved"),
- _("The entry was not saved\nHave you really finished?"),
- _("Yes"), _("No"), NULL);
- if (G_ALERTDEFAULT != val) {
+ val = alertpanel(_("Entry not saved"),
+ _("The entry was not saved\nHave you really finished?"),
+ _("Yes"), _("No"), NULL);
+ if (G_ALERTDEFAULT != val) {
g_free(str);
- return;
- }
+ return;
+ }
}
}
}
}
}
+/*!
+ *\brief Called when closing dialog box
+ *
+ *\param widget Dialog widget
+ *\param event Event info
+ *\param data User data
+ *
+ *\return gint TRUE
+ */
static gint prefs_matcher_deleted(GtkWidget *widget, GdkEventAny *event,
gpointer data)
{
return TRUE;
}
-static GtkWidget *exec_info_win;
-
-void prefs_matcher_exec_info(void)
-{
- if (!exec_info_win)
- prefs_matcher_exec_info_create();
-
- gtk_widget_show(exec_info_win);
- gtk_main();
- gtk_widget_hide(exec_info_win);
-}
-
-static void prefs_matcher_exec_info_create(void)
-{
- GtkWidget *vbox;
- GtkWidget *hbox;
- GtkWidget *hbbox;
- GtkWidget *label;
- GtkWidget *ok_btn;
+/*
+ * Strings describing exec format strings
+ *
+ * When adding new lines, remember to put 2 strings for each line
+ */
+static gchar *exec_desc_strings[] = {
+ "%%", "%",
+ "%s", N_("Subject"),
+ "%f", N_("From"),
+ "%t", N_("To"),
+ "%c", N_("Cc"),
+ "%d", N_("Date"),
+ "%i", N_("Message-ID"),
+ "%n", N_("Newsgroups"),
+ "%r", N_("References"),
+ "%F", N_("Filename - should not be modified"),
+ "\\n", N_("new line"),
+ "\\", N_("escape character for quotes"),
+ "\\\"",N_("quote character"),
+ NULL, NULL
+};
- exec_info_win = gtk_window_new(GTK_WINDOW_DIALOG);
- gtk_window_set_title(GTK_WINDOW(exec_info_win),
- _("Description of symbols"));
- gtk_container_set_border_width(GTK_CONTAINER(exec_info_win), 8);
- gtk_window_set_position(GTK_WINDOW(exec_info_win), GTK_WIN_POS_CENTER);
- gtk_window_set_modal(GTK_WINDOW(exec_info_win), TRUE);
- gtk_window_set_policy(GTK_WINDOW(exec_info_win), FALSE, TRUE, FALSE);
-
- vbox = gtk_vbox_new(FALSE, 8);
- gtk_container_add(GTK_CONTAINER(exec_info_win), vbox);
-
- hbox = gtk_hbox_new(FALSE, 4);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
-
- label = gtk_label_new
- ("%%:\n"
- "%s:\n"
- "%f:\n"
- "%t:\n"
- "%c:\n"
- "%d:\n"
- "%i:\n"
- "%n:\n"
- "%r:\n"
- "%F:\n"
- "\\n:\n"
- "\\:\n"
- "\\\":\n"
- "%%:");
-
- gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
- gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
-
- label = gtk_label_new
- (_("%\n"
- "Subject\n"
- "From\n"
- "To\n"
- "Cc\n"
- "Date\n"
- "Message-ID\n"
- "Newsgroups\n"
- "References\n"
- "Filename - should not be modified\n"
- "new line\n"
- "escape character for quotes\n"
- "quote character\n"
- "%"));
-
- gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
- gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
-
- gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
- NULL, NULL, NULL, NULL);
- gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
+static DescriptionWindow exec_desc_win = {
+ NULL,
+ 2,
+ N_("Description of symbols"),
+ exec_desc_strings
+};
- gtk_widget_grab_default(ok_btn);
- gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
- GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
- gtk_signal_connect(GTK_OBJECT(exec_info_win), "delete_event",
- GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
- gtk_widget_show_all(vbox);
+/*!
+ *\brief Show Execute action's info
+ */
+void prefs_matcher_exec_info(void)
+{
+ description_window_create(&exec_desc_win);
}
+