summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathieu Lacage <mathieu@eazel.com>2000-08-15 07:24:22 +0000
committerMathieu Lacage <mathieu@src.gnome.org>2000-08-15 07:24:22 +0000
commitf951f6f3552762c020155273fa59e43fc1534869 (patch)
tree3fd91db4721b0b8a4afc6f6565c4f1f4c34d2533
parent73a96dd98e03019d790b690912c488fa78ed7c03 (diff)
downloadnautilus-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--ChangeLog25
-rw-r--r--libnautilus-extensions/Makefile.am2
-rw-r--r--libnautilus-extensions/nautilus-search-uri.c634
-rw-r--r--libnautilus-extensions/nautilus-search-uri.h37
-rw-r--r--libnautilus-private/Makefile.am2
-rw-r--r--libnautilus-private/nautilus-search-uri.c634
-rw-r--r--libnautilus-private/nautilus-search-uri.h37
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/file-manager/fm-search-list-view.c3
-rw-r--r--src/nautilus-complex-search-bar.c15
10 files changed, 1384 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index a0f6a41b2..930792e6d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);