medit/moo/mooutils/moofileview/moofileview-private.h

196 lines
5.5 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
* moofilesystem-private.h
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#include <string.h>
#include <glib.h>
#define COLUMN_FILE MOO_FOLDER_MODEL_COLUMN_FILE
/* TODO: strncmp should accept char len, not byte len? */
typedef struct {
int (*strcmp_func) (const char *str,
MooFile *file);
int (*strncmp_func) (const char *str,
MooFile *file,
guint len);
char* (*normalize_func) (const char *str,
gssize len);
} TextFuncs;
static int strcmp_func (const char *str,
MooFile *file)
{
return strcmp (str, moo_file_display_name (file));
}
static int strncmp_func (const char *str,
MooFile *file,
guint len)
{
return strncmp (str, moo_file_display_name (file), len);
}
static char *normalize_func (const char *str,
gssize len)
{
return g_utf8_normalize (str, len, G_NORMALIZE_ALL);
}
static int case_strcmp_func (const char *str,
MooFile *file)
{
return strcmp (str, moo_file_case_display_name (file));
}
static int case_strncmp_func (const char *str,
MooFile *file,
guint len)
{
return strncmp (str, moo_file_case_display_name (file), len);
}
static char *case_normalize_func (const char *str,
gssize len)
{
char *norm = g_utf8_normalize (str, len, G_NORMALIZE_ALL);
char *res = g_utf8_casefold (norm, -1);
g_free (norm);
return res;
}
static gboolean model_find_next_match (GtkTreeModel *model,
GtkTreeIter *iter,
const char *text,
gssize len,
TextFuncs *funcs,
gboolean exact_match)
{
char *normalized_text;
guint normalized_text_len;
g_return_val_if_fail (text != NULL, FALSE);
normalized_text = funcs->normalize_func (text, len);
normalized_text_len = strlen (normalized_text);
while (TRUE)
{
MooFile *file = NULL;
gboolean match;
gtk_tree_model_get (model, iter, COLUMN_FILE, &file, -1);
if (file)
{
if (exact_match)
match = !funcs->strcmp_func (normalized_text, file);
else
match = !funcs->strncmp_func (normalized_text, file,
normalized_text_len);
moo_file_unref (file);
if (match)
{
g_free (normalized_text);
return TRUE;
}
}
if (!gtk_tree_model_iter_next (model, iter))
{
g_free (normalized_text);
return FALSE;
}
}
}
static GString *model_find_max_prefix (GtkTreeModel *model,
const char *text,
TextFuncs *funcs,
gboolean *unique_p,
GtkTreeIter *unique_iter_p)
{
GtkTreeIter iter, unique_iter;
guint text_len;
GString *prefix = NULL;
gboolean unique = FALSE;
g_assert (text && text[0]);
text_len = strlen (text);
if (!gtk_tree_model_get_iter_first (model, &iter))
goto out;
while (TRUE)
{
MooFile *file = NULL;
const char *name;
guint i;
if (!model_find_next_match (model, &iter, text, text_len, funcs, FALSE))
goto out;
gtk_tree_model_get (model, &iter,
COLUMN_FILE, &file, -1);
g_assert (file != NULL);
name = moo_file_display_name (file);
if (!prefix)
{
prefix = g_string_new (moo_file_display_name (file));
unique_iter = iter;
unique = TRUE;
/* nothing to look for, just check if it's really unique */
if (prefix->len == text_len)
{
if (gtk_tree_model_iter_next (model, &iter) &&
model_find_next_match (model, &iter, text, text_len, funcs, FALSE))
unique = FALSE;
goto out;
}
}
else
{
for (i = text_len; i < prefix->len && name[i] == prefix->str[i]; ++i) ;
prefix->str[i] = 0;
prefix->len = i;
unique = FALSE;
if (prefix->len == text_len)
goto out;
}
if (!gtk_tree_model_iter_next (model, &iter))
goto out;
}
out:
if (unique_p)
*unique_p = unique;
if (unique_iter_p)
*unique_iter_p = unique_iter;
return prefix;
}