summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--po/POTFILES.in6
-rw-r--r--src/Makefile.am4
-rw-r--r--src/nautilus-location-bar.c355
-rw-r--r--src/nautilus-location-dialog.c191
-rw-r--r--src/nautilus-location-dialog.h51
-rw-r--r--src/nautilus-location-entry.c512
-rw-r--r--src/nautilus-location-entry.h54
-rw-r--r--src/nautilus-spatial-window.c13
9 files changed, 848 insertions, 351 deletions
diff --git a/ChangeLog b/ChangeLog
index 34e73bf84..2102e2b20 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2003-10-11 Dave Camp <dave@ximian.com>
+
+ * src/Makefile.am: Add nautilus-location-dialog.[ch] and
+ nautilus-location-entry.[ch]
+ * src/nautilus-location-bar.c: (editable_event_after_callback),
+ (nautilus_location_bar_init):
+ * src/nautilus-location-entry.c: Moved the tab-completing entry
+ into its own widget.
+ * src/nautilus-location-dialog.c
+ * src/nautilus-spatial-window.c: (real_prompt_for_location),
+ (nautilus_spatial_window_class_init): Add an Open Location
+ dialog for the spatial windows.
+
2003-10-10 Christophe Fergeau <teuf@gnome.org>
* components/tree/nautilus-tree-view.c : expand rows in the
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 15dd0def5..23e8f4463 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -98,6 +98,8 @@ src/nautilus-file-management-properties.glade
src/nautilus-first-time-druid.c
src/nautilus-information-panel.c
src/nautilus-location-bar.c
+src/nautilus-location-dialog.c
+src/nautilus-location-entry.c
src/nautilus-main.c
src/nautilus-navigation-window-menus.c
src/nautilus-navigation-window-ui.xml
@@ -113,8 +115,12 @@ src/nautilus-shell.c
src/nautilus-side-pane.c
src/nautilus-sidebar-title.c
src/nautilus-simple-search-bar.c
+<<<<<<< POTFILES.in
+src/nautilus-spatial-window.c
+=======
src/nautilus-spatial-window-ui.xml
src/nautilus-spatial-window.c
+>>>>>>> 1.132
src/nautilus-switchable-search-bar.c
src/nautilus-view-frame.c
src/nautilus-window-manage-views.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 08f523c84..c17871e5f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,6 +69,8 @@ nautilus_SOURCES = \
nautilus-first-time-druid.c \
nautilus-information-panel.c \
nautilus-location-bar.c \
+ nautilus-location-dialog.c \
+ nautilus-location-entry.c \
nautilus-main.c \
nautilus-navigation-bar.c \
nautilus-navigation-window.c \
@@ -104,6 +106,8 @@ nautilus_SOURCES = \
nautilus-first-time-druid.h \
nautilus-information-panel.h \
nautilus-location-bar.h \
+ nautilus-location-dialog.h \
+ nautilus-location-entry.h \
nautilus-main.h \
nautilus-navigation-bar.h \
nautilus-navigation-window.h \
diff --git a/src/nautilus-location-bar.c b/src/nautilus-location-bar.c
index 8efbd45c5..fd4092dfd 100644
--- a/src/nautilus-location-bar.c
+++ b/src/nautilus-location-bar.c
@@ -33,14 +33,15 @@
#include <config.h>
#include "nautilus-location-bar.h"
+#include "nautilus-location-entry.h"
#include "nautilus-window-private.h"
#include "nautilus-window.h"
#include <eel/eel-accessibility.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gtk-macros.h>
+#include <eel/eel-input-event-box.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string.h>
-#include <eel/eel-input-event-box.h>
#include <eel/eel-vfs-extensions.h>
#include <gtk/gtkdnd.h>
#include <gtk/gtksignal.h>
@@ -48,7 +49,6 @@
#include <libgnomeui/gnome-stock-icons.h>
#include <libgnomeui/gnome-uidefs.h>
#include <libgnomevfs/gnome-vfs.h>
-#include <libnautilus-private/nautilus-entry.h>
#include <libnautilus-private/nautilus-icon-dnd.h>
#include <libnautilus/nautilus-clipboard.h>
#include <stdio.h>
@@ -250,290 +250,6 @@ style_set_handler (GtkWidget *widget, GtkStyle *previous_style)
gtk_widget_set_size_request (widget, width, -1);
}
-static gboolean
-have_broken_filenames (void)
-{
- static gboolean initialized = FALSE;
- static gboolean broken;
-
- if (initialized) {
- return broken;
- }
-
- broken = g_getenv ("G_BROKEN_FILENAMES") != NULL;
-
- initialized = TRUE;
-
- return broken;
-}
-
-
-/* utility routine to determine the string to expand to. If we don't have anything yet, accept
- the whole string, otherwise accept the largest part common to both */
-
-static char *
-accumulate_name_utf8 (char *full_name, char *candidate_name)
-{
- char *result_name, *str1, *str2;
-
- if (!g_utf8_validate (candidate_name, -1, NULL)) {
- return full_name;
- }
-
- if (full_name == NULL) {
- result_name = g_strdup (candidate_name);
- } else {
- result_name = full_name;
- if (!eel_str_has_prefix (full_name, candidate_name)) {
- str1 = full_name;
- str2 = candidate_name;
-
- while ((g_utf8_get_char (str1) == g_utf8_get_char (str2))) {
- str1 = g_utf8_next_char (str1);
- str2 = g_utf8_next_char (str2);
- }
- *str1 = '\0';
- }
- }
-
- return result_name;
-}
-
-static char *
-accumulate_name_locale (char *full_name, char *candidate_name)
-{
- char *result_name, *str1, *str2;
-
- if (full_name == NULL)
- result_name = g_strdup (candidate_name);
- else {
- result_name = full_name;
- if (!eel_str_has_prefix (full_name, candidate_name)) {
- str1 = full_name;
- str2 = candidate_name;
-
- while (*str1 == *str2) {
- str1++;
- str2++;
- }
- *str1 = '\0';
- }
- }
-
- return result_name;
-}
-
-/* utility routine to load the file info list for the current directory, if necessary */
-static void
-get_file_info_list (NautilusLocationBar *bar, const char* dir_name)
-{
- GnomeVFSResult result;
-
- if (eel_strcmp (bar->details->current_directory, dir_name) != 0) {
- g_free (bar->details->current_directory);
- if (bar->details->file_info_list) {
- gnome_vfs_file_info_list_free (bar->details->file_info_list);
- bar->details->file_info_list = NULL;
- }
-
- bar->details->current_directory = g_strdup (dir_name);
- result = gnome_vfs_directory_list_load (&bar->details->file_info_list, dir_name,
- GNOME_VFS_FILE_INFO_DEFAULT);
- if (result != GNOME_VFS_OK) {
- if (bar->details->file_info_list) {
- gnome_vfs_file_info_list_free (bar->details->file_info_list);
- bar->details->file_info_list = NULL;
- }
- }
- }
-}
-
-/* routine that performs the tab expansion using gnome-vfs. Extract the directory name and
- incomplete basename, then iterate through the directory trying to complete it. If we
- find something, add it to the entry */
-
-static gboolean
-try_to_expand_path (gpointer callback_data)
-{
- NautilusLocationBar *bar;
-
- GnomeVFSFileInfo *current_file_info;
- GList *element;
- GnomeVFSURI *uri;
- GtkEditable *editable;
-
- char *base_name_uri_escaped;
- char *base_name;
- char *base_name_utf8;
- char *user_location;
- char *current_path;
- char *dir_name;
- char *expand_text;
- char *expand_text_utf8;
- char *expand_name;
- char *insert_text;
-
- int base_name_length;
- int user_location_length;
- int expand_text_length;
- int pos;
-
- bar = NAUTILUS_LOCATION_BAR (callback_data);
- editable = GTK_EDITABLE (bar->details->entry);
- user_location = gtk_editable_get_chars (editable, 0, -1);
- bar->details->idle_id = 0;
-
- /* if it's just '~' don't expand because slash shouldn't be appended */
- if (eel_strcmp (user_location, "~") == 0) {
- g_free (user_location);
- return FALSE;
- }
-
- /* Trailing whitespace is OK here since the cursor is known to
- be at the end of the text and therefor after the whitespace. */
- current_path = eel_make_uri_from_input_with_trailing_ws (user_location);
- if (!eel_istr_has_prefix (current_path, "file://")) {
- g_free (user_location);
- g_free (current_path);
- return FALSE;
- }
-
- /* We already completed if we have a trailing '/' */
- if (current_path[strlen (current_path) - 1] == GNOME_VFS_URI_PATH_CHR) {
- g_free (user_location);
- g_free (current_path);
- return FALSE;
- }
-
- user_location_length = g_utf8_strlen (user_location, -1);
-
- g_free (user_location);
-
- uri = gnome_vfs_uri_new (current_path);
-
- base_name_uri_escaped = gnome_vfs_uri_extract_short_name (uri);
- if (base_name_uri_escaped == NULL) {
- base_name = NULL;
- } else {
- base_name = gnome_vfs_unescape_string (base_name_uri_escaped, NULL);
- }
- g_free (base_name_uri_escaped);
-
- if (base_name == NULL) {
- gnome_vfs_uri_unref (uri);
- g_free (current_path);
- return FALSE;
- }
-
- dir_name = gnome_vfs_uri_extract_dirname (uri);
-
- gnome_vfs_uri_unref (uri);
- uri = NULL;
-
- /* get file info for the directory, if it hasn't changed since last time */
- get_file_info_list (bar, dir_name);
- if (bar->details->file_info_list == NULL) {
- g_free (dir_name);
- g_free (base_name);
- g_free (current_path);
- return FALSE;
- }
-
- /* iterate through the directory, keeping the intersection of all the names that
- have the current basename as a prefix. */
- expand_text = NULL;
- for (element = bar->details->file_info_list; element != NULL; element = element->next) {
- current_file_info = element->data;
- if (eel_str_has_prefix (current_file_info->name, base_name)) {
- if (current_file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
- expand_name = g_strconcat (current_file_info->name, "/", NULL);
- } else {
- expand_name = g_strdup (current_file_info->name);
- }
- if (have_broken_filenames()) {
- expand_text = accumulate_name_locale (expand_text, expand_name);
- } else {
- expand_text = accumulate_name_utf8 (expand_text, expand_name);
- }
- g_free (expand_name);
- }
- }
-
- if (have_broken_filenames ()) {
- if (expand_text) {
- expand_text_utf8 = g_locale_to_utf8 (expand_text, -1, NULL, NULL, NULL);
- g_free (expand_text);
- expand_text = expand_text_utf8;
- }
-
- base_name_utf8 = g_locale_to_utf8 (base_name, -1, NULL, NULL, NULL);
- g_free (base_name);
- base_name = base_name_utf8;
- }
-
- /* if we've got something, add it to the entry */
- if (expand_text != NULL && base_name != NULL) {
- expand_text_length = g_utf8_strlen (expand_text, -1);
- base_name_length = g_utf8_strlen (base_name, -1);
-
- if (!eel_str_has_suffix (base_name, expand_text)
- && base_name_length < expand_text_length) {
- insert_text = g_utf8_offset_to_pointer (expand_text, base_name_length);
- pos = user_location_length;
- gtk_editable_insert_text (editable,
- insert_text,
- g_utf8_strlen (insert_text, -1),
- &pos);
-
- pos = user_location_length;
- gtk_editable_select_region (editable, pos, -1);
- }
- }
- g_free (expand_text);
-
- g_free (dir_name);
- g_free (base_name);
- g_free (current_path);
-
- return FALSE;
-}
-
-/* Until we have a more elegant solution, this is how we figure out if
- * the GtkEntry inserted characters, assuming that the return value is
- * TRUE indicating that the GtkEntry consumed the key event for some
- * reason. This is a clone of code from GtkEntry.
- */
-static gboolean
-entry_would_have_inserted_characters (const GdkEventKey *event)
-{
- switch (event->keyval) {
- case GDK_BackSpace:
- case GDK_Clear:
- case GDK_Insert:
- case GDK_Delete:
- case GDK_Home:
- case GDK_End:
- case GDK_KP_Home:
- case GDK_KP_End:
- case GDK_Left:
- case GDK_Right:
- case GDK_KP_Left:
- case GDK_KP_Right:
- case GDK_Return:
- return FALSE;
- default:
- if (event->keyval >= 0x20 && event->keyval <= 0xFF) {
- if ((event->state & GDK_CONTROL_MASK) != 0) {
- return FALSE;
- }
- if ((event->state & GDK_MOD1_MASK) != 0) {
- return FALSE;
- }
- }
- return event->length > 0;
- }
-}
-
static int
get_editable_number_of_chars (GtkEditable *editable)
{
@@ -556,71 +272,12 @@ set_position_and_selection_to_end (GtkEditable *editable)
gtk_editable_set_position (editable, end);
}
-static gboolean
-position_and_selection_are_at_end (GtkEditable *editable)
-{
- int end;
- int start_sel, end_sel;
-
- end = get_editable_number_of_chars (editable);
- if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel)) {
- if (start_sel != end || end_sel != end) {
- return FALSE;
- }
- }
- return gtk_editable_get_position (editable) == end;
-}
-
static void
editable_event_after_callback (GtkEntry *entry,
GdkEvent *event,
gpointer user_data)
{
- GtkEditable *editable;
- GdkEventKey *keyevent;
- NautilusLocationBar *bar;
-
- if (event->type != GDK_KEY_PRESS) {
- return;
- }
-
- editable = GTK_EDITABLE (entry);
- keyevent = (GdkEventKey *)event;
- bar = NAUTILUS_LOCATION_BAR (user_data);
-
- /* After typing the right arrow key we move the selection to
- * the end, if we have a valid selection - since this is most
- * likely an auto-completion. We ignore shift / control since
- * they can validly be used to extend the selection.
- */
- if ((keyevent->keyval == GDK_Right || keyevent->keyval == GDK_End) &&
- !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) &&
- gtk_editable_get_selection_bounds (editable, NULL, NULL)) {
- set_position_and_selection_to_end (editable);
- }
-
- /* Only do expanding when we are typing at the end of the
- * text. Do the expand at idle time to avoid slowing down
- * typing when the directory is large. Only trigger the expand
- * when we type a key that would have inserted characters.
- */
- if (position_and_selection_are_at_end (editable)) {
- if (entry_would_have_inserted_characters (keyevent)) {
- if (bar->details->idle_id == 0) {
- bar->details->idle_id = g_idle_add (try_to_expand_path, bar);
- }
- }
- } else {
- /* FIXME: Also might be good to do this when you click
- * to change the position or selection.
- */
- if (bar->details->idle_id != 0) {
- g_source_remove (bar->details->idle_id);
- bar->details->idle_id = 0;
- }
- }
-
- nautilus_location_bar_update_label (bar);
+ nautilus_location_bar_update_label (NAUTILUS_LOCATION_BAR (user_data));
}
static void
@@ -721,15 +378,13 @@ nautilus_location_bar_init (NautilusLocationBar *bar)
gtk_box_pack_start (GTK_BOX (hbox), event_box, FALSE, TRUE,
GNOME_PAD_SMALL);
- entry = nautilus_entry_new ();
-
- nautilus_entry_set_special_tab_handling (NAUTILUS_ENTRY (entry), TRUE);
+ entry = nautilus_location_entry_new ();
g_signal_connect_object (entry, "activate",
G_CALLBACK (nautilus_navigation_bar_location_changed),
bar, G_CONNECT_SWAPPED);
g_signal_connect_object (entry, "event_after",
- G_CALLBACK (editable_event_after_callback), bar, 0);
+ G_CALLBACK (editable_event_after_callback), bar, G_CONNECT_AFTER);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
diff --git a/src/nautilus-location-dialog.c b/src/nautilus-location-dialog.c
new file mode 100644
index 000000000..ebbe30f6f
--- /dev/null
+++ b/src/nautilus-location-dialog.c
@@ -0,0 +1,191 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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.
+ */
+
+#include <config.h>
+#include "nautilus-location-dialog.h"
+
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-vfs-extensions.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+#include "nautilus-location-entry.h"
+
+struct _NautilusLocationDialogDetails {
+ GtkWidget *entry;
+ NautilusWindow *window;
+};
+
+static void nautilus_location_dialog_class_init (NautilusLocationDialogClass *class);
+static void nautilus_location_dialog_init (NautilusLocationDialog *dialog);
+
+EEL_CLASS_BOILERPLATE (NautilusLocationDialog,
+ nautilus_location_dialog,
+ GTK_TYPE_DIALOG)
+enum {
+ RESPONSE_OPEN,
+ RESPONSE_CANCEL
+};
+
+static void
+nautilus_location_dialog_finalize (GObject *object)
+{
+ NautilusLocationDialog *dialog;
+
+ dialog = NAUTILUS_LOCATION_DIALOG (object);
+
+ g_free (dialog->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+nautilus_location_dialog_destroy (GtkObject *object)
+{
+ NautilusLocationDialog *dialog;
+
+ dialog = NAUTILUS_LOCATION_DIALOG (object);
+
+ EEL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
+}
+
+static void
+open_current_location (NautilusLocationDialog *dialog)
+{
+ char *uri;
+ char *user_location;
+
+ user_location = gtk_editable_get_chars (GTK_EDITABLE (dialog->details->entry), 0, -1);
+ uri = eel_make_uri_from_input (user_location);
+ g_free (user_location);
+
+ nautilus_window_go_to (dialog->details->window, uri);
+
+ g_free (uri);
+}
+
+static void
+response_callback (NautilusLocationDialog *dialog,
+ int response_id,
+ gpointer data)
+{
+ switch (response_id) {
+ case RESPONSE_OPEN :
+ open_current_location (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+ case GTK_RESPONSE_NONE :
+ case GTK_RESPONSE_DELETE_EVENT :
+ case RESPONSE_CANCEL :
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+ default :
+ g_assert_not_reached ();
+ }
+}
+
+static void
+entry_activate_callback (GtkEntry *entry,
+ gpointer user_data)
+{
+ NautilusLocationDialog *dialog;
+
+ dialog = NAUTILUS_LOCATION_DIALOG (user_data);
+ gtk_dialog_response (GTK_DIALOG (dialog), RESPONSE_OPEN);
+}
+
+static void
+nautilus_location_dialog_class_init (NautilusLocationDialogClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = nautilus_location_dialog_finalize;
+
+ object_class = GTK_OBJECT_CLASS (class);
+ object_class->destroy = nautilus_location_dialog_destroy;
+}
+
+static void
+nautilus_location_dialog_init (NautilusLocationDialog *dialog)
+{
+ GtkWidget *box;
+ GtkWidget *label;
+
+ dialog->details = g_new0 (NautilusLocationDialogDetails, 1);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Open Location"));
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (box);
+
+ label = gtk_label_new (_("Location:"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 6);
+
+ dialog->details->entry = nautilus_location_entry_new ();
+ g_signal_connect (dialog->details->entry,
+ "activate",
+ G_CALLBACK (entry_activate_callback),
+ dialog);
+
+ gtk_widget_show (dialog->details->entry);
+
+ gtk_box_pack_start (GTK_BOX (box), dialog->details->entry,
+ TRUE, TRUE, 6);
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ box, TRUE, TRUE, 12);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_OPEN,
+ RESPONSE_OPEN);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ RESPONSE_OPEN);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (response_callback),
+ dialog);
+}
+
+GtkWidget *
+nautilus_location_dialog_new (NautilusWindow *window)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_widget_new (NAUTILUS_TYPE_LOCATION_DIALOG, NULL);
+
+ if (window) {
+ gtk_window_set_screen (GTK_WINDOW (dialog),
+ gtk_window_get_screen (GTK_WINDOW (window)));
+ NAUTILUS_LOCATION_DIALOG (dialog)->details->window = window;
+ }
+
+ return dialog;
+}
diff --git a/src/nautilus-location-dialog.h b/src/nautilus-location-dialog.h
new file mode 100644
index 000000000..5368f4087
--- /dev/null
+++ b/src/nautilus-location-dialog.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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.
+ */
+
+#ifndef NAUTILUS_LOCATION_DIALOG_H
+#define NAUTILUS_LOCATION_DIALOG_H
+
+#include <gtk/gtkdialog.h>
+#include "nautilus-window.h"
+
+#define NAUTILUS_TYPE_LOCATION_DIALOG (nautilus_location_dialog_get_type ())
+#define NAUTILUS_LOCATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_LOCATION_DIALOG, NautilusLocationDialog))
+#define NAUTILUS_LOCATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_LOCATION_DIALOG, NautilusLocationDialogClass))
+#define NAUTILUS_IS_LOCATION_DIALOG(obj) (G_TYPE_INSTANCE_CHECK_TYPE ((obj), NAUTILUS_TYPE_LOCATION_DIALOG)
+
+typedef struct _NautilusLocationDialog NautilusLocationDialog;
+typedef struct _NautilusLocationDialogClass NautilusLocationDialogClass;
+typedef struct _NautilusLocationDialogDetails NautilusLocationDialogDetails;
+
+struct _NautilusLocationDialog {
+ GtkDialog parent;
+ NautilusLocationDialogDetails *details;
+};
+
+struct _NautilusLocationDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType nautilus_location_dialog_get_type (void);
+GtkWidget* nautilus_location_dialog_new (NautilusWindow *window);
+
+#endif /* NAUTILUS_LOCATION_DIALOG_H */
diff --git a/src/nautilus-location-entry.c b/src/nautilus-location-entry.c
new file mode 100644
index 000000000..623f2fa99
--- /dev/null
+++ b/src/nautilus-location-entry.c
@@ -0,0 +1,512 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2000 Eazel, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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: Maciej Stachowiak <mjs@eazel.com>
+ * Ettore Perazzoli <ettore@gnu.org>
+ * Michael Meeks <michael@nuclecu.unam.mx>
+ * Andy Hertzfeld <andy@eazel.com>
+ *
+ */
+
+/* nautilus-location-bar.c - Location bar for Nautilus
+ */
+
+#include <config.h>
+#include "nautilus-location-entry.h"
+
+#include "nautilus-window-private.h"
+#include "nautilus-window.h"
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-stock-dialogs.h>
+#include <eel/eel-string.h>
+#include <eel/eel-input-event-box.h>
+#include <eel/eel-vfs-extensions.h>
+#include <gtk/gtkdnd.h>
+#include <gtk/gtksignal.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomeui/gnome-stock-icons.h>
+#include <libgnomeui/gnome-uidefs.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libnautilus-private/nautilus-entry.h>
+#include <libnautilus-private/nautilus-icon-dnd.h>
+#include <libnautilus/nautilus-clipboard.h>
+#include <stdio.h>
+#include <string.h>
+
+struct NautilusLocationEntryDetails {
+ GtkLabel *label;
+
+ char *current_directory;
+ GList *file_info_list;
+
+ guint idle_id;
+};
+
+static void nautilus_location_entry_class_init (NautilusLocationEntryClass *class);
+static void nautilus_location_entry_init (NautilusLocationEntry *entry);
+
+EEL_CLASS_BOILERPLATE (NautilusLocationEntry,
+ nautilus_location_entry,
+ NAUTILUS_TYPE_ENTRY)
+
+static gboolean
+have_broken_filenames (void)
+{
+ static gboolean initialized = FALSE;
+ static gboolean broken;
+
+ if (initialized) {
+ return broken;
+ }
+
+ broken = g_getenv ("G_BROKEN_FILENAMES") != NULL;
+
+ initialized = TRUE;
+
+ return broken;
+}
+
+
+/* utility routine to determine the string to expand to. If we don't have anything yet, accept
+ the whole string, otherwise accept the largest part common to both */
+
+static char *
+accumulate_name_utf8 (char *full_name, char *candidate_name)
+{
+ char *result_name, *str1, *str2;
+
+ if (!g_utf8_validate (candidate_name, -1, NULL)) {
+ return full_name;
+ }
+
+ if (full_name == NULL) {
+ result_name = g_strdup (candidate_name);
+ } else {
+ result_name = full_name;
+ if (!eel_str_has_prefix (full_name, candidate_name)) {
+ str1 = full_name;
+ str2 = candidate_name;
+
+ while ((g_utf8_get_char (str1) == g_utf8_get_char (str2))) {
+ str1 = g_utf8_next_char (str1);
+ str2 = g_utf8_next_char (str2);
+ }
+ *str1 = '\0';
+ }
+ }
+
+ return result_name;
+}
+
+static char *
+accumulate_name_locale (char *full_name, char *candidate_name)
+{
+ char *result_name, *str1, *str2;
+
+ if (full_name == NULL)
+ result_name = g_strdup (candidate_name);
+ else {
+ result_name = full_name;
+ if (!eel_str_has_prefix (full_name, candidate_name)) {
+ str1 = full_name;
+ str2 = candidate_name;
+
+ while (*str1 == *str2) {
+ str1++;
+ str2++;
+ }
+ *str1 = '\0';
+ }
+ }
+
+ return result_name;
+}
+
+/* utility routine to load the file info list for the current directory, if necessary */
+static void
+get_file_info_list (NautilusLocationEntry *entry, const char* dir_name)
+{
+ GnomeVFSResult result;
+
+ if (eel_strcmp (entry->details->current_directory, dir_name) != 0) {
+ g_free (entry->details->current_directory);
+ if (entry->details->file_info_list) {
+ gnome_vfs_file_info_list_free (entry->details->file_info_list);
+ entry->details->file_info_list = NULL;
+ }
+
+ entry->details->current_directory = g_strdup (dir_name);
+ result = gnome_vfs_directory_list_load (&entry->details->file_info_list, dir_name,
+ GNOME_VFS_FILE_INFO_DEFAULT);
+ if (result != GNOME_VFS_OK) {
+ if (entry->details->file_info_list) {
+ gnome_vfs_file_info_list_free (entry->details->file_info_list);
+ entry->details->file_info_list = NULL;
+ }
+ }
+ }
+}
+
+/* routine that performs the tab expansion using gnome-vfs. Extract the directory name and
+ incomplete basename, then iterate through the directory trying to complete it. If we
+ find something, add it to the entry */
+
+static gboolean
+try_to_expand_path (gpointer callback_data)
+{
+ NautilusLocationEntry *entry;
+
+ GnomeVFSFileInfo *current_file_info;
+ GList *element;
+ GnomeVFSURI *uri;
+ GtkEditable *editable;
+
+ char *base_name_uri_escaped;
+ char *base_name;
+ char *base_name_utf8;
+ char *user_location;
+ char *current_path;
+ char *dir_name;
+ char *expand_text;
+ char *expand_text_utf8;
+ char *expand_name;
+ char *insert_text;
+
+ int base_name_length;
+ int user_location_length;
+ int expand_text_length;
+ int pos;
+
+ entry = NAUTILUS_LOCATION_ENTRY (callback_data);
+ editable = GTK_EDITABLE (entry);
+ user_location = gtk_editable_get_chars (editable, 0, -1);
+ entry->details->idle_id = 0;
+
+ /* if it's just '~' don't expand because slash shouldn't be appended */
+ if (eel_strcmp (user_location, "~") == 0) {
+ g_free (user_location);
+ return FALSE;
+ }
+
+ /* Trailing whitespace is OK here since the cursor is known to
+ be at the end of the text and therefor after the whitespace. */
+ current_path = eel_make_uri_from_input_with_trailing_ws (user_location);
+ if (!eel_istr_has_prefix (current_path, "file://")) {
+ g_free (user_location);
+ g_free (current_path);
+ return FALSE;
+ }
+
+ /* We already completed if we have a trailing '/' */
+ if (current_path[strlen (current_path) - 1] == GNOME_VFS_URI_PATH_CHR) {
+ g_free (user_location);
+ g_free (current_path);
+ return FALSE;
+ }
+
+ user_location_length = g_utf8_strlen (user_location, -1);
+
+ g_free (user_location);
+
+ uri = gnome_vfs_uri_new (current_path);
+
+ base_name_uri_escaped = gnome_vfs_uri_extract_short_name (uri);
+ if (base_name_uri_escaped == NULL) {
+ base_name = NULL;
+ } else {
+ base_name = gnome_vfs_unescape_string (base_name_uri_escaped, NULL);
+ }
+ g_free (base_name_uri_escaped);
+
+ if (base_name == NULL) {
+ gnome_vfs_uri_unref (uri);
+ g_free (current_path);
+ return FALSE;
+ }
+
+ dir_name = gnome_vfs_uri_extract_dirname (uri);
+
+ gnome_vfs_uri_unref (uri);
+ uri = NULL;
+
+ /* get file info for the directory, if it hasn't changed since last time */
+ get_file_info_list (entry, dir_name);
+ if (entry->details->file_info_list == NULL) {
+ g_free (dir_name);
+ g_free (base_name);
+ g_free (current_path);
+ return FALSE;
+ }
+
+ /* iterate through the directory, keeping the intersection of all the names that
+ have the current basename as a prefix. */
+ expand_text = NULL;
+ for (element = entry->details->file_info_list; element != NULL; element = element->next) {
+ current_file_info = element->data;
+ if (eel_str_has_prefix (current_file_info->name, base_name)) {
+ if (current_file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+ expand_name = g_strconcat (current_file_info->name, "/", NULL);
+ } else {
+ expand_name = g_strdup (current_file_info->name);
+ }
+ if (have_broken_filenames()) {
+ expand_text = accumulate_name_locale (expand_text, expand_name);
+ } else {
+ expand_text = accumulate_name_utf8 (expand_text, expand_name);
+ }
+ g_free (expand_name);
+ }
+ }
+
+ if (have_broken_filenames ()) {
+ if (expand_text) {
+ expand_text_utf8 = g_locale_to_utf8 (expand_text, -1, NULL, NULL, NULL);
+ g_free (expand_text);
+ expand_text = expand_text_utf8;
+ }
+
+ base_name_utf8 = g_locale_to_utf8 (base_name, -1, NULL, NULL, NULL);
+ g_free (base_name);
+ base_name = base_name_utf8;
+ }
+
+ /* if we've got something, add it to the entry */
+ if (expand_text != NULL && base_name != NULL) {
+ expand_text_length = g_utf8_strlen (expand_text, -1);
+ base_name_length = g_utf8_strlen (base_name, -1);
+
+ if (!eel_str_has_suffix (base_name, expand_text)
+ && base_name_length < expand_text_length) {
+ insert_text = g_utf8_offset_to_pointer (expand_text, base_name_length);
+ pos = user_location_length;
+ gtk_editable_insert_text (editable,
+ insert_text,
+ g_utf8_strlen (insert_text, -1),
+ &pos);
+
+ pos = user_location_length;
+ gtk_editable_select_region (editable, pos, -1);
+ }
+ }
+ g_free (expand_text);
+
+ g_free (dir_name);
+ g_free (base_name);
+ g_free (current_path);
+
+ return FALSE;
+}
+
+/* Until we have a more elegant solution, this is how we figure out if
+ * the GtkEntry inserted characters, assuming that the return value is
+ * TRUE indicating that the GtkEntry consumed the key event for some
+ * reason. This is a clone of code from GtkEntry.
+ */
+static gboolean
+entry_would_have_inserted_characters (const GdkEventKey *event)
+{
+ switch (event->keyval) {
+ case GDK_BackSpace:
+ case GDK_Clear:
+ case GDK_Insert:
+ case GDK_Delete:
+ case GDK_Home:
+ case GDK_End:
+ case GDK_KP_Home:
+ case GDK_KP_End:
+ case GDK_Left:
+ case GDK_Right:
+ case GDK_KP_Left:
+ case GDK_KP_Right:
+ case GDK_Return:
+ return FALSE;
+ default:
+ if (event->keyval >= 0x20 && event->keyval <= 0xFF) {
+ if ((event->state & GDK_CONTROL_MASK) != 0) {
+ return FALSE;
+ }
+ if ((event->state & GDK_MOD1_MASK) != 0) {
+ return FALSE;
+ }
+ }
+ return event->length > 0;
+ }
+}
+
+static int
+get_editable_number_of_chars (GtkEditable *editable)
+{
+ char *text;
+ int length;
+
+ text = gtk_editable_get_chars (editable, 0, -1);
+ length = g_utf8_strlen (text, -1);
+ g_free (text);
+ return length;
+}
+
+static void
+set_position_and_selection_to_end (GtkEditable *editable)
+{
+ int end;
+
+ end = get_editable_number_of_chars (editable);
+ gtk_editable_select_region (editable, end, end);
+ gtk_editable_set_position (editable, end);
+}
+
+static gboolean
+position_and_selection_are_at_end (GtkEditable *editable)
+{
+ int end;
+ int start_sel, end_sel;
+
+ end = get_editable_number_of_chars (editable);
+ if (gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel)) {
+ if (start_sel != end || end_sel != end) {
+ return FALSE;
+ }
+ }
+ return gtk_editable_get_position (editable) == end;
+}
+
+static void
+editable_event_after_callback (GtkEntry *entry,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GtkEditable *editable;
+ GdkEventKey *keyevent;
+ NautilusLocationEntry *location_entry;
+
+ if (event->type != GDK_KEY_PRESS) {
+ return;
+ }
+
+ editable = GTK_EDITABLE (entry);
+ keyevent = (GdkEventKey *)event;
+ location_entry = NAUTILUS_LOCATION_ENTRY (user_data);
+
+ /* After typing the right arrow key we move the selection to
+ * the end, if we have a valid selection - since this is most
+ * likely an auto-completion. We ignore shift / control since
+ * they can validly be used to extend the selection.
+ */
+ if ((keyevent->keyval == GDK_Right || keyevent->keyval == GDK_End) &&
+ !(keyevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) &&
+ gtk_editable_get_selection_bounds (editable, NULL, NULL)) {
+ set_position_and_selection_to_end (editable);
+ }
+
+ /* Only do expanding when we are typing at the end of the
+ * text. Do the expand at idle time to avoid slowing down
+ * typing when the directory is large. Only trigger the expand
+ * when we type a key that would have inserted characters.
+ */
+ if (position_and_selection_are_at_end (editable)) {
+ if (entry_would_have_inserted_characters (keyevent)) {
+ if (location_entry->details->idle_id == 0) {
+ location_entry->details->idle_id = g_idle_add (try_to_expand_path, location_entry);
+ }
+ }
+ } else {
+ /* FIXME: Also might be good to do this when you click
+ * to change the position or selection.
+ */
+ if (location_entry->details->idle_id != 0) {
+ g_source_remove (location_entry->details->idle_id);
+ location_entry->details->idle_id = 0;
+ }
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ NautilusLocationEntry *entry;
+
+ entry = NAUTILUS_LOCATION_ENTRY (object);
+
+ g_free (entry->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+destroy (GtkObject *object)
+{
+ NautilusLocationEntry *entry;
+
+ entry = NAUTILUS_LOCATION_ENTRY (object);
+
+ /* cancel the pending idle call, if any */
+ if (entry->details->idle_id != 0) {
+ g_source_remove (entry->details->idle_id);
+ entry->details->idle_id = 0;
+ }
+
+ if (entry->details->file_info_list) {
+ gnome_vfs_file_info_list_free (entry->details->file_info_list);
+ entry->details->file_info_list = NULL;
+ }
+
+ g_free (entry->details->current_directory);
+ entry->details->current_directory = NULL;
+
+ EEL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
+}
+
+static void
+nautilus_location_entry_class_init (NautilusLocationEntryClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ object_class = GTK_OBJECT_CLASS (class);
+ object_class->destroy = destroy;
+}
+
+static void
+nautilus_location_entry_init (NautilusLocationEntry *entry)
+{
+ entry->details = g_new0 (NautilusLocationEntryDetails, 1);
+
+ nautilus_entry_set_special_tab_handling (NAUTILUS_ENTRY (entry), TRUE);
+
+ g_signal_connect_object (entry, "event_after",
+ G_CALLBACK (editable_event_after_callback), entry, 0);
+
+}
+
+GtkWidget *
+nautilus_location_entry_new (void)
+{
+ GtkWidget *entry;
+
+ entry = gtk_widget_new (NAUTILUS_TYPE_LOCATION_ENTRY, NULL);
+
+ return entry;
+}
diff --git a/src/nautilus-location-entry.h b/src/nautilus-location-entry.h
new file mode 100644
index 000000000..596f18a33
--- /dev/null
+++ b/src/nautilus-location-entry.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/*
+ * Nautilus
+ *
+ * Copyright (C) 2000 Eazel, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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: Maciej Stachowiak <mjs@eazel.com>
+ * Ettore Perazzoli <ettore@gnu.org>
+ */
+
+#ifndef NAUTILUS_LOCATION_ENTRY_H
+#define NAUTILUS_LOCATION_ENTRY_H
+
+#include <libnautilus-private/nautilus-entry.h>
+
+#define NAUTILUS_TYPE_LOCATION_ENTRY (nautilus_location_entry_get_type ())
+#define NAUTILUS_LOCATION_ENTRY(obj) \
+ GTK_CHECK_CAST (obj, NAUTILUS_TYPE_LOCATION_ENTRY, NautilusLocationEntry)
+#define NAUTILUS_LOCATION_ENTRY_CLASS(klass) \
+ GTK_CHECK_CLASS_CAST (klass, NAUTILUS_TYPE_LOCATION_ENTRY, NautilusLocationEntryClass)
+#define NAUTILUS_IS_LOCATION_ENTRY(obj) \
+ GTK_CHECK_TYPE (obj, NAUTILUS_TYPE_LOCATION_ENTRY)
+
+typedef struct NautilusLocationEntryDetails NautilusLocationEntryDetails;
+
+typedef struct NautilusLocationEntry {
+ NautilusEntry parent;
+ NautilusLocationEntryDetails *details;
+} NautilusLocationEntry;
+
+typedef struct {
+ NautilusEntryClass parent_class;
+} NautilusLocationEntryClass;
+
+GType nautilus_location_entry_get_type (void);
+GtkWidget* nautilus_location_entry_new (void);
+
+#endif /* NAUTILUS_LOCATION_ENTRY_H */
diff --git a/src/nautilus-spatial-window.c b/src/nautilus-spatial-window.c
index 04d753143..cf608a71b 100644
--- a/src/nautilus-spatial-window.c
+++ b/src/nautilus-spatial-window.c
@@ -34,7 +34,7 @@
#include "nautilus-application.h"
#include "nautilus-desktop-window.h"
#include "nautilus-bookmarks-window.h"
-#include "nautilus-information-panel.h"
+#include "nautilus-location-dialog.h"
#include "nautilus-main.h"
#include "nautilus-signaller.h"
#include "nautilus-switchable-navigation-bar.h"
@@ -247,6 +247,15 @@ file_menu_close_with_parent_windows_callback (BonoboUIComponent *component,
}
static void
+real_prompt_for_location (NautilusWindow *window)
+{
+ GtkWidget *dialog;
+
+ dialog = nautilus_location_dialog_new (window);
+ gtk_widget_show (dialog);
+}
+
+static void
real_set_title (NautilusWindow *window, const char *title)
{
@@ -327,6 +336,8 @@ nautilus_spatial_window_class_init (NautilusSpatialWindowClass *class)
GTK_WIDGET_CLASS (class)->configure_event = nautilus_spatial_window_configure_event;
GTK_WIDGET_CLASS (class)->unrealize = nautilus_spatial_window_unrealize;
+ NAUTILUS_WINDOW_CLASS (class)->prompt_for_location =
+ real_prompt_for_location;
NAUTILUS_WINDOW_CLASS (class)->set_title =
real_set_title;
NAUTILUS_WINDOW_CLASS (class)->merge_menus =