/*
* grn_nglist.c: newsgroups window
*
* $Id: grn_nglist.c,v 1.38 2000/06/28 11:28:28 sc Exp $
*/
/* Copyright (C) 1999-2000 Sergey Chernikov (sc@ivvs.ul.ru)
*
* Authors: Sergey Chernikov <sc@ivvs.ul.ru>
*
* 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
*/
#include "grn_consts.h"
#include <gnome.h>
#include <regex.h>
#include "grn_nglist.h"
#include "grn_menu.h"
#include "grn_vars.h"
#include "grn_util.h"
#include "grn_threadlist.h"
#include "grn_news.h"
#include "grn_config.h"
#include "queue.h"
#include "nntp.h"
#include "grn_misc.h"
#include "grn_commands.h"
#define NCOLS 5
static gint evt_ng_btnpress(GtkWidget *, GdkEventButton *, gpointer);
static gint evt_ng_keypress(GtkWidget *, GdkEventKey *, gpointer);
static gint evt_fg_keypress(GtkWidget *, GdkEventKey *, gpointer);
static void evt_ng_delete(GtkWidget *, gpointer);
static void evt_ng_hide(GtkWidget *, gpointer);
static void evt_ng_show(GtkWidget *, gpointer);
static void evt_click_col(GtkCList *, int);
static void en_find_changed(GtkWidget *, GtkWidget *);
static void en_find_activate(GtkWidget *, GtkWidget *);
static void ng_list_sort(GtkCList *);
static gboolean add_group(GtkCList *clist, grn_newsgroup *grp, gboolean flag)
{
GdkPixmap *pixmap=NULL;
GdkBitmap *mask=NULL;
gint i, idx;
gchar *grp_col[NCOLS];
if (grp->seq && newsrc_ht && (grp->nunread < 0))
grp->nunread = grn_news_get_unread(grp);
if ((grn_prefs.srt_ng_subscr >= 1) && (! grp->seq) && flag) return FALSE;
if ((grn_prefs.srt_ng_subscr >= 2) && (grp->nunread <= 0) && flag) return FALSE;
if (grp->nunread > 0)
{
pixmap = GRN->pixmaps.new_art_group.pixmap;
mask = GRN->pixmaps.new_art_group.mask;
}
else if (grp->seq)
{
pixmap = GRN->pixmaps.subscr_group.pixmap;
mask = GRN->pixmaps.subscr_group.mask;
}
grp_col[0] = NULL;
grp_col[1] = NULL;
if (grp->nunread > 0) grp_col[2] = g_strdup_printf("%lu", grp->nunread);
else grp_col[2] = NULL;
if (grp->name) grp_col[3] = g_strdup(grp->name);
else grp_col[3] = NULL;
if (grp->descr) grp_col[4] = g_strdup(grp->descr);
else grp_col[4] = NULL;
grn_lock();
idx = gtk_clist_append(clist, grp_col);
gtk_clist_set_row_data(clist, idx, grp);
if (pixmap) gtk_clist_set_pixmap(clist, idx, 1, pixmap, mask);
grn_unlock();
for (i=0; i<NCOLS; i++) str_free(&grp_col[i]);
return TRUE;
}
void grouplist_refresh(GtkWidget *grouplist, GList *ng_list)
{
GtkCList *clist;
GList *l;
g_return_if_fail(grouplist != NULL);
g_return_if_fail(ng_list != NULL);
grn_lock();
clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(grouplist), KEY_CL_GROUPS));
grn_unlock();
if ((! clist) || (! GTK_IS_CLIST(clist))) return;
grn_widget_set_style(GTK_WIDGET(clist), grn_prefs.fonts[4], NULL, NULL, NULL);
grn_lock();
gtk_clist_freeze(clist);
gtk_clist_clear(clist);
grn_unlock();
for (l=ng_list; l; l=l->next)
{
grn_newsgroup *grp = (grn_newsgroup *) l->data;
if (! add_group(clist, grp, TRUE)) continue;
}
grn_lock();
gtk_clist_columns_autosize(clist);
grn_unlock();
ng_list_sort(clist);
grn_lock();
gtk_clist_thaw(clist);
grn_unlock();
grn_appbar_set_status(GRN->appbar, _("Total %ld group[s]; %ld group[s] with unread messages"),
g_list_length(ng_list), grouplist_get_nunread(ng_list));
}
static void grouplist_refresh_row(GtkCList *clist, gint row, grn_newsgroup *grp)
{
GdkPixmap *pixmap=NULL;
GdkBitmap *mask=NULL;
gchar *s_tmp = NULL;
if (flags.open_grouplist) return;
if (grp->nunread > 0)
{
pixmap = GRN->pixmaps.new_art_group.pixmap;
mask = GRN->pixmaps.new_art_group.mask;
s_tmp = g_strdup_printf("%lu", grp->nunread);
}
else if (grp->seq)
{
pixmap = GRN->pixmaps.subscr_group.pixmap;
mask = GRN->pixmaps.subscr_group.mask;
}
grn_lock();
if (pixmap) gtk_clist_set_pixmap(clist, row, 1, pixmap, mask);
else gtk_clist_set_text(clist, row, 1, "");
if (s_tmp)
{
gtk_clist_set_text(clist, row, 2, s_tmp);
str_free(&s_tmp);
}
else gtk_clist_set_text(clist, row, 2, "");
grn_unlock();
}
void grouplist_recalc_unread(GtkWidget *grouplist)
{
gint i;
GtkCList *clist;
g_return_if_fail(grouplist != NULL);
grn_lock();
clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(grouplist), KEY_CL_GROUPS));
grn_unlock();
if (! clist) return;
if (! clist->selection) return;
i = GPOINTER_TO_INT(clist->selection->data);
{
grn_newsgroup *grp;
grn_lock();
grp = (grn_newsgroup *) gtk_clist_get_row_data(clist, i);
grn_unlock();
if (grp) grouplist_refresh_row(clist, i, grp);
}
grn_appbar_set_status(GRN->appbar, _("Total %ld group[s]; %ld group[s] with unread messages"),
g_list_length(GRN->ng_list), grouplist_get_nunread(GRN->ng_list));
}
static GtkWidget *grn_get_filt_ball(void)
{
GdkPixmap *pixmap;
GdkBitmap *mask;
GtkWidget *ret;
if (grn_prefs.srt_ng_subscr == 1)
{
pixmap = GRN->pixmaps.subscr_group.pixmap;
mask = GRN->pixmaps.subscr_group.mask;
}
else if (grn_prefs.srt_ng_subscr == 2)
{
pixmap = GRN->pixmaps.new_art_group.pixmap;
mask = GRN->pixmaps.new_art_group.mask;
}
else {
pixmap = GRN->pixmaps.caption_subscr.pixmap;
mask = GRN->pixmaps.caption_subscr.mask;
}
grn_lock();
ret = gtk_pixmap_new(pixmap, mask);
grn_unlock();
return ret;
}
GtkWidget *grouplist_create()
{
gchar *ttl[NCOLS] = {_("No"), "", _("Unread"), _("Name"), _("Description")};
GtkWidget *vbox, *scrwin, *hbox, *w, *en_find;
GtkCList *clist;
gchar *title;
gshort n;
grn_lock();
vbox = gtk_vbox_new(FALSE, 0);
clist = GTK_CLIST(gtk_clist_new_with_titles(NCOLS, ttl));
gtk_clist_set_column_justification(clist, 0, GTK_JUSTIFY_RIGHT);
gtk_clist_set_column_justification(clist, 1, GTK_JUSTIFY_CENTER);
gtk_clist_set_column_justification(clist, 2, GTK_JUSTIFY_RIGHT);
gtk_clist_column_title_passive(clist, 0);
gtk_clist_column_title_passive(clist, 4);
gtk_tooltips_set_tip(GRN->tooltips, clist->column[1].button, _("Toggle all/subscribed/unread groups"), NULL);
gtk_tooltips_set_tip(GRN->tooltips, clist->column[2].button, _("Sort by unread messages"), NULL);
gtk_tooltips_set_tip(GRN->tooltips, clist->column[3].button, _("Sort by name"), NULL);
gtk_clist_set_selection_mode(clist, GTK_SELECTION_BROWSE);
gtk_clist_set_reorderable(clist, TRUE);
n = grn_prefs.srt_ng_col;
clist->sort_type = GTK_SORT_ASCENDING;
if (n >= 100)
{
clist->sort_type = GTK_SORT_DESCENDING;
n -= 100;
}
gtk_clist_set_sort_column(clist, n);
gtk_clist_set_column_widget(clist, 1, grn_get_filt_ball());
scrwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scrwin), GTK_WIDGET(clist));
gtk_box_pack_start(GTK_BOX(vbox), scrwin, TRUE, TRUE, 0);
hbox = gtk_hbox_new(FALSE, FALSE);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
w = gtk_label_new(_("Find newsgroup:"));
gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 3);
en_find = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), en_find, TRUE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(en_find), "key_press_event",
GTK_SIGNAL_FUNC(evt_fg_keypress), NULL);
title = g_strdup_printf(_(GRN_TITLE" - %s"), _("Groups listing"));
gtk_object_set_data(GTK_OBJECT(vbox), KEY_CL_GROUPS, clist);
gtk_object_set_data(GTK_OBJECT(vbox), KEY_FOCUS, clist);
gtk_object_set_data_full(GTK_OBJECT(vbox), KEY_TITLE, title,
(GtkDestroyNotify) str_destroy);
gtk_signal_connect(GTK_OBJECT(clist), "key_press_event",
GTK_SIGNAL_FUNC(evt_ng_keypress), NULL);
gtk_signal_connect(GTK_OBJECT(clist), "button_press_event",
GTK_SIGNAL_FUNC(evt_ng_btnpress), NULL);
gtk_signal_connect(GTK_OBJECT(clist), "click_column",
GTK_SIGNAL_FUNC(evt_click_col), NULL);
gtk_signal_connect(GTK_OBJECT(en_find), "changed",
GTK_SIGNAL_FUNC(en_find_changed), clist);
gtk_signal_connect(GTK_OBJECT(en_find), "activate",
GTK_SIGNAL_FUNC(en_find_activate), clist);
gtk_signal_connect(GTK_OBJECT(vbox), "destroy",
GTK_SIGNAL_FUNC(evt_ng_delete), NULL);
gtk_signal_connect(GTK_OBJECT(vbox), "hide",
GTK_SIGNAL_FUNC(evt_ng_hide), NULL);
gtk_widget_show_all(vbox);
gtk_signal_connect(GTK_OBJECT(vbox), "show",
GTK_SIGNAL_FUNC(evt_ng_show), NULL);
grn_unlock();
show_newsgroups_menu(TRUE);
return vbox;
}
void ng_list_download(gboolean update)
{
GList *grouplist;
gchar *rc;
if (GRN->ng_list) grouplist_free(&(GRN->ng_list));
grn_appbar_set_status(GRN->appbar, "");
grn_appbar_push(GRN->appbar, update, _("Connecting to server '%s'..."), grn_prefs.nntp_server);
rc = nntp_connect(GRN->nntp_sock);
if (rc) grn_error(_("NNTP connect"), rc);
grn_appbar_pop(GRN->appbar);
if (! nntp_is_online(GRN->nntp_sock))
{
grn_appbar_set_status(GRN->appbar, _("Connection to server '%s' failed"), grn_prefs.nntp_server);
return;
}
grn_appbar_push(GRN->appbar, update, _("Fetching grouplist from server..."));
if ((grouplist = nntp_get_grouplist(GRN->nntp_sock)) != NULL)
{
GRN->ng_list = grouplist;
grn_appbar_pop(GRN->appbar);
grn_appbar_push(GRN->appbar, update, _("Reading newsrc file..."));
if (! newsrc_ht) newsrc_ht = read_newsrc(grn_prefs.paths[0]);
grn_appbar_pop(GRN->appbar);
grn_appbar_push(GRN->appbar, update, _("Calculating groups status..."));
if (newsrc_ht) fill_newsrc_ng_list(GRN->ng_list, newsrc_ht);
grn_appbar_pop(GRN->appbar);
grn_appbar_push(GRN->appbar, update, _("Fetching newsgroups descriptions from server..."));
if (! ng_desc_ht) ng_desc_ht = nntp_get_groupdesc(GRN->nntp_sock);
if (ng_desc_ht) fill_newsrc_ng_desc(GRN->ng_list, ng_desc_ht);
else {
if (GRN->nntp_sock->error)
grn_error(_("Socket error"), GRN->nntp_sock->err_msg);
}
}
else {
if (GRN->nntp_sock->error)
grn_error(_("Socket error"), GRN->nntp_sock->err_msg);
}
grn_appbar_pop(GRN->appbar);
}
void clist_renumber(GtkCList *clist)
{
gint i;
for (i=0; i<clist->rows; i++)
{
gchar *buf = g_strdup_printf("%d", i+1);
grn_lock();
gtk_clist_set_text(clist, i, 0, buf);
grn_unlock();
str_free(&buf);
}
}
static grn_newsgroup *get_newsgroup_from_row(gconstpointer ptr)
{
const GtkCListRow *row = (GtkCListRow *) ptr;
if (row->data) return (grn_newsgroup *) row->data;
else return NULL;
}
static gint ng_list_compare_unread(GtkCList *clist, gconstpointer a, gconstpointer b)
{
grn_newsgroup *grp1, *grp2;
g_return_val_if_fail(a != NULL, -1);
g_return_val_if_fail(b != NULL, 1);
grp1 = get_newsgroup_from_row(a);
grp2 = get_newsgroup_from_row(b);
if (! grp2) return (grp1 != NULL);
if (! grp1) return (-1);
if (grp2->nunread < 0) return (grp1->nunread >= 0);
if (grp1->nunread < 0) return (-1);
if (grp2->nunread == 0) return (grp1->nunread >= 0);
if (grp1->nunread == 0) return (-1);
return (grp1->nunread - grp2->nunread);
}
static gint ng_list_compare_name(GtkCList *clist, gconstpointer a, gconstpointer b)
{
grn_newsgroup *grp1, *grp2;
g_return_val_if_fail(a != NULL, -1);
g_return_val_if_fail(b != NULL, -1);
grp1 = get_newsgroup_from_row(a);
grp2 = get_newsgroup_from_row(b);
if (! grp2) return (grp1 != NULL);
if (! grp1) return (-1);
if (! grp2->name) return (grp1->name != NULL);
if (! grp1->name) return (-1);
return (g_strcasecmp(grp1->name, grp2->name));
}
static void ng_list_sort(GtkCList *clist)
{
g_return_if_fail(clist != NULL);
grn_lock();
switch (clist->sort_column)
{
case 2:
gtk_clist_set_compare_func(clist, (GtkCListCompareFunc) ng_list_compare_unread);
break;
case 3:
gtk_clist_set_compare_func(clist, (GtkCListCompareFunc) ng_list_compare_name);
break;
default:
g_assert_not_reached();
break;
}
gtk_clist_sort(clist);
clist_renumber(clist);
if (GTK_WIDGET_REALIZED(clist))
{
gtk_clist_select_row(clist, 0, 0);
gtk_widget_grab_focus(GTK_WIDGET(clist));
}
grn_unlock();
grn_prefs.srt_ng_col = clist->sort_column;
if (clist->sort_type == GTK_SORT_DESCENDING) grn_prefs.srt_ng_col += 100;
}
static GtkCList *get_clist(GtkWidget *w)
{
GtkCList *clist;
g_return_val_if_fail(w != NULL, NULL);
if (! GTK_IS_CLIST(w))
{
clist = (GtkCList *) gtk_object_get_data(GTK_OBJECT(GRN->grouplist), KEY_CL_GROUPS);
g_return_val_if_fail(clist != NULL, NULL);
g_return_val_if_fail(GTK_IS_CLIST(clist), NULL);
}
else clist = GTK_CLIST(w);
return clist;
}
extern pthread_mutex_t groups_m;
void ng_list_open_group(GtkWidget *w)
{
gint row;
grn_newsgroup *grp;
GtkCList *clist = get_clist(w);
g_return_if_fail(clist != NULL);
if (flags.open_group) return;
if ((! clist) || (! clist->selection)) return;
pthread_mutex_lock(&groups_m);
row = GPOINTER_TO_INT(clist->selection->data);
grp = gtk_clist_get_row_data(clist, row);
if (grp)
{
gchar *title = g_strdup_printf(_("%s - %s - %s"), GRN_TITLE, _("Threadlist"),
grp->name);
if (GRN->threadlist) gtk_widget_destroy(GRN->threadlist);
GRN->threadlist = threadlist_create();
gtk_object_set_data_full(GTK_OBJECT(GRN->threadlist), KEY_TITLE, title,
(GtkDestroyNotify) str_destroy);
grn_set_contents(GRN->threadlist);
grnq_add_download_msghdrlist(grp);
grnq_add_draw_msglist();
}
pthread_mutex_unlock(&groups_m);
}
static gint evt_ng_btnpress(GtkWidget *w, GdkEventButton *event, gpointer data)
{
gboolean processed = FALSE;
g_return_val_if_fail(event != NULL, FALSE);
g_return_val_if_fail(w != NULL, FALSE);
if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1))
{
ng_list_open_group(w);
processed = TRUE;
}
if (processed)
{
gtk_signal_emit_stop_by_name(GTK_OBJECT(w), "button_press_event");
return TRUE;
}
return FALSE;
}
static gint evt_ng_keypress(GtkWidget *w, GdkEventKey *event, gpointer data)
{
g_return_val_if_fail(event != NULL, FALSE);
g_return_val_if_fail(w != NULL, FALSE);
switch (event->keyval)
{
case GDK_Select:
case GDK_Execute:
case GDK_Return:
case GDK_KP_Enter:
case GDK_Right:
case GDK_KP_Right:
ng_list_open_group(w);
break;
case GDK_Up:
if (event->state & GDK_CONTROL_MASK) evt_group_urprev(w);
else return FALSE;
break;
case GDK_Down:
if (event->state & GDK_CONTROL_MASK) evt_group_urnext(w);
else return FALSE;
break;
default: return FALSE;
}
gtk_signal_emit_stop_by_name(GTK_OBJECT(w), "key_press_event");
return TRUE;
}
static void evt_ng_delete(GtkWidget *w, gpointer data)
{
g_return_if_fail(w != NULL);
GRN->grouplist = NULL;
}
static void evt_ng_show(GtkWidget *w, gpointer data)
{
if (GRN->ng_list)
grn_appbar_set_status(GRN->appbar, _("Total %ld groups; %ld groups with unread messages"),
g_list_length(GRN->ng_list), grouplist_get_nunread(GRN->ng_list));
show_newsgroups_menu(TRUE);
grnq_add_grouplist_recalc();
}
static void evt_ng_hide(GtkWidget *w, gpointer data)
{
grn_appbar_set_status(GRN->appbar, "");
show_newsgroups_menu(FALSE);
}
static void evt_click_col(GtkCList *clist, int n)
{
if (n == 1)
{
grn_prefs.srt_ng_subscr++;
if (grn_prefs.srt_ng_subscr > 2) grn_prefs.srt_ng_subscr = 0;
grouplist_refresh(GRN->grouplist, GRN->ng_list);
ng_list_sort(clist);
grn_lock();
gtk_clist_set_column_widget(clist, 1, grn_get_filt_ball());
grn_unlock();
return;
}
if (clist->sort_column == n)
{
if (clist->sort_type == GTK_SORT_ASCENDING)
clist->sort_type = GTK_SORT_DESCENDING;
else clist->sort_type = GTK_SORT_ASCENDING;
}
else clist->sort_type = GTK_SORT_ASCENDING;
switch (n)
{
case 2:
case 3:
gtk_clist_set_sort_column(clist, n);
break;
default:
g_assert_not_reached();
break;
}
ng_list_sort(clist);
}
void evt_group_subscribe(GtkWidget *w)
{
GList *l;
GtkCList *clist = get_clist(w);
g_return_if_fail(clist != NULL);
for (l=clist->selection; l; l=l->next)
{
gint row = GPOINTER_TO_INT(l->data);
grn_newsgroup *grp = gtk_clist_get_row_data(clist, row);
if (grp && grp->name && newsrc_ht)
{
gchar *seq;
grn_news_group_subscribe(newsrc_ht, grp);
seq = g_hash_table_lookup(newsrc_ht, grp->name);
if (seq)
{
grn_newsgroup_set_seq(grp, g_strdup(seq));
grouplist_refresh_row(clist, row, grp);
grnq_add_grouplist_recalc();
}
}
}
}
void evt_group_unsubscribe(GtkWidget *w)
{
GList *l;
GtkCList *clist = get_clist(w);
g_return_if_fail(clist != NULL);
for (l=clist->selection; l; l=l->next)
{
gint row = GPOINTER_TO_INT(l->data);
grn_newsgroup *grp = gtk_clist_get_row_data(clist, row);
if (grp && grp->name && newsrc_ht)
{
gchar *seq;
grn_news_group_unsubscribe(newsrc_ht, grp);
seq = g_hash_table_lookup(newsrc_ht, grp->name);
if (! seq)
{
grn_newsgroup_set_seq(grp, NULL);
grouplist_refresh_row(clist, row, grp);
grnq_add_grouplist_recalc();
}
}
}
}
typedef struct catchup_data
{
grn_newsgroup *grp;
gint row;
GtkCList *clist;
} catchup_data;
static void catchup_cb(gint reply, catchup_data *cdata)
{
g_return_if_fail(cdata != NULL);
if (reply == GNOME_YES)
{
grn_newsgroup_set_seq(cdata->grp, grn_news_read_all(MAX(1, cdata->grp->total)));
grouplist_refresh_row(cdata->clist, cdata->row, cdata->grp);
grnq_add_grouplist_recalc();
}
g_free(cdata);
}
void evt_group_catchup(GtkWidget *w)
{
GList *l;
GtkCList *clist = get_clist(w);
g_return_if_fail(clist != NULL);
for (l=clist->selection; l; l=l->next)
{
gint row = GPOINTER_TO_INT(l->data);
grn_newsgroup *grp = gtk_clist_get_row_data(clist, row);
if (grp && grp->name && newsrc_ht)
{
gchar *seq;
seq = g_hash_table_lookup(newsrc_ht, grp->name);
if (seq)
{
if (grn_prefs.cfms[0])
{
catchup_data *cdata = g_new(catchup_data, 1);
gchar *buf = g_strdup_printf(_("Do you really wish to catchup group\n%s?"), grp->name);
cdata->grp = grp; cdata->clist = clist; cdata->row = row;
gnome_app_question(GNOME_APP(GRN->window), buf,
(GnomeReplyCallback) catchup_cb, cdata);
str_free(&buf);
}
else {
grn_newsgroup_set_seq(grp, grn_news_read_all(MAX(1, grp->total)));
grouplist_refresh_row(clist, row, grp);
grnq_add_grouplist_recalc();
}
}
}
}
}
static void unread_cb(gint reply, catchup_data *cdata)
{
g_return_if_fail(cdata != NULL);
if (reply == GNOME_YES)
{
grn_newsgroup_set_seq(cdata->grp, grn_news_read_all(MAX(1, cdata->grp->first - 1)));
grouplist_refresh_row(cdata->clist, cdata->row, cdata->grp);
grnq_add_grouplist_recalc();
}
g_free(cdata);
}
void evt_group_unread(GtkWidget *w)
{
GList *l;
GtkCList *clist = get_clist(w);
g_return_if_fail(clist != NULL);
for (l=clist->selection; l; l=l->next)
{
gint row = GPOINTER_TO_INT(l->data);
grn_newsgroup *grp = gtk_clist_get_row_data(clist, row);
if (grp && grp->name && newsrc_ht)
{
gchar *seq;
seq = g_hash_table_lookup(newsrc_ht, grp->name);
if (seq)
{
if (grn_prefs.cfms[1])
{
catchup_data *cdata = g_new(catchup_data, 1);
gchar *buf = g_strdup_printf(_("Do you really wish to mark group\n'%s' unread?"), grp->name);
cdata->grp = grp; cdata->clist = clist; cdata->row = row;
gnome_app_question(GNOME_APP(GRN->window), buf,
(GnomeReplyCallback) unread_cb, cdata);
str_free(&buf);
}
else {
grn_newsgroup_set_seq(grp, grn_news_read_all(MAX(1, grp->first - 1)));
grouplist_refresh_row(clist, row, grp);
grnq_add_grouplist_recalc();
}
}
}
}
}
static void group_next_prev(GtkWidget *w, gboolean prev)
{
GtkCList *clist = get_clist(w);
gint row;
g_return_if_fail(clist != NULL);
if (! clist->selection) return;
row = GPOINTER_TO_INT(clist->selection->data);
if (prev) row--;
else row++;
while ((row >= 0) && (row < clist->rows))
{
grn_newsgroup *grp = gtk_clist_get_row_data(clist, row);
if (grp->nunread > 0)
{
clist->focus_row = row;
gtk_clist_select_row(clist, row, 0);
if (gtk_clist_row_is_visible(clist, row) != GTK_VISIBILITY_FULL)
gtk_clist_moveto(clist, row, 0, 0,0);
break;
}
if (prev) row--;
else row++;
}
}
void evt_group_urprev(GtkWidget *w)
{ group_next_prev(w, TRUE); }
void evt_group_urnext(GtkWidget *w)
{ group_next_prev(w, FALSE); }
void evt_groups_refresh(GtkWidget *w)
{
if (newsrc_ht)
{
write_newsrc(grn_prefs.paths[0], grn_prefs.paths[0], newsrc_ht);
free_newsrc(newsrc_ht); newsrc_ht = NULL;
}
if (GRN->ng_list) grouplist_free(&(GRN->ng_list));
if (! GRN->grouplist) GRN->grouplist = grouplist_create();
grn_set_contents(GRN->grouplist);
grnq_add_download_grouplist();
grnq_add_draw_grouplist();
// ng_list_download(TRUE);
// grouplist_refresh(GRN->grouplist, GRN->ng_list);
}
static void find_changed(GtkWidget *en, GtkWidget *clist, gboolean flag)
{
const gchar *en_text = gtk_entry_get_text(GTK_ENTRY(en));
gchar *buf;
regex_t re;
gint i;
if (! str_check(en_text)) return;
g_return_if_fail(en != NULL);
g_return_if_fail(clist != NULL);
g_return_if_fail(GTK_IS_CLIST(clist));
buf = g_strconcat("^", en_text, NULL);
if (regcomp(&re, buf, REG_EXTENDED|REG_NOSUB|REG_ICASE))
{
str_free(&buf); return;
}
if (flag) flags.open_group = TRUE;
for (i=0; i<GTK_CLIST(clist)->rows; i++)
{
gchar *text;
gtk_clist_get_text(GTK_CLIST(clist), i, 3, &text);
if (! regexec(&re, text, 0, NULL, 0))
{
if (flag) gtk_clist_select_row(GTK_CLIST(clist), i, 3);
else GTK_CLIST(clist)->focus_row = i;
if (gtk_clist_row_is_visible(GTK_CLIST(clist), i) != GTK_VISIBILITY_FULL)
gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0,0);
break;
}
}
if (flag) flags.open_group = FALSE;
}
static void en_find_changed(GtkWidget *en, GtkWidget *clist)
{
if (flags.open_group) return;
find_changed(en, clist, TRUE);
}
static void gs_find_changed(GtkWidget *en, GtkWidget *clist)
{
find_changed(en, clist, FALSE);
}
static void en_find_activate(GtkWidget *en, GtkWidget *clist)
{
if (flags.open_group) return;
g_return_if_fail(clist != NULL);
ng_list_open_group(clist);
}
static void gs_find_activate(GtkWidget *en, GtkWidget *clist)
{
const gchar *en_text = gtk_entry_get_text(GTK_ENTRY(en));
gint i;
if (! str_check(en_text)) return;
g_return_if_fail(clist != NULL);
for (i=0; i<GTK_CLIST(clist)->rows; i++)
{
gchar *text;
gtk_clist_get_text(GTK_CLIST(clist), i, 3, &text);
if (! strcmp(text, en_text))
{
gtk_clist_select_row(GTK_CLIST(clist), i, 3);
if (gtk_clist_row_is_visible(GTK_CLIST(clist), i) != GTK_VISIBILITY_FULL)
gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0,0);
break;
}
}
}
static gint evt_fg_keypress(GtkWidget *w, GdkEventKey *event, gpointer data)
{
if (event->keyval == GDK_Tab)
{
GCompletion *cmpl;
GList *l, *list=NULL;
gchar *prefix, *nprefix = NULL;
gint pos;
if (! GRN->ng_list) return FALSE;
gtk_signal_emit_stop_by_name(GTK_OBJECT(w), "key_press_event");
for (l=GRN->ng_list; l; l=l->next)
{
grn_newsgroup *grp = l->data;
if (! grp) continue;
list = g_list_prepend(list, g_strdup(grp->name));
}
list = g_list_reverse(list);
cmpl = g_completion_new(NULL);
g_completion_add_items(cmpl, list);
pos = GTK_EDITABLE(w)->current_pos;
prefix = gtk_editable_get_chars(GTK_EDITABLE(w), 0, pos);
g_completion_complete(cmpl, prefix, &nprefix);
if (nprefix)
{
gtk_editable_insert_text(GTK_EDITABLE(w), nprefix+pos,
strlen(nprefix) - strlen(prefix), &pos);
GTK_EDITABLE(w)->current_pos = pos;
g_free(nprefix);
}
g_free(prefix); g_completion_free(cmpl);
for (l=list; l; l=l->next) g_free(l->data);
g_list_free(list);
return TRUE;
}
return FALSE;
}
GtkWidget *groupsel_create()
{
gchar *ttl[NCOLS] = {_("No"), "", _("Unread"), _("Name"), _("Description")};
GtkWidget *vbox, *scrwin, *hbox, *w, *en_find;
GtkCList *clist;
GList *l;
grn_lock();
vbox = gtk_vbox_new(FALSE, 0);
clist = GTK_CLIST(gtk_clist_new_with_titles(NCOLS, ttl));
gtk_widget_set_usize(GTK_WIDGET(clist), 512, 300);
gtk_clist_set_column_justification(clist, 0, GTK_JUSTIFY_RIGHT);
gtk_clist_set_column_justification(clist, 1, GTK_JUSTIFY_CENTER);
gtk_clist_set_column_justification(clist, 2, GTK_JUSTIFY_RIGHT);
gtk_clist_column_titles_passive(clist);
gtk_clist_set_selection_mode(clist, GTK_SELECTION_MULTIPLE);
w = gtk_pixmap_new(GRN->pixmaps.caption_subscr.pixmap, GRN->pixmaps.caption_subscr.mask);
gtk_clist_set_column_widget(clist, 1, w);
scrwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scrwin), GTK_WIDGET(clist));
gtk_box_pack_start(GTK_BOX(vbox), scrwin, TRUE, TRUE, 0);
hbox = gtk_hbox_new(FALSE, FALSE);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 1);
w = gtk_label_new(_("Find newsgroup:"));
gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 3);
en_find = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), en_find, TRUE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(en_find), "key_press_event",
GTK_SIGNAL_FUNC(evt_fg_keypress), NULL);
gtk_object_set_data(GTK_OBJECT(vbox), KEY_CL_GROUPS, clist);
gtk_signal_connect(GTK_OBJECT(en_find), "changed",
GTK_SIGNAL_FUNC(gs_find_changed), clist);
gtk_signal_connect(GTK_OBJECT(en_find), "activate",
GTK_SIGNAL_FUNC(gs_find_activate), clist);
gtk_clist_freeze(clist);
gtk_clist_clear(clist);
grn_unlock();
for (l=GRN->ng_list; l; l=l->next)
{
grn_newsgroup *grp = (grn_newsgroup *) l->data;
if (! add_group(clist, grp, FALSE)) continue;
}
clist_renumber(clist);
grn_lock();
gtk_clist_columns_autosize(clist);
gtk_clist_thaw(clist);
gtk_widget_show_all(vbox);
grn_unlock();
return vbox;
}
void groupsel_refresh(GtkWidget *groupsel, GSList *groups)
{
GtkCList *clist;
GSList *sl;
GList *l;
gint min, i;
g_return_if_fail(groupsel != NULL);
grn_lock();
clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(groupsel), KEY_CL_GROUPS));
grn_unlock();
if ((! clist) || (! GTK_IS_CLIST(clist))) return;
grn_lock();
for (sl=groups; sl; sl=sl->next)
{
gchar *grp_name = (gchar *) sl->data;
gint i;
for (i=0; i<clist->rows; i++)
{
gchar *text;
gtk_clist_get_text(GTK_CLIST(clist), i, 3, &text);
if (! strcmp(text, grp_name))
{
gtk_clist_select_row(GTK_CLIST(clist), i, 3);
break;
}
}
}
grn_unlock();
min = clist->rows;
for (l=clist->selection; l; l=l->next)
{
i = GPOINTER_TO_INT(l->data);
if (i < min) min = i;
}
clist->focus_row = min;
grn_lock();
if (gtk_clist_row_is_visible(clist, min) != GTK_VISIBILITY_FULL)
gtk_clist_moveto(clist, min, 0, 0,0);
gtk_widget_grab_focus(GTK_WIDGET(clist));
grn_unlock();
}
static gboolean gsdlg_delete(GtkWidget *w)
{
grn_save_ws(3, w);
return FALSE;
}
static void btn_event(GtkWidget *btn, GtkWidget *w)
{ gsdlg_delete(w); }
GtkWidget *groupsel_dlg_create(GSList *list)
{
GtkWidget *dlg, *gs;
grn_lock();
dlg = gnome_dialog_new(_("Select newsgroups"), GNOME_STOCK_BUTTON_CANCEL,
GNOME_STOCK_BUTTON_OK, NULL);
gnome_dialog_set_close(GNOME_DIALOG(dlg), TRUE);
gtk_window_set_policy(GTK_WINDOW(dlg), FALSE, TRUE, FALSE);
gtk_window_set_default_size(GTK_WINDOW(dlg), grn_prefs.ws[3].width, grn_prefs.ws[3].height);
gtk_widget_set_uposition(dlg, grn_prefs.ws[3].x, grn_prefs.ws[3].y);
gtk_signal_connect(GTK_OBJECT(dlg), "delete_event",
GTK_SIGNAL_FUNC(gsdlg_delete), NULL);
gnome_dialog_button_connect(GNOME_DIALOG(dlg), 0,
GTK_SIGNAL_FUNC(btn_event), dlg);
gnome_dialog_button_connect(GNOME_DIALOG(dlg), 1,
GTK_SIGNAL_FUNC(btn_event), dlg);
grn_unlock();
gs = groupsel_create();
grn_lock();
gtk_object_set_data(GTK_OBJECT(dlg), KEY_GROUPSEL, gs);
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dlg)->vbox), gs, TRUE, TRUE, 0);
gtk_widget_show_all(dlg);
groupsel_refresh(gs, list);
grn_unlock();
return dlg;
}
syntax highlighted by Code2HTML, v. 0.9.1