diff options
author | Mathieu Lacage <mathieu@eazel.com> | 2000-08-15 07:24:22 +0000 |
---|---|---|
committer | Mathieu Lacage <mathieu@src.gnome.org> | 2000-08-15 07:24:22 +0000 |
commit | f951f6f3552762c020155273fa59e43fc1534869 (patch) | |
tree | 3fd91db4721b0b8a4afc6f6565c4f1f4c34d2533 | |
parent | 73a96dd98e03019d790b690912c488fa78ed7c03 (diff) | |
download | nautilus-f951f6f3552762c020155273fa59e43fc1534869.tar.gz |
Implements core of task 1761
2000-08-15 Mathieu Lacage <mathieu@eazel.com>
Implements core of task 1761
* libnautilus-extensions/Makefile.am: add my new files
to the build.
* libnautilus-extensions/nautilus-search-uri.c:
(strip_uri_begenning), (free_tokenized_uri), (tokenize_uri),
(get_item_number), (get_translated_criterion),
(get_first_criterion_prefix), (get_nth_criterion_prefix),
(get_nth_criterion_suffix), (get_first_criterion_suffix),
(parse_uri), (nautilus_search_uri_to_human): add file.
* libnautilus-extensions/nautilus-search-uri.h: add file.
* po/POTFILES.in: add my files there.
* src/file-manager/fm-search-list-view.c: (load_location_callback):
a space.
* src/nautilus-complex-search-bar.c:
(nautilus_complex_search_bar_initialize),
(attach_criterion_to_search_bar),
(unattach_criterion_from_search_bar):
fix multiple bugs: the size text entry would not be removed by
the "fewer options" button. Changed a few "pressed" to "clicked".
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | libnautilus-extensions/Makefile.am | 2 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-search-uri.c | 634 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-search-uri.h | 37 | ||||
-rw-r--r-- | libnautilus-private/Makefile.am | 2 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-uri.c | 634 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-uri.h | 37 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/file-manager/fm-search-list-view.c | 3 | ||||
-rw-r--r-- | src/nautilus-complex-search-bar.c | 15 |
10 files changed, 1384 insertions, 6 deletions
@@ -1,3 +1,26 @@ +2000-08-15 Mathieu Lacage <mathieu@eazel.com> + + Implements core of task 1761 + + * libnautilus-extensions/Makefile.am: add my new files + to the build. + * libnautilus-extensions/nautilus-search-uri.c: + (strip_uri_begenning), (free_tokenized_uri), (tokenize_uri), + (get_item_number), (get_translated_criterion), + (get_first_criterion_prefix), (get_nth_criterion_prefix), + (get_nth_criterion_suffix), (get_first_criterion_suffix), + (parse_uri), (nautilus_search_uri_to_human): add file. + * libnautilus-extensions/nautilus-search-uri.h: add file. + * po/POTFILES.in: add my files there. + * src/file-manager/fm-search-list-view.c: (load_location_callback): + a space. + * src/nautilus-complex-search-bar.c: + (nautilus_complex_search_bar_initialize), + (attach_criterion_to_search_bar), + (unattach_criterion_from_search_bar): + fix multiple bugs: the size text entry would not be removed by + the "fewer options" button. Changed a few "pressed" to "clicked". + 2000-08-14 Gene Z. Ragan <gzr@eazel.com> * libnautilus-extensions/nautilus-icon-container.c: @@ -97,6 +120,7 @@ (create_install_page), (create_finish_page), (create_window): Revamped large parts of the ui, much prettier now. +>>>>>>> 1.1394 2000-08-14 Pavel Cisler <pavel@eazel.com> * src/file-manager/fm-desktop-icon-view.c: @@ -449,6 +473,7 @@ (nautilus_sidebar_tabs_size_allocate): removed unnecessary override of size_request +>>>>>>> 1.1392 2000-08-12 Raph Levien <raph@acm.org> * librsvg/rsvg-ft.c: Got glyph cache working. Eviction when diff --git a/libnautilus-extensions/Makefile.am b/libnautilus-extensions/Makefile.am index 8a66c98e7..91da8cd95 100644 --- a/libnautilus-extensions/Makefile.am +++ b/libnautilus-extensions/Makefile.am @@ -92,6 +92,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-program-choosing.c \ nautilus-radio-button-group.c \ nautilus-search-bar-criterion.c \ + nautilus-search-uri.c \ nautilus-self-checks.c \ nautilus-stock-dialogs.c \ nautilus-string-list.c \ @@ -173,6 +174,7 @@ noinst_HEADERS = \ nautilus-program-choosing.h \ nautilus-radio-button-group.h \ nautilus-search-bar-criterion.h \ + nautilus-search-uri.h \ nautilus-search-bar-criterion-private.h \ nautilus-self-checks.h \ nautilus-stock-dialogs.h \ diff --git a/libnautilus-extensions/nautilus-search-uri.c b/libnautilus-extensions/nautilus-search-uri.c new file mode 100644 index 000000000..8757fc3ec --- /dev/null +++ b/libnautilus-extensions/nautilus-search-uri.c @@ -0,0 +1,634 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Code to generate human-readable strings from search uris. + + Copyright (C) 2000 Eazel, Inc. + + 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. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Mathieu Lacage <mathieu@eazel.com> +*/ + +#include <config.h> +#include "nautilus-search-uri.h" + +/* FIXME: including only libgnome/gnome-i18n.h gives + what seems to be random erros on /usr/include/libintl.h + gnome.h fixes the pb but is ugly. +*/ +#include <gnome.h> + +#include <glib.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +static const char * strip_uri_begenning (const char *location_uri); +static GSList * tokenize_uri (const char *string); +static char * get_translated_criterion (const GSList *criterion); +static char * get_first_criterion_prefix (GSList *criterion); +static char * get_nth_criterion_prefix (GSList *criterion); +static char * get_nth_criterion_suffix (GSList *criterion); +static char * get_first_criterion_suffix (GSList *criterion); +static char * parse_uri (const char *search_uri); +static void free_tokenized_uri (GSList *list); + + + +/** + * strip_uri_begenning: + * @location_uri: search uri. + * + * strips the search:[file:///...] part of the input uri. + * + */ +static const char * +strip_uri_begenning (const char *location_uri) +{ + char **first_token; + char *ptr; + const char *ret_val; + + first_token = g_strsplit (location_uri, " ", 1); + + /* parse the first token from the end to the begenning. + to extract the search:[] part. + */ + for (ptr = first_token[0]+strlen(first_token[0]); + ptr != first_token[0] && *ptr != ']'; + ptr--) {} + + ret_val = location_uri + (ptr - first_token[0]) + 1; + + g_strfreev (first_token); + + return ret_val; +} + +/** + * free_tokenized_uri: + * @list: tokenized uri to free + * + */ +static void +free_tokenized_uri (GSList *list) +{ + GSList *temp_list; + + for (temp_list = list; temp_list != NULL; temp_list = temp_list->next) { + GSList *inner_list, *temp_inner_list; + + inner_list = (GSList *)temp_list->data; + for (temp_inner_list = inner_list; temp_inner_list != NULL; + temp_inner_list = temp_inner_list->next) { + g_free ((char *)temp_inner_list->data); + } + + g_slist_free (inner_list); + } + g_slist_free (list); +} + + +/** + * tokenize_uri + * @string: string to parse + * + * This function tokenizes a subset of the grand medusa uri specification. + * If it cannot, it returns NULL. CHECK FOR NULL upon return. + * + * Return value: a Singly linked list of singly linked lists. + * each of the element of the root linked list is a complete criterion. + * each criterin sinlgly linked list is made of the different tokens + * of the criterion. + */ +static GSList * +tokenize_uri (const char *string) +{ + const char *temp_string; + char **criterions; + GSList *criterion_list; + int i, j; + + if (string == NULL) { + return NULL; + } + + criterion_list = NULL; + + string = strip_uri_begenning (string); + + /* make sure we can handle this uri */ + if ( strchr (string , '(') != NULL + || strchr (string, ')') != NULL + || strchr (string, '|') != NULL) { + return NULL; + } + + /* split the uri in different criterions */ + criterions = g_strsplit (string, " & ", 0); + for (i = 0, temp_string = criterions[0]; + temp_string != NULL; + i++, temp_string = criterions[i]) { + char **tokens; + char *token; + GSList *token_list; + + /* split a criterion in different tokens */ + token_list = NULL; + tokens = g_strsplit (temp_string, " ", 2); + for (j = 0, token = tokens[0]; token != NULL; j++, token = tokens[j]) { + /* g_strstrip does not return a newly allocated string. */ + token_list = g_slist_append (token_list, g_strdup(g_strstrip (token))); + } + criterion_list = g_slist_append (criterion_list, token_list); + g_strfreev (tokens); + } + g_strfreev (criterions); + + return criterion_list; +} + +typedef struct _value_criterion_item value_criterion_item; +typedef value_criterion_item *value_criterion_table; + +typedef struct _operand_criterion_item operand_criterion_item; +typedef operand_criterion_item *operand_criterion_table; + +typedef struct _field_criterion_item field_criterion_item; +typedef field_criterion_item *field_criterion_table; + +/* toplevel structure each entry points to a level 2 structure */ +struct _field_criterion_item { + char *id; + char *prefix; + operand_criterion_table items; +}; +/* second level structure. if items is NULL, the entry is a leaf + of our hierarchy. If it is not, it points to a level 3 leaf +*/ +struct _operand_criterion_item { + char *id; + char *translation; + value_criterion_table items; +}; +/* third level structure. leaf */ +struct _value_criterion_item { + char *id; + char *translation; +}; + + +/* ------------------------------------------------------- + - file name - + ------------------------------------------------------- +*/ + +static operand_criterion_item file_name2_table [] = { + {"contains", + N_("name contains \"%s\""), + NULL}, + {"starts_with", + N_("name starts with \"%s\""), + NULL}, + {"ends_with", + "name ends with %s", + NULL}, + {"does_not_contain", + N_("name does not contain \"%s\""), + NULL}, + {"regexp_matches", + N_("name matches regexp \"%s\""), + NULL}, + {"matches", + N_("name matches glob \"%s\""), + NULL}, + {NULL, NULL, NULL} + +}; + + +/* ------------------------------------------------------- + - file type - + ------------------------------------------------------- +*/ +static value_criterion_item file_type_options3_table [] = { + {"file", + N_("regular files")}, + {"text_file", + N_("text files")}, + {"application", + N_("applications")}, + {"directory", + N_("directories")}, + {"music", + N_("music")}, + {NULL, NULL} +}; +static operand_criterion_item file_type2_table [] = { + /* this one is not yet implemented in medusa */ + {"is_not", + N_("are not %s"), + file_type_options3_table}, + /* this one is implemented */ + {"is", + N_("are %s"), + file_type_options3_table}, +}; + + +/* ------------------------------------------------------- + - owner - + ------------------------------------------------------- +*/ +static operand_criterion_item owner2_table [] = { + {"is_not", + N_("owner is not \"%s\""), + NULL}, + {"is", + N_("owner is \"%s\""), + NULL}, + /* folowing ones are not supported by Nautilus UI */ + {"has_uid", + N_("owner has uid of \"%s\""), + NULL}, + {"does_not_have_uid", + N_("does not have UID"), + NULL}, + {NULL, NULL, NULL} +}; + +/* ------------------------------------------------------- + - size - + ------------------------------------------------------- +*/ +static operand_criterion_item size2_table [] = { + {"larger_than", + N_("size is larger than %s kilobytes"), + NULL}, + {"smaller_than", + N_("size is smaller than %s kilobytes"), + NULL}, + {"is", + N_("size is %s kilobytes"), + NULL}, + {NULL, NULL, NULL} +}; + +/* ------------------------------------------------------- + - modified time - + ------------------------------------------------------- +*/ +static operand_criterion_item mod_time2_table [] = { + {"updated", + N_("after"), + NULL}, + {"not_updated", + N_("before"), + NULL}, + {NULL, NULL, NULL} +}; + +/* ------------------------------------------------------- + - emblems - + ------------------------------------------------------- +*/ + +/* not implemented in nautilus yet */ +static operand_criterion_item emblem2_table [] = { + {NULL, NULL, NULL} +}; + + +/* ------------------------------------------------------- + - contains - + ------------------------------------------------------- +*/ + +/* I cannot find any doc on this one */ +static operand_criterion_item contains2_table [] = { + {NULL, NULL, NULL}, +}; + + + +/* ------------------------------------------------------- + - main table - + ------------------------------------------------------- +*/ + +static field_criterion_item main_table[] = { + {"file_name", + N_("whose"), + file_name2_table}, + {"file_type", + N_("who"), + file_type2_table}, + {"owner", + N_("whose"), + owner2_table}, + {"size", + N_("whose"), + size2_table}, + /* waiting for doc */ + {"contains", + N_("who"), + contains2_table}, + /* waiting for spec */ + {"mod_time", + N_("whose"), + mod_time2_table}, + /* waiting for implementation */ + {"emblem", + N_(""), + emblem2_table}, + {NULL, NULL, NULL} +}; + + + +/** + * get_item_number: + * @current_table: the table to parse. + * @item: the string to search into the table. + * + * Small helper function which allows whoich serches for @item + * into the @current_table. + * it returns -1 if it could not find it. + * Yes, I know it is wrong to use the normal function return value + * to pass error status. + */ +static int get_item_number (field_criterion_item *current_table, + char *item); +static int +get_item_number (field_criterion_item *current_table, char *item) +{ + int i; + + i = 0; + while (strcmp (current_table[i].id, + item) != 0) { + i++; + if (current_table[i].id == NULL) { + return -1; + } + } + + return i; +} + + +/** + * get_translated_criterion: + * @criterion: criterion uri to parse + * + * Returns a translated string for a given criterion uri. + */ +static char * +get_translated_criterion (const GSList *criterion) +{ + + int item_number, value_item_number; + operand_criterion_item *operand_table; + value_criterion_item *value_table; + char *ret_val; + + + /* get through begening of criterion structure */ + item_number = get_item_number (main_table, (char *)criterion->data); + if (item_number == -1) { + return NULL; + } + operand_table = main_table[item_number].items; + criterion = criterion->next; + + /* get through operanddle criterion structure */ + item_number = get_item_number ((field_criterion_item *)operand_table, + (char *)criterion->data); + if (item_number == -1) { + return NULL; + } + value_table = operand_table[item_number].items; + criterion = criterion->next; + + /* get through value criterion structure. + The fun begins NOW. */ + + if (value_table == NULL && operand_table[item_number].translation != NULL) { + /* simplest case: if the pointer to the value criterion + structure is NULL and we have a translation, + we output a concat of the translation and the + last part of the uri. + */ + ret_val = g_strdup_printf (_(operand_table[item_number].translation), + (char *)criterion->data); + return ret_val; + } else if (value_table != NULL) { + /* get through level 3 structure */ + + value_item_number = get_item_number ((field_criterion_item *)value_table, + (char *)criterion->data); + if (value_item_number == -1) { + return NULL; + } + + if (operand_table[item_number].translation == NULL) { + /* if we had no translation in operand criterion table */ + ret_val = g_strdup (_(value_table[value_item_number].translation)); + } else { + /* if we have both some translation in level 2 and level 3 */ + ret_val = g_strdup_printf (_(operand_table[item_number].translation), + _(value_table[value_item_number].translation)); + } + return ret_val; + } + + return g_strdup (_("are directories")); +} + +/** + * get_first_criterion_prefix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "whose", "who" or "which" prefix for a given criterion. + * FIXME: it is an ugly hack I added after arlo asked me to: + * it is likely to be a pain for translations. I need to modify the data struct + * for this to work cleanly. + * + * return value: the translated prefix. + */ +static char * +get_first_criterion_prefix (GSList *criterion) +{ + GSList *criterion_list; + char *criterion_type; + int item_number; + + criterion_list = (GSList *)criterion->data; + criterion_type = (char *)criterion_list->data; + + + item_number = get_item_number (main_table, criterion_type); + + return g_strdup (_(main_table[item_number].prefix)); +} + +/** + * get_nth_criterion_prefix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "," or "and" prefix for any criterion. + * + * return value: the translated prefix. + */ +static char * +get_nth_criterion_prefix (GSList *criterion) +{ + /* if we are the last criterion, put it here. */ + + if (criterion->next == NULL) { + return g_strdup (_(" and ")); + } + return g_strdup (", "); +} + +/** + * get_nth_criterion_suffix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "." suffix for any criterion. + * + * return value: the translated suffix. + */ +static char * +get_nth_criterion_suffix (GSList *criterion) +{ + /* if we are the last criterion, put it here. */ + + if (criterion->next == NULL) { + return g_strdup ("."); + } + return g_strdup (""); +} + + +/** + * get_first_criterion_suffix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "." suffix for any criterion. + * + * return value: the translated suffix. + */ +static char * +get_first_criterion_suffix (GSList *criterion) +{ + return get_nth_criterion_suffix (criterion); +} + + + +/** + * parse_uri: + * @search_uri: uri to translate. + * + * returns the translated version of the uri. + */ +static char * +parse_uri (const char *search_uri) +{ + GSList *criterions, *criterion; + char *translated_criterion, *translated_prefix, *translated_suffix; + char *ret_val, *temp; + + + criterions = tokenize_uri (search_uri); + if (criterions == NULL) { + return NULL; + } + + /* processes the first criterion and add the necessary "whose" prefix */ + translated_prefix = get_first_criterion_prefix (criterions); + translated_criterion = get_translated_criterion ((GSList *)criterions->data); + if (translated_criterion == NULL) { + free_tokenized_uri (criterions); + g_free (translated_prefix); + return NULL; + } + translated_suffix = get_first_criterion_suffix (criterions); + ret_val = g_strdup_printf (_("Search results for items %s %s%s"), + translated_prefix, translated_criterion, translated_suffix); + g_free (translated_suffix); + g_free (translated_criterion); + g_free (translated_prefix); + + /* processes the other criterions and add the necessary "and" prefixes */ + for (criterion = (GSList *)criterions->next; criterion != NULL; criterion = criterion->next) { + translated_criterion = get_translated_criterion ((const GSList *)criterion->data); + if (translated_criterion == NULL) { + g_free (ret_val); + free_tokenized_uri (criterions); + return NULL; + } + translated_prefix = get_nth_criterion_prefix (criterion); + translated_suffix = get_nth_criterion_suffix (criterion); + temp = g_strconcat (ret_val, translated_prefix, + translated_criterion, translated_suffix, NULL); + g_free (ret_val); + ret_val = temp; + g_free (translated_criterion); + g_free (translated_suffix); + g_free (translated_prefix); + } + + free_tokenized_uri (criterions); + + return ret_val; +} + + +/** + * nautilus_search_uri_to_human: + * @search_uri: search uri to translate to human langage. + * + * The returned string is already internationalized. + */ +char * nautilus_search_uri_to_human (const char *search_uri) +{ + char *uri, *human; + + uri = gnome_vfs_unescape_string_for_display (search_uri); + human = parse_uri (uri); + if (human == NULL) { + g_print ("mathieu: %s\n", uri); + return uri; + } + + g_free (uri); + g_print ("mathieu: %s\n", human); + + return human; +} + + + + + + + + + + + + diff --git a/libnautilus-extensions/nautilus-search-uri.h b/libnautilus-extensions/nautilus-search-uri.h new file mode 100644 index 000000000..f0544ceb2 --- /dev/null +++ b/libnautilus-extensions/nautilus-search-uri.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Code to generate human-readable strings from search uris. + + Copyright (C) 2000 Eazel, Inc. + + 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. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Mathieu Lacage <mathieu@eazel.com> +*/ + +#ifndef NAUTILUS_SEARCH_URI_H +#define NAUTILUS_SEARCH_URI_H + + + +char * nautilus_search_uri_to_human (const char *search_uri); + + + + + + + +#endif /* NAUTILUS_SEARCH_URI_H */ diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index 8a66c98e7..91da8cd95 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -92,6 +92,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-program-choosing.c \ nautilus-radio-button-group.c \ nautilus-search-bar-criterion.c \ + nautilus-search-uri.c \ nautilus-self-checks.c \ nautilus-stock-dialogs.c \ nautilus-string-list.c \ @@ -173,6 +174,7 @@ noinst_HEADERS = \ nautilus-program-choosing.h \ nautilus-radio-button-group.h \ nautilus-search-bar-criterion.h \ + nautilus-search-uri.h \ nautilus-search-bar-criterion-private.h \ nautilus-self-checks.h \ nautilus-stock-dialogs.h \ diff --git a/libnautilus-private/nautilus-search-uri.c b/libnautilus-private/nautilus-search-uri.c new file mode 100644 index 000000000..8757fc3ec --- /dev/null +++ b/libnautilus-private/nautilus-search-uri.c @@ -0,0 +1,634 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Code to generate human-readable strings from search uris. + + Copyright (C) 2000 Eazel, Inc. + + 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. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Mathieu Lacage <mathieu@eazel.com> +*/ + +#include <config.h> +#include "nautilus-search-uri.h" + +/* FIXME: including only libgnome/gnome-i18n.h gives + what seems to be random erros on /usr/include/libintl.h + gnome.h fixes the pb but is ugly. +*/ +#include <gnome.h> + +#include <glib.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +static const char * strip_uri_begenning (const char *location_uri); +static GSList * tokenize_uri (const char *string); +static char * get_translated_criterion (const GSList *criterion); +static char * get_first_criterion_prefix (GSList *criterion); +static char * get_nth_criterion_prefix (GSList *criterion); +static char * get_nth_criterion_suffix (GSList *criterion); +static char * get_first_criterion_suffix (GSList *criterion); +static char * parse_uri (const char *search_uri); +static void free_tokenized_uri (GSList *list); + + + +/** + * strip_uri_begenning: + * @location_uri: search uri. + * + * strips the search:[file:///...] part of the input uri. + * + */ +static const char * +strip_uri_begenning (const char *location_uri) +{ + char **first_token; + char *ptr; + const char *ret_val; + + first_token = g_strsplit (location_uri, " ", 1); + + /* parse the first token from the end to the begenning. + to extract the search:[] part. + */ + for (ptr = first_token[0]+strlen(first_token[0]); + ptr != first_token[0] && *ptr != ']'; + ptr--) {} + + ret_val = location_uri + (ptr - first_token[0]) + 1; + + g_strfreev (first_token); + + return ret_val; +} + +/** + * free_tokenized_uri: + * @list: tokenized uri to free + * + */ +static void +free_tokenized_uri (GSList *list) +{ + GSList *temp_list; + + for (temp_list = list; temp_list != NULL; temp_list = temp_list->next) { + GSList *inner_list, *temp_inner_list; + + inner_list = (GSList *)temp_list->data; + for (temp_inner_list = inner_list; temp_inner_list != NULL; + temp_inner_list = temp_inner_list->next) { + g_free ((char *)temp_inner_list->data); + } + + g_slist_free (inner_list); + } + g_slist_free (list); +} + + +/** + * tokenize_uri + * @string: string to parse + * + * This function tokenizes a subset of the grand medusa uri specification. + * If it cannot, it returns NULL. CHECK FOR NULL upon return. + * + * Return value: a Singly linked list of singly linked lists. + * each of the element of the root linked list is a complete criterion. + * each criterin sinlgly linked list is made of the different tokens + * of the criterion. + */ +static GSList * +tokenize_uri (const char *string) +{ + const char *temp_string; + char **criterions; + GSList *criterion_list; + int i, j; + + if (string == NULL) { + return NULL; + } + + criterion_list = NULL; + + string = strip_uri_begenning (string); + + /* make sure we can handle this uri */ + if ( strchr (string , '(') != NULL + || strchr (string, ')') != NULL + || strchr (string, '|') != NULL) { + return NULL; + } + + /* split the uri in different criterions */ + criterions = g_strsplit (string, " & ", 0); + for (i = 0, temp_string = criterions[0]; + temp_string != NULL; + i++, temp_string = criterions[i]) { + char **tokens; + char *token; + GSList *token_list; + + /* split a criterion in different tokens */ + token_list = NULL; + tokens = g_strsplit (temp_string, " ", 2); + for (j = 0, token = tokens[0]; token != NULL; j++, token = tokens[j]) { + /* g_strstrip does not return a newly allocated string. */ + token_list = g_slist_append (token_list, g_strdup(g_strstrip (token))); + } + criterion_list = g_slist_append (criterion_list, token_list); + g_strfreev (tokens); + } + g_strfreev (criterions); + + return criterion_list; +} + +typedef struct _value_criterion_item value_criterion_item; +typedef value_criterion_item *value_criterion_table; + +typedef struct _operand_criterion_item operand_criterion_item; +typedef operand_criterion_item *operand_criterion_table; + +typedef struct _field_criterion_item field_criterion_item; +typedef field_criterion_item *field_criterion_table; + +/* toplevel structure each entry points to a level 2 structure */ +struct _field_criterion_item { + char *id; + char *prefix; + operand_criterion_table items; +}; +/* second level structure. if items is NULL, the entry is a leaf + of our hierarchy. If it is not, it points to a level 3 leaf +*/ +struct _operand_criterion_item { + char *id; + char *translation; + value_criterion_table items; +}; +/* third level structure. leaf */ +struct _value_criterion_item { + char *id; + char *translation; +}; + + +/* ------------------------------------------------------- + - file name - + ------------------------------------------------------- +*/ + +static operand_criterion_item file_name2_table [] = { + {"contains", + N_("name contains \"%s\""), + NULL}, + {"starts_with", + N_("name starts with \"%s\""), + NULL}, + {"ends_with", + "name ends with %s", + NULL}, + {"does_not_contain", + N_("name does not contain \"%s\""), + NULL}, + {"regexp_matches", + N_("name matches regexp \"%s\""), + NULL}, + {"matches", + N_("name matches glob \"%s\""), + NULL}, + {NULL, NULL, NULL} + +}; + + +/* ------------------------------------------------------- + - file type - + ------------------------------------------------------- +*/ +static value_criterion_item file_type_options3_table [] = { + {"file", + N_("regular files")}, + {"text_file", + N_("text files")}, + {"application", + N_("applications")}, + {"directory", + N_("directories")}, + {"music", + N_("music")}, + {NULL, NULL} +}; +static operand_criterion_item file_type2_table [] = { + /* this one is not yet implemented in medusa */ + {"is_not", + N_("are not %s"), + file_type_options3_table}, + /* this one is implemented */ + {"is", + N_("are %s"), + file_type_options3_table}, +}; + + +/* ------------------------------------------------------- + - owner - + ------------------------------------------------------- +*/ +static operand_criterion_item owner2_table [] = { + {"is_not", + N_("owner is not \"%s\""), + NULL}, + {"is", + N_("owner is \"%s\""), + NULL}, + /* folowing ones are not supported by Nautilus UI */ + {"has_uid", + N_("owner has uid of \"%s\""), + NULL}, + {"does_not_have_uid", + N_("does not have UID"), + NULL}, + {NULL, NULL, NULL} +}; + +/* ------------------------------------------------------- + - size - + ------------------------------------------------------- +*/ +static operand_criterion_item size2_table [] = { + {"larger_than", + N_("size is larger than %s kilobytes"), + NULL}, + {"smaller_than", + N_("size is smaller than %s kilobytes"), + NULL}, + {"is", + N_("size is %s kilobytes"), + NULL}, + {NULL, NULL, NULL} +}; + +/* ------------------------------------------------------- + - modified time - + ------------------------------------------------------- +*/ +static operand_criterion_item mod_time2_table [] = { + {"updated", + N_("after"), + NULL}, + {"not_updated", + N_("before"), + NULL}, + {NULL, NULL, NULL} +}; + +/* ------------------------------------------------------- + - emblems - + ------------------------------------------------------- +*/ + +/* not implemented in nautilus yet */ +static operand_criterion_item emblem2_table [] = { + {NULL, NULL, NULL} +}; + + +/* ------------------------------------------------------- + - contains - + ------------------------------------------------------- +*/ + +/* I cannot find any doc on this one */ +static operand_criterion_item contains2_table [] = { + {NULL, NULL, NULL}, +}; + + + +/* ------------------------------------------------------- + - main table - + ------------------------------------------------------- +*/ + +static field_criterion_item main_table[] = { + {"file_name", + N_("whose"), + file_name2_table}, + {"file_type", + N_("who"), + file_type2_table}, + {"owner", + N_("whose"), + owner2_table}, + {"size", + N_("whose"), + size2_table}, + /* waiting for doc */ + {"contains", + N_("who"), + contains2_table}, + /* waiting for spec */ + {"mod_time", + N_("whose"), + mod_time2_table}, + /* waiting for implementation */ + {"emblem", + N_(""), + emblem2_table}, + {NULL, NULL, NULL} +}; + + + +/** + * get_item_number: + * @current_table: the table to parse. + * @item: the string to search into the table. + * + * Small helper function which allows whoich serches for @item + * into the @current_table. + * it returns -1 if it could not find it. + * Yes, I know it is wrong to use the normal function return value + * to pass error status. + */ +static int get_item_number (field_criterion_item *current_table, + char *item); +static int +get_item_number (field_criterion_item *current_table, char *item) +{ + int i; + + i = 0; + while (strcmp (current_table[i].id, + item) != 0) { + i++; + if (current_table[i].id == NULL) { + return -1; + } + } + + return i; +} + + +/** + * get_translated_criterion: + * @criterion: criterion uri to parse + * + * Returns a translated string for a given criterion uri. + */ +static char * +get_translated_criterion (const GSList *criterion) +{ + + int item_number, value_item_number; + operand_criterion_item *operand_table; + value_criterion_item *value_table; + char *ret_val; + + + /* get through begening of criterion structure */ + item_number = get_item_number (main_table, (char *)criterion->data); + if (item_number == -1) { + return NULL; + } + operand_table = main_table[item_number].items; + criterion = criterion->next; + + /* get through operanddle criterion structure */ + item_number = get_item_number ((field_criterion_item *)operand_table, + (char *)criterion->data); + if (item_number == -1) { + return NULL; + } + value_table = operand_table[item_number].items; + criterion = criterion->next; + + /* get through value criterion structure. + The fun begins NOW. */ + + if (value_table == NULL && operand_table[item_number].translation != NULL) { + /* simplest case: if the pointer to the value criterion + structure is NULL and we have a translation, + we output a concat of the translation and the + last part of the uri. + */ + ret_val = g_strdup_printf (_(operand_table[item_number].translation), + (char *)criterion->data); + return ret_val; + } else if (value_table != NULL) { + /* get through level 3 structure */ + + value_item_number = get_item_number ((field_criterion_item *)value_table, + (char *)criterion->data); + if (value_item_number == -1) { + return NULL; + } + + if (operand_table[item_number].translation == NULL) { + /* if we had no translation in operand criterion table */ + ret_val = g_strdup (_(value_table[value_item_number].translation)); + } else { + /* if we have both some translation in level 2 and level 3 */ + ret_val = g_strdup_printf (_(operand_table[item_number].translation), + _(value_table[value_item_number].translation)); + } + return ret_val; + } + + return g_strdup (_("are directories")); +} + +/** + * get_first_criterion_prefix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "whose", "who" or "which" prefix for a given criterion. + * FIXME: it is an ugly hack I added after arlo asked me to: + * it is likely to be a pain for translations. I need to modify the data struct + * for this to work cleanly. + * + * return value: the translated prefix. + */ +static char * +get_first_criterion_prefix (GSList *criterion) +{ + GSList *criterion_list; + char *criterion_type; + int item_number; + + criterion_list = (GSList *)criterion->data; + criterion_type = (char *)criterion_list->data; + + + item_number = get_item_number (main_table, criterion_type); + + return g_strdup (_(main_table[item_number].prefix)); +} + +/** + * get_nth_criterion_prefix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "," or "and" prefix for any criterion. + * + * return value: the translated prefix. + */ +static char * +get_nth_criterion_prefix (GSList *criterion) +{ + /* if we are the last criterion, put it here. */ + + if (criterion->next == NULL) { + return g_strdup (_(" and ")); + } + return g_strdup (", "); +} + +/** + * get_nth_criterion_suffix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "." suffix for any criterion. + * + * return value: the translated suffix. + */ +static char * +get_nth_criterion_suffix (GSList *criterion) +{ + /* if we are the last criterion, put it here. */ + + if (criterion->next == NULL) { + return g_strdup ("."); + } + return g_strdup (""); +} + + +/** + * get_first_criterion_suffix: + * @criterion: The GSList whose data field points to the criterion GSList. + * + * calculates the "." suffix for any criterion. + * + * return value: the translated suffix. + */ +static char * +get_first_criterion_suffix (GSList *criterion) +{ + return get_nth_criterion_suffix (criterion); +} + + + +/** + * parse_uri: + * @search_uri: uri to translate. + * + * returns the translated version of the uri. + */ +static char * +parse_uri (const char *search_uri) +{ + GSList *criterions, *criterion; + char *translated_criterion, *translated_prefix, *translated_suffix; + char *ret_val, *temp; + + + criterions = tokenize_uri (search_uri); + if (criterions == NULL) { + return NULL; + } + + /* processes the first criterion and add the necessary "whose" prefix */ + translated_prefix = get_first_criterion_prefix (criterions); + translated_criterion = get_translated_criterion ((GSList *)criterions->data); + if (translated_criterion == NULL) { + free_tokenized_uri (criterions); + g_free (translated_prefix); + return NULL; + } + translated_suffix = get_first_criterion_suffix (criterions); + ret_val = g_strdup_printf (_("Search results for items %s %s%s"), + translated_prefix, translated_criterion, translated_suffix); + g_free (translated_suffix); + g_free (translated_criterion); + g_free (translated_prefix); + + /* processes the other criterions and add the necessary "and" prefixes */ + for (criterion = (GSList *)criterions->next; criterion != NULL; criterion = criterion->next) { + translated_criterion = get_translated_criterion ((const GSList *)criterion->data); + if (translated_criterion == NULL) { + g_free (ret_val); + free_tokenized_uri (criterions); + return NULL; + } + translated_prefix = get_nth_criterion_prefix (criterion); + translated_suffix = get_nth_criterion_suffix (criterion); + temp = g_strconcat (ret_val, translated_prefix, + translated_criterion, translated_suffix, NULL); + g_free (ret_val); + ret_val = temp; + g_free (translated_criterion); + g_free (translated_suffix); + g_free (translated_prefix); + } + + free_tokenized_uri (criterions); + + return ret_val; +} + + +/** + * nautilus_search_uri_to_human: + * @search_uri: search uri to translate to human langage. + * + * The returned string is already internationalized. + */ +char * nautilus_search_uri_to_human (const char *search_uri) +{ + char *uri, *human; + + uri = gnome_vfs_unescape_string_for_display (search_uri); + human = parse_uri (uri); + if (human == NULL) { + g_print ("mathieu: %s\n", uri); + return uri; + } + + g_free (uri); + g_print ("mathieu: %s\n", human); + + return human; +} + + + + + + + + + + + + diff --git a/libnautilus-private/nautilus-search-uri.h b/libnautilus-private/nautilus-search-uri.h new file mode 100644 index 000000000..f0544ceb2 --- /dev/null +++ b/libnautilus-private/nautilus-search-uri.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Code to generate human-readable strings from search uris. + + Copyright (C) 2000 Eazel, Inc. + + 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. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Mathieu Lacage <mathieu@eazel.com> +*/ + +#ifndef NAUTILUS_SEARCH_URI_H +#define NAUTILUS_SEARCH_URI_H + + + +char * nautilus_search_uri_to_human (const char *search_uri); + + + + + + + +#endif /* NAUTILUS_SEARCH_URI_H */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 904e9c6a1..5e886d4ea 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -54,6 +54,7 @@ components/services/time/service/trilobite-eazel-time-service.c libnautilus-extensions/nautilus-entry.c libnautilus-extensions/nautilus-file.c libnautilus-extensions/nautilus-global-preferences.c +libnautilus-extensions/nautilus-search-uri.c libnautilus-extensions/nautilus-icon-canvas-item.c libnautilus-extensions/nautilus-icon-dnd.c libnautilus-extensions/nautilus-icon-text-item.c diff --git a/src/file-manager/fm-search-list-view.c b/src/file-manager/fm-search-list-view.c index 12f6e0b6e..e92c030fe 100644 --- a/src/file-manager/fm-search-list-view.c +++ b/src/file-manager/fm-search-list-view.c @@ -34,6 +34,7 @@ #include <libnautilus-extensions/nautilus-file-attributes.h> #include <libnautilus-extensions/nautilus-file-utilities.h> #include <libnautilus-extensions/nautilus-search-bar-criterion.h> +#include <libnautilus-extensions/nautilus-search-uri.h> #include <libnautilus-extensions/nautilus-string.h> #include <libgnomevfs/gnome-vfs-utils.h> @@ -81,7 +82,7 @@ load_location_callback (NautilusView *nautilus_view, char *location) { char *human_string; - human_string = nautilus_search_bar_criterion_human_from_uri (location); + human_string = nautilus_search_uri_to_human (location); nautilus_view_set_title (nautilus_view, human_string); diff --git a/src/nautilus-complex-search-bar.c b/src/nautilus-complex-search-bar.c index be7dbcc5a..cd90200a5 100644 --- a/src/nautilus-complex-search-bar.c +++ b/src/nautilus-complex-search-bar.c @@ -183,7 +183,7 @@ nautilus_complex_search_bar_initialize (NautilusComplexSearchBar *bar) 1); gtk_container_add (GTK_CONTAINER (bar->details->find_them), find_them_box); - gtk_signal_connect_object (GTK_OBJECT (bar->details->find_them), "pressed", + gtk_signal_connect_object (GTK_OBJECT (bar->details->find_them), "clicked", nautilus_navigation_bar_location_changed, GTK_OBJECT (bar)); @@ -312,9 +312,9 @@ attach_criterion_to_search_bar (NautilusComplexSearchBar *bar, 2, 3, row - 1, row); } else { - gtk_table_attach_defaults (bar->details->table, - GTK_WIDGET (criterion->details->value_entry), - 2, 3, row - 1, row); + gtk_table_attach_defaults (bar->details->table, + GTK_WIDGET (criterion->details->value_entry), + 2, 3, row - 1, row); } /* We want to track whether the entry text is empty or not. */ gtk_signal_connect_object (GTK_OBJECT (criterion->details->value_entry), @@ -342,7 +342,8 @@ unattach_criterion_from_search_bar (NautilusComplexSearchBar *bar, GTK_WIDGET (criterion->details->relation_menu)); g_assert (criterion->details->use_value_entry + criterion->details->use_value_menu == 1); - if (criterion->details->use_value_entry) { + if (criterion->details->use_value_entry + && !criterion->details->use_value_suffix) { gtk_container_remove (GTK_CONTAINER (bar->details->table), GTK_WIDGET (criterion->details->value_entry)); } @@ -350,6 +351,10 @@ unattach_criterion_from_search_bar (NautilusComplexSearchBar *bar, gtk_container_remove (GTK_CONTAINER (bar->details->table), GTK_WIDGET (criterion->details->value_menu)); } + if (criterion->details->use_value_suffix) { + gtk_container_remove (GTK_CONTAINER (bar->details->table), + GTK_WIDGET (criterion->details->value_suffix)->parent); + } gtk_table_resize (bar->details->table, g_slist_length (bar->details->search_criteria) - 1, 3); |