forked from AuroraMiddleware/gtk
224 lines
4.7 KiB
C
224 lines
4.7 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|