* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
GtkEntryClass parent_class;
};
-/* Action to take when the current folder finishes loading (for explicit or automatic completion) */
-typedef enum {
- LOAD_COMPLETE_NOTHING,
- LOAD_COMPLETE_EXPLICIT_COMPLETION
-} LoadCompleteAction;
-
struct _GtkFileChooserEntry
{
GtkEntry parent_instance;
gchar *dir_part;
gchar *file_part;
- LoadCompleteAction load_complete_action;
-
GtkTreeModel *completion_store;
guint current_folder_loaded : 1;
+ guint complete_on_load : 1;
guint eat_tabs : 1;
guint local_only : 1;
};
static void gtk_file_chooser_entry_finalize (GObject *object);
static void gtk_file_chooser_entry_dispose (GObject *object);
static void gtk_file_chooser_entry_grab_focus (GtkWidget *widget);
-static gboolean gtk_file_chooser_entry_key_press_event (GtkWidget *widget,
- GdkEventKey *event);
+static gboolean gtk_file_chooser_entry_tab_handler (GtkWidget *widget,
+ GdkEventKey *event);
static gboolean gtk_file_chooser_entry_focus_out_event (GtkWidget *widget,
GdkEventFocus *event);
GtkTreeIter *iter,
GtkFileChooserEntry *chooser_entry);
+static void set_complete_on_load (GtkFileChooserEntry *chooser_entry,
+ gboolean complete_on_load);
static void refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry);
static void set_completion_folder (GtkFileChooserEntry *chooser_entry,
GFile *folder);
pspecs[i]->name == I_("selection-bound") ||
pspecs[i]->name == I_("text"))
{
- chooser_entry->load_complete_action = LOAD_COMPLETE_NOTHING;
-
+ set_complete_on_load (chooser_entry, FALSE);
refresh_current_folder_and_file_part (chooser_entry);
-
break;
}
}
gobject_class->dispatch_properties_changed = gtk_file_chooser_entry_dispatch_properties_changed;
widget_class->grab_focus = gtk_file_chooser_entry_grab_focus;
- widget_class->key_press_event = gtk_file_chooser_entry_key_press_event;
widget_class->focus_out_event = gtk_file_chooser_entry_focus_out_event;
}
GtkCellRenderer *cell;
chooser_entry->local_only = TRUE;
- chooser_entry->base_folder = g_file_new_for_path (g_get_home_dir ());
g_object_set (chooser_entry, "truncate-multiline", TRUE, NULL);
gtk_entry_set_completion (GTK_ENTRY (chooser_entry), comp);
g_object_unref (comp);
+ /* NB: This needs to happen after the completion is set, so this handler
+ * runs before the handler installed by entrycompletion */
+ g_signal_connect (chooser_entry, "key-press-event",
+ G_CALLBACK (gtk_file_chooser_entry_tab_handler), NULL);
#ifdef G_OS_WIN32
g_signal_connect (chooser_entry, "insert-text",
{
GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (object);
- g_object_unref (chooser_entry->base_folder);
+ if (chooser_entry->base_folder)
+ g_object_unref (chooser_entry->base_folder);
if (chooser_entry->current_folder_file)
g_object_unref (chooser_entry->current_folder_file);
}
static void
-clear_completions (GtkFileChooserEntry *chooser_entry)
+set_complete_on_load (GtkFileChooserEntry *chooser_entry,
+ gboolean complete_on_load)
{
- chooser_entry->load_complete_action = LOAD_COMPLETE_NOTHING;
-}
+ /* a completion was triggered, but we couldn't do it.
+ * So no text was inserted when pressing tab, so we beep */
+ if (chooser_entry->complete_on_load && !complete_on_load)
+ gtk_widget_error_bell (GTK_WIDGET (chooser_entry));
-static void
-beep (GtkFileChooserEntry *chooser_entry)
-{
- gtk_widget_error_bell (GTK_WIDGET (chooser_entry));
+ chooser_entry->complete_on_load = complete_on_load;
}
static gboolean
if (str[0] == '~' || g_path_is_absolute (str) || has_uri_scheme (str))
file = g_file_parse_name (str);
- else
+ else if (chooser_entry->base_folder != NULL)
file = g_file_resolve_relative_path (chooser_entry->base_folder, str);
+ else
+ file = NULL;
return file;
}
file = gtk_file_chooser_get_file_for_text (chooser_entry, text);
+ if (file == NULL)
+ return NULL;
+
if (text[0] == 0 || text[strlen (text) - 1] == G_DIR_SEPARATOR)
return file;
static void
explicitly_complete (GtkFileChooserEntry *chooser_entry)
{
- clear_completions (chooser_entry);
+ chooser_entry->complete_on_load = FALSE;
if (chooser_entry->completion_store)
{
}
}
- beep (chooser_entry);
+ gtk_widget_error_bell (GTK_WIDGET (chooser_entry));
}
static void
if (chooser_entry->current_folder_loaded)
explicitly_complete (chooser_entry);
else
- chooser_entry->load_complete_action = LOAD_COMPLETE_EXPLICIT_COMPLETION;
+ set_complete_on_load (chooser_entry, TRUE);
}
static gboolean
-gtk_file_chooser_entry_key_press_event (GtkWidget *widget,
- GdkEventKey *event)
+gtk_file_chooser_entry_tab_handler (GtkWidget *widget,
+ GdkEventKey *event)
{
GtkFileChooserEntry *chooser_entry;
GtkEditable *editable;
GdkModifierType state;
- gboolean control_pressed;
+ gint start, end;
chooser_entry = GTK_FILE_CHOOSER_ENTRY (widget);
editable = GTK_EDITABLE (widget);
if (!chooser_entry->eat_tabs)
- return GTK_WIDGET_CLASS (_gtk_file_chooser_entry_parent_class)->key_press_event (widget, event);
+ return FALSE;
- control_pressed = FALSE;
+ if (event->keyval != GDK_KEY_Tab)
+ return FALSE;
- if (gtk_get_current_event_state (&state))
- {
- if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
- control_pressed = TRUE;
- }
+ if (gtk_get_current_event_state (&state) &&
+ (state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ return FALSE;
/* This is a bit evil -- it makes Tab never leave the entry. It basically
* makes it 'safe' for people to hit. */
- if (event->keyval == GDK_KEY_Tab && !control_pressed)
- {
- gint start, end;
-
- gtk_editable_get_selection_bounds (editable, &start, &end);
+ gtk_editable_get_selection_bounds (editable, &start, &end);
- if (start != end)
- gtk_editable_set_position (editable, MAX (start, end));
- else
- start_explicit_completion (chooser_entry);
-
- return TRUE;
- }
-
- return GTK_WIDGET_CLASS (_gtk_file_chooser_entry_parent_class)->key_press_event (widget, event);
+ if (start != end)
+ gtk_editable_set_position (editable, MAX (start, end));
+ else
+ start_explicit_completion (chooser_entry);
+ return TRUE;
}
static gboolean
{
GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (widget);
- chooser_entry->load_complete_action = LOAD_COMPLETE_NOTHING;
+ set_complete_on_load (chooser_entry, FALSE);
return GTK_WIDGET_CLASS (_gtk_file_chooser_entry_parent_class)->focus_out_event (widget, event);
}
+static void
+update_inline_completion (GtkFileChooserEntry *chooser_entry)
+{
+ GtkEntryCompletion *completion = gtk_entry_get_completion (GTK_ENTRY (chooser_entry));
+
+ if (!chooser_entry->current_folder_loaded)
+ {
+ gtk_entry_completion_set_inline_completion (completion, FALSE);
+ return;
+ }
+
+ switch (chooser_entry->action)
+ {
+ case GTK_FILE_CHOOSER_ACTION_OPEN:
+ case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+ gtk_entry_completion_set_inline_completion (completion, TRUE);
+ break;
+ case GTK_FILE_CHOOSER_ACTION_SAVE:
+ case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
+ gtk_entry_completion_set_inline_completion (completion, FALSE);
+ break;
+ }
+}
+
static void
discard_completion_store (GtkFileChooserEntry *chooser_entry)
{
return;
gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (chooser_entry)), NULL);
- gtk_entry_completion_set_inline_completion (gtk_entry_get_completion (GTK_ENTRY (chooser_entry)), FALSE);
+ update_inline_completion (chooser_entry);
g_object_unref (chooser_entry->completion_store);
chooser_entry->completion_store = NULL;
}
_gtk_file_system_model_set_filter_folders (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
TRUE);
+ _gtk_file_system_model_set_show_files (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
+ chooser_entry->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ chooser_entry->action == GTK_FILE_CHOOSER_ACTION_SAVE);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (chooser_entry->completion_store),
DISPLAY_NAME_COLUMN, GTK_SORT_ASCENDING);
chooser_entry->completion_store);
}
-/* When we finish loading the current folder, this function should get called to
- * perform the deferred explicit completion.
- */
-static void
-perform_load_complete_action (GtkFileChooserEntry *chooser_entry)
-{
- switch (chooser_entry->load_complete_action)
- {
- case LOAD_COMPLETE_NOTHING:
- break;
-
- case LOAD_COMPLETE_EXPLICIT_COMPLETION:
- explicitly_complete (chooser_entry);
- break;
-
- default:
- g_assert_not_reached ();
- }
-
-}
-
/* Callback when the current folder finishes loading */
static void
finished_loading_cb (GtkFileSystemModel *model,
if (error)
{
- LoadCompleteAction old_load_complete_action;
-
- 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)
- {
- /* Since this came from explicit user action (Tab completion), we'll present errors visually */
-
- beep (chooser_entry);
- }
-
+ set_complete_on_load (chooser_entry, FALSE);
return;
}
- perform_load_complete_action (chooser_entry);
+ if (chooser_entry->complete_on_load)
+ explicitly_complete (chooser_entry);
gtk_widget_set_tooltip_text (GTK_WIDGET (chooser_entry), NULL);
completion = gtk_entry_get_completion (GTK_ENTRY (chooser_entry));
- gtk_entry_completion_set_inline_completion (completion, TRUE);
+ update_inline_completion (chooser_entry);
gtk_entry_completion_complete (completion);
gtk_entry_completion_insert_prefix (completion);
}
_gtk_file_chooser_entry_set_base_folder (GtkFileChooserEntry *chooser_entry,
GFile *file)
{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER_ENTRY (chooser_entry));
+ g_return_if_fail (file == NULL || G_IS_FILE (file));
+
+ if (chooser_entry->base_folder == file ||
+ (file != NULL && chooser_entry->base_folder != NULL
+ && g_file_equal (chooser_entry->base_folder, file)))
+ return;
+
if (file)
g_object_ref (file);
- else
- file = g_file_new_for_path (g_get_home_dir ());
-
- if (g_file_equal (chooser_entry->base_folder, file))
- {
- g_object_unref (file);
- return;
- }
if (chooser_entry->base_folder)
g_object_unref (chooser_entry->base_folder);
chooser_entry->base_folder = file;
- clear_completions (chooser_entry);
+ refresh_current_folder_and_file_part (chooser_entry);
}
/**
gtk_entry_completion_set_popup_single_match (comp, TRUE);
break;
}
+
+ if (chooser_entry->completion_store)
+ _gtk_file_system_model_set_show_files (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
+ action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ action == GTK_FILE_CHOOSER_ACTION_SAVE);
+
+ update_inline_completion (chooser_entry);
}
}
gboolean local_only)
{
chooser_entry->local_only = local_only;
- clear_completions (chooser_entry);
+ refresh_current_folder_and_file_part (chooser_entry);
}
gboolean