Esempio n. 1
0
static void
feed_list_node_check_if_folder_is_empty (const gchar *nodeId)
{
	GtkTreeIter	*iter;
	int		count;

	debug1 (DEBUG_GUI, "folder empty check for node id \"%s\"", nodeId);

	/* this function does two things:
	   
	1. add "(empty)" entry to an empty folder
	2. remove an "(empty)" entry from a non empty folder
	(this state is possible after a drag&drop action) */

	iter = feed_list_node_to_iter (nodeId);
	if (!iter)
		return;
		
	count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (feedstore), iter);
	
	/* case 1 */
	if (0 == count) {
		feed_list_node_add_empty_node (iter);
		return;
	}
	
	if (1 == count)
		return;
	
	/* else we could have case 2 */
	feed_list_node_remove_empty_node (iter);
}
Esempio n. 2
0
void
feed_list_node_add (nodePtr node)
{
	gint		position;
	GtkTreeIter	*iter, *parentIter = NULL;

	debug2 (DEBUG_GUI, "adding node \"%s\" as child of parent=\"%s\"", node_get_title(node), (NULL != node->parent)?node_get_title(node->parent):"feed list root");

	g_assert (NULL != node->parent);
	g_assert (NULL == feed_list_node_to_iter (node->id));

	/* if parent is NULL we have the root folder and don't create a new row! */
	iter = (GtkTreeIter *)g_new0 (GtkTreeIter, 1);
	
	/* if reduced feedlist, show flat treeview */
	if (feedlist_reduced_unread)
		parentIter = NULL;
	else if (node->parent != feedlist_get_root ())
		parentIter = feed_list_node_to_iter (node->parent->id);

	position = g_slist_index (node->parent->children, node);

	if (feedlist_reduced_unread || position < 0)
		gtk_tree_store_append (feedstore, iter, parentIter);
	else
		gtk_tree_store_insert (feedstore, iter, parentIter, position);

	gtk_tree_store_set (feedstore, iter, FS_PTR, node, -1);
	feed_list_node_add_iter (node->id, iter);
	feed_list_node_update (node->id);
	
	if (node->parent != feedlist_get_root ())
		feed_list_node_check_if_folder_is_empty (node->parent->id);

	if (IS_FOLDER (node))
		feed_list_node_check_if_folder_is_empty (node->id);
}
Esempio n. 3
0
gboolean
feed_list_node_is_expanded (const gchar *nodeId)
{
	GtkTreeIter	*iter;
	gboolean 	expanded = FALSE;
	
	if (feedlist_reduced_unread)
		return FALSE;

	iter = feed_list_node_to_iter (nodeId);
	if (iter) {
		GtkTreeView *treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
		GtkTreePath *path = gtk_tree_model_get_path (gtk_tree_view_get_model (treeview), iter);
		expanded = gtk_tree_view_row_expanded (treeview, path);
		gtk_tree_path_free (path);
	}

	return expanded;
}
Esempio n. 4
0
void
feed_list_node_set_expansion (nodePtr folder, gboolean expanded)
{
	GtkTreeIter		*iter;
	GtkTreePath		*path;
	GtkTreeView		*treeview;
	
	if (feedlist_reduced_unread)
		return;

	iter = feed_list_node_to_iter (folder->id);
	if (!iter)
		return;

	treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
	path = gtk_tree_model_get_path (gtk_tree_view_get_model (treeview), iter);
	if (expanded)
		gtk_tree_view_expand_row (treeview, path, FALSE);
	else
		gtk_tree_view_collapse_row (treeview, path);
	gtk_tree_path_free (path);
}
Esempio n. 5
0
void
feed_list_node_remove_node (nodePtr node)
{
	GtkTreeIter	*iter;
	gboolean 	parentExpanded = FALSE;
	
	iter = feed_list_node_to_iter (node->id);
	if (!iter)
		return;	/* must be tolerant because of DnD handling */

	if (node->parent)
		parentExpanded = feed_list_node_is_expanded (node->parent->id); /* If the folder becomes empty, the folder would collapse */
	
	gtk_tree_store_remove (feedstore, iter);
	g_hash_table_remove (flIterHash, node->id);
	
	if (node->parent) {
		feed_list_node_check_if_folder_is_empty (node->parent->id);
		if (parentExpanded)
			feed_list_node_set_expansion (node->parent, TRUE);

		feed_list_node_update (node->parent->id);
	}
}
Esempio n. 6
0
void
feed_list_node_update (const gchar *nodeId)
{
	GtkTreeIter	*iter;
	gchar		*label, *count = NULL;
	guint		labeltype;
	nodePtr		node;

	static gchar	*countColor = NULL;

	node = node_from_id (nodeId);
	iter = feed_list_node_to_iter (nodeId);
	if (!iter)
		return;

	/* Initialize unread item color Pango CSS */
	if (!countColor) {
		const gchar *bg = NULL, *fg = NULL;

		bg = render_get_theme_color ("FEEDLIST_UNREAD_BG");
		fg = render_get_theme_color ("FEEDLIST_UNREAD_FG");
		if (fg && bg) {
			countColor = g_strdup_printf ("foreground='#%s' background='#%s'", fg, bg);
			debug1 (DEBUG_HTML, "Feed list unread CSS: %s\n", countColor);
		}
	}

	labeltype = NODE_TYPE (node)->capabilities;
	labeltype &= (NODE_CAPABILITY_SHOW_UNREAD_COUNT |
        	      NODE_CAPABILITY_SHOW_ITEM_COUNT);

	if (node->unreadCount == 0 && (labeltype & NODE_CAPABILITY_SHOW_UNREAD_COUNT))
		labeltype -= NODE_CAPABILITY_SHOW_UNREAD_COUNT;

	label = g_markup_escape_text (node_get_title (node), -1);
	switch (labeltype) {
		case NODE_CAPABILITY_SHOW_UNREAD_COUNT |
		     NODE_CAPABILITY_SHOW_ITEM_COUNT:
	     		/* treat like show unread count */
		case NODE_CAPABILITY_SHOW_UNREAD_COUNT:
			count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor?countColor:"", node->unreadCount);
			break;
		case NODE_CAPABILITY_SHOW_ITEM_COUNT:
			count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor?countColor:"", node->itemCount);
		     	break;
		default:
			break;
	}

	/* Extra message for search folder rebuilds */
	if (IS_VFOLDER (node) && node->data) {
		if (((vfolderPtr)node->data)->reloading) {
			gchar *tmp = label;
			label = g_strdup_printf (_("%s\n<i>Rebuilding</i>"), label);
			g_free (tmp);
		}
	}

	gtk_tree_store_set (feedstore, iter,
	                    FS_LABEL, label,
	                    FS_UNREAD, node->unreadCount,
	                    FS_ICON, node->available?node_get_icon (node):icon_get (ICON_UNAVAILABLE),
	                    FS_COUNT, count,
	                    -1);
	g_free (label);

	if (node->parent)
		feed_list_node_update (node->parent->id);
}
Esempio n. 7
0
static gboolean
ui_dnd_feed_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data)
{
	GtkTreeIter	iter, iter2, parentIter;
	nodePtr		node, oldParent, newParent;
	gboolean	result, valid, added;
	gint		oldPos, pos;

	result = old_feed_drag_data_received (drag_dest, dest, selection_data);
	if (result) {
		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest), &iter, dest)) {
			gtk_tree_model_get (GTK_TREE_MODEL (drag_dest), &iter, FS_PTR, &node, -1);

			/* If we don't do anything, then because DnD is implemented by removal and
			   re-insertion, and the removed node is selected, the treeview selects
			   the next row after the removal, which is supremely irritating.
			   But setting a selection at this point is pointless, because the treeview
			   will reset it as soon as the DnD callback returns. Instead, we set
			   the cursor, which controls where treeview resets the selection later.
			 */
			gtk_tree_view_set_cursor(GTK_TREE_VIEW (liferea_shell_lookup ("feedlist")),
			    dest, NULL, FALSE);

			/* remove from old parents child list */
			oldParent = node->parent;
			g_assert (oldParent);
			oldPos = g_slist_index (oldParent->children, node);
			oldParent->children = g_slist_remove (oldParent->children, node);
			node_update_counters (oldParent);
			
			if (0 == g_slist_length (oldParent->children))
				feed_list_node_add_empty_node (feed_list_node_to_iter (oldParent->id));
			
			/* and rebuild new parents child list */
			if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (drag_dest), &parentIter, &iter)) {
				gtk_tree_model_get (GTK_TREE_MODEL (drag_dest), &parentIter, FS_PTR, &newParent, -1);
			} else {
				gtk_tree_model_get_iter_first (GTK_TREE_MODEL (drag_dest), &parentIter);
				newParent = feedlist_get_root ();
			}

			/* drop old list... */
			debug3 (DEBUG_GUI, "old parent is %s (%d, position=%d)", oldParent->title, g_slist_length (oldParent->children), oldPos);
			debug2 (DEBUG_GUI, "new parent is %s (%d)", newParent->title, g_slist_length (newParent->children));
			g_slist_free (newParent->children);
			newParent->children = NULL;
			node->parent = newParent;
			
			debug0 (DEBUG_GUI, "new newParent child list:");
				
			/* and rebuild it from the tree model */
			if (feedlist_get_root() != newParent)
				valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (drag_dest), &iter2, &parentIter);
			else
				valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (drag_dest), &iter2, NULL);
				
			pos = 0;
			added = FALSE;
			while (valid) {
				nodePtr	child;			
				gtk_tree_model_get (GTK_TREE_MODEL (drag_dest), &iter2, FS_PTR, &child, -1);
				if (child) {
					/* Well this is a bit complicated... If we move a feed inside a folder
					   we need to skip the old insertion point (oldPos). This is easy if the
					   feed is added behind this position. If it is dropped before the flag
					   added is set once the new copy is encountered. The remaining copy
					   is skipped automatically when the flag is set.
					 */
					 
					/* check if this is a copy of the dragged node or the original itself */
					if ((newParent == oldParent) && !strcmp(node->id, child->id)) {
						if ((pos == oldPos) || added) {
							/* it is the original */
							debug2 (DEBUG_GUI, "   -> %d: skipping old insertion point %s", pos, child->title);
						} else {
							/* it is a copy inserted before the original */
							added = TRUE;
							debug2 (DEBUG_GUI, "   -> %d: new insertion point of %s", pos, child->title);
							newParent->children = g_slist_append (newParent->children, child);
						}
					} else {
						/* all other nodes */
						debug2 (DEBUG_GUI, "   -> %d: adding %s", pos, child->title);
						newParent->children = g_slist_append (newParent->children, child);
					}
				} else {
					debug0 (DEBUG_GUI, "   -> removing empty node");
					/* remove possible existing "(empty)" node from newParent */
					feed_list_node_remove_empty_node (&parentIter);
				}
				valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (drag_dest), &iter2);
				pos++;
			}
			
			db_node_update (node);
			node_update_counters (newParent);
			
			feedlist_schedule_save ();
		}
	}
						      
	return result;
}