+2005-08-05 [colin] 1.9.13cvs16
+
+ * src/Makefile.am
+ * src/prefs_folder_column.c
+ * src/prefs_folder_column.h
+ Add prefs for folder columns
+ * src/folderview.c
+ * src/folderview.h
+ * src/mainwindow.c
+ * src/mainwindow.h
+ * src/prefs_common.c
+ * src/prefs_common.h
+ * src/prefs_summaries.c
+ Use them
+ * src/prefs_summary_column.c
+ * src/summaryview.c
+ * src/summaryview.h
+ Add a To column
+ * src/textview.c
+ * src/common/utils.c
+ * src/common/utils.h
+ Move uri colourisation functions
+ to utils
+ * src/compose.c
+ Colourise URIs
+ * src/imap.c
+ Fix bug with LIST where we'd try
+ to get Folder//////[...]///
+
2005-08-05 [paul] 1.9.13cvs15
* src/prefs_summaries.c
( cvs diff -u -r 1.382.2.145 -r 1.382.2.146 src/compose.c; cvs diff -u -r 1.207.2.50 -r 1.207.2.51 src/folderview.c; cvs diff -u -r 1.94.2.58 -r 1.94.2.59 src/messageview.c; cvs diff -u -r 1.101.2.11 -r 1.101.2.12 src/news.c; cvs diff -u -r 1.2.2.7 -r 1.2.2.8 src/news_gtk.c; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/news_gtk.h; cvs diff -u -r 1.1.2.19 -r 1.1.2.20 src/gtk/quicksearch.c; ) > 1.9.13cvs13.patchset
( cvs diff -u -r 1.204.2.47 -r 1.204.2.48 src/prefs_common.c; cvs diff -u -r 1.103.2.21 -r 1.103.2.22 src/prefs_common.h; cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/prefs_summaries.c; cvs diff -u -r 1.395.2.100 -r 1.395.2.101 src/summaryview.c; ) > 1.9.13cvs14.patchset
( cvs diff -u -r 1.1.2.7 -r 1.1.2.8 src/prefs_summaries.c; cvs diff -u -r 1.395.2.101 -r 1.395.2.102 src/summaryview.c; ) > 1.9.13cvs15.patchset
+( cvs diff -u -r 1.155.2.29 -r 1.155.2.30 src/Makefile.am; cvs diff -u -r 1.382.2.146 -r 1.382.2.147 src/compose.c; cvs diff -u -r 1.207.2.51 -r 1.207.2.52 src/folderview.c; cvs diff -u -r 1.20.2.5 -r 1.20.2.6 src/folderview.h; cvs diff -u -r 1.179.2.56 -r 1.179.2.57 src/imap.c; cvs diff -u -r 1.274.2.48 -r 1.274.2.49 src/mainwindow.c; cvs diff -u -r 1.39.2.3 -r 1.39.2.4 src/mainwindow.h; cvs diff -u -r 1.204.2.48 -r 1.204.2.49 src/prefs_common.c; cvs diff -u -r 1.103.2.22 -r 1.103.2.23 src/prefs_common.h; diff -u /dev/null src/prefs_folder_column.c; diff -u /dev/null src/prefs_folder_column.h; cvs diff -u -r 1.1.2.8 -r 1.1.2.9 src/prefs_summaries.c; cvs diff -u -r 1.10.2.8 -r 1.10.2.9 src/prefs_summary_column.c; cvs diff -u -r 1.395.2.102 -r 1.395.2.103 src/summaryview.c; cvs diff -u -r 1.68.2.10 -r 1.68.2.11 src/summaryview.h; cvs diff -u -r 1.96.2.68 -r 1.96.2.69 src/textview.c; cvs diff -u -r 1.36.2.38 -r 1.36.2.39 src/common/utils.c; cvs diff -u -r 1.20.2.20 -r 1.20.2.21 src/common/utils.h; ) > 1.9.13cvs16.patchset
MICRO_VERSION=13
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=15
+EXTRA_VERSION=16
EXTRA_RELEASE=
EXTRA_GTK2_VERSION=
prefs_spelling.c \
prefs_summaries.c \
prefs_summary_column.c \
+ prefs_folder_column.c \
prefs_template.c \
prefs_themes.c \
prefs_toolbar.c \
prefs_spelling.h \
prefs_summaries.h \
prefs_summary_column.h \
+ prefs_folder_column.h \
prefs_template.h \
prefs_themes.h \
prefs_toolbar.h \
*strstr(str, "\r") = ' ';
}
}
+
+/* get_uri_part() - retrieves a URI starting from scanpos.
+ Returns TRUE if succesful */
+gboolean get_uri_part(const gchar *start, const gchar *scanpos,
+ const gchar **bp, const gchar **ep)
+{
+ const gchar *ep_;
+
+ g_return_val_if_fail(start != NULL, FALSE);
+ g_return_val_if_fail(scanpos != NULL, FALSE);
+ g_return_val_if_fail(bp != NULL, FALSE);
+ g_return_val_if_fail(ep != NULL, FALSE);
+
+ *bp = scanpos;
+
+ /* find end point of URI */
+ for (ep_ = scanpos; *ep_ != '\0'; ep_++) {
+ if (!isgraph(*(const guchar *)ep_) ||
+ !IS_ASCII(*(const guchar *)ep_) ||
+ strchr("[]{}()<>\"", *ep_))
+ break;
+ }
+
+ /* no punctuation at end of string */
+
+ /* FIXME: this stripping of trailing punctuations may bite with other URIs.
+ * should pass some URI type to this function and decide on that whether
+ * to perform punctuation stripping */
+
+#define IS_REAL_PUNCT(ch) (ispunct(ch) && ((ch) != '/'))
+
+ for (; ep_ - 1 > scanpos + 1 &&
+ IS_REAL_PUNCT(*(const guchar *)(ep_ - 1));
+ ep_--)
+ ;
+
+#undef IS_REAL_PUNCT
+
+ *ep = ep_;
+
+ return TRUE;
+}
+
+gchar *make_uri_string(const gchar *bp, const gchar *ep)
+{
+ return g_strndup(bp, ep - bp);
+}
+
+/* valid mail address characters */
+#define IS_RFC822_CHAR(ch) \
+ (IS_ASCII(ch) && \
+ (ch) > 32 && \
+ (ch) != 127 && \
+ !g_ascii_isspace(ch) && \
+ !strchr("(),;<>\"", (ch)))
+
+/* alphabet and number within 7bit ASCII */
+#define IS_ASCII_ALNUM(ch) (IS_ASCII(ch) && g_ascii_isalnum(ch))
+#define IS_QUOTE(ch) ((ch) == '\'' || (ch) == '"')
+
+static GHashTable *create_domain_tab(void)
+{
+ static const gchar *toplvl_domains [] = {
+ "museum", "aero",
+ "arpa", "coop", "info", "name", "biz", "com", "edu", "gov",
+ "int", "mil", "net", "org", "ac", "ad", "ae", "af", "ag",
+ "ai", "al", "am", "an", "ao", "aq", "ar", "as", "at", "au",
+ "aw", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi",
+ "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by",
+ "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl",
+ "cm", "cn", "co", "cr", "cu", "cv", "cx", "cy", "cz", "de",
+ "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er",
+ "es", "et", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gd",
+ "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq",
+ "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr",
+ "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir",
+ "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki",
+ "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc",
+ "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc",
+ "md", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq",
+ "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na",
+ "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu",
+ "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm",
+ "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "ru",
+ "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sj",
+ "sk", "sl", "sm", "sn", "so", "sr", "st", "sv", "sy", "sz",
+ "tc", "td", "tf", "tg", "th", "tj", "tk", "tm", "tn", "to",
+ "tp", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um",
+ "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu",
+ "wf", "ws", "ye", "yt", "yu", "za", "zm", "zw"
+ };
+ gint n;
+ GHashTable *htab = g_hash_table_new(g_stricase_hash, g_stricase_equal);
+
+ g_return_val_if_fail(htab, NULL);
+ for (n = 0; n < sizeof toplvl_domains / sizeof toplvl_domains[0]; n++)
+ g_hash_table_insert(htab, (gpointer) toplvl_domains[n], (gpointer) toplvl_domains[n]);
+ return htab;
+}
+
+static gboolean is_toplvl_domain(GHashTable *tab, const gchar *first, const gchar *last)
+{
+ const gint MAX_LVL_DOM_NAME_LEN = 6;
+ gchar buf[MAX_LVL_DOM_NAME_LEN + 1];
+ const gchar *m = buf + MAX_LVL_DOM_NAME_LEN + 1;
+ register gchar *p;
+
+ if (last - first > MAX_LVL_DOM_NAME_LEN || first > last)
+ return FALSE;
+
+ for (p = buf; p < m && first < last; *p++ = *first++)
+ ;
+ *p = 0;
+
+ return g_hash_table_lookup(tab, buf) != NULL;
+}
+
+/* get_email_part() - retrieves an email address. Returns TRUE if succesful */
+gboolean get_email_part(const gchar *start, const gchar *scanpos,
+ const gchar **bp, const gchar **ep)
+{
+ /* more complex than the uri part because we need to scan back and forward starting from
+ * the scan position. */
+ gboolean result = FALSE;
+ const gchar *bp_ = NULL;
+ const gchar *ep_ = NULL;
+ static GHashTable *dom_tab;
+ const gchar *last_dot = NULL;
+ const gchar *prelast_dot = NULL;
+ const gchar *last_tld_char = NULL;
+
+ /* the informative part of the email address (describing the name
+ * of the email address owner) may contain quoted parts. the
+ * closure stack stores the last encountered quotes. */
+ gchar closure_stack[128];
+ gchar *ptr = closure_stack;
+
+ g_return_val_if_fail(start != NULL, FALSE);
+ g_return_val_if_fail(scanpos != NULL, FALSE);
+ g_return_val_if_fail(bp != NULL, FALSE);
+ g_return_val_if_fail(ep != NULL, FALSE);
+
+ if (!dom_tab)
+ dom_tab = create_domain_tab();
+ g_return_val_if_fail(dom_tab, FALSE);
+
+ /* scan start of address */
+ for (bp_ = scanpos - 1;
+ bp_ >= start && IS_RFC822_CHAR(*(const guchar *)bp_); bp_--)
+ ;
+
+ /* TODO: should start with an alnum? */
+ bp_++;
+ for (; bp_ < scanpos && !IS_ASCII_ALNUM(*(const guchar *)bp_); bp_++)
+ ;
+
+ if (bp_ != scanpos) {
+ /* scan end of address */
+ for (ep_ = scanpos + 1;
+ *ep_ && IS_RFC822_CHAR(*(const guchar *)ep_); ep_++)
+ if (*ep_ == '.') {
+ prelast_dot = last_dot;
+ last_dot = ep_;
+ if (*(last_dot + 1) == '.') {
+ if (prelast_dot == NULL)
+ return FALSE;
+ last_dot = prelast_dot;
+ break;
+ }
+ }
+
+ /* TODO: really should terminate with an alnum? */
+ for (; ep_ > scanpos && !IS_ASCII_ALNUM(*(const guchar *)ep_);
+ --ep_)
+ ;
+ ep_++;
+
+ if (last_dot == NULL)
+ return FALSE;
+ if (last_dot >= ep_)
+ last_dot = prelast_dot;
+ if (last_dot == NULL || (scanpos + 1 >= last_dot))
+ return FALSE;
+ last_dot++;
+
+ for (last_tld_char = last_dot; last_tld_char < ep_; last_tld_char++)
+ if (*last_tld_char == '?')
+ break;
+
+ if (is_toplvl_domain(dom_tab, last_dot, last_tld_char))
+ result = TRUE;
+
+ *ep = ep_;
+ *bp = bp_;
+ }
+
+ if (!result) return FALSE;
+
+ if (*ep_ && *(bp_ - 1) == '"' && *(ep_) == '"'
+ && *(ep_ + 1) == ' ' && *(ep_ + 2) == '<'
+ && IS_RFC822_CHAR(*(ep_ + 3))) {
+ /* this informative part with an @ in it is
+ * followed by the email address */
+ ep_ += 3;
+
+ /* go to matching '>' (or next non-rfc822 char, like \n) */
+ for (; *ep_ != '>' && *ep != '\0' && IS_RFC822_CHAR(*ep_); ep_++)
+ ;
+
+ /* include the bracket */
+ if (*ep_ == '>') ep_++;
+
+ /* include the leading quote */
+ bp_--;
+
+ *ep = ep_;
+ *bp = bp_;
+ return TRUE;
+ }
+
+ /* skip if it's between quotes "'alfons@proteus.demon.nl'" <alfons@proteus.demon.nl> */
+ if (bp_ - 1 > start && IS_QUOTE(*(bp_ - 1)) && IS_QUOTE(*ep_))
+ return FALSE;
+
+ /* see if this is <bracketed>; in this case we also scan for the informative part. */
+ if (bp_ - 1 <= start || *(bp_ - 1) != '<' || *ep_ != '>')
+ return TRUE;
+
+#define FULL_STACK() ((size_t) (ptr - closure_stack) >= sizeof closure_stack)
+#define IN_STACK() (ptr > closure_stack)
+/* has underrun check */
+#define POP_STACK() if(IN_STACK()) --ptr
+/* has overrun check */
+#define PUSH_STACK(c) if(!FULL_STACK()) *ptr++ = (c); else return TRUE
+/* has underrun check */
+#define PEEK_STACK() (IN_STACK() ? *(ptr - 1) : 0)
+
+ ep_++;
+
+ /* scan for the informative part. */
+ for (bp_ -= 2; bp_ >= start; bp_--) {
+ /* if closure on the stack keep scanning */
+ if (PEEK_STACK() == *bp_) {
+ POP_STACK();
+ continue;
+ }
+ if (*bp_ == '\'' || *bp_ == '"') {
+ PUSH_STACK(*bp_);
+ continue;
+ }
+
+ /* if nothing in the closure stack, do the special conditions
+ * the following if..else expression simply checks whether
+ * a token is acceptable. if not acceptable, the clause
+ * should terminate the loop with a 'break' */
+ if (!PEEK_STACK()) {
+ if (*bp_ == '-'
+ && (((bp_ - 1) >= start) && isalnum(*(bp_ - 1)))
+ && (((bp_ + 1) < ep_) && isalnum(*(bp_ + 1)))) {
+ /* hyphens are allowed, but only in
+ between alnums */
+ } else if (!strchr(",;:=?./+<>!&\r\n\t", *bp_)) {
+ /* but anything not being a punctiation
+ is ok */
+ } else {
+ break; /* anything else is rejected */
+ }
+ }
+ }
+
+ bp_++;
+
+#undef PEEK_STACK
+#undef PUSH_STACK
+#undef POP_STACK
+#undef IN_STACK
+#undef FULL_STACK
+
+ /* scan forward (should start with an alnum) */
+ for (; *bp_ != '<' && isspace(*bp_) && *bp_ != '"'; bp_++)
+ ;
+
+ *ep = ep_;
+ *bp = bp_;
+
+ return result;
+}
+
+#undef IS_QUOTE
+#undef IS_ASCII_ALNUM
+#undef IS_RFC822_CHAR
+
+gchar *make_email_string(const gchar *bp, const gchar *ep)
+{
+ /* returns a mailto: URI; mailto: is also used to detect the
+ * uri type later on in the button_pressed signal handler */
+ gchar *tmp;
+ gchar *result;
+
+ tmp = g_strndup(bp, ep - bp);
+ result = g_strconcat("mailto:", tmp, NULL);
+ g_free(tmp);
+
+ return result;
+}
+
+gchar *make_http_string(const gchar *bp, const gchar *ep)
+{
+ /* returns an http: URI; */
+ gchar *tmp;
+ gchar *result;
+
+ tmp = g_strndup(bp, ep - bp);
+ result = g_strconcat("http://", tmp, NULL);
+ g_free(tmp);
+
+ return result;
+}
+
GAuto *g_auto_pointer_copy (GAuto *auto_ptr);
void g_auto_pointer_free (GAuto *auto_ptr);
void replace_returns (gchar *str);
+
+gboolean get_uri_part(const gchar *start, const gchar *scanpos,
+ const gchar **bp, const gchar **ep);
+gchar *make_uri_string(const gchar *bp, const gchar *ep);
+gboolean get_email_part(const gchar *start, const gchar *scanpos,
+ const gchar **bp, const gchar **ep);
+gchar *make_email_string(const gchar *bp, const gchar *ep);
+gchar *make_http_string(const gchar *bp, const gchar *ep);
+
#ifdef __cplusplus
}
#endif
MsgInfo *msginfo);
static void compose_wrap_paragraph (Compose *compose,
- GtkTextIter *par_iter);
+ GtkTextIter *par_iter,
+ gboolean force);
static void compose_wrap_all (Compose *compose);
static void compose_wrap_all_full (Compose *compose,
gboolean autowrap);
(gushort)0x7fff
};
+static GdkColor uri_color = {
+ (gulong)0,
+ (gushort)0,
+ (gushort)0,
+ (gushort)0
+};
+
static void compose_create_tags(GtkTextView *text, Compose *compose)
{
GtkTextBuffer *buffer;
"e_color);
gtkut_convert_int_to_gdk_color(prefs_common.signature_col,
&signature_color);
+ gtkut_convert_int_to_gdk_color(prefs_common.uri_col,
+ &uri_color);
} else {
- signature_color = quote_color = black;
+ signature_color = quote_color = uri_color = black;
}
gtk_text_buffer_create_tag(buffer, "quote",
gtk_text_buffer_create_tag(buffer, "signature",
"foreground-gdk", &signature_color,
NULL);
+ gtk_text_buffer_create_tag(buffer, "link",
+ "foreground-gdk", &uri_color,
+ NULL);
}
Compose *compose_new(PrefsAccount *account, const gchar *mailto,
compose_ext_editor_cb(compose, 0, NULL);
break;
case A_LINEWRAP_CURRENT:
- compose_wrap_paragraph(compose, NULL);
+ compose_wrap_paragraph(compose, NULL, TRUE);
break;
case A_LINEWRAP_ALL:
- compose_wrap_all(compose);
+ compose_wrap_all_full(compose, TRUE);
break;
case A_ADDRBOOK:
compose_address_cb(compose, 0, NULL);
return TRUE;
}
-static void compose_wrap_paragraph(Compose *compose, GtkTextIter *par_iter)
+#define ADD_TXT_POS(bp_, ep_, pti_) \
+ if ((last->next = alloca(sizeof(struct txtpos))) != NULL) { \
+ last = last->next; \
+ last->bp = (bp_); last->ep = (ep_); last->pti = (pti_); \
+ last->next = NULL; \
+ } else { \
+ g_warning("alloc error scanning URIs\n"); \
+ }
+
+static void compose_wrap_paragraph(Compose *compose, GtkTextIter *par_iter, gboolean force)
{
GtkTextView *text = GTK_TEXT_VIEW(compose->text);
GtkTextBuffer *buffer;
- GtkTextIter iter, break_pos;
+ GtkTextIter iter, break_pos, end_of_line;
gchar *quote_str = NULL;
gint quote_len;
gboolean wrap_quote = prefs_common.linewrap_quote;
gboolean prev_autowrap = compose->autowrap;
gint startq_offset = -1, noq_offset = -1;
+ gint uri_start = -1, uri_stop = -1;
+ gint nouri_start = -1, nouri_stop = -1;
compose->autowrap = FALSE;
/* go until paragraph end (empty line) */
while (!gtk_text_iter_ends_line(&iter)) {
+ gchar *scanpos = NULL;
+ /* parse table - in order of priority */
+ struct table {
+ const gchar *needle; /* token */
+
+ /* token search function */
+ gchar *(*search) (const gchar *haystack,
+ const gchar *needle);
+ /* part parsing function */
+ gboolean (*parse) (const gchar *start,
+ const gchar *scanpos,
+ const gchar **bp_,
+ const gchar **ep_);
+ /* part to URI function */
+ gchar *(*build_uri) (const gchar *bp,
+ const gchar *ep);
+ };
+
+ static struct table parser[] = {
+ {"http://", strcasestr, get_uri_part, make_uri_string},
+ {"https://", strcasestr, get_uri_part, make_uri_string},
+ {"ftp://", strcasestr, get_uri_part, make_uri_string},
+ {"www.", strcasestr, get_uri_part, make_http_string},
+ {"mailto:", strcasestr, get_uri_part, make_uri_string},
+ {"@", strcasestr, get_email_part, make_email_string}
+ };
+ const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
+ gint last_index = PARSE_ELEMS;
+ gint n;
+ gchar *o_walk, *walk, *bp, *ep;
+ gint walk_pos;
+
+ uri_start = uri_stop = -1;
quote_str = compose_get_quote_str(buffer, &iter, "e_len);
+
if (quote_str) {
if (!wrap_quote) {
if (startq_offset == -1) {
startq_offset = gtk_text_iter_get_offset(&iter);
}
- gtk_text_iter_forward_line(&iter);
- g_free(quote_str);
goto colorize;
}
debug_print("compose_wrap_paragraph(): quote_str = '%s'\n", quote_str);
noq_offset = gtk_text_iter_get_offset(&iter);
}
- if (prev_autowrap == FALSE) {
- gtk_text_iter_forward_line(&iter);
- g_free(quote_str);
+ if (prev_autowrap == FALSE && !force) {
goto colorize;
}
if (compose_get_line_break_pos(buffer, &iter, &break_pos,
/* move iter to current line start */
gtk_text_iter_set_line_offset(&iter, 0);
+ continue;
} else {
/* move iter to next line start */
iter = break_pos;
- gtk_text_iter_forward_line(&iter);
}
- g_free(quote_str);
colorize:
+ end_of_line = iter;
+ while (!gtk_text_iter_ends_line(&end_of_line)) {
+ gtk_text_iter_forward_char(&end_of_line);
+ }
+ o_walk = walk = gtk_text_buffer_get_text(buffer, &iter, &end_of_line, FALSE);
+
+ nouri_start = gtk_text_iter_get_offset(&iter);
+ nouri_stop = gtk_text_iter_get_offset(&end_of_line);
+
+ walk_pos = gtk_text_iter_get_offset(&iter);
+ /* FIXME: this looks phony. scanning for anything in the parse table */
+ for (n = 0; n < PARSE_ELEMS; n++) {
+ gchar *tmp;
+
+ tmp = parser[n].search(walk, parser[n].needle);
+ if (tmp) {
+ if (scanpos == NULL || tmp < scanpos) {
+ scanpos = tmp;
+ last_index = n;
+ }
+ }
+ }
+
+ bp = ep = 0;
+ if (scanpos) {
+ /* check if URI can be parsed */
+ if (parser[last_index].parse(walk, scanpos, (const gchar **)&bp,(const gchar **)&ep)
+ && (size_t) (ep - bp - 1) > strlen(parser[last_index].needle)) {
+ walk = ep;
+ } else
+ walk = scanpos +
+ strlen(parser[last_index].needle);
+ }
+ if (bp && ep) {
+ uri_start = walk_pos + (bp - o_walk);
+ uri_stop = walk_pos + (ep - o_walk);
+ }
+ g_free(o_walk);
+ gtk_text_iter_forward_line(&iter);
+ g_free(quote_str);
if (startq_offset != -1) {
GtkTextIter startquote, endquote;
gtk_text_buffer_get_iter_at_offset(
buffer, "quote", &startnoquote, &endnoquote);
noq_offset = -1;
}
+
+ /* always */ {
+ GtkTextIter nouri_start_iter, nouri_end_iter;
+ gtk_text_buffer_get_iter_at_offset(
+ buffer, &nouri_start_iter, nouri_start);
+ gtk_text_buffer_get_iter_at_offset(
+ buffer, &nouri_end_iter, nouri_stop);
+ gtk_text_buffer_remove_tag_by_name(
+ buffer, "link", &nouri_start_iter, &nouri_end_iter);
+ }
+ if (uri_start > 0 && uri_stop > 0) {
+ GtkTextIter uri_start_iter, uri_end_iter;
+ gtk_text_buffer_get_iter_at_offset(
+ buffer, &uri_start_iter, uri_start);
+ gtk_text_buffer_get_iter_at_offset(
+ buffer, &uri_end_iter, uri_stop);
+ gtk_text_buffer_apply_tag_by_name(
+ buffer, "link", &uri_start_iter, &uri_end_iter);
+ }
}
if (par_iter)
compose_wrap_all_full(compose, FALSE);
}
-static void compose_wrap_all_full(Compose *compose, gboolean autowrap)
+static void compose_wrap_all_full(Compose *compose, gboolean force)
{
GtkTextView *text = GTK_TEXT_VIEW(compose->text);
GtkTextBuffer *buffer;
gtk_text_buffer_get_start_iter(buffer, &iter);
while (!gtk_text_iter_is_end(&iter))
- compose_wrap_paragraph(compose, &iter);
+ compose_wrap_paragraph(compose, &iter, force);
undo_unblock(compose->undostruct);
}
Compose *compose = (Compose *)data;
if (action == 1)
- compose_wrap_all(compose);
+ compose_wrap_all_full(compose, TRUE);
else
- compose_wrap_paragraph(compose, NULL);
+ compose_wrap_paragraph(compose, NULL, TRUE);
}
static void compose_toggle_autowrap_cb(gpointer data, guint action,
gtk_text_buffer_insert(buffer, iter, text, len);
mark = gtk_text_buffer_create_mark(buffer, NULL, iter, FALSE);
- compose_wrap_all_full(compose, TRUE);
+ compose_wrap_all_full(compose, FALSE);
gtk_text_buffer_get_iter_at_mark(buffer, iter, mark);
gtk_text_buffer_delete_mark(buffer, mark);
#include "hooks.h"
#include "folderutils.h"
#include "partial_download.h"
+#include "prefs_folder_column.h"
-typedef enum
-{
- COL_FOLDER = 0,
- COL_NEW = 1,
- COL_UNREAD = 2,
- COL_TOTAL = 3
-} FolderColumnPos;
-
-#define N_FOLDER_COLS 4
#define COL_FOLDER_WIDTH 150
#define COL_NUM_WIDTH 32
g_hash_table_insert(folderview->popups, fpopup->klass, factory);
}
-FolderView *folderview_create(void)
+static void folderview_column_set_titles(FolderView *folderview)
+{
+ GtkWidget *ctree = folderview->ctree;
+ GtkWidget *label_new;
+ GtkWidget *label_unread;
+ GtkWidget *label_total;
+ GtkWidget *hbox_new;
+ GtkWidget *hbox_unread;
+ GtkWidget *hbox_total;
+ gint *col_pos = folderview->col_pos;
+
+ gtk_widget_realize(folderview->ctree);
+ gtk_widget_show_all(folderview->scrolledwin);
+
+ /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
+ * instead text (text overflows making them unreadable and ugly) */
+ stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
+ &newxpm, &newxpmmask);
+ stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
+ &unreadxpm, &unreadxpmmask);
+ stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
+ &readxpm, &readxpmmask);
+
+ label_new = gtk_pixmap_new(newxpm, newxpmmask);
+ label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
+ label_total = gtk_pixmap_new(readxpm, readxpmmask);
+
+ hbox_new = gtk_hbox_new(FALSE, 4);
+ hbox_unread = gtk_hbox_new(FALSE, 4);
+ hbox_total = gtk_hbox_new(FALSE, 4);
+
+ /* left justified */
+ gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
+
+ gtk_widget_show_all(hbox_new);
+ gtk_widget_show_all(hbox_unread);
+ gtk_widget_show_all(hbox_total);
+
+ gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
+ gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
+ gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
+}
+
+GtkWidget *folderview_ctree_create(FolderView *folderview)
{
- FolderView *folderview;
- GtkWidget *scrolledwin;
GtkWidget *ctree;
+ gint *col_pos;
+ FolderColumnState *col_state;
+ FolderColumnType type;
gchar *titles[N_FOLDER_COLS];
gint i;
+ GtkWidget *scrolledwin = folderview->scrolledwin;
- debug_print("Creating folder view...\n");
- folderview = g_new0(FolderView, 1);
+ memset(titles, 0, sizeof(titles));
- titles[COL_FOLDER] = _("Folder");
- titles[COL_NEW] = _("New");
- titles[COL_UNREAD] = _("Unread");
- titles[COL_TOTAL] = _("#");
+ col_state = prefs_folder_column_get_config();
+ memset(titles, 0, sizeof(titles));
- scrolledwin = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy
- (GTK_SCROLLED_WINDOW(scrolledwin),
- GTK_POLICY_AUTOMATIC,
- prefs_common.folderview_vscrollbar_policy);
- gtk_widget_set_size_request(scrolledwin,
- prefs_common.folderview_width,
- prefs_common.folderview_height);
+ col_pos = folderview->col_pos;
+
+ for (i = 0; i < N_FOLDER_COLS; i++) {
+ folderview->col_state[i] = col_state[i];
+ type = col_state[i].type;
+ col_pos[type] = i;
+ }
- ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
+ titles[col_pos[F_COL_FOLDER]] = _("Folder");
+ titles[col_pos[F_COL_NEW]] = _("New");
+ titles[col_pos[F_COL_UNREAD]] = _("Unread");
+ titles[col_pos[F_COL_TOTAL]] = _("#");
+
+ ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
+ titles);
- gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
- gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
+ gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
GTK_JUSTIFY_RIGHT);
- gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
+ gtk_clist_set_column_justification(GTK_CLIST(ctree),
+ col_pos[F_COL_UNREAD],
GTK_JUSTIFY_RIGHT);
- gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
+ gtk_clist_set_column_justification(GTK_CLIST(ctree),
+ col_pos[F_COL_TOTAL],
GTK_JUSTIFY_RIGHT);
- gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
- prefs_common.folder_col_folder);
- gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
- prefs_common.folder_col_new);
- gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,
- prefs_common.folder_col_unread);
- gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
- prefs_common.folder_col_total);
gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
gtk_ctree_set_expander_style(GTK_CTREE(ctree),
GTK_CTREE_EXPANDER_SQUARE);
gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
- /* create popup factories */
- folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
- g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
-
/* don't let title buttons take key focus */
- for (i = 0; i < N_FOLDER_COLS; i++)
+ for (i = 0; i < N_FOLDER_COLS; i++) {
GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
GTK_CAN_FOCUS);
-
+ gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
+ prefs_common.folder_col_size[i]);
+ gtk_clist_set_column_visibility
+ (GTK_CLIST(ctree), i, col_state[i].visible);
+ }
g_signal_connect(G_OBJECT(ctree), "key_press_event",
G_CALLBACK(folderview_key_pressed),
G_CALLBACK(folderview_drag_end_cb),
folderview);
+ gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
+
+ return ctree;
+}
+
+void folderview_set_column_order(FolderView *folderview)
+{
+ GtkWidget *ctree;
+ FolderItem *item = folderview_get_selected_item(folderview);
+ GtkWidget *scrolledwin = folderview->scrolledwin;
+
+ gtk_widget_destroy(folderview->ctree);
+
+ folderview->ctree = ctree = folderview_ctree_create(folderview);
+ gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_CLIST(ctree)->hadjustment);
+ gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_CLIST(ctree)->vadjustment);
+ gtk_widget_show(ctree);
+
+ folderview_set(folderview);
+ folderview_column_set_titles(folderview);
+
+ folderview_select(folderview,item);
+}
+
+FolderView *folderview_create(void)
+{
+ FolderView *folderview;
+ GtkWidget *scrolledwin;
+ GtkWidget *ctree;
+
+ debug_print("Creating folder view...\n");
+ folderview = g_new0(FolderView, 1);
+
+ scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy
+ (GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_POLICY_AUTOMATIC,
+ prefs_common.folderview_vscrollbar_policy);
+ gtk_widget_set_size_request(scrolledwin,
+ prefs_common.folderview_width,
+ prefs_common.folderview_height);
+
folderview->scrolledwin = scrolledwin;
+ ctree = folderview_ctree_create(folderview);
+
+ /* create popup factories */
+ folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
+ g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
+
folderview->ctree = ctree;
folderview->folder_update_callback_id =
hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
gtk_widget_show_all(scrolledwin);
-
+
folderview->target_list = gtk_target_list_new(folderview_drag_types, 1);
folderview_list = g_list_append(folderview_list, folderview);
void folderview_init(FolderView *folderview)
{
GtkWidget *ctree = folderview->ctree;
- GtkWidget *label_new;
- GtkWidget *label_unread;
- GtkWidget *label_total;
- GtkWidget *hbox_new;
- GtkWidget *hbox_unread;
- GtkWidget *hbox_total;
-
- gtk_widget_realize(ctree);
+
stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
-
- /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
- * instead text (text overflows making them unreadable and ugly) */
- stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
- &newxpm, &newxpmmask);
- stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
- &unreadxpm, &unreadxpmmask);
- stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
- &readxpm, &readxpmmask);
-
- label_new = gtk_pixmap_new(newxpm, newxpmmask);
- label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
- label_total = gtk_pixmap_new(readxpm, readxpmmask);
-
- hbox_new = gtk_hbox_new(FALSE, 4);
- hbox_unread = gtk_hbox_new(FALSE, 4);
- hbox_total = gtk_hbox_new(FALSE, 4);
-
- /* left justified */
- gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
- gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
- gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
-
- gtk_widget_show_all(hbox_new);
- gtk_widget_show_all(hbox_unread);
- gtk_widget_show_all(hbox_total);
-
- gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_NEW,hbox_new);
- gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_UNREAD,hbox_unread);
- gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_TOTAL,hbox_total);
if (!normal_style) {
PangoFontDescription *font_desc;
FolderItem *item;
gint new, unread, total;
gchar *new_str, *unread_str, *total_str;
+ gint *col_pos = folderview->col_pos;
if (!row) return;
item = gtk_ctree_node_get_row_data(ctree, row);
if (!item) return;
- gtk_ctree_node_get_text(ctree, row, COL_NEW, &new_str);
- gtk_ctree_node_get_text(ctree, row, COL_UNREAD, &unread_str);
- gtk_ctree_node_get_text(ctree, row, COL_TOTAL, &total_str);
+ gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
+ gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
+ gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
new = atoi(new_str);
unread = atoi(unread_str);
total = atoi(total_str);
void folderview_append_item(FolderItem *item)
{
GList *list;
-
+
g_return_if_fail(item != NULL);
g_return_if_fail(item->folder != NULL);
if (folder_item_parent(item)) return;
FolderView *folderview = (FolderView *)list->data;
GtkCTree *ctree = GTK_CTREE(folderview->ctree);
GtkCTreeNode *node, *child;
+ gint *col_pos = folderview->col_pos;
node = gtk_ctree_find_by_row_data(ctree, NULL,
folder_item_parent(item));
gtk_clist_freeze(GTK_CLIST(ctree));
- text[COL_FOLDER] = item->name;
+ text[col_pos[F_COL_FOLDER]] = item->name;
child = gtk_ctree_insert_node
(ctree, node, NULL, text,
FOLDER_SPACING,
gboolean add_unread_mark;
gboolean add_sub_match_mark;
gboolean use_bold, use_color;
+ gint *col_pos = folderview->col_pos;
item = gtk_ctree_node_get_row_data(ctree, node);
g_return_if_fail(item != NULL);
g_free(name);
if (!folder_item_parent(item)) {
- gtk_ctree_node_set_text(ctree, node, COL_NEW, "-");
- gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
- gtk_ctree_node_set_text(ctree, node, COL_TOTAL, "-");
+ gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
+ gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
+ gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
} else {
- gtk_ctree_node_set_text(ctree, node, COL_NEW, itos(item->new_msgs));
- gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread_msgs));
- gtk_ctree_node_set_text(ctree, node, COL_TOTAL, itos(item->total_msgs));
+ gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
+ gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
+ gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
}
if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
static void folderview_col_resized(GtkCList *clist, gint column, gint width,
FolderView *folderview)
{
- switch (column) {
- case COL_FOLDER:
- prefs_common.folder_col_folder = width;
- break;
- case COL_NEW:
- prefs_common.folder_col_new = width;
- break;
- case COL_UNREAD:
- prefs_common.folder_col_unread = width;
- break;
- case COL_TOTAL:
- prefs_common.folder_col_total = width;
- break;
- default:
- break;
- }
+ FolderColumnType type = folderview->col_state[column].type;
+
+ prefs_common.folder_col_size[type] = width;
}
void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
GtkCTree *ctree = GTK_CTREE(folderview->ctree);
gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
GtkCTreeNode *node, *parent_node;
-
+ gint *col_pos = folderview->col_pos;
+
parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
if (parent_node == NULL)
return;
gtk_clist_freeze(GTK_CLIST(ctree));
- text[COL_FOLDER] = item->name;
+ text[col_pos[F_COL_FOLDER]] = item->name;
node = gtk_ctree_insert_node(ctree, parent_node, NULL, text,
FOLDER_SPACING,
folderxpm, folderxpmmask,
FolderView *folderview = mainwindow_get_mainwindow()->folderview;
normal_style = normal_color_style = bold_style =
bold_color_style = bold_tgtfold_style = NULL;
-
+ FolderItem *item = folderview_get_selected_item(folderview);
folderview_init(folderview);
+ folderview_column_set_titles(folderview);
folderview_set_all();
+ if (item)
+ folderview_select(folderview, item);
}
static void drag_state_stop(FolderView *folderview)
typedef struct _FolderView FolderView;
typedef struct _FolderViewPopup FolderViewPopup;
+typedef struct _FolderColumnState FolderColumnState;
#include <glib.h>
#include <gtk/gtkwidget.h>
#include "summaryview.h"
#include "folder.h"
+typedef enum
+{
+ F_COL_FOLDER,
+ F_COL_NEW,
+ F_COL_UNREAD,
+ F_COL_TOTAL
+} FolderColumnType;
+
+#define N_FOLDER_COLS 4
+
+struct _FolderColumnState
+{
+ FolderColumnType type;
+ gboolean visible;
+};
+
struct _FolderView
{
GtkWidget *scrolledwin;
GtkCTreeNode *drag_node; /* drag node */
GtkTargetList *target_list; /* DnD */
+ FolderColumnState col_state[N_FOLDER_COLS];
+ gint col_pos[N_FOLDER_COLS];
};
struct _FolderViewPopup
void folderview_unregister_popup (FolderViewPopup *fpopup);
void folderview_update_search_icon (FolderItem *item,
gboolean matches);
+void folderview_set_column_order (FolderView *folderview);
#endif /* __FOLDERVIEW_H__ */
free(dup_name);
continue;
}
+
+ if (dup_name[strlen(dup_name)-1] == '/') {
+ g_free(base);
+ free(dup_name);
+ continue;
+ }
loc_name = imap_modified_utf7_to_utf8(base);
loc_path = imap_modified_utf7_to_utf8(dup_name);
#include "prefs_filtering.h"
#include "prefs_account.h"
#include "prefs_summary_column.h"
+#include "prefs_folder_column.h"
#include "prefs_template.h"
#include "action.h"
#include "account.h"
guint action,
GtkWidget *widget);
-static void set_display_item_cb (MainWindow *mainwin,
+static void set_summary_display_item_cb (MainWindow *mainwin,
+ guint action,
+ GtkWidget *widget);
+static void set_folder_display_item_cb (MainWindow *mainwin,
guint action,
GtkWidget *widget);
static void sort_summary_cb (MainWindow *mainwin,
{N_("/_View/E_xpand all threads"), NULL, expand_threads_cb, 0, NULL},
{N_("/_View/Co_llapse all threads"), NULL, collapse_threads_cb, 0, NULL},
{N_("/_View/_Hide read messages"), NULL, hide_read_messages, 0, "<ToggleItem>"},
- {N_("/_View/Set displayed _items..."), NULL, set_display_item_cb, 0, NULL},
+ {N_("/_View/Set displayed _items"), NULL, NULL, 0, "<Branch>"},
+ {N_("/_View/Set displayed _items/ in _Summary view..."),NULL, set_summary_display_item_cb, 0, NULL},
+ {N_("/_View/Set displayed _items/ in _Folder view..."), NULL, set_folder_display_item_cb, 0, NULL},
{N_("/_View/---"), NULL, NULL, 0, "<Separator>"},
{N_("/_View/_Go to"), NULL, NULL, 0, "<Branch>"},
}
}
+void main_window_set_folder_column(void)
+{
+ GList *cur;
+ MainWindow *mainwin;
+
+ for (cur = mainwin_list; cur != NULL; cur = cur->next) {
+ mainwin = (MainWindow *)cur->data;
+ folderview_set_column_order(mainwin->folderview);
+ }
+}
+
static void main_window_set_account_selector_menu(MainWindow *mainwin,
GList *account_list)
{
summary_collapse_threads(mainwin->summaryview);
}
-static void set_display_item_cb(MainWindow *mainwin, guint action,
+static void set_summary_display_item_cb(MainWindow *mainwin, guint action,
GtkWidget *widget)
{
prefs_summary_column_open();
}
+static void set_folder_display_item_cb(MainWindow *mainwin, guint action,
+ GtkWidget *widget)
+{
+ prefs_folder_column_open();
+}
+
static void sort_summary_cb(MainWindow *mainwin, guint action,
GtkWidget *widget)
{
void main_window_reflect_prefs_all_real (gboolean pixmap_theme_changed);
void main_window_reflect_prefs_all (void);
void main_window_set_summary_column (void);
+void main_window_set_folder_column (void);
void main_window_set_account_menu (GList *account_list);
GtkWidget *main_window_get_folder_window (MainWindow *mainwin);
#include "prefs_common.h"
#include "prefs_display_header.h"
#include "prefs_summary_column.h"
+#include "prefs_folder_column.h"
#include "mainwindow.h"
#include "summaryview.h"
+#include "folderview.h"
#include "messageview.h"
#include "manage_window.h"
#include "inc.h"
NULL, NULL, NULL},
/* Display: Summary View */
- {"enable_swap_from", "FALSE", &prefs_common.swap_from, P_BOOL,
- NULL, NULL, NULL},
{"use_address_book", "FALSE", &prefs_common.use_addr_book, P_BOOL,
NULL, NULL, NULL},
{"thread_by_subject", "TRUE", &prefs_common.thread_by_subject, P_BOOL,
&prefs_common.summary_col_visible[S_COL_SUBJECT], P_BOOL, NULL, NULL, NULL},
{"summary_col_show_from", "TRUE",
&prefs_common.summary_col_visible[S_COL_FROM], P_BOOL, NULL, NULL, NULL},
+ {"summary_col_show_to", "FALSE",
+ &prefs_common.summary_col_visible[S_COL_TO], P_BOOL, NULL, NULL, NULL},
{"summary_col_show_date", "TRUE",
&prefs_common.summary_col_visible[S_COL_DATE], P_BOOL, NULL, NULL, NULL},
{"summary_col_show_size", "TRUE",
&prefs_common.summary_col_pos[S_COL_SCORE], P_INT, NULL, NULL, NULL},
{"summary_col_pos_locked", "9",
&prefs_common.summary_col_pos[S_COL_LOCKED], P_INT, NULL, NULL, NULL},
+ {"summary_col_pos_to", "10",
+ &prefs_common.summary_col_pos[S_COL_TO], P_INT, NULL, NULL, NULL},
{"summary_col_size_mark", "10",
&prefs_common.summary_col_size[S_COL_MARK], P_INT, NULL, NULL, NULL},
&prefs_common.summary_col_size[S_COL_SUBJECT], P_INT, NULL, NULL, NULL},
{"summary_col_size_from", "120",
&prefs_common.summary_col_size[S_COL_FROM], P_INT, NULL, NULL, NULL},
+ {"summary_col_size_to", "120",
+ &prefs_common.summary_col_size[S_COL_TO], P_INT, NULL, NULL, NULL},
{"summary_col_size_date", "118",
&prefs_common.summary_col_size[S_COL_DATE], P_INT, NULL, NULL, NULL},
{"summary_col_size_size", "45",
{"folderview_visible", "TRUE", &prefs_common.folderview_visible, P_BOOL,
NULL, NULL, NULL},
- {"folder_col_folder", "150", &prefs_common.folder_col_folder, P_INT,
- NULL, NULL, NULL},
- {"folder_col_new", "32", &prefs_common.folder_col_new, P_INT,
- NULL, NULL, NULL},
- {"folder_col_unread", "32", &prefs_common.folder_col_unread, P_INT,
- NULL, NULL, NULL},
- {"folder_col_total", "32", &prefs_common.folder_col_total, P_INT,
- NULL, NULL, NULL},
+ {"folder_col_show_folder", "TRUE",
+ &prefs_common.folder_col_visible[F_COL_FOLDER], P_BOOL, NULL, NULL, NULL},
+ {"folder_col_show_new", "TRUE",
+ &prefs_common.folder_col_visible[F_COL_NEW], P_BOOL, NULL, NULL, NULL},
+ {"folder_col_show_unread", "TRUE",
+ &prefs_common.folder_col_visible[F_COL_UNREAD], P_BOOL, NULL, NULL, NULL},
+ {"folder_col_show_total", "TRUE",
+ &prefs_common.folder_col_visible[F_COL_TOTAL], P_BOOL, NULL, NULL, NULL},
+
+ {"folder_col_pos_folder", "0",
+ &prefs_common.folder_col_pos[F_COL_FOLDER], P_INT, NULL, NULL, NULL},
+ {"folder_col_pos_new", "1",
+ &prefs_common.folder_col_pos[F_COL_NEW], P_INT, NULL, NULL, NULL},
+ {"folder_col_pos_unread", "2",
+ &prefs_common.folder_col_pos[F_COL_UNREAD], P_INT, NULL, NULL, NULL},
+ {"folder_col_pos_total", "3",
+ &prefs_common.folder_col_pos[F_COL_TOTAL], P_INT, NULL, NULL, NULL},
+
+ {"folder_col_size_folder", "150",
+ &prefs_common.folder_col_size[F_COL_FOLDER], P_INT, NULL, NULL, NULL},
+ {"folder_col_size_new", "32",
+ &prefs_common.folder_col_size[F_COL_NEW], P_INT, NULL, NULL, NULL},
+ {"folder_col_size_unread", "32",
+ &prefs_common.folder_col_size[F_COL_UNREAD], P_INT, NULL, NULL, NULL},
+ {"folder_col_size_total", "32",
+ &prefs_common.folder_col_size[F_COL_TOTAL], P_INT, NULL, NULL, NULL},
{"summaryview_width", "600", &prefs_common.summaryview_width, P_INT,
NULL, NULL, NULL},
#include "mainwindow.h"
#include "summaryview.h"
+#include "folderview.h"
#include "codeconv.h"
#include "textview.h"
#include "procmime.h"
gint ng_abbrev_len;
gboolean show_searchbar;
- gboolean swap_from;
gboolean expand_thread;
gboolean use_addr_book;
gchar *date_format;
gint summary_col_pos[N_SUMMARY_COLS];
gint summary_col_size[N_SUMMARY_COLS];
+ gboolean folder_col_visible[N_FOLDER_COLS];
+ gint folder_col_pos[N_FOLDER_COLS];
+ gint folder_col_size[N_FOLDER_COLS];
+
/* Widget visibility, position and size */
gint folderwin_x;
gint folderwin_y;
gint folderview_height;
gboolean folderview_visible;
- gint folder_col_folder;
- gint folder_col_new;
- gint folder_col_unread;
- gint folder_col_total;
-
gint summaryview_width;
gint summaryview_height;
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2005 Hiroyuki Yamamoto & the Sylpheed-Claws team
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkbutton.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "prefs_gtk.h"
+#include "prefs_common.h"
+#include "prefs_folder_column.h"
+#include "manage_window.h"
+#include "folderview.h"
+#include "mainwindow.h"
+#include "inc.h"
+#include "gtkutils.h"
+#include "utils.h"
+
+enum {
+ SUMCOL_NAME,
+ SUMCOL_TYPE,
+ N_SUMCOL_COLUMNS
+};
+
+#define TARGET_INFO_SUMCOL (0xFEEDBABE)
+
+static const GtkTargetEntry row_targets[] = {
+ { "PREFS_SUM_COL_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_INFO_SUMCOL }
+};
+
+
+static struct _FolderColumnDialog
+{
+ GtkWidget *window;
+
+ GtkWidget *stock_list_view;
+ GtkWidget *shown_list_view;
+
+ GtkWidget *add_btn;
+ GtkWidget *remove_btn;
+ GtkWidget *up_btn;
+ GtkWidget *down_btn;
+
+ GtkWidget *default_btn;
+
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+
+ gboolean finished;
+} folder_col;
+
+static const gchar *const col_name[N_FOLDER_COLS] = {
+ N_("Folder"), /* F_COL_FOLDER */
+ N_("New"), /* F_COL_NEW */
+ N_("Unread"), /* F_COL_UNREAD */
+ N_("Total"), /* F_COL_TOTAL */
+};
+
+static FolderColumnState default_state[N_FOLDER_COLS] = {
+ { F_COL_FOLDER , TRUE },
+ { F_COL_NEW , TRUE },
+ { F_COL_UNREAD , TRUE },
+ { F_COL_TOTAL , TRUE },
+};
+
+static void prefs_folder_column_create (void);
+
+static void prefs_folder_column_set_dialog (FolderColumnState *state);
+static void prefs_folder_column_set_view (void);
+
+/* callback functions */
+static void prefs_folder_column_add (void);
+static void prefs_folder_column_remove (void);
+
+static void prefs_folder_column_up (void);
+static void prefs_folder_column_down (void);
+
+static void prefs_folder_column_set_to_default (void);
+
+static void prefs_folder_column_ok (void);
+static void prefs_folder_column_cancel (void);
+
+static gint prefs_folder_column_delete_event (GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer data);
+static gboolean prefs_folder_column_key_pressed(GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data);
+
+static GtkListStore *prefs_folder_column_create_store (void);
+
+static void prefs_folder_column_insert_column (GtkListStore *store,
+ gint row,
+ const gchar *name,
+ FolderColumnType type);
+
+static FolderColumnType prefs_folder_column_get_column (GtkWidget *list,
+ gint row);
+
+static GtkWidget *prefs_folder_column_list_view_create (const gchar *name);
+
+static void prefs_filtering_create_list_view_columns (GtkWidget *list_view,
+ const gchar *name);
+
+static void drag_data_get (GtkTreeView *tree_view,
+ GdkDragContext *context,
+ GtkSelectionData *data,
+ guint info,
+ guint time,
+ GtkTreeModel *model);
+
+static void drag_data_received (GtkTreeView *tree_view,
+ GdkDragContext *context,
+ gint x, gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint time,
+ GtkTreeModel *model);
+
+void prefs_folder_column_open(void)
+{
+ inc_lock();
+
+ if (!folder_col.window)
+ prefs_folder_column_create();
+
+ manage_window_set_transient(GTK_WINDOW(folder_col.window));
+ gtk_widget_grab_focus(folder_col.ok_btn);
+
+ prefs_folder_column_set_dialog(NULL);
+
+ gtk_widget_show(folder_col.window);
+
+ folder_col.finished = FALSE;
+ while (folder_col.finished == FALSE)
+ gtk_main_iteration();
+
+ gtk_widget_hide(folder_col.window);
+
+ inc_unlock();
+}
+
+static void prefs_folder_column_create(void)
+{
+ GtkWidget *window;
+ GtkWidget *vbox;
+
+ GtkWidget *label_hbox;
+ GtkWidget *label;
+
+ GtkWidget *vbox1;
+
+ GtkWidget *hbox1;
+ GtkWidget *clist_hbox;
+ GtkWidget *scrolledwin;
+ GtkWidget *stock_list_view;
+ GtkWidget *shown_list_view;
+
+ GtkWidget *btn_vbox;
+ GtkWidget *btn_vbox1;
+ GtkWidget *add_btn;
+ GtkWidget *remove_btn;
+ GtkWidget *up_btn;
+ GtkWidget *down_btn;
+
+ GtkWidget *btn_hbox;
+ GtkWidget *default_btn;
+ GtkWidget *confirm_area;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+
+ debug_print("Creating folder column setting window...\n");
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 8);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_window_set_title(GTK_WINDOW(window),
+ _("Displayed items configuration"));
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(prefs_folder_column_delete_event),
+ NULL);
+ g_signal_connect(G_OBJECT(window), "key_press_event",
+ G_CALLBACK(prefs_folder_column_key_pressed),
+ NULL);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+ gtk_widget_show(vbox);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ label_hbox = gtk_hbox_new(FALSE, 0);
+ gtk_widget_show(label_hbox);
+ gtk_box_pack_start(GTK_BOX(vbox), label_hbox, FALSE, FALSE, 4);
+
+ label = gtk_label_new
+ (_("Select items to be displayed in the folder view. You can modify\n"
+ "the order by using the Up / Down buttons or by dragging the items."));
+ gtk_widget_show(label);
+ gtk_box_pack_start(GTK_BOX(label_hbox), label, FALSE, FALSE, 4);
+ gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+
+ vbox1 = gtk_vbox_new(FALSE, VSPACING);
+ gtk_widget_show(vbox1);
+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, TRUE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox1), 2);
+
+ hbox1 = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(hbox1);
+ gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
+
+ clist_hbox = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(clist_hbox);
+ gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
+
+ scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_size_request(scrolledwin, 180, 210);
+ gtk_widget_show(scrolledwin);
+ gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+
+ stock_list_view = prefs_folder_column_list_view_create
+ (_("Available items"));
+ gtk_widget_show(stock_list_view);
+ gtk_container_add(GTK_CONTAINER(scrolledwin), stock_list_view);
+
+ /* add/remove button */
+ btn_vbox = gtk_vbox_new(FALSE, 0);
+ gtk_widget_show(btn_vbox);
+ gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
+
+ btn_vbox1 = gtk_vbox_new(FALSE, 8);
+ gtk_widget_show(btn_vbox1);
+ gtk_box_pack_start(GTK_BOX(btn_vbox), btn_vbox1, TRUE, FALSE, 0);
+
+ add_btn = gtk_button_new_with_label(_(" -> "));
+ gtk_widget_show(add_btn);
+ gtk_box_pack_start(GTK_BOX(btn_vbox1), add_btn, FALSE, FALSE, 0);
+
+ remove_btn = gtk_button_new_with_label(_(" <- "));
+ gtk_widget_show(remove_btn);
+ gtk_box_pack_start(GTK_BOX(btn_vbox1), remove_btn, FALSE, FALSE, 0);
+
+ g_signal_connect(G_OBJECT(add_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_add), NULL);
+ g_signal_connect(G_OBJECT(remove_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_remove), NULL);
+
+ clist_hbox = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(clist_hbox);
+ gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
+
+ scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_size_request(scrolledwin, 180, 210);
+ gtk_widget_show(scrolledwin);
+ gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ shown_list_view = prefs_folder_column_list_view_create
+ (_("Displayed items"));
+ gtk_widget_show(shown_list_view);
+ gtk_container_add(GTK_CONTAINER(scrolledwin), shown_list_view);
+
+ /* up/down button */
+ btn_vbox = gtk_vbox_new(FALSE, 0);
+ gtk_widget_show(btn_vbox);
+ gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
+
+ btn_vbox1 = gtk_vbox_new(FALSE, 8);
+ gtk_widget_show(btn_vbox1);
+ gtk_box_pack_start(GTK_BOX(btn_vbox), btn_vbox1, TRUE, FALSE, 0);
+
+ up_btn = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
+ gtk_widget_show(up_btn);
+ gtk_box_pack_start(GTK_BOX(btn_vbox1), up_btn, FALSE, FALSE, 0);
+
+ down_btn = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
+ gtk_widget_show(down_btn);
+ gtk_box_pack_start(GTK_BOX(btn_vbox1), down_btn, FALSE, FALSE, 0);
+
+ g_signal_connect(G_OBJECT(up_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_up), NULL);
+ g_signal_connect(G_OBJECT(down_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_down), NULL);
+
+ btn_hbox = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(btn_hbox);
+ gtk_box_pack_end(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 0);
+
+ btn_vbox = gtk_vbox_new(FALSE, 0);
+ gtk_widget_show(btn_vbox);
+ gtk_box_pack_start(GTK_BOX(btn_hbox), btn_vbox, FALSE, FALSE, 0);
+
+ default_btn = gtk_button_new_with_label(_(" Use default "));
+ gtk_widget_show(default_btn);
+ gtk_box_pack_start(GTK_BOX(btn_vbox), default_btn, TRUE, FALSE, 0);
+ g_signal_connect(G_OBJECT(default_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_set_to_default),
+ NULL);
+
+ gtkut_stock_button_set_create(&confirm_area, &ok_btn, GTK_STOCK_OK,
+ &cancel_btn, GTK_STOCK_CANCEL,
+ NULL, NULL);
+ gtk_widget_show(confirm_area);
+ gtk_box_pack_end(GTK_BOX(btn_hbox), confirm_area, FALSE, FALSE, 0);
+ gtk_widget_grab_default(ok_btn);
+
+ g_signal_connect(G_OBJECT(ok_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_ok), NULL);
+ g_signal_connect(G_OBJECT(cancel_btn), "clicked",
+ G_CALLBACK(prefs_folder_column_cancel), NULL);
+
+
+ folder_col.window = window;
+ folder_col.add_btn = add_btn;
+ folder_col.remove_btn = remove_btn;
+ folder_col.up_btn = up_btn;
+ folder_col.down_btn = down_btn;
+ folder_col.ok_btn = ok_btn;
+ folder_col.cancel_btn = cancel_btn;
+ folder_col.stock_list_view = stock_list_view;
+ folder_col.shown_list_view = shown_list_view;
+}
+
+FolderColumnState *prefs_folder_column_get_config(void)
+{
+ static FolderColumnState state[N_FOLDER_COLS];
+ FolderColumnType type;
+ gint pos;
+
+ for (pos = 0; pos < N_FOLDER_COLS; pos++)
+ state[pos].type = -1;
+
+ for (type = 0; type < N_FOLDER_COLS; type++) {
+ pos = prefs_common.folder_col_pos[type];
+ if (pos < 0 || pos >= N_FOLDER_COLS ||
+ state[pos].type != -1) {
+ g_warning("Wrong column position\n");
+ prefs_folder_column_set_config(default_state);
+ return default_state;
+ }
+
+ state[pos].type = type;
+ state[pos].visible = prefs_common.folder_col_visible[type];
+ }
+
+ return state;
+}
+
+void prefs_folder_column_set_config(FolderColumnState *state)
+{
+ FolderColumnType type;
+ gint pos;
+
+ for (pos = 0; pos < N_FOLDER_COLS; pos++) {
+ type = state[pos].type;
+ prefs_common.folder_col_visible[type] = state[pos].visible;
+ prefs_common.folder_col_pos[type] = pos;
+ }
+}
+
+static void prefs_folder_column_set_dialog(FolderColumnState *state)
+{
+ GtkListStore *stock_store, *shown_store;
+ gint pos;
+ FolderColumnType type;
+ gchar *name;
+
+ stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.stock_list_view)));
+ shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.shown_list_view)));
+
+ gtk_list_store_clear(stock_store);
+ gtk_list_store_clear(shown_store);
+
+ if (!state)
+ state = prefs_folder_column_get_config();
+
+ for (pos = 0; pos < N_FOLDER_COLS; pos++) {
+ type = state[pos].type;
+ name = gettext(col_name[type]);
+
+ if (state[pos].visible)
+ prefs_folder_column_insert_column(shown_store,
+ -1, name,
+ type);
+ else
+ prefs_folder_column_insert_column(stock_store,
+ -1, name,
+ type);
+ }
+}
+
+static void prefs_folder_column_set_view(void)
+{
+ gint stock_n_rows, shown_n_rows;
+ FolderColumnState state[N_FOLDER_COLS];
+ FolderColumnType type;
+ gint row, pos = 0;
+
+ stock_n_rows = gtk_tree_model_iter_n_children
+ (gtk_tree_view_get_model(GTK_TREE_VIEW
+ (folder_col.stock_list_view)), NULL);
+ shown_n_rows = gtk_tree_model_iter_n_children
+ (gtk_tree_view_get_model(GTK_TREE_VIEW
+ (folder_col.shown_list_view)), NULL);
+
+ g_return_if_fail
+ (stock_n_rows + shown_n_rows == N_FOLDER_COLS);
+
+ for (row = 0; row < stock_n_rows; row++) {
+ type = prefs_folder_column_get_column
+ (folder_col.stock_list_view, row);
+ state[row].type = type;
+ state[row].visible = FALSE;
+ }
+
+ pos = row;
+ for (row = 0; row < shown_n_rows; row++) {
+ type = prefs_folder_column_get_column
+ (folder_col.shown_list_view, row);
+ state[pos + row].type = type;
+ state[pos + row].visible = TRUE;
+ }
+
+ prefs_folder_column_set_config(state);
+ main_window_set_folder_column();
+}
+
+static void prefs_folder_column_add(void)
+{
+ GtkListStore *stock_store, *shown_store;
+ GtkTreeIter stock_sel, shown_sel, shown_add;
+ gboolean shown_sel_valid;
+ gchar *name;
+ FolderColumnType type;
+
+ stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.stock_list_view)));
+ shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.shown_list_view)));
+
+ if (!gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.stock_list_view)),
+ NULL,
+ &stock_sel))
+ return;
+
+ shown_sel_valid = gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.shown_list_view)),
+ NULL,
+ &shown_sel);
+
+ gtk_tree_model_get(GTK_TREE_MODEL(stock_store), &stock_sel,
+ SUMCOL_TYPE, &type,
+ -1);
+
+ gtk_list_store_remove(stock_store, &stock_sel);
+
+ gtk_list_store_insert_after(shown_store, &shown_add,
+ shown_sel_valid ? &shown_sel : NULL);
+
+ name = gettext(col_name[type]);
+
+ gtk_list_store_set(shown_store, &shown_add,
+ SUMCOL_NAME, name,
+ SUMCOL_TYPE, type,
+ -1);
+
+ gtk_tree_selection_select_iter(gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.shown_list_view)),
+ &shown_add);
+}
+
+static void prefs_folder_column_remove(void)
+{
+ GtkListStore *stock_store, *shown_store;
+ GtkTreeIter shown_sel, stock_sel, stock_add;
+ gboolean stock_sel_valid;
+ gchar *name;
+ FolderColumnType type;
+
+ stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.stock_list_view)));
+ shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.shown_list_view)));
+
+ if (!gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.shown_list_view)),
+ NULL,
+ &shown_sel))
+ return;
+
+ stock_sel_valid = gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.stock_list_view)),
+ NULL,
+ &stock_sel);
+
+ gtk_tree_model_get(GTK_TREE_MODEL(shown_store), &shown_sel,
+ SUMCOL_TYPE, &type,
+ -1);
+
+ gtk_list_store_remove(shown_store, &shown_sel);
+
+ gtk_list_store_insert_after(stock_store, &stock_add,
+ stock_sel_valid ? &stock_sel : NULL);
+
+ name = gettext(col_name[type]);
+
+ gtk_list_store_set(stock_store, &stock_add,
+ SUMCOL_NAME, name,
+ SUMCOL_TYPE, type,
+ -1);
+
+ gtk_tree_selection_select_iter(gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.stock_list_view)),
+ &stock_add);
+}
+
+static void prefs_folder_column_up(void)
+{
+ GtkTreePath *prev, *sel;
+ GtkTreeIter isel;
+ GtkListStore *shown_store;
+ GtkTreeIter iprev;
+
+ if (!gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.shown_list_view)),
+ NULL,
+ &isel))
+ return;
+
+ shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.shown_list_view)));
+
+ sel = gtk_tree_model_get_path(GTK_TREE_MODEL(shown_store),
+ &isel);
+ if (!sel)
+ return;
+
+ prev = gtk_tree_path_copy(sel);
+ if (!gtk_tree_path_prev(prev)) {
+ gtk_tree_path_free(prev);
+ gtk_tree_path_free(sel);
+ return;
+ }
+
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(shown_store),
+ &iprev, prev);
+ gtk_tree_path_free(sel);
+ gtk_tree_path_free(prev);
+
+ gtk_list_store_swap(shown_store, &iprev, &isel);
+}
+
+static void prefs_folder_column_down(void)
+{
+ GtkListStore *shown_store;
+ GtkTreeIter next, sel;
+
+ if (!gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(folder_col.shown_list_view)),
+ NULL,
+ &sel))
+ return;
+
+ shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(folder_col.shown_list_view)));
+
+ next = sel;
+ if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(shown_store), &next))
+ return;
+
+ gtk_list_store_swap(shown_store, &next, &sel);
+}
+
+static void prefs_folder_column_set_to_default(void)
+{
+ prefs_folder_column_set_dialog(default_state);
+}
+
+static void prefs_folder_column_ok(void)
+{
+ if (!folder_col.finished) {
+ folder_col.finished = TRUE;
+ prefs_folder_column_set_view();
+ }
+}
+
+static void prefs_folder_column_cancel(void)
+{
+ folder_col.finished = TRUE;
+}
+
+static gint prefs_folder_column_delete_event(GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer data)
+{
+ folder_col.finished = TRUE;
+ return TRUE;
+}
+
+static gboolean prefs_folder_column_key_pressed(GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data)
+{
+ if (event && event->keyval == GDK_Escape)
+ folder_col.finished = TRUE;
+ return FALSE;
+}
+
+static GtkListStore *prefs_folder_column_create_store(void)
+{
+ return gtk_list_store_new(N_SUMCOL_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_INT,
+ -1);
+}
+
+static void prefs_folder_column_insert_column(GtkListStore *store,
+ gint row,
+ const gchar *name,
+ FolderColumnType type)
+{
+ GtkTreeIter iter;
+
+ if (row >= 0) {
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store),
+ &iter, NULL, row))
+ row = -1;
+ }
+ if (row < 0) {
+ /* add new */
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter,
+ SUMCOL_NAME, name,
+ SUMCOL_TYPE, type,
+ -1);
+ return;
+ } else {
+ /* change existing */
+ gtk_list_store_set(store, &iter,
+ SUMCOL_NAME, name,
+ SUMCOL_TYPE, type,
+ -1);
+ }
+}
+
+/*!
+ *\brief Return the columnn type for a row
+ */
+static FolderColumnType prefs_folder_column_get_column(GtkWidget *list, gint row)
+{
+ GtkTreeView *list_view = GTK_TREE_VIEW(list);
+ GtkTreeModel *model = gtk_tree_view_get_model(list_view);
+ GtkTreeIter iter;
+ FolderColumnType result;
+
+ if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
+ return -1;
+
+ gtk_tree_model_get(model, &iter,
+ SUMCOL_TYPE, &result,
+ -1);
+
+ return result;
+}
+
+static GtkWidget *prefs_folder_column_list_view_create(const gchar *name)
+{
+ GtkWidget *list_view;
+ GtkTreeSelection *selector;
+ GtkTreeModel *model;
+
+ model = GTK_TREE_MODEL(prefs_folder_column_create_store());
+ list_view = gtk_tree_view_new_with_model(model);
+ g_object_unref(G_OBJECT(model));
+
+ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(list_view),
+ prefs_common.enable_rules_hint);
+
+ selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+ gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+
+ prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view), name);
+
+ gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(list_view),
+ GDK_BUTTON1_MASK,
+ row_targets,
+ G_N_ELEMENTS(row_targets),
+ GDK_ACTION_MOVE);
+
+ gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(list_view),
+ row_targets,
+ G_N_ELEMENTS(row_targets),
+ GDK_ACTION_MOVE);
+
+ g_signal_connect(G_OBJECT(list_view), "drag_data_get",
+ G_CALLBACK(drag_data_get),
+ model);
+
+ g_signal_connect(G_OBJECT(list_view), "drag_data_received",
+ G_CALLBACK(drag_data_received),
+ model);
+
+ return list_view;
+}
+
+static void prefs_filtering_create_list_view_columns(GtkWidget *list_view,
+ const gchar *name)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes
+ (name, renderer, "text", SUMCOL_NAME, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
+}
+
+static void drag_data_get(GtkTreeView *tree_view, GdkDragContext *context,
+ GtkSelectionData *data, guint info,
+ guint time, GtkTreeModel *model)
+{
+ GtkTreeIter iter;
+ FolderColumnType type;
+ GtkTreeModel *source_model;
+
+ if (info != TARGET_INFO_SUMCOL)
+ return;
+
+ if (!gtk_tree_selection_get_selected
+ (gtk_tree_view_get_selection(tree_view),
+ &source_model, &iter))
+ return;
+
+ gtk_tree_model_get(source_model, &iter,
+ SUMCOL_TYPE, &type,
+ -1);
+
+ /* send the type */
+ gtk_selection_data_set(data, data->target, 8, (gchar *) &type, sizeof type);
+}
+
+static void drag_data_received(GtkTreeView *tree_view, GdkDragContext *context,
+ gint x, gint y, GtkSelectionData *data,
+ guint info, guint time, GtkTreeModel *model)
+{
+ GtkWidget *source;
+ GtkTreePath *dst = NULL, *sel = NULL;
+ GtkTreeIter isel, idst;
+ GtkTreeViewDropPosition pos;
+ FolderColumnType type;
+ GtkTreeModel *sel_model;
+ gchar *name;
+
+ source = gtk_drag_get_source_widget(context);
+
+ if (source == GTK_WIDGET(tree_view)) {
+
+ /*
+ * Same widget: re-order
+ */
+
+ gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree_view),
+ NULL, &isel);
+ sel = gtk_tree_model_get_path(model, &isel);
+ gtk_tree_view_get_dest_row_at_pos(tree_view, x, y,
+ &dst, &pos);
+
+ /* NOTE: dst is invalid if selection beyond last row, in that
+ * case move beyond last one (XXX_move_before(..., NULL)) */
+
+ if (dst)
+ gtk_tree_model_get_iter(model, &idst, dst);
+ else
+ gtk_list_store_move_before(GTK_LIST_STORE(model),
+ &isel,
+ NULL);
+
+ /* we do not drag if no valid dst and sel, and when
+ * dst and sel are the same (moving after or before
+ * itself doesn't change order...) */
+ if ((dst && sel) && gtk_tree_path_compare(sel, dst) != 0) {
+ if (pos == GTK_TREE_VIEW_DROP_BEFORE
+ || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
+ gtk_list_store_move_before(GTK_LIST_STORE(model),
+ &isel,
+ &idst);
+ else
+ gtk_list_store_move_after(GTK_LIST_STORE(model),
+ &isel,
+ &idst);
+
+ }
+ gtk_tree_path_free(dst);
+ gtk_tree_path_free(sel);
+ gtk_drag_finish(context, TRUE, FALSE, time);
+
+ } else if (source == folder_col.stock_list_view
+ || source == folder_col.shown_list_view) {
+
+ /*
+ * Other widget: change and update
+ */
+
+
+ /* get source information and remove */
+ gtk_tree_selection_get_selected(gtk_tree_view_get_selection(
+ GTK_TREE_VIEW(source)),
+ &sel_model, &isel);
+ type = *((gint *) data->data);
+ name = gettext(col_name[type]);
+ gtk_list_store_remove(GTK_LIST_STORE(sel_model), &isel);
+
+ /* get insertion position */
+ gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, &dst, &pos);
+
+ /* NOTE: dst is invalid if insertion point beyond last row,
+ * just append to list in that case (XXX_store_append()) */
+
+ if (dst) {
+ gtk_tree_model_get_iter(model, &idst, dst);
+
+ if (pos == GTK_TREE_VIEW_DROP_BEFORE
+ || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
+ gtk_list_store_insert_before(GTK_LIST_STORE(model),
+ &isel,
+ &idst);
+ else
+ gtk_list_store_insert_after(GTK_LIST_STORE(model),
+ &isel,
+ &idst);
+ } else
+ gtk_list_store_append(GTK_LIST_STORE(model),
+ &isel);
+
+ gtk_list_store_set(GTK_LIST_STORE(model), &isel,
+ SUMCOL_NAME, name,
+ SUMCOL_TYPE, type, -1);
+ gtk_tree_path_free(dst);
+ gtk_drag_finish(context, TRUE, FALSE, time);
+ }
+
+ /* XXXX: should we call gtk_drag_finish() for other code paths? */
+}
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2005 Hiroyuki Yamamoto & the Sylpheed-Claws team
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 __PREFS_FOLDER_COLUMN_H__
+#define __PREFS_FOLDER_COLUMN_H__
+
+#include "folderview.h"
+
+void prefs_folder_column_open(void);
+
+FolderColumnState *prefs_folder_column_get_config(void);
+void prefs_folder_column_set_config(FolderColumnState *state);
+
+#endif /* __PREFS_FOLDER_COLUMN_H__ */
#include "prefs_common.h"
#include "prefs_gtk.h"
#include "prefs_summary_column.h"
+#include "prefs_folder_column.h"
#include "gtk/menu.h"
#include "gtk/gtkutils.h"
GtkWidget *chkbtn_transhdr;
GtkWidget *chkbtn_folder_unread;
GtkWidget *spinbtn_ng_abbrev_len;
- GtkWidget *chkbtn_swapfrom;
GtkWidget *chkbtn_useaddrbook;
GtkWidget *chkbtn_threadsubj;
GtkWidget *button_datefmt;
GtkWidget *label_ng_abbrev;
GtkWidget *spinbtn_ng_abbrev_len;
GtkObject *spinbtn_ng_abbrev_len_adj;
- GtkWidget *frame_summary;
GtkWidget *vbox2;
- GtkWidget *chkbtn_swapfrom;
GtkWidget *chkbtn_useaddrbook;
GtkWidget *chkbtn_threadsubj;
GtkWidget *vbox3;
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_ng_abbrev_len),
TRUE);
- label_ng_abbrev = gtk_label_new
- (_("letters"));
+ label_ng_abbrev = gtk_label_new (_("letters"));
gtk_widget_show (label_ng_abbrev);
gtk_box_pack_start (GTK_BOX (hbox1), label_ng_abbrev, FALSE, FALSE, 0);
/* ---- Summary ---- */
- PACK_FRAME(vbox1, frame_summary, _("Summary View"));
-
vbox2 = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox2);
- gtk_container_add (GTK_CONTAINER (frame_summary), vbox2);
- gtk_container_set_border_width (GTK_CONTAINER (vbox2), 8);
+ gtk_container_add (GTK_CONTAINER (vbox1), vbox2);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox2), 0);
- PACK_CHECK_BUTTON
- (vbox2, chkbtn_swapfrom,
- _("Display recipient in 'From' column if sender is yourself"));
PACK_CHECK_BUTTON
(vbox2, chkbtn_useaddrbook,
_("Display sender using address book"));
G_CALLBACK (prefs_summary_column_open),
NULL);
+ button_dispitem = gtk_button_new_with_label
+ (_(" Set displayed items in folder view... "));
+ gtk_widget_show (button_dispitem);
+ gtk_box_pack_start (GTK_BOX (hbox1), button_dispitem, FALSE, TRUE, 0);
+ g_signal_connect (G_OBJECT (button_dispitem), "clicked",
+ G_CALLBACK (prefs_folder_column_open),
+ NULL);
+
vbox2 = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox2);
gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0);
prefs_common.trans_hdr);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_folder_unread),
prefs_common.display_folder_unread);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_swapfrom),
- prefs_common.swap_from);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_useaddrbook),
prefs_common.use_addr_book);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_threadsubj),
prefs_summaries->chkbtn_transhdr = chkbtn_transhdr;
prefs_summaries->chkbtn_folder_unread = chkbtn_folder_unread;
prefs_summaries->spinbtn_ng_abbrev_len = spinbtn_ng_abbrev_len;
- prefs_summaries->chkbtn_swapfrom = chkbtn_swapfrom;
prefs_summaries->chkbtn_useaddrbook = chkbtn_useaddrbook;
prefs_summaries->chkbtn_threadsubj = chkbtn_threadsubj;
prefs_summaries->entry_datefmt = entry_datefmt;
GTK_TOGGLE_BUTTON(page->chkbtn_transhdr));
prefs_common.display_folder_unread = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->chkbtn_folder_unread));
- prefs_common.swap_from = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(page->chkbtn_swapfrom));
prefs_common.use_addr_book = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->chkbtn_useaddrbook));
prefs_common.thread_by_subject = gtk_toggle_button_get_active(
N_("Attachment"), /* S_COL_MIME */
N_("Subject"), /* S_COL_SUBJECT */
N_("From"), /* S_COL_FROM */
+ N_("To"), /* S_COL_TO */
N_("Date"), /* S_COL_DATE */
N_("Size"), /* S_COL_SIZE */
N_("Number"), /* S_COL_NUMBER */
{ S_COL_MIME , TRUE },
{ S_COL_SUBJECT, TRUE },
{ S_COL_FROM , TRUE },
+ { S_COL_TO , FALSE },
{ S_COL_DATE , TRUE },
{ S_COL_SIZE , TRUE },
{ S_COL_NUMBER , FALSE },
{ S_COL_SCORE , FALSE },
- { S_COL_LOCKED , FALSE },
+ { S_COL_LOCKED , FALSE },
};
static void prefs_summary_column_create (void);
SummaryView *summaryview);
static void summary_from_clicked (GtkWidget *button,
SummaryView *summaryview);
+static void summary_to_clicked (GtkWidget *button,
+ SummaryView *summaryview);
static void summary_subject_clicked (GtkWidget *button,
SummaryView *summaryview);
static void summary_score_clicked (GtkWidget *button,
"", /* S_COL_MIME */
N_("Subject"), /* S_COL_SUBJECT */
N_("From"), /* S_COL_FROM */
+ N_("To"), /* S_COL_TO */
N_("Date"), /* S_COL_DATE */
N_("Size"), /* S_COL_SIZE */
N_("No."), /* S_COL_NUMBER */
SORT_BY_MIME,
SORT_BY_SUBJECT,
SORT_BY_FROM,
+ SORT_BY_TO,
SORT_BY_DATE,
SORT_BY_SIZE,
SORT_BY_NUMBER,
switch (type) {
case S_COL_SUBJECT:
case S_COL_FROM:
+ case S_COL_TO:
case S_COL_DATE:
case S_COL_NUMBER:
if (prefs_common.trans_hdr)
GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
GtkCList *clist = GTK_CLIST(summaryview->ctree);
GtkCListCompareFunc cmp_func = NULL;
+ g_signal_handlers_block_by_func(G_OBJECT(summaryview->ctree),
+ G_CALLBACK(summary_tree_expanded), summaryview);
+ gtk_clist_freeze(GTK_CLIST(summaryview->ctree));
switch (sort_key) {
case SORT_BY_MARK:
case SORT_BY_NONE:
break;
default:
- return;
+ goto unlock;
}
summaryview->sort_key = sort_key;
/* allow fallback to don't sort */
if (summaryview->sort_key == SORT_BY_NONE)
- return;
+ goto unlock;
if (cmp_func != NULL) {
debug_print("Sorting summary...");
debug_print("done.\n");
STATUSBAR_POP(summaryview->mainwin);
}
+unlock:
+ gtk_clist_thaw(GTK_CLIST(summaryview->ctree));
+ g_signal_handlers_unblock_by_func(G_OBJECT(summaryview->ctree),
+ G_CALLBACK(summary_tree_expanded), summaryview);
}
gboolean summary_insert_gnode_func(GtkCTree *ctree, guint depth, GNode *gnode,
SET_TEXT(S_COL_SIZE);
SET_TEXT(S_COL_DATE);
SET_TEXT(S_COL_FROM);
+ SET_TEXT(S_COL_TO);
SET_TEXT(S_COL_SUBJECT);
#undef SET_TEXT
END_TIMING();
}
-static gchar *summary_complete_address(const gchar *addr)
-{
- gint count;
- gchar *res, *tmp, *email_addr;
-
- Xstrdup_a(email_addr, addr, return NULL);
- extract_address(email_addr);
- g_return_val_if_fail(*email_addr, NULL);
-
- /*
- * completion stuff must be already initialized
- */
- res = NULL;
- if (1 < (count = complete_address(email_addr))) {
- tmp = get_complete_address(1);
-/* tmp = addressbook_lookup_name( email_addr );
- if( tmp ) { */
- res = procheader_get_fromname(tmp);
- g_free(tmp);
- }
-
- return res;
-}
-
static void summary_set_header(SummaryView *summaryview, gchar *text[],
MsgInfo *msginfo)
{
static gchar date_modified[80];
- static gchar *to = NULL;
static gchar col_score[11];
static gchar buf[BUFFSIZE];
gint *col_pos = summaryview->col_pos;
text[col_pos[S_COL_FROM]] = msginfo->fromname ? msginfo->fromname :
_("(No From)");
+ text[col_pos[S_COL_TO]] = msginfo->to ? msginfo->to :
+ _("(No Recipient)");
if (msginfo->folder && msginfo->folder->folder)
ftype = msginfo->folder->folder->klass->type;
- if (ftype != F_NEWS && prefs_common.swap_from && msginfo->from && msginfo->to) {
- gchar *addr = NULL;
-
- Xstrdup_a(addr, msginfo->from, return);
- extract_address(addr);
- if (prefs_common.use_addr_book) {
- if (account_find_from_address(addr)) {
- addr = summary_complete_address(msginfo->to);
- g_free(to);
- to = g_strconcat("-->", addr == NULL ? msginfo->to : addr, NULL);
- text[col_pos[S_COL_FROM]] = to;
- g_free(addr);
- }
- } else {
- if (account_find_from_address(addr)) {
- g_free(to);
- to = g_strconcat("-->", msginfo->to, NULL);
- text[col_pos[S_COL_FROM]] = to;
- }
- }
- }
-
- /*
- * CLAWS: note that the "text[col_pos[S_COL_FROM]] != to" is really a hack,
- * checking whether the above block (which handles the special case of
- * the --> in sent boxes) was executed.
- */
- if (text[col_pos[S_COL_FROM]] != to && prefs_common.use_addr_book && msginfo->from) {
- gchar *from = summary_complete_address(msginfo->from);
- if (from) {
- g_free(to);
- to = from;
- text[col_pos[S_COL_FROM]] = to;
- }
- }
-
if (summaryview->simplify_subject_preg != NULL)
text[col_pos[S_COL_SUBJECT]] = msginfo->subject ?
string_remove_match(buf, BUFFSIZE, msginfo->subject,
prefs_common.summary_col_size[S_COL_SUBJECT]);
gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_FROM],
prefs_common.summary_col_size[S_COL_FROM]);
+ gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_TO],
+ prefs_common.summary_col_size[S_COL_TO]);
gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_DATE],
prefs_common.summary_col_size[S_COL_DATE]);
gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[S_COL_SIZE],
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SIZE , summary_size_clicked);
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_DATE , summary_date_clicked);
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_FROM , summary_from_clicked);
+ CLIST_BUTTON_SIGNAL_CONNECT(S_COL_TO , summary_to_clicked);
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SUBJECT, summary_subject_clicked);
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SCORE, summary_score_clicked);
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_LOCKED, summary_locked_clicked);
{
GtkCTreeNode *node = NULL;
START_TIMING("summary_sort_by_column_click");
- g_signal_handlers_block_by_func(G_OBJECT(summaryview->ctree),
- G_CALLBACK(summary_tree_expanded), summaryview);
- gtk_clist_freeze(GTK_CLIST(summaryview->ctree));
if (summaryview->sort_key == sort_key)
summary_sort(summaryview, sort_key,
summaryview->sort_type == SORT_ASCENDING
else
summary_sort(summaryview, sort_key, SORT_ASCENDING);
- gtk_clist_thaw(GTK_CLIST(summaryview->ctree));
- g_signal_handlers_unblock_by_func(G_OBJECT(summaryview->ctree),
- G_CALLBACK(summary_tree_expanded), summaryview);
-
node = GTK_CTREE_NODE(GTK_CLIST(summaryview->ctree)->row_list);
while (prefs_common.bold_unread && node) {
summary_sort_by_column_click(summaryview, SORT_BY_FROM);
}
+static void summary_to_clicked(GtkWidget *button, SummaryView *summaryview)
+{
+ summary_sort_by_column_click(summaryview, SORT_BY_TO);
+}
+
static void summary_subject_clicked(GtkWidget *button,
SummaryView *summaryview)
{
CMP_FUNC_DEF(summary_cmp_by_size, msginfo1->size - msginfo2->size)
CMP_FUNC_DEF(summary_cmp_by_date, msginfo1->date_t - msginfo2->date_t)
-#undef CMP_FUNC_DEF
-#define CMP_FUNC_DEF(func_name, var_name) \
-static gint func_name(GtkCList *clist, \
- gconstpointer ptr1, gconstpointer ptr2) \
-{ \
- MsgInfo *msginfo1 = ((GtkCListRow *)ptr1)->data; \
- MsgInfo *msginfo2 = ((GtkCListRow *)ptr2)->data; \
- \
- if (!msginfo1->var_name) \
- return (msginfo2->var_name != NULL); \
- if (!msginfo2->var_name) \
- return -1; \
- \
- return g_utf8_collate(msginfo1->var_name, msginfo2->var_name); \
-}
-
-CMP_FUNC_DEF(summary_cmp_by_to, to);
-
#undef CMP_FUNC_DEF
static gint summary_cmp_by_subject(GtkCList *clist,
return g_utf8_collate(str1, str2);
}
+static gint summary_cmp_by_to(GtkCList *clist, gconstpointer ptr1,
+ gconstpointer ptr2)
+{
+ const gchar *str1, *str2;
+ const GtkCListRow *r1 = (const GtkCListRow *) ptr1;
+ const GtkCListRow *r2 = (const GtkCListRow *) ptr2;
+ const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
+
+ g_return_val_if_fail(sv, -1);
+
+ str1 = GTK_CELL_TEXT(r1->cell[sv->col_pos[S_COL_TO]])->text;
+ str2 = GTK_CELL_TEXT(r2->cell[sv->col_pos[S_COL_TO]])->text;
+
+ if (!str1)
+ return str2 != NULL;
+
+ if (!str2)
+ return -1;
+
+ return g_utf8_collate(str1, str2);
+}
+
static gint summary_cmp_by_simplified_subject
(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
{
S_COL_MIME,
S_COL_SUBJECT,
S_COL_FROM,
+ S_COL_TO,
S_COL_DATE,
S_COL_SIZE,
S_COL_NUMBER,
S_COL_LOCKED
} SummaryColumnType;
-#define N_SUMMARY_COLS 10
+#define N_SUMMARY_COLS 11
typedef enum
{
ertf_parser_destroy(parser);
}
-/* get_uri_part() - retrieves a URI starting from scanpos.
- Returns TRUE if succesful */
-static gboolean get_uri_part(const gchar *start, const gchar *scanpos,
- const gchar **bp, const gchar **ep)
-{
- const gchar *ep_;
-
- g_return_val_if_fail(start != NULL, FALSE);
- g_return_val_if_fail(scanpos != NULL, FALSE);
- g_return_val_if_fail(bp != NULL, FALSE);
- g_return_val_if_fail(ep != NULL, FALSE);
-
- *bp = scanpos;
-
- /* find end point of URI */
- for (ep_ = scanpos; *ep_ != '\0'; ep_++) {
- if (!isgraph(*(const guchar *)ep_) ||
- !IS_ASCII(*(const guchar *)ep_) ||
- strchr("[]{}()<>\"", *ep_))
- break;
- }
-
- /* no punctuation at end of string */
-
- /* FIXME: this stripping of trailing punctuations may bite with other URIs.
- * should pass some URI type to this function and decide on that whether
- * to perform punctuation stripping */
-
-#define IS_REAL_PUNCT(ch) (ispunct(ch) && ((ch) != '/'))
-
- for (; ep_ - 1 > scanpos + 1 &&
- IS_REAL_PUNCT(*(const guchar *)(ep_ - 1));
- ep_--)
- ;
-
-#undef IS_REAL_PUNCT
-
- *ep = ep_;
-
- return TRUE;
-}
-
-static gchar *make_uri_string(const gchar *bp, const gchar *ep)
-{
- return g_strndup(bp, ep - bp);
-}
-
-/* valid mail address characters */
-#define IS_RFC822_CHAR(ch) \
- (IS_ASCII(ch) && \
- (ch) > 32 && \
- (ch) != 127 && \
- !g_ascii_isspace(ch) && \
- !strchr("(),;<>\"", (ch)))
-
-/* alphabet and number within 7bit ASCII */
-#define IS_ASCII_ALNUM(ch) (IS_ASCII(ch) && g_ascii_isalnum(ch))
-#define IS_QUOTE(ch) ((ch) == '\'' || (ch) == '"')
-
-static GHashTable *create_domain_tab(void)
-{
- static const gchar *toplvl_domains [] = {
- "museum", "aero",
- "arpa", "coop", "info", "name", "biz", "com", "edu", "gov",
- "int", "mil", "net", "org", "ac", "ad", "ae", "af", "ag",
- "ai", "al", "am", "an", "ao", "aq", "ar", "as", "at", "au",
- "aw", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi",
- "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by",
- "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl",
- "cm", "cn", "co", "cr", "cu", "cv", "cx", "cy", "cz", "de",
- "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er",
- "es", "et", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gd",
- "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq",
- "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr",
- "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir",
- "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki",
- "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc",
- "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc",
- "md", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq",
- "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na",
- "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu",
- "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm",
- "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "ru",
- "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sj",
- "sk", "sl", "sm", "sn", "so", "sr", "st", "sv", "sy", "sz",
- "tc", "td", "tf", "tg", "th", "tj", "tk", "tm", "tn", "to",
- "tp", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um",
- "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu",
- "wf", "ws", "ye", "yt", "yu", "za", "zm", "zw"
- };
- gint n;
- GHashTable *htab = g_hash_table_new(g_stricase_hash, g_stricase_equal);
-
- g_return_val_if_fail(htab, NULL);
- for (n = 0; n < sizeof toplvl_domains / sizeof toplvl_domains[0]; n++)
- g_hash_table_insert(htab, (gpointer) toplvl_domains[n], (gpointer) toplvl_domains[n]);
- return htab;
-}
-
-static gboolean is_toplvl_domain(GHashTable *tab, const gchar *first, const gchar *last)
-{
- const gint MAX_LVL_DOM_NAME_LEN = 6;
- gchar buf[MAX_LVL_DOM_NAME_LEN + 1];
- const gchar *m = buf + MAX_LVL_DOM_NAME_LEN + 1;
- register gchar *p;
-
- if (last - first > MAX_LVL_DOM_NAME_LEN || first > last)
- return FALSE;
-
- for (p = buf; p < m && first < last; *p++ = *first++)
- ;
- *p = 0;
-
- return g_hash_table_lookup(tab, buf) != NULL;
-}
-
-/* get_email_part() - retrieves an email address. Returns TRUE if succesful */
-static gboolean get_email_part(const gchar *start, const gchar *scanpos,
- const gchar **bp, const gchar **ep)
-{
- /* more complex than the uri part because we need to scan back and forward starting from
- * the scan position. */
- gboolean result = FALSE;
- const gchar *bp_ = NULL;
- const gchar *ep_ = NULL;
- static GHashTable *dom_tab;
- const gchar *last_dot = NULL;
- const gchar *prelast_dot = NULL;
- const gchar *last_tld_char = NULL;
-
- /* the informative part of the email address (describing the name
- * of the email address owner) may contain quoted parts. the
- * closure stack stores the last encountered quotes. */
- gchar closure_stack[128];
- gchar *ptr = closure_stack;
-
- g_return_val_if_fail(start != NULL, FALSE);
- g_return_val_if_fail(scanpos != NULL, FALSE);
- g_return_val_if_fail(bp != NULL, FALSE);
- g_return_val_if_fail(ep != NULL, FALSE);
-
- if (!dom_tab)
- dom_tab = create_domain_tab();
- g_return_val_if_fail(dom_tab, FALSE);
-
- /* scan start of address */
- for (bp_ = scanpos - 1;
- bp_ >= start && IS_RFC822_CHAR(*(const guchar *)bp_); bp_--)
- ;
-
- /* TODO: should start with an alnum? */
- bp_++;
- for (; bp_ < scanpos && !IS_ASCII_ALNUM(*(const guchar *)bp_); bp_++)
- ;
-
- if (bp_ != scanpos) {
- /* scan end of address */
- for (ep_ = scanpos + 1;
- *ep_ && IS_RFC822_CHAR(*(const guchar *)ep_); ep_++)
- if (*ep_ == '.') {
- prelast_dot = last_dot;
- last_dot = ep_;
- if (*(last_dot + 1) == '.') {
- if (prelast_dot == NULL)
- return FALSE;
- last_dot = prelast_dot;
- break;
- }
- }
-
- /* TODO: really should terminate with an alnum? */
- for (; ep_ > scanpos && !IS_ASCII_ALNUM(*(const guchar *)ep_);
- --ep_)
- ;
- ep_++;
-
- if (last_dot == NULL)
- return FALSE;
- if (last_dot >= ep_)
- last_dot = prelast_dot;
- if (last_dot == NULL || (scanpos + 1 >= last_dot))
- return FALSE;
- last_dot++;
-
- for (last_tld_char = last_dot; last_tld_char < ep_; last_tld_char++)
- if (*last_tld_char == '?')
- break;
-
- if (is_toplvl_domain(dom_tab, last_dot, last_tld_char))
- result = TRUE;
-
- *ep = ep_;
- *bp = bp_;
- }
-
- if (!result) return FALSE;
-
- if (*ep_ && *(bp_ - 1) == '"' && *(ep_) == '"'
- && *(ep_ + 1) == ' ' && *(ep_ + 2) == '<'
- && IS_RFC822_CHAR(*(ep_ + 3))) {
- /* this informative part with an @ in it is
- * followed by the email address */
- ep_ += 3;
-
- /* go to matching '>' (or next non-rfc822 char, like \n) */
- for (; *ep_ != '>' && *ep != '\0' && IS_RFC822_CHAR(*ep_); ep_++)
- ;
-
- /* include the bracket */
- if (*ep_ == '>') ep_++;
-
- /* include the leading quote */
- bp_--;
-
- *ep = ep_;
- *bp = bp_;
- return TRUE;
- }
-
- /* skip if it's between quotes "'alfons@proteus.demon.nl'" <alfons@proteus.demon.nl> */
- if (bp_ - 1 > start && IS_QUOTE(*(bp_ - 1)) && IS_QUOTE(*ep_))
- return FALSE;
-
- /* see if this is <bracketed>; in this case we also scan for the informative part. */
- if (bp_ - 1 <= start || *(bp_ - 1) != '<' || *ep_ != '>')
- return TRUE;
-
-#define FULL_STACK() ((size_t) (ptr - closure_stack) >= sizeof closure_stack)
-#define IN_STACK() (ptr > closure_stack)
-/* has underrun check */
-#define POP_STACK() if(IN_STACK()) --ptr
-/* has overrun check */
-#define PUSH_STACK(c) if(!FULL_STACK()) *ptr++ = (c); else return TRUE
-/* has underrun check */
-#define PEEK_STACK() (IN_STACK() ? *(ptr - 1) : 0)
-
- ep_++;
-
- /* scan for the informative part. */
- for (bp_ -= 2; bp_ >= start; bp_--) {
- /* if closure on the stack keep scanning */
- if (PEEK_STACK() == *bp_) {
- POP_STACK();
- continue;
- }
- if (*bp_ == '\'' || *bp_ == '"') {
- PUSH_STACK(*bp_);
- continue;
- }
-
- /* if nothing in the closure stack, do the special conditions
- * the following if..else expression simply checks whether
- * a token is acceptable. if not acceptable, the clause
- * should terminate the loop with a 'break' */
- if (!PEEK_STACK()) {
- if (*bp_ == '-'
- && (((bp_ - 1) >= start) && isalnum(*(bp_ - 1)))
- && (((bp_ + 1) < ep_) && isalnum(*(bp_ + 1)))) {
- /* hyphens are allowed, but only in
- between alnums */
- } else if (!strchr(",;:=?./+<>!&\r\n\t", *bp_)) {
- /* but anything not being a punctiation
- is ok */
- } else {
- break; /* anything else is rejected */
- }
- }
- }
-
- bp_++;
-
-#undef PEEK_STACK
-#undef PUSH_STACK
-#undef POP_STACK
-#undef IN_STACK
-#undef FULL_STACK
-
- /* scan forward (should start with an alnum) */
- for (; *bp_ != '<' && isspace(*bp_) && *bp_ != '"'; bp_++)
- ;
-
- *ep = ep_;
- *bp = bp_;
-
- return result;
-}
-
-#undef IS_QUOTE
-#undef IS_ASCII_ALNUM
-#undef IS_RFC822_CHAR
-
-static gchar *make_email_string(const gchar *bp, const gchar *ep)
-{
- /* returns a mailto: URI; mailto: is also used to detect the
- * uri type later on in the button_pressed signal handler */
- gchar *tmp;
- gchar *result;
-
- tmp = g_strndup(bp, ep - bp);
- result = g_strconcat("mailto:", tmp, NULL);
- g_free(tmp);
-
- return result;
-}
-
-static gchar *make_http_string(const gchar *bp, const gchar *ep)
-{
- /* returns an http: URI; */
- gchar *tmp;
- gchar *result;
-
- tmp = g_strndup(bp, ep - bp);
- result = g_strconcat("http://", tmp, NULL);
- g_free(tmp);
-
- return result;
-}
-
#define ADD_TXT_POS(bp_, ep_, pti_) \
if ((last->next = alloca(sizeof(struct txtpos))) != NULL) { \
last = last->next; \