2
* @file ui_feedlist.c GUI feed list handling
4
* Copyright (C) 2004-2009 Lars Lindner <lars.lindner@gmail.com>
5
* Copyright (C) 2004-2006 Nathan J. Conrad <t98502@users.sourceforge.net>
6
* Copyright (C) 2005 Raphael Slinckx <raphael@slinckx.net>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#include "ui/ui_feedlist.h"
26
#include <gdk/gdkkeysyms.h>
37
#include "ui/browser_tabs.h"
38
#include "ui/liferea_shell.h"
39
#include "ui/ui_common.h"
40
#include "ui/ui_dnd.h"
41
#include "ui/ui_node.h"
42
#include "ui/ui_subscription.h"
43
#include "fl_sources/node_source.h"
46
GtkTreeStore *feedstore = NULL;
48
gboolean feedlist_reduced_unread = FALSE;
51
ui_feedlist_row_changed_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter)
55
gtk_tree_model_get (model, iter, FS_PTR, &node, -1);
57
ui_node_update_iter(node->id, iter);
61
ui_feedlist_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
66
gboolean realNode = TRUE;
68
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
69
gtk_tree_model_get (model, &iter, FS_PTR, &node, -1);
71
debug1 (DEBUG_GUI, "feed list selection changed to \"%s\"", node_get_title(node));
73
/* make sure thats no grouping iterator */
74
// FIXME: check based on node capabilities!!!
75
realNode = (node && (IS_FEED (node) ||
78
IS_NODE_SOURCE (node)));
80
browser_tabs_show_headlines ();
82
/* update feed list and item list states */
83
feedlist_selection_changed (node);
86
gboolean allowModify = (NODE_SOURCE_TYPE (node->source->root)->capabilities & NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST);
87
liferea_shell_update_update_menu ((NODE_TYPE (node)->capabilities & NODE_CAPABILITY_UPDATE) ||
88
(NODE_TYPE (node)->capabilities & NODE_CAPABILITY_UPDATE_CHILDS));
89
liferea_shell_update_feed_menu (allowModify, TRUE, allowModify);
91
liferea_shell_update_feed_menu (TRUE, FALSE, FALSE);
94
/* If we cannot get the new selection we keep the old one
95
this happens when we're doing drag&drop for example. */
100
ui_feedlist_row_activated_cb (GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
105
gtk_tree_model_get_iter (gtk_tree_view_get_model (tv), &iter, path);
106
gtk_tree_model_get (gtk_tree_view_get_model (tv), &iter, FS_PTR, &node, -1);
107
if (node && IS_FOLDER (node)) {
108
if (gtk_tree_view_row_expanded (tv, path))
109
gtk_tree_view_collapse_row (tv, path);
111
gtk_tree_view_expand_row (tv, path, FALSE);
117
ui_feedlist_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
119
if ((event->type == GDK_KEY_PRESS) &&
120
(event->state == 0) &&
121
(event->keyval == GDK_Delete)) {
122
nodePtr node = feedlist_get_selected ();
125
if (event->state & GDK_SHIFT_MASK)
126
feedlist_remove_node (node);
128
ui_feedlist_delete_prompt (node);
136
ui_feedlist_filter_visible_function (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
141
if (!feedlist_reduced_unread)
144
gtk_tree_model_get (model, iter, FS_PTR, &np, FS_UNREAD, &count, -1);
146
if (np && (IS_FOLDER (np) || IS_NODE_SOURCE (np)))
156
ui_feedlist_reduce_unread (gboolean reduced) {
157
GtkTreeView *treeview;
159
treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
161
feedlist_reduced_unread = reduced;
162
conf_set_bool_value (REDUCED_FEEDLIST, reduced);
165
gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), FALSE);
166
gtk_tree_view_set_model (GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(filter));
167
gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER (filter));
170
gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), TRUE);
171
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER (filter));
172
gtk_tree_view_set_model (GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(feedstore));
176
/* sets up the entry list store and connects it to the entry list
177
view in the main window */
179
ui_feedlist_init (GtkTreeView *treeview)
181
GtkCellRenderer *textRenderer;
182
GtkCellRenderer *iconRenderer;
183
GtkTreeViewColumn *column;
184
GtkTreeSelection *select;
186
debug_enter ("ui_feedlist_init");
189
feedstore = gtk_tree_store_new (FS_LEN,
195
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (feedstore));
198
filter = gtk_tree_model_filter_new (GTK_TREE_MODEL(feedstore), NULL);
199
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER(filter),
200
ui_feedlist_filter_visible_function,
204
g_signal_connect (G_OBJECT (feedstore), "row-changed", G_CALLBACK (ui_feedlist_row_changed_cb), NULL);
206
/* we only render the state and title */
207
iconRenderer = gtk_cell_renderer_pixbuf_new ();
208
textRenderer = gtk_cell_renderer_text_new ();
210
column = gtk_tree_view_column_new ();
212
gtk_tree_view_column_pack_start (column, iconRenderer, FALSE);
213
gtk_tree_view_column_pack_start (column, textRenderer, TRUE);
215
gtk_tree_view_column_add_attribute (column, iconRenderer, "pixbuf", FS_ICON);
216
gtk_tree_view_column_add_attribute (column, textRenderer, "markup", FS_LABEL);
218
gtk_tree_view_column_set_resizable (column, TRUE);
219
gtk_tree_view_append_column (treeview, column);
221
g_object_set (textRenderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
223
g_signal_connect (G_OBJECT (treeview), "row-activated", G_CALLBACK (ui_feedlist_row_activated_cb), NULL);
224
g_signal_connect (G_OBJECT (treeview), "key-press-event", G_CALLBACK (ui_feedlist_key_press_cb), NULL);
226
select = gtk_tree_view_get_selection (treeview);
227
gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
229
g_signal_connect (G_OBJECT (select), "changed",
230
G_CALLBACK (ui_feedlist_selection_changed_cb),
231
liferea_shell_lookup ("feedlist"));
233
ui_feedlist_reduce_unread (conf_get_bool_value (REDUCED_FEEDLIST)); /* before menu setup for reduced mode check box to be correct */
235
ui_dnd_setup_feedlist (feedstore);
236
liferea_shell_update_feed_menu (TRUE, FALSE, FALSE);
237
liferea_shell_update_allitems_actions (FALSE, FALSE);
239
debug_exit ("ui_feedlist_init");
243
ui_feedlist_expand_parents (nodePtr parentNode)
245
if (parentNode->parent)
246
ui_feedlist_expand_parents (parentNode->parent);
248
ui_node_set_expansion (parentNode, TRUE);
252
ui_feedlist_select (nodePtr node)
254
GtkTreeView *treeview;
256
GtkWindow *mainwindow;
258
mainwindow = GTK_WINDOW (liferea_shell_get_window ());
259
treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
260
model = gtk_tree_view_get_model (treeview);
262
if (node && node != feedlist_get_root ()) {
265
/* in filtered mode we need to convert the iterator */
266
if (feedlist_reduced_unread) {
268
gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (filter), &iter, ui_node_to_iter (node->id));
269
path = gtk_tree_model_get_path (model, &iter);
271
path = gtk_tree_model_get_path (model, ui_node_to_iter (node->id));
275
ui_feedlist_expand_parents (node->parent);
277
gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0.0, 0.0);
278
gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
279
gtk_tree_path_free (path);
282
GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
283
gtk_tree_selection_unselect_all (selection);
287
/* delete feed callbacks */
290
ui_feedlist_delete_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
292
switch (response_id) {
293
case GTK_RESPONSE_ACCEPT:
294
feedlist_remove_node ((nodePtr)user_data);
297
gtk_widget_destroy (GTK_WIDGET (dialog));
301
ui_feedlist_delete_prompt (nodePtr node)
304
GtkWindow *mainwindow;
307
g_assert (node == feedlist_get_selected ());
309
liferea_shell_set_status_bar ("%s \"%s\"", _("Deleting entry"), node_get_title (node));
310
text = g_strdup_printf (IS_FOLDER (node)?_("Are you sure that you want to delete \"%s\" and its contents?"):_("Are you sure that you want to delete \"%s\"?"), node_get_title (node));
312
mainwindow = GTK_WINDOW (liferea_shell_get_window ());
313
dialog = gtk_message_dialog_new (mainwindow,
314
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
315
GTK_MESSAGE_QUESTION,
318
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
319
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
320
GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
322
gtk_window_set_title (GTK_WINDOW (dialog), _("Deletion Confirmation"));
323
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
324
gtk_window_set_transient_for (GTK_WINDOW (dialog), mainwindow);
328
gtk_widget_show_all (dialog);
330
g_signal_connect (G_OBJECT (dialog), "response",
331
G_CALLBACK (ui_feedlist_delete_response_cb), node);
335
on_menu_properties (GtkMenuItem *menuitem, gpointer user_data)
337
nodePtr node = feedlist_get_selected ();
339
NODE_TYPE (node)->request_properties (node);
342
void on_menu_delete(GtkWidget *widget, gpointer user_data)
344
ui_feedlist_delete_prompt (feedlist_get_selected());
348
on_menu_update (void)
350
if (!feedlist_get_selected ()) {
351
ui_show_error_box (_("You have to select a feed entry"));
355
if (network_is_online ())
356
node_update_subscription (feedlist_get_selected (), GUINT_TO_POINTER (FEED_REQ_PRIORITY_HIGH));
358
liferea_shell_set_status_bar (_("Liferea is in offline mode. No update possible."));
362
on_menu_update_all(void)
364
if (network_is_online ())
365
node_update_subscription (feedlist_get_root(), GUINT_TO_POINTER (FEED_REQ_PRIORITY_HIGH));
367
liferea_shell_set_status_bar (_("Liferea is in offline mode. No update possible."));
371
on_menu_allread (GtkWidget *widget, gpointer user_data)
373
feedlist_mark_all_read (feedlist_get_selected ());
377
on_menu_allfeedsread (GtkWidget *widget, gpointer user_data)
379
feedlist_mark_all_read (feedlist_get_root ());
383
on_newbtn_clicked (GtkButton *button, gpointer user_data)
385
node_type_request_interactive_add (feed_get_node_type ());
389
on_menu_feed_new (GtkMenuItem *menuitem, gpointer user_data)
391
node_type_request_interactive_add (feed_get_node_type ());
395
on_new_plugin_activate (GtkMenuItem *menuitem, gpointer user_data)
397
node_type_request_interactive_add (node_source_get_node_type ());
401
on_new_newsbin_activate (GtkMenuItem *menuitem, gpointer user_data)
403
node_type_request_interactive_add (newsbin_get_node_type ());
407
on_menu_folder_new (GtkMenuItem *menuitem, gpointer user_data)
409
node_type_request_interactive_add (folder_get_node_type ());
413
on_feedlist_reduced_activate (GtkToggleAction *menuitem, gpointer user_data)
415
ui_feedlist_reduce_unread (gtk_toggle_action_get_active (menuitem));
416
ui_node_reload_feedlist ();