/* * Copyright (c) 2014 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ #include "treewalk.h" struct _GtkTreeWalk { GtkTreeModel *model; GtkTreeIter position; gboolean visited; RowPredicate predicate; gpointer data; GDestroyNotify destroy; }; GtkTreeWalk * gtk_tree_walk_new (GtkTreeModel *model, RowPredicate predicate, gpointer data, GDestroyNotify destroy) { GtkTreeWalk *walk; walk = g_new (GtkTreeWalk, 1); walk->model = g_object_ref (model); walk->visited = FALSE; walk->predicate = predicate; walk->data = data; walk->destroy = destroy; return walk; } void gtk_tree_walk_free (GtkTreeWalk *walk) { g_object_unref (walk->model); if (walk->destroy) walk->destroy (walk->data); g_free (walk); } void gtk_tree_walk_reset (GtkTreeWalk *walk, GtkTreeIter *iter) { if (iter) { walk->position = *iter; walk->visited = TRUE; } else { walk->visited = FALSE; } } static gboolean gtk_tree_walk_step_forward (GtkTreeWalk *walk) { GtkTreeIter next, up; if (!walk->visited) { if (!gtk_tree_model_get_iter_first (walk->model, &walk->position)) return FALSE; walk->visited = TRUE; return TRUE; } if (gtk_tree_model_iter_children (walk->model, &next, &walk->position)) { walk->position = next; return TRUE; } next = walk->position; do { up = next; if (gtk_tree_model_iter_next (walk->model, &next)) { walk->position = next; return TRUE; } } while (gtk_tree_model_iter_parent (walk->model, &next, &up)); return FALSE; } static gboolean gtk_tree_model_iter_last_child (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent) { GtkTreeIter next; if (!gtk_tree_model_iter_children (model, &next, parent)) return FALSE; do *iter = next; while (gtk_tree_model_iter_next (model, &next)); return TRUE; } static gboolean gtk_tree_model_get_iter_last (GtkTreeModel *model, GtkTreeIter *iter) { GtkTreeIter next; if (!gtk_tree_model_iter_last_child (model, &next, NULL)) return FALSE; do *iter = next; while (gtk_tree_model_iter_last_child (model, &next, &next)); return TRUE; } static gboolean gtk_tree_walk_step_back (GtkTreeWalk *walk) { GtkTreeIter previous, down; if (!walk->visited) { if (!gtk_tree_model_get_iter_last (walk->model, &walk->position)) return FALSE; walk->visited = TRUE; return TRUE; } previous = walk->position; if (gtk_tree_model_iter_previous (walk->model, &previous)) { while (gtk_tree_model_iter_last_child (walk->model, &down, &previous)) previous = down; walk->position = previous; return TRUE; } if (gtk_tree_model_iter_parent (walk->model, &previous, &walk->position)) { walk->position = previous; return TRUE; } return FALSE; } static gboolean gtk_tree_walk_step (GtkTreeWalk *walk, gboolean backwards) { if (backwards) return gtk_tree_walk_step_back (walk); else return gtk_tree_walk_step_forward (walk); } static gboolean row_is_match (GtkTreeWalk *walk) { if (walk->predicate) return walk->predicate (walk->model, &walk->position, walk->data); return TRUE; } gboolean gtk_tree_walk_next_match (GtkTreeWalk *walk, gboolean force_move, gboolean backwards, GtkTreeIter *iter) { gboolean moved = FALSE; gboolean was_visited; GtkTreeIter position; was_visited = walk->visited; position = walk->position; do { if (moved || (!force_move && walk->visited)) { if (row_is_match (walk)) { *iter = walk->position; return TRUE; } } moved = TRUE; } while (gtk_tree_walk_step (walk, backwards)); walk->visited = was_visited; walk->position = position; return FALSE; } gboolean gtk_tree_walk_get_position (GtkTreeWalk *walk, GtkTreeIter *iter) { *iter = walk->position; return walk->visited; }