1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Alexander Larsson <alexl@redhat.com>
24 #include "gfilenamecompleter.h"
25 #include "gfileenumerator.h"
26 #include "gfileattribute.h"
28 #include "gfileinfo.h"
29 #include "gcancellable.h"
36 * SECTION:gfilenamecompleter
37 * @short_description: Filename Completer
40 * Completes partial file and directory names given a partial string by
41 * looking in the file system for clues. Can return a list of possible
42 * completion strings for widget implementations.
51 static guint signals
[LAST_SIGNAL
] = { 0 };
54 GFilenameCompleter
*completer
;
55 GFileEnumerator
*enumerator
;
56 GCancellable
*cancellable
;
57 gboolean should_escape
;
63 struct _GFilenameCompleter
{
67 gboolean basenames_are_escaped
;
71 LoadBasenamesData
*basename_loader
;
74 G_DEFINE_TYPE (GFilenameCompleter
, g_filename_completer
, G_TYPE_OBJECT
);
76 static void cancel_load_basenames (GFilenameCompleter
*completer
);
79 g_filename_completer_finalize (GObject
*object
)
81 GFilenameCompleter
*completer
;
83 completer
= G_FILENAME_COMPLETER (object
);
85 cancel_load_basenames (completer
);
87 if (completer
->basenames_dir
)
88 g_object_unref (completer
->basenames_dir
);
90 g_list_foreach (completer
->basenames
, (GFunc
)g_free
, NULL
);
91 g_list_free (completer
->basenames
);
93 G_OBJECT_CLASS (g_filename_completer_parent_class
)->finalize (object
);
97 g_filename_completer_class_init (GFilenameCompleterClass
*klass
)
99 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
101 gobject_class
->finalize
= g_filename_completer_finalize
;
103 * GFilenameCompleter::got-completion-data:
105 * Emitted when the file name completion information comes available.
107 signals
[GOT_COMPLETION_DATA
] = g_signal_new (I_("got_completion_data"),
108 G_TYPE_FILENAME_COMPLETER
,
110 G_STRUCT_OFFSET (GFilenameCompleterClass
, got_completion_data
),
112 g_cclosure_marshal_VOID__VOID
,
117 g_filename_completer_init (GFilenameCompleter
*completer
)
122 * g_filename_completer_new:
124 * Creates a new filename completer.
126 * Returns: a #GFilenameCompleter.
129 g_filename_completer_new (void)
131 return g_object_new (G_TYPE_FILENAME_COMPLETER
, NULL
);
135 longest_common_prefix (char *a
, char *b
)
141 while (g_utf8_get_char (a
) == g_utf8_get_char (b
))
143 a
= g_utf8_next_char (a
);
144 b
= g_utf8_next_char (b
);
147 return g_strndup (start
, a
- start
);
151 load_basenames_data_free (LoadBasenamesData
*data
)
153 if (data
->enumerator
)
154 g_object_unref (data
->enumerator
);
156 g_object_unref (data
->cancellable
);
157 g_object_unref (data
->dir
);
159 g_list_foreach (data
->basenames
, (GFunc
)g_free
, NULL
);
160 g_list_free (data
->basenames
);
166 got_more_files (GObject
*source_object
,
170 LoadBasenamesData
*data
= user_data
;
174 gboolean append_slash
;
178 if (data
->completer
== NULL
)
181 load_basenames_data_free (data
);
185 infos
= g_file_enumerator_next_files_finish (data
->enumerator
, res
, NULL
);
187 for (l
= infos
; l
!= NULL
; l
= l
->next
)
191 if (data
->dirs_only
&&
192 g_file_info_get_file_type (info
) != G_FILE_TYPE_DIRECTORY
)
194 g_object_unref (info
);
198 append_slash
= g_file_info_get_file_type (info
) == G_FILE_TYPE_DIRECTORY
;
199 name
= g_file_info_get_name (info
);
202 g_object_unref (info
);
207 if (data
->should_escape
)
208 basename
= g_uri_escape_string (name
,
209 G_URI_RESERVED_CHARS_ALLOWED_IN_PATH
,
212 /* If not should_escape, must be a local filename, convert to utf8 */
213 basename
= g_filename_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
220 basename
= g_strconcat (basename
, "/", NULL
);
224 data
->basenames
= g_list_prepend (data
->basenames
, basename
);
227 g_object_unref (info
);
234 /* Not last, get more files */
235 g_file_enumerator_next_files_async (data
->enumerator
,
239 got_more_files
, data
);
243 data
->completer
->basename_loader
= NULL
;
245 if (data
->completer
->basenames_dir
)
246 g_object_unref (data
->completer
->basenames_dir
);
247 g_list_foreach (data
->completer
->basenames
, (GFunc
)g_free
, NULL
);
248 g_list_free (data
->completer
->basenames
);
250 data
->completer
->basenames_dir
= g_object_ref (data
->dir
);
251 data
->completer
->basenames
= data
->basenames
;
252 data
->completer
->basenames_are_escaped
= data
->should_escape
;
253 data
->basenames
= NULL
;
255 g_file_enumerator_close_async (data
->enumerator
, 0, NULL
, NULL
, NULL
);
257 g_signal_emit (data
->completer
, signals
[GOT_COMPLETION_DATA
], 0);
258 load_basenames_data_free (data
);
264 got_enum (GObject
*source_object
,
268 LoadBasenamesData
*data
= user_data
;
270 if (data
->completer
== NULL
)
273 load_basenames_data_free (data
);
277 data
->enumerator
= g_file_enumerate_children_finish (G_FILE (source_object
), res
, NULL
);
279 if (data
->enumerator
== NULL
)
281 data
->completer
->basename_loader
= NULL
;
283 if (data
->completer
->basenames_dir
)
284 g_object_unref (data
->completer
->basenames_dir
);
285 g_list_foreach (data
->completer
->basenames
, (GFunc
)g_free
, NULL
);
286 g_list_free (data
->completer
->basenames
);
288 /* Mark uptodate with no basenames */
289 data
->completer
->basenames_dir
= g_object_ref (data
->dir
);
290 data
->completer
->basenames
= NULL
;
291 data
->completer
->basenames_are_escaped
= data
->should_escape
;
293 load_basenames_data_free (data
);
297 g_file_enumerator_next_files_async (data
->enumerator
,
301 got_more_files
, data
);
305 schedule_load_basenames (GFilenameCompleter
*completer
,
307 gboolean should_escape
)
309 LoadBasenamesData
*data
;
311 cancel_load_basenames (completer
);
313 data
= g_new0 (LoadBasenamesData
, 1);
314 data
->completer
= completer
;
315 data
->cancellable
= g_cancellable_new ();
316 data
->dir
= g_object_ref (dir
);
317 data
->should_escape
= should_escape
;
318 data
->dirs_only
= completer
->dirs_only
;
320 completer
->basename_loader
= data
;
322 g_file_enumerate_children_async (dir
,
323 G_FILE_ATTRIBUTE_STANDARD_NAME
"," G_FILE_ATTRIBUTE_STANDARD_TYPE
,
330 cancel_load_basenames (GFilenameCompleter
*completer
)
332 LoadBasenamesData
*loader
;
334 if (completer
->basename_loader
)
336 loader
= completer
->basename_loader
;
337 loader
->completer
= NULL
;
339 g_cancellable_cancel (loader
->cancellable
);
341 completer
->basename_loader
= NULL
;
346 /* Returns a list of possible matches and the basename to use for it */
348 init_completion (GFilenameCompleter
*completer
,
349 const char *initial_text
,
352 gboolean should_escape
;
353 GFile
*file
, *parent
;
358 *basename_out
= NULL
;
360 should_escape
= ! (g_path_is_absolute (initial_text
) || *initial_text
== '~');
362 len
= strlen (initial_text
);
365 initial_text
[len
- 1] == '/')
368 file
= g_file_parse_name (initial_text
);
369 parent
= g_file_get_parent (file
);
372 g_object_unref (file
);
376 if (completer
->basenames_dir
== NULL
||
377 completer
->basenames_are_escaped
!= should_escape
||
378 !g_file_equal (parent
, completer
->basenames_dir
))
380 schedule_load_basenames (completer
, parent
, should_escape
);
381 g_object_unref (file
);
385 basename
= g_file_get_basename (file
);
389 basename
= g_uri_escape_string (basename
, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH
, TRUE
);
395 basename
= g_filename_to_utf8 (basename
, -1, NULL
, NULL
, NULL
);
398 if (basename
== NULL
)
402 *basename_out
= basename
;
404 return completer
->basenames
;
408 * g_filename_completer_get_completion_suffix:
409 * @completer: the filename completer.
410 * @initial_text: text to be completed.
412 * Obtains a completion for @initial_text from @completer.
414 * Returns: a completed string, or %NULL if no completion exists.
415 * This string is not owned by GIO, so remember to g_free() it
419 g_filename_completer_get_completion_suffix (GFilenameCompleter
*completer
,
420 const char *initial_text
)
422 GList
*possible_matches
, *l
;
425 char *possible_match
;
428 g_return_val_if_fail (G_IS_FILENAME_COMPLETER (completer
), NULL
);
429 g_return_val_if_fail (initial_text
!= NULL
, NULL
);
431 possible_matches
= init_completion (completer
, initial_text
, &prefix
);
435 for (l
= possible_matches
; l
!= NULL
; l
= l
->next
)
437 possible_match
= l
->data
;
439 if (g_str_has_prefix (possible_match
, prefix
))
442 suffix
= g_strdup (possible_match
+ strlen (prefix
));
445 lcp
= longest_common_prefix (suffix
,
446 possible_match
+ strlen (prefix
));
462 * g_filename_completer_get_completions:
463 * @completer: the filename completer.
464 * @initial_text: text to be completed.
466 * Gets an array of completion strings for a given initial text.
468 * Returns: array of strings with possible completions for @initial_text.
469 * This array must be freed by g_strfreev() when finished.
472 g_filename_completer_get_completions (GFilenameCompleter
*completer
,
473 const char *initial_text
)
475 GList
*possible_matches
, *l
;
477 char *possible_match
;
480 g_return_val_if_fail (G_IS_FILENAME_COMPLETER (completer
), NULL
);
481 g_return_val_if_fail (initial_text
!= NULL
, NULL
);
483 possible_matches
= init_completion (completer
, initial_text
, &prefix
);
485 res
= g_ptr_array_new ();
486 for (l
= possible_matches
; l
!= NULL
; l
= l
->next
)
488 possible_match
= l
->data
;
490 if (g_str_has_prefix (possible_match
, prefix
))
491 g_ptr_array_add (res
,
492 g_strconcat (initial_text
, possible_match
+ strlen (prefix
), NULL
));
497 return (char**)g_ptr_array_free (res
, FALSE
);
501 * g_filename_completer_set_dirs_only:
502 * @completer: the filename completer.
503 * @dirs_only: a #gboolean.
505 * If @dirs_only is %TRUE, @completer will only
506 * complete directory names, and not file names.
509 g_filename_completer_set_dirs_only (GFilenameCompleter
*completer
,
512 g_return_if_fail (G_IS_FILENAME_COMPLETER (completer
));
514 completer
->dirs_only
= dirs_only
;
517 #define __G_FILENAME_COMPLETER_C__
518 #include "gioaliasdef.c"