Bugzilla – Attachment 267093 Details for
Bug 459744
can't use sftp:// in file-selector ...
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Forgot Password
[patch]
gtk2-bnc459744-bgo545980-file-chooser-entry-uris.diff
gtk2-bnc459744-bgo545980-file-chooser-entry-uris.diff (text/plain), 32.93 KB, created by
Federico Mena Quintero
on 2009-01-23 01:59:33 UTC
(
hide
)
Description:
gtk2-bnc459744-bgo545980-file-chooser-entry-uris.diff
Filename:
MIME Type:
Creator:
Federico Mena Quintero
Created:
2009-01-23 01:59:33 UTC
Size:
32.93 KB
patch
obsolete
>bnc459744 - file chooser doesn't handle URIs in the filename entry >http://bugzilla.gnome.org/show_bug.cgi?id=545980 > >2009-01-22 Federico Mena Quintero <federico@novell.com> > > * gtk/gtkfilechooserentry.c (autocomplete): Relax the assertion; > just do nothing if the folder is not loaded or if the cursor position > is not at the end of the text. A very slow-to-load folder can get > us into the latter state if the user starts typing first. > >2009-01-22 Federico Mena Quintero <federico@novell.com> > > Fix the computation of "complete but unique" in > GtkFileChooserEntry. Fix the case where "/" was not appended to a > unique directory name during explicit Tab completion. > > * gtk/gtkfilechooserentry.c (maybe_append_separator_to_file): > Return whether anything was appended as well as the new string > itself. > (find_common_prefix): Oops, only turn on > is_complete_not_unique_ret if we had a unique match! > (append_common_prefix): If we appended a directory separator, we > *did* expand the common prefix, so we are not in the "nothing > inserted" case. > >2009-01-22 Federico Mena Quintero <federico@novell.com> > > Return an error code when refreshing the entry from the user's > input. We use this in the completion code to know when completion > can't happen due to (for example) having a non-local URI in a file > chooser that is local_only=TRUE. > > Also, we start maintaining an invariant that > chooser_entry->current_folder_file != NULL implies that: > > * what the user entered is valid > > * we are loading that folder (chooser_entry->load_folder_cancellable != NULL) > > * or we are done loading that folder, or we have a handle > to it at least (chooser_entry->current_folder != NULL) > > The invariant also says that all of the above are NULL (and > chooser_entry->current_folder_file == NULL) implies that the user > typed something invalid. This makes > _gtk_file_chooser_entry_get_current_folder() not able to return > an invalid folder. > > * gtk/gtkfilechooserentry.c (RefreshStatus): New enum. > (refresh_current_folder_and_file_part): Return a RefreshStatus. > We filter out incomplete hostnames here (typing > "sftp://incompl[tab]" will error out), as well as completely > unparsable input. > (start_explicit_completion): Process the result from refresh...(). > Here we present the actual feedback about only being able to > display local folders for local_only=TRUE. > (commit_completion_and_refresh): Don't do anything with the result > of refresh...(), since this function doesn't get called during > completion-related interaction. > (start_autocompletion): Process the result from refresh...(). We > only do completion in the REFRESH_OK case. For the error cases, > we don't do anything, as this is autocompletion and must not > result in non-asked-for errors popping up. > (discard_loading_and_current_folder_file): Factor out function to > cancel the cancellable and discard the current_folder_file, > i.e. to reset the invariant to the "nothing valid is loaded" case. > (gtk_file_chooser_entry_dispose): Use > discard_loading_and_current_folder_file(). > (reload_current_folder): Likewise. > (refresh_current_folder_and_file_part): Likewise, and ensure that > the error cases result in the invariant being held. > (start_loading_current_folder): Check if the folder to be loaded > is non-native for the local_only=TRUE case; if so, return an error > as we are configured to load only local folders. > (reload_current_folder): Pass on errors from > start_loading_current_folder(). Tighten the preconditions, as we > are sure that we can only receive non-NULL folder-files to load. > (refresh_current_folder_and_file_part): Pass on errors from > reload_current_folder(). At the very end, assert the invariant > described above. > (start_explicit_completion): Add comments for translators, to > explain the purpose of the various feedback messages used during > completion. > >2009-01-21 Federico Mena Quintero <federico@novell.com> > > * gtk/gtkfilechooserdefault.c (save_widgets_create): Set > local_only on the location entry when we create it... > (set_local_only): ... and set it here only if the location entry > exists. > >2009-01-20 Federico Mena Quintero <federico@novell.com> > > http://bugzilla.gnome.org/show_bug.cgi?id=545980 - > GtkFileChooserEntry should handle URIs > > * gtk/gtkfilesystem.c (_gtk_file_system_parse): Detect URI schemes > and parse the full URI. > (has_uri_scheme): New function, stolen from the old > gtkfilesystemgnomevfs.c. > > Patch by Carlos Garnacho <carlos@imendio.com>: > > * gtk/gtkfilechooserentry.c (discard_current_folder): New > function, factored out for when we need to get rid of the > current_folder. > (gtk_file_chooser_entry_dispose): Use discard_current_folder(). > (finished_loading_cb): Fix prototype. > (load_directory_get_folder_callback): Discard the completion > store, as well as clearing the completion feedback, if we find an > error while loading the folder. Also, use > discard_current_folder(). > (reload_current_folder): Use discard_current_folder(). > > Patch by Carlos Garnacho <carlos@imendio.com> - add a local_only > property to GtkFileChooserEntry: > > * gtk/gtkfilechooserentry.c (struct _GtkFileChooserEntry): Add a > local_only field. > (_gtk_file_chooser_entry_init): Default to local_only being true. > (start_explicit_completion): Don't allow completion of non-native > files if local_only is turned on. > (start_loading_current_folder): Don't start loading non-native > folders if local_only is turned on. > (_gtk_file_chooser_entry_set_local_only): New function. > (_gtk_file_chooser_entry_get_local_only): New function. > > * gtk/gtkfilechooserentry.h (_gtk_file_chooser_entry_set_local_only, > _gtk_file_chooser_entry_get_local_only): New prototypes. > > * gtk/gtkfilechooserdefault.c (set_local_only): Set the local_only > property on the entry. > > Fix completion so it doesn't pop up for every character in a URI > hostname: > > * gtk/gtkfilechooser.h (GtkFileChooserError): Add a > GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME. > > * gtk/gtkfilesystem.c (_gtk_file_system_parse): Return an > "incomplete hostname" error if the user has not typed a full > hostname yet in an URI. > > * gtk/gtkfilechooserentry.c (append_common_prefix): If we get an > incomplete hostname, just don't pop up an error, since that is a > transient state and the user doesn't need to be notified about it. > (refresh_current_folder_and_file_part): Don't revert to showing > the base folder if we have an incomplete hostname. > (reload_current_folder): Handle the passed folder being NULL, even > if we must force a reload. Also, reload the folder if we didn't > have a cancellable for it (i.e. we hadn't started to load it > before). > >diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h >index e085a79..b7983a9 100644 >--- a/gtk/gtkfilechooser.h >+++ b/gtk/gtkfilechooser.h >@@ -60,7 +60,8 @@ GType gtk_file_chooser_get_type (void) G_GNUC_CONST; > typedef enum { > GTK_FILE_CHOOSER_ERROR_NONEXISTENT, > GTK_FILE_CHOOSER_ERROR_BAD_FILENAME, >- GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS >+ GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS, >+ GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME > } GtkFileChooserError; > > GQuark gtk_file_chooser_error_quark (void); >diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c >index 20f087b..1232b87 100644 >--- a/gtk/gtkfilechooserdefault.c >+++ b/gtk/gtkfilechooserdefault.c >@@ -4865,6 +4865,7 @@ save_widgets_create (GtkFileChooserDefault *impl) > impl->location_entry = _gtk_file_chooser_entry_new (TRUE); > _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), > impl->file_system); >+ _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->local_only); > gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45); > gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE); > gtk_table_attach (GTK_TABLE (table), impl->location_entry, >@@ -5304,6 +5305,9 @@ set_local_only (GtkFileChooserDefault *impl, > { > impl->local_only = local_only; > >+ if (impl->location_entry) >+ _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), local_only); >+ > if (impl->shortcuts_model && impl->file_system) > { > shortcuts_add_volumes (impl); >diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c >index a40e429..6e2554c 100644 >--- a/gtk/gtkfilechooserentry.c >+++ b/gtk/gtkfilechooserentry.c >@@ -50,6 +50,15 @@ typedef enum { > LOAD_COMPLETE_EXPLICIT_COMPLETION > } LoadCompleteAction; > >+typedef enum >+{ >+ REFRESH_OK, >+ REFRESH_INVALID_INPUT, >+ REFRESH_INCOMPLETE_HOSTNAME, >+ REFRESH_NONEXISTENT, >+ REFRESH_NOT_LOCAL >+} RefreshStatus; >+ > struct _GtkFileChooserEntry > { > GtkEntry parent_instance; >@@ -79,6 +88,7 @@ struct _GtkFileChooserEntry > guint has_completion : 1; > guint in_change : 1; > guint eat_tabs : 1; >+ guint local_only : 1; > }; > > enum >@@ -136,17 +146,18 @@ static gboolean completion_match_func (GtkEntryCompletion *comp, > gpointer data); > static char *maybe_append_separator_to_file (GtkFileChooserEntry *chooser_entry, > GFile *file, >- gchar *display_name); >+ gchar *display_name, >+ gboolean *appended); > > typedef enum { > REFRESH_UP_TO_CURSOR_POSITION, > REFRESH_WHOLE_TEXT > } RefreshMode; > >-static void refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, >+static RefreshStatus refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, > RefreshMode refresh_mode); >-static void finished_loading_cb (GFile *file, >- gpointer data); >+static void finished_loading_cb (GtkFolder *folder, >+ gpointer data); > static void autocomplete (GtkFileChooserEntry *chooser_entry); > static void install_start_autocompletion_idle (GtkFileChooserEntry *chooser_entry); > static void remove_completion_feedback (GtkFileChooserEntry *chooser_entry); >@@ -194,6 +205,8 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry) > GtkEntryCompletion *comp; > GtkCellRenderer *cell; > >+ chooser_entry->local_only = TRUE; >+ > g_object_set (chooser_entry, "truncate-multiline", TRUE, NULL); > > comp = gtk_entry_completion_new (); >@@ -245,11 +258,41 @@ gtk_file_chooser_entry_finalize (GObject *object) > } > > static void >+discard_current_folder (GtkFileChooserEntry *chooser_entry) >+{ >+ if (chooser_entry->current_folder) >+ { >+ g_signal_handlers_disconnect_by_func (chooser_entry->current_folder, >+ G_CALLBACK (finished_loading_cb), chooser_entry); >+ g_object_unref (chooser_entry->current_folder); >+ chooser_entry->current_folder = NULL; >+ } >+} >+ >+static void >+discard_loading_and_current_folder_file (GtkFileChooserEntry *chooser_entry) >+{ >+ if (chooser_entry->load_folder_cancellable) >+ { >+ g_cancellable_cancel (chooser_entry->load_folder_cancellable); >+ chooser_entry->load_folder_cancellable = NULL; >+ } >+ >+ if (chooser_entry->current_folder_file) >+ { >+ g_object_unref (chooser_entry->current_folder_file); >+ chooser_entry->current_folder_file = NULL; >+ } >+} >+ >+static void > gtk_file_chooser_entry_dispose (GObject *object) > { > GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (object); > > remove_completion_feedback (chooser_entry); >+ discard_current_folder (chooser_entry); >+ discard_loading_and_current_folder_file (chooser_entry); > > if (chooser_entry->start_autocompletion_idle_id != 0) > { >@@ -263,20 +306,6 @@ gtk_file_chooser_entry_dispose (GObject *object) > chooser_entry->completion_store = NULL; > } > >- if (chooser_entry->load_folder_cancellable) >- { >- g_cancellable_cancel (chooser_entry->load_folder_cancellable); >- chooser_entry->load_folder_cancellable = NULL; >- } >- >- if (chooser_entry->current_folder) >- { >- g_signal_handlers_disconnect_by_func (chooser_entry->current_folder, >- G_CALLBACK (finished_loading_cb), chooser_entry); >- g_object_unref (chooser_entry->current_folder); >- chooser_entry->current_folder = NULL; >- } >- > if (chooser_entry->file_system) > { > g_object_unref (chooser_entry->file_system); >@@ -296,6 +325,7 @@ match_selected_callback (GtkEntryCompletion *completion, > char *display_name; > GFile *file; > gint pos; >+ gboolean dummy; > > gtk_tree_model_get (model, iter, > DISPLAY_NAME_COLUMN, &display_name, >@@ -310,7 +340,7 @@ match_selected_callback (GtkEntryCompletion *completion, > return FALSE; > } > >- display_name = maybe_append_separator_to_file (chooser_entry, file, display_name); >+ display_name = maybe_append_separator_to_file (chooser_entry, file, display_name, &dummy); > > pos = chooser_entry->file_part_pos; > >@@ -422,15 +452,18 @@ beep (GtkFileChooserEntry *chooser_entry) > * return a new one if needed. Otherwise, it will return the old one. > * You should be safe calling > * >- * display_name = maybe_append_separator_to_file (entry, file, display_name); >+ * display_name = maybe_append_separator_to_file (entry, file, display_name, &appended); > * ... > * g_free (display_name); > */ > static char * > maybe_append_separator_to_file (GtkFileChooserEntry *chooser_entry, > GFile *file, >- gchar *display_name) >+ gchar *display_name, >+ gboolean *appended) > { >+ *appended = FALSE; >+ > if (!g_str_has_suffix (display_name, G_DIR_SEPARATOR_S) && file) > { > GFileInfo *info; >@@ -443,6 +476,7 @@ maybe_append_separator_to_file (GtkFileChooserEntry *chooser_entry, > { > gchar *tmp = display_name; > display_name = g_strconcat (tmp, G_DIR_SEPARATOR_S, NULL); >+ *appended = TRUE; > g_free (tmp); > } > >@@ -581,7 +615,7 @@ find_common_prefix (GtkFileChooserEntry *chooser_entry, > if (G_IS_DIR_SEPARATOR (display_name[len - 1])) > len--; > >- if (strncmp (*common_prefix_ret, display_name, len) == 0) >+ if (*unique_file_ret == NULL && strncmp (*common_prefix_ret, display_name, len) == 0) > *is_complete_not_unique_ret = TRUE; > > g_free (display_name); >@@ -653,7 +687,12 @@ append_common_prefix (GtkFileChooserEntry *chooser_entry, > error = NULL; > if (!find_common_prefix (chooser_entry, &common_prefix, &unique_file, &is_complete_not_unique, &prefix_expands_the_file_part, &error)) > { >- if (show_errors) >+ /* If the user types an incomplete hostname ("http://foo" without a slash >+ * after that), it's not an error. We just don't want to pop up a >+ * meaningless completion window in that state. >+ */ >+ if (!g_error_matches (error, GTK_FILE_CHOOSER_ERROR, GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME) >+ && show_errors) > { > beep (chooser_entry); > pop_up_completion_feedback (chooser_entry, _("Invalid path")); >@@ -669,21 +708,23 @@ append_common_prefix (GtkFileChooserEntry *chooser_entry, > if (unique_file) > { > if (!char_after_cursor_is_directory_separator (chooser_entry)) >- common_prefix = maybe_append_separator_to_file (chooser_entry, >- unique_file, >- common_prefix); >+ { >+ gboolean appended; >+ >+ common_prefix = maybe_append_separator_to_file (chooser_entry, >+ unique_file, >+ common_prefix, >+ &appended); >+ if (appended) >+ prefix_expands_the_file_part = TRUE; >+ } > > g_object_unref (unique_file); > >- if (common_prefix) >- { >- if (prefix_expands_the_file_part) >- result = COMPLETED_UNIQUE; >- else >- result = NOTHING_INSERTED_UNIQUE; >- } >+ if (prefix_expands_the_file_part) >+ result = COMPLETED_UNIQUE; > else >- result = INVALID_INPUT; >+ result = NOTHING_INSERTED_UNIQUE; > > have_result = TRUE; > } >@@ -1105,32 +1146,89 @@ explicitly_complete (GtkFileChooserEntry *chooser_entry) > static void > start_explicit_completion (GtkFileChooserEntry *chooser_entry) > { >- refresh_current_folder_and_file_part (chooser_entry, REFRESH_UP_TO_CURSOR_POSITION); >+ RefreshStatus status; >+ gboolean is_error; >+ char *feedback_msg; > >- if (!chooser_entry->current_folder_file) >+ status = refresh_current_folder_and_file_part (chooser_entry, REFRESH_UP_TO_CURSOR_POSITION); >+ >+ is_error = FALSE; >+ >+ switch (status) > { >- /* Here, no folder path means we couldn't parse what the user typed. */ >+ case REFRESH_OK: >+ g_assert (chooser_entry->current_folder_file != NULL); > >- beep (chooser_entry); >- pop_up_completion_feedback (chooser_entry, _("Invalid path")); >+ if (chooser_entry->current_folder && _gtk_folder_is_finished_loading (chooser_entry->current_folder)) >+ explicitly_complete (chooser_entry); >+ else >+ { >+ chooser_entry->load_complete_action = LOAD_COMPLETE_EXPLICIT_COMPLETION; > >- chooser_entry->load_complete_action = LOAD_COMPLETE_NOTHING; >+ /* Translators: this text is shown while the system is searching >+ * for possible completions for filenames in a file chooser entry. */ >+ pop_up_completion_feedback (chooser_entry, _("Completing...")); >+ } >+ >+ break; >+ >+ case REFRESH_INVALID_INPUT: >+ is_error = TRUE; >+ /* Translators: this is shown in the feedback for Tab-completion in a file >+ * chooser's text entry, when the user enters an invalid path. */ >+ feedback_msg = _("Invalid path"); >+ break; >+ >+ case REFRESH_INCOMPLETE_HOSTNAME: >+ is_error = TRUE; >+ >+ if (chooser_entry->local_only) >+ { >+ /* hostnames in a local_only file chooser? user error */ >+ >+ /* Translators: this is shown in the feedback for Tab-completion in a >+ * file chooser's text entry when the user enters something like >+ * "sftp://blahblah" in an app that only supports local filenames. */ >+ feedback_msg = _("Only local files may be selected"); >+ } >+ else >+ { >+ /* Another option is to complete the hostname based on the remote volumes that are mounted */ >+ >+ /* Translators: this is shown in the feedback for Tab-completion in a >+ * file chooser's text entry when the user hasn't entered the first '/' >+ * after a hostname and yet hits Tab (such as "sftp://blahblah[Tab]") */ >+ feedback_msg = _("Incomplete hostname; end it with '/'"); >+ } >+ >+ break; >+ >+ case REFRESH_NONEXISTENT: >+ is_error = TRUE; >+ >+ /* Translators: this is shown in the feedback for Tab-completion in a file >+ * chooser's text entry when the user enters a path that does not exist >+ * and then hits Tab */ >+ feedback_msg = _("Path does not exist"); >+ break; >+ >+ case REFRESH_NOT_LOCAL: >+ is_error = TRUE; >+ feedback_msg = _("Only local files may be selected"); >+ break; >+ >+ default: >+ g_assert_not_reached (); > return; > } > >- if (chooser_entry->current_folder >- && _gtk_folder_is_finished_loading (chooser_entry->current_folder)) >- { >- explicitly_complete (chooser_entry); >- } >- else >+ if (is_error) > { >- chooser_entry->load_complete_action = LOAD_COMPLETE_EXPLICIT_COMPLETION; >+ g_assert (chooser_entry->current_folder_file == NULL); > >- /* translators: this text is shown while the system is searching >- * for possible completions for text in a file chooser entry >- */ >- pop_up_completion_feedback (chooser_entry, _("Completing...")); >+ beep (chooser_entry); >+ pop_up_completion_feedback (chooser_entry, feedback_msg); >+ chooser_entry->load_complete_action = LOAD_COMPLETE_NOTHING; > } > } > >@@ -1196,6 +1294,7 @@ commit_completion_and_refresh (GtkFileChooserEntry *chooser_entry) > GTK_ENTRY (chooser_entry)->text_length); > } > >+ /* Here we ignore the result of refresh_current_folder_and_file_part(); there is nothing we can do with it */ > refresh_current_folder_and_file_part (chooser_entry, REFRESH_WHOLE_TEXT); > } > >@@ -1247,8 +1346,9 @@ populate_completion_store (GtkFileChooserEntry *chooser_entry) > { > gchar *display_name = g_strdup (g_file_info_get_display_name (info)); > GtkTreeIter iter; >+ gboolean dummy; > >- display_name = maybe_append_separator_to_file (chooser_entry, file, display_name); >+ display_name = maybe_append_separator_to_file (chooser_entry, file, display_name, &dummy); > > gtk_list_store_append (chooser_entry->completion_store, &iter); > gtk_list_store_set (chooser_entry->completion_store, &iter, >@@ -1308,8 +1408,8 @@ finish_folder_load (GtkFileChooserEntry *chooser_entry) > > /* Callback when the current folder finishes loading */ > static void >-finished_loading_cb (GFile *file, >- gpointer data) >+finished_loading_cb (GtkFolder *folder, >+ gpointer data) > { > GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (data); > >@@ -1337,6 +1437,7 @@ load_directory_get_folder_callback (GCancellable *cancellable, > > old_load_complete_action = chooser_entry->load_complete_action; > >+ discard_completion_store (chooser_entry); > clear_completions (chooser_entry); > > if (old_load_complete_action == LOAD_COMPLETE_EXPLICIT_COMPLETION) >@@ -1347,11 +1448,7 @@ load_directory_get_folder_callback (GCancellable *cancellable, > pop_up_completion_feedback (chooser_entry, error->message); > } > >- if (chooser_entry->current_folder) >- { >- g_object_unref (chooser_entry->current_folder); >- chooser_entry->current_folder = NULL; >- } >+ discard_current_folder (chooser_entry); > } > > if (cancelled || error) >@@ -1373,68 +1470,71 @@ out: > g_object_unref (cancellable); > } > >-static void >+static RefreshStatus > start_loading_current_folder (GtkFileChooserEntry *chooser_entry) > { >- if (chooser_entry->current_folder_file == NULL || >- chooser_entry->file_system == NULL) >- return; >+ if (chooser_entry->file_system == NULL) >+ return REFRESH_OK; > >+ g_assert (chooser_entry->current_folder_file != NULL); > g_assert (chooser_entry->current_folder == NULL); > g_assert (chooser_entry->load_folder_cancellable == NULL); > >+ if (chooser_entry->local_only >+ && !g_file_is_native (chooser_entry->current_folder_file)) >+ { >+ g_object_unref (chooser_entry->current_folder_file); >+ chooser_entry->current_folder_file = NULL; >+ >+ return REFRESH_NOT_LOCAL; >+ } >+ > chooser_entry->load_folder_cancellable = > _gtk_file_system_get_folder (chooser_entry->file_system, > chooser_entry->current_folder_file, > "standard::name,standard::display-name,standard::type", > load_directory_get_folder_callback, > g_object_ref (chooser_entry)); >+ >+ return REFRESH_OK; > } > >-static void >+static RefreshStatus > reload_current_folder (GtkFileChooserEntry *chooser_entry, > GFile *folder_file, > gboolean force_reload) > { > gboolean reload = FALSE; > >+ g_assert (folder_file != NULL); >+ > if (chooser_entry->current_folder_file) > { >- if ((folder_file && !g_file_equal (folder_file, chooser_entry->current_folder_file)) >+ if ((!(g_file_equal (folder_file, chooser_entry->current_folder_file) >+ && chooser_entry->load_folder_cancellable)) > || force_reload) > { > reload = TRUE; > >- /* We changed our current directory. We need to clear out the old >- * directory information. >- */ >- if (chooser_entry->current_folder) >- { >- if (chooser_entry->load_folder_cancellable) >- { >- g_cancellable_cancel (chooser_entry->load_folder_cancellable); >- chooser_entry->load_folder_cancellable = NULL; >- } >- >- g_object_unref (chooser_entry->current_folder); >- chooser_entry->current_folder = NULL; >- } >+ discard_current_folder (chooser_entry); >+ discard_loading_and_current_folder_file (chooser_entry); > >- g_object_unref (chooser_entry->current_folder_file); > chooser_entry->current_folder_file = g_object_ref (folder_file); > } > } > else > { >- chooser_entry->current_folder_file = (folder_file) ? g_object_ref (folder_file) : NULL; >+ chooser_entry->current_folder_file = g_object_ref (folder_file); > reload = TRUE; > } > > if (reload) >- start_loading_current_folder (chooser_entry); >+ return start_loading_current_folder (chooser_entry); >+ else >+ return REFRESH_OK; > } > >-static void >+static RefreshStatus > refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, > RefreshMode refresh_mode) > { >@@ -1445,6 +1545,8 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, > gchar *file_part; > gsize total_len, file_part_len; > gint file_part_pos; >+ GError *error; >+ RefreshStatus result; > > editable = GTK_EDITABLE (chooser_entry); > >@@ -1460,29 +1562,51 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, > > default: > g_assert_not_reached (); >- return; >+ return REFRESH_INVALID_INPUT; > } > > text = gtk_editable_get_chars (editable, 0, end_pos); >- >+ >+ error = NULL; > if (!chooser_entry->file_system || > !chooser_entry->base_folder || > !_gtk_file_system_parse (chooser_entry->file_system, > chooser_entry->base_folder, text, >- &folder_file, &file_part, NULL)) /* NULL-GError */ >+ &folder_file, &file_part, &error)) > { >- folder_file = (chooser_entry->base_folder) ? g_object_ref (chooser_entry->base_folder) : NULL; >+ if (g_error_matches (error, GTK_FILE_CHOOSER_ERROR, GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME)) >+ { >+ folder_file = NULL; >+ result = REFRESH_INCOMPLETE_HOSTNAME; >+ } >+ else >+ { >+ folder_file = (chooser_entry->base_folder) ? g_object_ref (chooser_entry->base_folder) : NULL; >+ >+ if (g_error_matches (error, GTK_FILE_CHOOSER_ERROR, GTK_FILE_CHOOSER_ERROR_NONEXISTENT)) >+ result = REFRESH_NONEXISTENT; >+ else >+ result = REFRESH_INVALID_INPUT; >+ } >+ >+ if (error) >+ g_error_free (error); >+ > file_part = g_strdup (""); > file_part_pos = -1; > } > else > { >+ g_assert (folder_file != NULL); >+ > file_part_len = strlen (file_part); > total_len = strlen (text); > if (total_len > file_part_len) > file_part_pos = g_utf8_strlen (text, total_len - file_part_len); > else > file_part_pos = 0; >+ >+ result = REFRESH_OK; > } > > g_free (text); >@@ -1492,18 +1616,40 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, > chooser_entry->file_part = file_part; > chooser_entry->file_part_pos = file_part_pos; > >- reload_current_folder (chooser_entry, folder_file, file_part_pos == -1); >+ if (result == REFRESH_OK) >+ { >+ result = reload_current_folder (chooser_entry, folder_file, file_part_pos == -1); >+ } >+ else >+ { >+ discard_current_folder (chooser_entry); >+ discard_loading_and_current_folder_file (chooser_entry); >+ } > > if (folder_file) > g_object_unref (folder_file); >+ >+ g_assert (/* we are OK and we have a current folder file and (loading process or folder handle)... */ >+ ((result == REFRESH_OK) >+ && (chooser_entry->current_folder_file != NULL) >+ && (((chooser_entry->load_folder_cancellable != NULL) && (chooser_entry->current_folder == NULL)) >+ || ((chooser_entry->load_folder_cancellable == NULL) && (chooser_entry->current_folder != NULL)))) >+ /* ... OR we have an error, and we don't have a current folder file nor a loading process nor a folder handle */ >+ || ((result != REFRESH_OK) >+ && (chooser_entry->current_folder_file == NULL) >+ && (chooser_entry->load_folder_cancellable == NULL) >+ && (chooser_entry->current_folder == NULL))); >+ >+ return result; > } > > static void > autocomplete (GtkFileChooserEntry *chooser_entry) > { >- g_assert (chooser_entry->current_folder != NULL); >- g_assert (_gtk_folder_is_finished_loading (chooser_entry->current_folder)); >- g_assert (gtk_editable_get_position (GTK_EDITABLE (chooser_entry)) == GTK_ENTRY (chooser_entry)->text_length); >+ if (!(chooser_entry->current_folder != NULL >+ && _gtk_folder_is_finished_loading (chooser_entry->current_folder) >+ && gtk_editable_get_position (GTK_EDITABLE (chooser_entry)) == GTK_ENTRY (chooser_entry)->text_length)) >+ return; > > append_common_prefix (chooser_entry, TRUE, FALSE); > } >@@ -1511,20 +1657,34 @@ autocomplete (GtkFileChooserEntry *chooser_entry) > static void > start_autocompletion (GtkFileChooserEntry *chooser_entry) > { >- refresh_current_folder_and_file_part (chooser_entry, REFRESH_UP_TO_CURSOR_POSITION); >+ RefreshStatus status; >+ >+ status = refresh_current_folder_and_file_part (chooser_entry, REFRESH_UP_TO_CURSOR_POSITION); > >- if (!chooser_entry->current_folder) >+ switch (status) > { >+ case REFRESH_OK: >+ g_assert (chooser_entry->current_folder_file != NULL); >+ >+ if (chooser_entry->current_folder && _gtk_folder_is_finished_loading (chooser_entry->current_folder)) >+ autocomplete (chooser_entry); >+ else >+ chooser_entry->load_complete_action = LOAD_COMPLETE_AUTOCOMPLETE; >+ >+ break; >+ >+ case REFRESH_INVALID_INPUT: >+ case REFRESH_INCOMPLETE_HOSTNAME: >+ case REFRESH_NONEXISTENT: >+ case REFRESH_NOT_LOCAL: > /* We don't beep or anything, since this is autocompletion - the user > * didn't request any action explicitly. > */ >- return; >- } >+ break; > >- if (_gtk_folder_is_finished_loading (chooser_entry->current_folder)) >- autocomplete (chooser_entry); >- else >- chooser_entry->load_complete_action = LOAD_COMPLETE_AUTOCOMPLETE; >+ default: >+ g_assert_not_reached (); >+ } > } > > static gboolean >@@ -1685,12 +1845,11 @@ _gtk_file_chooser_entry_set_base_folder (GtkFileChooserEntry *chooser_entry, > * @chooser_entry: a #GtkFileChooserEntry > * > * Gets the current folder for the #GtkFileChooserEntry. If the >- * user has only entered a filename, this will be the base folder >+ * user has only entered a filename, this will be in the base folder > * (see _gtk_file_chooser_entry_set_base_folder()), but if the > * user has entered a relative or absolute path, then it will >- * be different. If the user has entered a relative or absolute >- * path that doesn't point to a folder in the file system, it will >- * be %NULL. >+ * be different. If the user has entered unparsable text, or text which >+ * the entry cannot handle, this will return %NULL. > * > * Return value: the file for the current folder - this value is owned by the > * chooser entry and must not be modified or freed. >@@ -1845,3 +2004,16 @@ _gtk_file_chooser_entry_select_filename (GtkFileChooserEntry *chooser_entry) > gtk_editable_select_region (GTK_EDITABLE (chooser_entry), 0, (gint) len); > } > >+void >+_gtk_file_chooser_entry_set_local_only (GtkFileChooserEntry *chooser_entry, >+ gboolean local_only) >+{ >+ chooser_entry->local_only = local_only; >+ clear_completions (chooser_entry); >+} >+ >+gboolean >+_gtk_file_chooser_entry_get_local_only (GtkFileChooserEntry *chooser_entry) >+{ >+ return chooser_entry->local_only; >+} >diff --git a/gtk/gtkfilechooserentry.h b/gtk/gtkfilechooserentry.h >index 2818fd9..a9c9f83 100644 >--- a/gtk/gtkfilechooserentry.h >+++ b/gtk/gtkfilechooserentry.h >@@ -48,6 +48,9 @@ const gchar * _gtk_file_chooser_entry_get_file_part (GtkFileChooserEnt > gboolean _gtk_file_chooser_entry_get_is_folder (GtkFileChooserEntry *chooser_entry, > GFile *file); > void _gtk_file_chooser_entry_select_filename (GtkFileChooserEntry *chooser_entry); >+void _gtk_file_chooser_entry_set_local_only (GtkFileChooserEntry *chooser_entry, >+ gboolean local_only); >+gboolean _gtk_file_chooser_entry_get_local_only (GtkFileChooserEntry *chooser_entry); > > G_END_DECLS > >diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c >index 2b2d44a..6a90fd7 100644 >--- a/gtk/gtkfilesystem.c >+++ b/gtk/gtkfilesystem.c >@@ -596,6 +596,29 @@ _gtk_file_system_list_bookmarks (GtkFileSystem *file_system) > return g_slist_reverse (files); > } > >+static gboolean >+is_valid_scheme_character (char c) >+{ >+ return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.'; >+} >+ >+static gboolean >+has_uri_scheme (const char *str) >+{ >+ const char *p; >+ >+ p = str; >+ >+ if (!is_valid_scheme_character (*p)) >+ return FALSE; >+ >+ do >+ p++; >+ while (is_valid_scheme_character (*p)); >+ >+ return (strncmp (p, "://", 3) == 0); >+} >+ > gboolean > _gtk_file_system_parse (GtkFileSystem *file_system, > GFile *base_file, >@@ -608,6 +631,7 @@ _gtk_file_system_parse (GtkFileSystem *file_system, > gboolean result = FALSE; > gboolean is_dir = FALSE; > gchar *last_slash = NULL; >+ gboolean is_uri; > > DEBUG ("parse"); > >@@ -616,7 +640,37 @@ _gtk_file_system_parse (GtkFileSystem *file_system, > > last_slash = strrchr (str, G_DIR_SEPARATOR); > >- if (str[0] == '~') >+ is_uri = has_uri_scheme (str); >+ >+ if (is_uri) >+ { >+ const char *colon; >+ const char *slash_after_hostname; >+ >+ colon = strchr (str, ':'); >+ g_assert (colon != NULL); >+ g_assert (strncmp (colon, "://", 3) == 0); >+ >+ slash_after_hostname = strchr (colon + 3, '/'); >+ >+ if (slash_after_hostname == NULL) >+ { >+ /* We don't have a full hostname yet. So, don't switch the folder >+ * until we have seen a full hostname. Otherwise, completion will >+ * happen for every character the user types for the hostname. >+ */ >+ >+ *folder = NULL; >+ *file_part = NULL; >+ g_set_error (error, >+ GTK_FILE_CHOOSER_ERROR, >+ GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME, >+ "Incomplete hostname"); >+ return FALSE; >+ } >+ } >+ >+ if (str[0] == '~' || g_path_is_absolute (str) || is_uri) > file = g_file_parse_name (str); > else > file = g_file_resolve_relative_path (base_file, str);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 459744
: 267093