2
* @file feed_list_view.c the feed list in a GtkTreeView
4
* Copyright (C) 2004-2011 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/feed_list_view.h"
26
#include <gdk/gdkkeysyms.h>
34
#include "net_monitor.h"
37
#include "ui/browser_tabs.h"
38
#include "ui/liferea_shell.h"
39
#include "ui/subscription_dialog.h"
40
#include "ui/ui_common.h"
41
#include "ui/ui_dnd.h"
42
#include "ui/ui_node.h"
43
#include "fl_sources/node_source.h"
45
GtkTreeModel *filter = NULL;
46
GtkTreeStore *feedstore = NULL;
48
gboolean feedlist_reduced_unread = FALSE;
51
feed_list_view_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
feed_list_view_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
67
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
68
gtk_tree_model_get (model, &iter, FS_PTR, &node, -1);
70
debug1 (DEBUG_GUI, "feed list selection changed to \"%s\"", node_get_title(node));
72
browser_tabs_show_headlines (); // FIXME: emit signal to item list instead of bother the tabs manager
74
/* update feed list and item list states */
75
feedlist_selection_changed (node);
78
gboolean allowModify = (NODE_SOURCE_TYPE (node->source->root)->capabilities & NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST);
79
liferea_shell_update_update_menu ((NODE_TYPE (node)->capabilities & NODE_CAPABILITY_UPDATE) ||
80
(NODE_TYPE (node)->capabilities & NODE_CAPABILITY_UPDATE_CHILDS));
81
liferea_shell_update_feed_menu (allowModify, TRUE, allowModify);
83
liferea_shell_update_feed_menu (TRUE, FALSE, FALSE);
86
/* If we cannot get the new selection we keep the old one
87
this happens when we're doing drag&drop for example. */
92
feed_list_view_row_activated_cb (GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
97
gtk_tree_model_get_iter (gtk_tree_view_get_model (tv), &iter, path);
98
gtk_tree_model_get (gtk_tree_view_get_model (tv), &iter, FS_PTR, &node, -1);
99
if (node && IS_FOLDER (node)) {
100
if (gtk_tree_view_row_expanded (tv, path))
101
gtk_tree_view_collapse_row (tv, path);
103
gtk_tree_view_expand_row (tv, path, FALSE);
109
feed_list_view_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
111
if ((event->type == GDK_KEY_PRESS) &&
112
(event->state == 0) &&
113
(event->keyval == GDK_Delete)) {
114
nodePtr node = feedlist_get_selected ();
117
if (event->state & GDK_SHIFT_MASK)
118
feedlist_remove_node (node);
120
feed_list_view_delete_prompt (node);
128
feed_list_view_filter_visible_function (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
133
if (!feedlist_reduced_unread)
136
gtk_tree_model_get (model, iter, FS_PTR, &node, FS_UNREAD, &count, -1);
140
if (IS_FOLDER (node) || IS_NODE_SOURCE (node))
150
feed_list_view_expand (nodePtr node)
153
feed_list_view_expand (node->parent);
155
ui_node_set_expansion (node, TRUE);
159
feed_list_view_restore_folder_expansion (nodePtr node)
162
feed_list_view_expand (node);
164
node_foreach_child (node, feed_list_view_restore_folder_expansion);
168
feed_list_view_reduce_mode_changed ()
170
GtkTreeView *treeview;
172
treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
174
if (feedlist_reduced_unread) {
175
gtk_tree_view_set_reorderable (treeview, FALSE);
176
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (filter));
177
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
179
gtk_tree_view_set_reorderable (treeview, TRUE);
180
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
181
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (feedstore));
183
feedlist_foreach (feed_list_view_restore_folder_expansion);
188
feed_list_view_set_reduce_mode (gboolean newReduceMode)
190
feedlist_reduced_unread = newReduceMode;
191
conf_set_bool_value (REDUCED_FEEDLIST, feedlist_reduced_unread);
192
feed_list_view_reduce_mode_changed ();
193
ui_node_reload_feedlist ();
197
feed_list_view_sort_folder_compare (gconstpointer a, gconstpointer b)
199
nodePtr n1 = (nodePtr)a;
200
nodePtr n2 = (nodePtr)b;
202
return strcmp (n1->title, n2->title);
206
feed_list_view_sort_folder (nodePtr folder)
208
folder->children = g_slist_sort (folder->children, feed_list_view_sort_folder_compare);
209
ui_node_reload_feedlist ();
210
feedlist_foreach (feed_list_view_restore_folder_expansion);
211
feedlist_schedule_save ();
214
/* sets up the entry list store and connects it to the entry list
215
view in the main window */
217
feed_list_view_init (GtkTreeView *treeview)
219
GtkCellRenderer *textRenderer;
220
GtkCellRenderer *iconRenderer;
221
GtkTreeViewColumn *column;
222
GtkTreeSelection *select;
224
debug_enter ("feed_list_view_init");
227
feedstore = gtk_tree_store_new (FS_LEN,
233
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (feedstore));
236
filter = gtk_tree_model_filter_new (GTK_TREE_MODEL(feedstore), NULL);
237
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER(filter),
238
feed_list_view_filter_visible_function,
242
g_signal_connect (G_OBJECT (feedstore), "row-changed", G_CALLBACK (feed_list_view_row_changed_cb), NULL);
244
/* we only render the state and title */
245
iconRenderer = gtk_cell_renderer_pixbuf_new ();
246
textRenderer = gtk_cell_renderer_text_new ();
248
column = gtk_tree_view_column_new ();
250
gtk_tree_view_column_pack_start (column, iconRenderer, FALSE);
251
gtk_tree_view_column_pack_start (column, textRenderer, TRUE);
253
gtk_tree_view_column_add_attribute (column, iconRenderer, "pixbuf", FS_ICON);
254
gtk_tree_view_column_add_attribute (column, textRenderer, "markup", FS_LABEL);
256
gtk_tree_view_column_set_resizable (column, TRUE);
257
gtk_tree_view_append_column (treeview, column);
259
g_object_set (textRenderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
261
g_signal_connect (G_OBJECT (treeview), "row-activated", G_CALLBACK (feed_list_view_row_activated_cb), NULL);
262
g_signal_connect (G_OBJECT (treeview), "key-press-event", G_CALLBACK (feed_list_view_key_press_cb), NULL);
264
select = gtk_tree_view_get_selection (treeview);
265
gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
267
g_signal_connect (G_OBJECT (select), "changed",
268
G_CALLBACK (feed_list_view_selection_changed_cb),
269
liferea_shell_lookup ("feedlist"));
271
conf_get_bool_value (REDUCED_FEEDLIST, &feedlist_reduced_unread);
272
if (feedlist_reduced_unread)
273
feed_list_view_reduce_mode_changed (); /* before menu setup for reduced mode check box to be correct */
275
ui_dnd_setup_feedlist (feedstore);
276
liferea_shell_update_feed_menu (TRUE, FALSE, FALSE);
277
liferea_shell_update_allitems_actions (FALSE, FALSE);
279
debug_exit ("feed_list_view_init");
283
feed_list_view_select (nodePtr node)
285
GtkTreeView *treeview;
287
GtkWindow *mainwindow;
289
mainwindow = GTK_WINDOW (liferea_shell_get_window ());
290
treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
291
model = gtk_tree_view_get_model (treeview);
293
if (node && node != feedlist_get_root ()) {
296
/* in filtered mode we need to convert the iterator */
297
if (feedlist_reduced_unread) {
299
gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (filter), &iter, ui_node_to_iter (node->id));
300
path = gtk_tree_model_get_path (model, &iter);
302
path = gtk_tree_model_get_path (model, ui_node_to_iter (node->id));
306
feed_list_view_expand (node->parent);
308
gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0.0, 0.0);
309
gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
310
gtk_tree_path_free (path);
313
GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
314
gtk_tree_selection_unselect_all (selection);
318
/* delete feed callbacks */
321
feed_list_view_delete_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
323
if (GTK_RESPONSE_ACCEPT == response_id)
324
feedlist_remove_node ((nodePtr)user_data);
326
gtk_widget_destroy (GTK_WIDGET (dialog));
330
feed_list_view_delete_prompt (nodePtr node)
333
GtkWindow *mainwindow;
336
g_assert (node == feedlist_get_selected ());
338
liferea_shell_set_status_bar ("%s \"%s\"", _("Deleting entry"), node_get_title (node));
339
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));
341
mainwindow = GTK_WINDOW (liferea_shell_get_window ());
342
dialog = gtk_message_dialog_new (mainwindow,
343
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
344
GTK_MESSAGE_QUESTION,
347
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
348
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
349
GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
351
gtk_window_set_title (GTK_WINDOW (dialog), _("Deletion Confirmation"));
352
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
353
gtk_window_set_transient_for (GTK_WINDOW (dialog), mainwindow);
357
gtk_widget_show_all (dialog);
359
g_signal_connect (G_OBJECT (dialog), "response",
360
G_CALLBACK (feed_list_view_delete_response_cb), node);
364
on_menu_properties (GtkMenuItem *menuitem, gpointer user_data)
366
nodePtr node = feedlist_get_selected ();
368
NODE_TYPE (node)->request_properties (node);
371
void on_menu_delete(GtkWidget *widget, gpointer user_data)
373
feed_list_view_delete_prompt (feedlist_get_selected());
377
do_menu_update (nodePtr node)
379
if (network_monitor_is_online ())
380
node_update_subscription (node, GUINT_TO_POINTER (FEED_REQ_PRIORITY_HIGH));
382
liferea_shell_set_status_bar (_("Liferea is in offline mode. No update possible."));
387
on_menu_update (void)
389
nodePtr node = feedlist_get_selected ();
392
do_menu_update (node);
394
g_warning ("on_menu_update: no feedlist selected");
398
on_menu_update_all(void)
400
do_menu_update (feedlist_get_root ());
404
on_menu_allread (GtkWidget *widget, gpointer user_data)
406
feedlist_mark_all_read (feedlist_get_selected ());
410
on_menu_allfeedsread (GtkWidget *widget, gpointer user_data)
412
feedlist_mark_all_read (feedlist_get_root ());
416
on_newbtn_clicked (GtkButton *button, gpointer user_data)
418
node_type_request_interactive_add (feed_get_node_type ());
422
on_menu_feed_new (GtkMenuItem *menuitem, gpointer user_data)
424
node_type_request_interactive_add (feed_get_node_type ());
428
on_new_plugin_activate (GtkMenuItem *menuitem, gpointer user_data)
430
node_type_request_interactive_add (node_source_get_node_type ());
434
on_new_newsbin_activate (GtkMenuItem *menuitem, gpointer user_data)
436
node_type_request_interactive_add (newsbin_get_node_type ());
440
on_menu_folder_new (GtkMenuItem *menuitem, gpointer user_data)
442
node_type_request_interactive_add (folder_get_node_type ());
446
on_new_vfolder_activate (GtkMenuItem *menuitem, gpointer user_data)
448
node_type_request_interactive_add (vfolder_get_node_type ());
452
on_feedlist_reduced_activate (GtkToggleAction *menuitem, gpointer user_data)
454
feed_list_view_set_reduce_mode (gtk_toggle_action_get_active (menuitem));