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); }
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; }