Added support for nested directories inside the scripts directory,

starting with a patch by David Emory Watson <dwatson@cs.ucr.edu>.

	* src/file-manager/fm-directory-view.c: (get_scripts_directory):
	Keep the scripts directory URI and string length in a global
	variable.
	(add_scripts_directory): New function, replaces
	connect_script_handlers. Refs the directory, puts it on the
	scripts directory list, and monitors more attributes than before.
	(fm_directory_view_initialize): Use add_scripts_directory instead
	of connect_script_handlers.
	(fm_directory_view_destroy): Use remove_scripts_directory on the
	entire list instead of disconnect_script_handlers.
	(add_submenu): New function.
	(add_script_to_script_menus): Change name, pass in path.
	(add_submenu_to_script_menus): New function.
	(directory_belongs_in_scripts_menu): New function.
	(add_directory_to_scripts_directory_list): New function, high
	level call used to turn a NautilusFile into a NautilusDirectory
	and call add_scripts_directory.
	(update_directory_in_scripts_menu): New function.
	(update_scripts_menu): New function, replaces reset_scripts_menu
	and uses new nautilus_directory_get_files_list rather than
	nautilus_directory_call_when_ready.
	(open_scripts_folder_callback): Use new global variable instead
	of calling get_scripts_directory.
	(real_update_menus): Call update_scripts_menu instead of
	schedule_reset_scripts_menu.
	(remove_scripts_directory): New function, replaces
	disconnect_script_handlers. Removes the directory from the scripts
	directory list and unrefs it after disconnecting handlers.

	* libnautilus-private/nautilus-directory.h:
	* libnautilus-private/nautilus-directory.c: (is_tentative): Moved
	from nautilus-directory-async.c.
	(nautilus_directory_get_file_list): New, made from formerly-
	private get_non_tentative_file_list in nautilus-directory-async.c.
	(nautilus_directory_list_ref): New.
	(nautilus_directory_list_unref): New.
	(nautilus_directory_list_free): New.
	(nautilus_directory_list_copy): New.
	(compare_by_uri), (compare_by_uri_cover),
	(nautilus_directory_list_sort_by_uri): New. Sorrts directories by
	URI, parents before children, and children sorted as if by
	nautilus_file_list_sort_by_name.
	* libnautilus-private/nautilus-directory-async.c:
	(nautilus_directory_monitor_add_internal), (ready_callback_call):
	Use nautilus_directory_get_file_list instead of
	get_non_tentative_file_list.
This commit is contained in:
Darin Adler 2001-08-24 15:26:53 +00:00
parent e2341ed5f8
commit d31bf8d65b
6 changed files with 492 additions and 271 deletions

View file

@ -1,3 +1,55 @@
2001-08-24 Darin Adler <darin@bentspoon.com>
Added support for nested directories inside the scripts directory,
starting with a patch by David Emory Watson <dwatson@cs.ucr.edu>.
* src/file-manager/fm-directory-view.c: (get_scripts_directory):
Keep the scripts directory URI and string length in a global
variable.
(add_scripts_directory): New function, replaces
connect_script_handlers. Refs the directory, puts it on the
scripts directory list, and monitors more attributes than before.
(fm_directory_view_initialize): Use add_scripts_directory instead
of connect_script_handlers.
(fm_directory_view_destroy): Use remove_scripts_directory on the
entire list instead of disconnect_script_handlers.
(add_submenu): New function.
(add_script_to_script_menus): Change name, pass in path.
(add_submenu_to_script_menus): New function.
(directory_belongs_in_scripts_menu): New function.
(add_directory_to_scripts_directory_list): New function, high
level call used to turn a NautilusFile into a NautilusDirectory
and call add_scripts_directory.
(update_directory_in_scripts_menu): New function.
(update_scripts_menu): New function, replaces reset_scripts_menu
and uses new nautilus_directory_get_files_list rather than
nautilus_directory_call_when_ready.
(open_scripts_folder_callback): Use new global variable instead
of calling get_scripts_directory.
(real_update_menus): Call update_scripts_menu instead of
schedule_reset_scripts_menu.
(remove_scripts_directory): New function, replaces
disconnect_script_handlers. Removes the directory from the scripts
directory list and unrefs it after disconnecting handlers.
* libnautilus-private/nautilus-directory.h:
* libnautilus-private/nautilus-directory.c: (is_tentative): Moved
from nautilus-directory-async.c.
(nautilus_directory_get_file_list): New, made from formerly-
private get_non_tentative_file_list in nautilus-directory-async.c.
(nautilus_directory_list_ref): New.
(nautilus_directory_list_unref): New.
(nautilus_directory_list_free): New.
(nautilus_directory_list_copy): New.
(compare_by_uri), (compare_by_uri_cover),
(nautilus_directory_list_sort_by_uri): New. Sorrts directories by
URI, parents before children, and children sorted as if by
nautilus_file_list_sort_by_name.
* libnautilus-private/nautilus-directory-async.c:
(nautilus_directory_monitor_add_internal), (ready_callback_call):
Use nautilus_directory_get_file_list instead of
get_non_tentative_file_list.
2001-08-23 Anders Carlsson <andersca@gnu.org>
* nautilus.spec.in: Remove CONTROL_CENTER_REQUIRED since nautilus

1
THANKS
View file

@ -10,6 +10,7 @@ Christopher Blizzard <blizzard@redhat.com> - mozilla component fixes
Christopher James Lahey <clahey@ximian.com> - bug fixes
Cody Russell <bratsche@gnome.org> - bug fixes
Dan Mueth <d-mueth@uchicago.edu> - documentation, help system design
David Emory Watson <dwatson@cs.ucr.edu> - hierarchical scripts menu
Don Melton <don@eazel.com> - Management, moral support, design help
Eric Fischer <eric@eazel.com> - bug fixes
Fatih Demir <kabalak@kabalak.net> - bug fixes

View file

@ -561,31 +561,6 @@ nautilus_directory_set_up_request (Request *request,
eel_strcmp_compare_func) != NULL;
}
static gboolean
is_tentative (gpointer data, gpointer callback_data)
{
NautilusFile *file;
g_assert (callback_data == NULL);
file = NAUTILUS_FILE (data);
return file->details->info == NULL;
}
static GList *
get_non_tentative_file_list (NautilusDirectory *directory)
{
GList *tentative_files, *non_tentative_files;
tentative_files = eel_g_list_partition
(g_list_copy (directory->details->file_list),
is_tentative, NULL, &non_tentative_files);
g_list_free (tentative_files);
nautilus_file_list_ref (non_tentative_files);
return non_tentative_files;
}
void
nautilus_directory_monitor_add_internal (NautilusDirectory *directory,
NautilusFile *file,
@ -618,7 +593,7 @@ nautilus_directory_monitor_add_internal (NautilusDirectory *directory,
g_list_prepend (directory->details->monitor_list, monitor);
if (callback != NULL) {
file_list = get_non_tentative_file_list (directory);
file_list = nautilus_directory_get_file_list (directory);
(* callback) (directory, file_list, callback_data);
nautilus_file_list_free (file_list);
}
@ -1183,7 +1158,7 @@ ready_callback_call (NautilusDirectory *directory,
if (directory == NULL || !callback->request.file_list) {
file_list = NULL;
} else {
file_list = get_non_tentative_file_list (directory);
file_list = nautilus_directory_get_file_list (directory);
}
/* Pass back the file list if the user was waiting for it. */

View file

@ -1507,6 +1507,105 @@ nautilus_directory_is_not_empty (NautilusDirectory *directory)
is_not_empty, (directory));
}
static gboolean
is_tentative (gpointer data, gpointer callback_data)
{
NautilusFile *file;
g_assert (callback_data == NULL);
file = NAUTILUS_FILE (data);
return file->details->info == NULL;
}
GList *
nautilus_directory_get_file_list (NautilusDirectory *directory)
{
GList *tentative_files, *non_tentative_files;
tentative_files = eel_g_list_partition
(g_list_copy (directory->details->file_list),
is_tentative, NULL, &non_tentative_files);
g_list_free (tentative_files);
nautilus_file_list_ref (non_tentative_files);
return non_tentative_files;
}
/**
* nautilus_directory_list_ref
*
* Ref all the directories in a list.
* @list: GList of directories.
**/
GList *
nautilus_directory_list_ref (GList *list)
{
g_list_foreach (list, (GFunc) nautilus_directory_ref, NULL);
return list;
}
/**
* nautilus_directory_list_unref
*
* Unref all the directories in a list.
* @list: GList of directories.
**/
void
nautilus_directory_list_unref (GList *list)
{
eel_g_list_safe_for_each (list, (GFunc) nautilus_directory_unref, NULL);
}
/**
* nautilus_directory_list_free
*
* Free a list of directories after unrefing them.
* @list: GList of directories.
**/
void
nautilus_directory_list_free (GList *list)
{
nautilus_directory_list_unref (list);
g_list_free (list);
}
/**
* nautilus_directory_list_copy
*
* Copy the list of directories, making a new ref of each,
* @list: GList of directories.
**/
GList *
nautilus_directory_list_copy (GList *list)
{
return g_list_copy (nautilus_directory_list_ref (list));
}
static int
compare_by_uri (NautilusDirectory *a, NautilusDirectory *b)
{
return strcmp (a->details->uri, b->details->uri);
}
static int
compare_by_uri_cover (gconstpointer a, gconstpointer b)
{
return compare_by_uri (NAUTILUS_DIRECTORY (a), NAUTILUS_DIRECTORY (b));
}
/**
* nautilus_directory_list_sort_by_uri
*
* Sort the list of directories by directory uri.
* @list: GList of directories.
**/
GList *
nautilus_directory_list_sort_by_uri (GList *list)
{
return g_list_sort (list, compare_by_uri_cover);
}
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
#include <eel/eel-debug.h>

View file

@ -160,8 +160,8 @@ gboolean nautilus_directory_contains_file (NautilusDirector
NautilusFile *file);
/* Get the uri of the file in the directory, NULL if not found */
char * nautilus_directory_get_file_uri (NautilusDirectory *directory,
const char *file_name);
char * nautilus_directory_get_file_uri (NautilusDirectory *directory,
const char *file_name);
/* Get (and ref) a NautilusFile object for this directory. */
NautilusFile * nautilus_directory_get_corresponding_file (NautilusDirectory *directory);
@ -191,6 +191,9 @@ void nautilus_directory_file_monitor_remove (NautilusDirector
gconstpointer client);
void nautilus_directory_force_reload (NautilusDirectory *directory);
/* Get a list of all files currently known in the directory. */
GList * nautilus_directory_get_file_list (NautilusDirectory *directory);
/* Return true if the directory has information about all the files.
* This will be false until the directory has been read at least once.
*/
@ -204,7 +207,15 @@ gboolean nautilus_directory_is_local (NautilusDirector
*/
gboolean nautilus_directory_is_not_empty (NautilusDirectory *directory);
gboolean nautilus_directory_file_list_length_reached (NautilusDirectory *directory);
char * nautilus_directory_make_uri_canonical (const char *uri);
char * nautilus_directory_make_uri_canonical (const char *uri);
/* Convenience functions for dealing with a list of NautilusDirectory objects that each have a ref.
* These are just convenient names for functions that work on lists of GtkObject *.
*/
GList * nautilus_directory_list_ref (GList *directory_list);
void nautilus_directory_list_unref (GList *directory_list);
void nautilus_directory_list_free (GList *directory_list);
GList * nautilus_directory_list_copy (GList *directory_list);
GList * nautilus_directory_list_sort_by_uri (GList *directory_list);
#endif /* NAUTILUS_DIRECTORY_H */

View file

@ -22,8 +22,9 @@
*
* Authors: Ettore Perazzoli,
* John Sullivan <sullivan@eazel.com>,
* Darin Adler <darin@eazel.com>
* Pavel Cisler <pavel@eazel.com>
* Darin Adler <darin@eazel.com>,
* Pavel Cisler <pavel@eazel.com>,
* David Emory Watson <dwatson@cs.ucr.edu>
*/
#include <config.h>
@ -145,6 +146,8 @@
#define FM_DIRECTORY_VIEW_POPUP_PATH_OPEN_WITH "/popups/selection/Open Placeholder/Open With"
#define FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS "/popups/selection/Open Placeholder/Scripts"
#define MAX_MENU_LEVELS 5
enum {
ADD_FILE,
BEGIN_ADDING_FILES,
@ -167,6 +170,9 @@ static gboolean show_delete_command_auto_value;
static gboolean confirm_trash_auto_value;
static gboolean use_new_window_auto_value;
static char *scripts_directory_uri;
static int scripts_directory_uri_length;
struct FMDirectoryViewDetails
{
NautilusView *nautilus_view;
@ -176,9 +182,7 @@ struct FMDirectoryViewDetails
NautilusFile *directory_as_file;
BonoboUIComponent *ui;
NautilusDirectory *scripts_directory;
guint scripts_added_handler_id;
guint scripts_changed_handler_id;
GList *scripts_directory_list;
guint display_selection_idle_id;
guint update_menus_timeout_id;
@ -243,73 +247,74 @@ typedef struct {
/* forward declarations */
static void cancel_activate_callback (gpointer callback_data);
static gboolean display_selection_info_idle_callback (gpointer data);
static gboolean file_is_launchable (NautilusFile *file);
static void fm_directory_view_initialize_class (FMDirectoryViewClass *klass);
static void fm_directory_view_initialize (FMDirectoryView *view);
static void fm_directory_view_duplicate_selection (FMDirectoryView *view,
GList *files,
GArray *item_locations);
static gboolean fm_directory_view_confirm_deletion (FMDirectoryView *view,
GList *uris,
gboolean all);
static void fm_directory_view_create_links_for_files (FMDirectoryView *view,
GList *files,
GArray *item_locations);
static void trash_or_delete_files (FMDirectoryView *view,
const GList *files);
static void fm_directory_view_activate_file (FMDirectoryView *view,
NautilusFile *file,
WindowChoice choice);
static void load_directory (FMDirectoryView *view,
NautilusDirectory *directory);
static void fm_directory_view_merge_menus (FMDirectoryView *view);
static char * file_name_from_uri (const char *uri);
static void stop_loading_callback (NautilusView *nautilus_view,
FMDirectoryView *directory_view);
static void load_location_callback (NautilusView *nautilus_view,
const char *location,
FMDirectoryView *directory_view);
static void selection_changed_callback (NautilusView *nautilus_view,
GList *selection,
FMDirectoryView *directory_view);
static void open_one_in_new_window (gpointer data,
gpointer callback_data);
static void open_one_properties_window (gpointer data,
gpointer callback_data);
static void zoomable_set_zoom_level_callback (BonoboZoomable *zoomable,
float level,
FMDirectoryView *view);
static void zoomable_zoom_in_callback (BonoboZoomable *zoomable,
FMDirectoryView *directory_view);
static void zoomable_zoom_out_callback (BonoboZoomable *zoomable,
FMDirectoryView *directory_view);
static void zoomable_zoom_to_fit_callback (BonoboZoomable *zoomable,
FMDirectoryView *directory_view);
static void schedule_update_menus (FMDirectoryView *view);
static void schedule_update_menus_callback (gpointer callback_data);
static void remove_update_menus_timeout_callback (FMDirectoryView *view);
static void schedule_idle_display_of_pending_files (FMDirectoryView *view);
static void unschedule_idle_display_of_pending_files (FMDirectoryView *view);
static void schedule_timeout_display_of_pending_files (FMDirectoryView *view);
static void unschedule_timeout_display_of_pending_files (FMDirectoryView *view);
static void unschedule_display_of_pending_files (FMDirectoryView *view);
static void disconnect_model_handlers (FMDirectoryView *view);
static void disconnect_script_handlers (FMDirectoryView *view);
static void filtering_changed_callback (gpointer callback_data);
static void metadata_for_directory_as_file_ready_callback (NautilusFile *file,
gpointer callback_data);
static void metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory,
GList *files,
gpointer callback_data);
static void fm_directory_view_trash_state_changed_callback (NautilusTrashMonitor *trash,
gboolean state,
gpointer callback_data);
static void fm_directory_view_select_file (FMDirectoryView *view,
NautilusFile *file);
static void monitor_file_for_open_with (FMDirectoryView *view,
NautilusFile *file);
static void cancel_activate_callback (gpointer callback_data);
static gboolean display_selection_info_idle_callback (gpointer data);
static gboolean file_is_launchable (NautilusFile *file);
static void fm_directory_view_initialize_class (FMDirectoryViewClass *klass);
static void fm_directory_view_initialize (FMDirectoryView *view);
static void fm_directory_view_duplicate_selection (FMDirectoryView *view,
GList *files,
GArray *item_locations);
static gboolean fm_directory_view_confirm_deletion (FMDirectoryView *view,
GList *uris,
gboolean all);
static void fm_directory_view_create_links_for_files (FMDirectoryView *view,
GList *files,
GArray *item_locations);
static void trash_or_delete_files (FMDirectoryView *view,
const GList *files);
static void fm_directory_view_activate_file (FMDirectoryView *view,
NautilusFile *file,
WindowChoice choice);
static void load_directory (FMDirectoryView *view,
NautilusDirectory *directory);
static void fm_directory_view_merge_menus (FMDirectoryView *view);
static char * file_name_from_uri (const char *uri);
static void stop_loading_callback (NautilusView *nautilus_view,
FMDirectoryView *directory_view);
static void load_location_callback (NautilusView *nautilus_view,
const char *location,
FMDirectoryView *directory_view);
static void selection_changed_callback (NautilusView *nautilus_view,
GList *selection,
FMDirectoryView *directory_view);
static void open_one_in_new_window (gpointer data,
gpointer callback_data);
static void open_one_properties_window (gpointer data,
gpointer callback_data);
static void zoomable_set_zoom_level_callback (BonoboZoomable *zoomable,
float level,
FMDirectoryView *view);
static void zoomable_zoom_in_callback (BonoboZoomable *zoomable,
FMDirectoryView *directory_view);
static void zoomable_zoom_out_callback (BonoboZoomable *zoomable,
FMDirectoryView *directory_view);
static void zoomable_zoom_to_fit_callback (BonoboZoomable *zoomable,
FMDirectoryView *directory_view);
static void schedule_update_menus (FMDirectoryView *view);
static void schedule_update_menus_callback (gpointer callback_data);
static void remove_update_menus_timeout_callback (FMDirectoryView *view);
static void schedule_idle_display_of_pending_files (FMDirectoryView *view);
static void unschedule_idle_display_of_pending_files (FMDirectoryView *view);
static void schedule_timeout_display_of_pending_files (FMDirectoryView *view);
static void unschedule_timeout_display_of_pending_files (FMDirectoryView *view);
static void unschedule_display_of_pending_files (FMDirectoryView *view);
static void disconnect_model_handlers (FMDirectoryView *view);
static void remove_scripts_directory (FMDirectoryView *view,
NautilusDirectory *directory);
static void filtering_changed_callback (gpointer callback_data);
static void metadata_for_directory_as_file_ready_callback (NautilusFile *file,
gpointer callback_data);
static void metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory,
GList *files,
gpointer callback_data);
static void fm_directory_view_trash_state_changed_callback (NautilusTrashMonitor *trash,
gboolean state,
gpointer callback_data);
static void fm_directory_view_select_file (FMDirectoryView *view,
NautilusFile *file);
static void monitor_file_for_open_with (FMDirectoryView *view,
NautilusFile *file);
EEL_DEFINE_CLASS_BOILERPLATE (FMDirectoryView, fm_directory_view, GTK_TYPE_SCROLLED_WINDOW)
EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, add_file)
@ -1073,73 +1078,81 @@ get_scripts_directory (void)
{
char *main_directory_path;
char *scripts_directory_path;
NautilusDirectory *directory;
main_directory_path = nautilus_get_user_main_directory ();
/* Localizers: This is the name of a directory that's created in ~/Nautilus, and
* stores the scripts that appear in the Scripts submenu.
*/
scripts_directory_path = nautilus_make_path (main_directory_path, _("scripts"));
g_free (main_directory_path);
if (!g_file_exists (scripts_directory_path)) {
mkdir (scripts_directory_path,
GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_READ);
if (scripts_directory_uri == NULL) {
main_directory_path = nautilus_get_user_main_directory ();
/* Localizers: This is the name of a directory that's created in ~/Nautilus, and
* stores the scripts that appear in the Scripts submenu.
*/
scripts_directory_path = nautilus_make_path (main_directory_path, _("scripts"));
g_free (main_directory_path);
if (!g_file_exists (scripts_directory_path)) {
mkdir (scripts_directory_path,
GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_READ);
}
scripts_directory_uri = gnome_vfs_get_uri_from_local_path (scripts_directory_path);
scripts_directory_uri_length = strlen (scripts_directory_uri);
g_free (scripts_directory_path);
}
if (!g_file_exists (scripts_directory_path)) {
return NULL;
}
directory = nautilus_directory_get (scripts_directory_path);
g_free (scripts_directory_path);
return directory;
return nautilus_directory_get (scripts_directory_uri);
}
static void
scripts_added_or_changed_callback (NautilusDirectory *directory,
GList *files,
gpointer callback_data)
GList *files,
gpointer callback_data)
{
FMDirectoryView *view;
view = FM_DIRECTORY_VIEW (callback_data);
g_assert (directory == view->details->scripts_directory);
view->details->scripts_invalid = TRUE;
schedule_update_menus (view);
}
static void
connect_script_handlers (FMDirectoryView *view)
add_scripts_directory (FMDirectoryView *view,
NautilusDirectory *directory)
{
if (view->details->scripts_directory == NULL) {
return;
}
GList *attributes;
nautilus_directory_file_monitor_add (view->details->scripts_directory,
&view->details->scripts_directory,
FALSE, FALSE, NULL,
nautilus_directory_ref (directory);
attributes = nautilus_icon_factory_get_required_file_attributes ();
attributes = g_list_prepend (attributes, NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES);
attributes = g_list_prepend (attributes, NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT);
nautilus_directory_file_monitor_add (directory, &view->details->scripts_directory_list,
FALSE, FALSE, attributes,
scripts_added_or_changed_callback, view);
view->details->scripts_added_handler_id = gtk_signal_connect
(GTK_OBJECT (view->details->scripts_directory),
"files_added",
scripts_added_or_changed_callback,
view);
view->details->scripts_changed_handler_id = gtk_signal_connect
(GTK_OBJECT (view->details->scripts_directory),
"files_changed",
scripts_added_or_changed_callback,
view);
g_list_free (attributes);
gtk_signal_connect (GTK_OBJECT (directory),
"files_added",
scripts_added_or_changed_callback,
view);
gtk_signal_connect (GTK_OBJECT (directory),
"files_changed",
scripts_added_or_changed_callback,
view);
view->details->scripts_directory_list = g_list_prepend
(view->details->scripts_directory_list, directory);
}
static void
fm_directory_view_initialize (FMDirectoryView *view)
{
NautilusDirectory *scripts_directory;
view->details = g_new0 (FMDirectoryViewDetails, 1);
/* We need to have our own X window so that cut, copy, and
@ -1158,8 +1171,9 @@ fm_directory_view_initialize (FMDirectoryView *view)
view->details->nautilus_view = nautilus_view_new (GTK_WIDGET (view));
view->details->scripts_directory = get_scripts_directory ();
connect_script_handlers (view);
scripts_directory = get_scripts_directory ();
add_scripts_directory (view, scripts_directory);
nautilus_directory_unref (scripts_directory);
view->details->zoomable = bonobo_zoomable_new ();
bonobo_zoomable_set_parameters_full (view->details->zoomable,
@ -1259,6 +1273,7 @@ static void
fm_directory_view_destroy (GtkObject *object)
{
FMDirectoryView *view;
GList *node, *next;
view = FM_DIRECTORY_VIEW (object);
@ -1274,8 +1289,10 @@ fm_directory_view_destroy (GtkObject *object)
fm_directory_view_stop (view);
fm_directory_view_clear (view);
disconnect_script_handlers (view);
nautilus_directory_unref (view->details->scripts_directory);
for (node = view->details->scripts_directory_list; node != NULL; node = next) {
next = node->next;
remove_scripts_directory (view, node->data);
}
disconnect_model_handlers (view);
nautilus_directory_unref (view->details->model);
@ -3169,7 +3186,21 @@ add_numbered_menu_item (BonoboUIComponent *ui,
(ui, parent_path, index);
bonobo_ui_component_add_verb_full (ui, verb_name, callback, callback_data, destroy_notify);
g_free (verb_name);
}
}
static void
add_submenu (BonoboUIComponent *ui,
const char *parent_path,
const char *label,
GdkPixbuf *pixbuf)
{
char *escaped_label;
escaped_label = eel_str_double_underscores (label);
nautilus_bonobo_add_submenu (ui, parent_path, escaped_label);
g_free (escaped_label);
/* FIXME: Set icon too. */
}
static void
add_application_to_bonobo_menu (FMDirectoryView *directory_view,
@ -3514,12 +3545,14 @@ run_script_callback (BonoboUIComponent *component, gpointer callback_data, const
chdir (old_working_dir);
g_free (old_working_dir);
g_free (quoted_path);
}
}
static void
add_script_to_menus (FMDirectoryView *directory_view,
NautilusFile *file,
int index)
add_script_to_script_menus (FMDirectoryView *directory_view,
NautilusFile *file,
int index,
const char *menu_path,
const char *popup_path)
{
ScriptLaunchParameters *launch_parameters;
char *tip;
@ -3528,13 +3561,13 @@ add_script_to_menus (FMDirectoryView *directory_view,
name = nautilus_file_get_name (file);
tip = g_strdup_printf (_("Run \"%s\" on any selected items"), name);
launch_parameters = script_launch_parameters_new (file, directory_view);
pixbuf = nautilus_icon_factory_get_pixbuf_for_file
(file, NULL, NAUTILUS_ICON_SIZE_FOR_MENUS, TRUE);
add_numbered_menu_item (directory_view->details->ui,
FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER,
add_numbered_menu_item (directory_view->details->ui,
menu_path,
name,
tip,
index,
@ -3546,8 +3579,8 @@ add_script_to_menus (FMDirectoryView *directory_view,
/* Use same launch parameters and no DestroyNotify for popup item, which has same
* lifetime as the item in the File menu in the menu bar.
*/
add_numbered_menu_item (directory_view->details->ui,
FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER,
add_numbered_menu_item (directory_view->details->ui,
popup_path,
name,
tip,
index,
@ -3562,30 +3595,148 @@ add_script_to_menus (FMDirectoryView *directory_view,
}
static void
reset_scripts_menu (FMDirectoryView *view, GList *all_files)
add_submenu_to_script_menus (FMDirectoryView *directory_view,
NautilusFile *file,
const char *menu_path,
const char *popup_path)
{
GList *node;
NautilusFile *file;
int index;
gboolean any_scripts;
nautilus_bonobo_remove_menu_items_and_commands
(view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER);
nautilus_bonobo_remove_menu_items_and_commands
(view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER);
char *name;
GdkPixbuf *pixbuf;
all_files = nautilus_file_list_sort_by_name (all_files);
name = nautilus_file_get_name (file);
pixbuf = nautilus_icon_factory_get_pixbuf_for_file
(file, NULL, NAUTILUS_ICON_SIZE_FOR_MENUS, TRUE);
add_submenu (directory_view->details->ui, menu_path, name, pixbuf);
add_submenu (directory_view->details->ui, popup_path, name, pixbuf);
gdk_pixbuf_unref (pixbuf);
g_free (name);
}
static gboolean
directory_belongs_in_scripts_menu (const char *uri)
{
int num_levels;
int i;
if (!eel_str_has_prefix (uri, scripts_directory_uri)) {
return FALSE;
}
num_levels = 0;
for (i = scripts_directory_uri_length; uri[i] != '\0'; i++) {
if (uri[i] == '/') {
num_levels++;
}
}
if (num_levels > MAX_MENU_LEVELS) {
return FALSE;
}
return TRUE;
}
static gboolean
add_directory_to_scripts_directory_list (FMDirectoryView *view, NautilusFile *file)
{
char *uri;
NautilusDirectory *directory;
uri = nautilus_file_get_uri (file);
if (!directory_belongs_in_scripts_menu (uri)) {
g_free (uri);
return FALSE;
}
directory = nautilus_directory_get (uri);
if (g_list_find (view->details->scripts_directory_list, directory) == NULL) {
add_scripts_directory (view, directory);
}
nautilus_directory_unref (directory);
g_free (uri);
return TRUE;
}
static gboolean
update_directory_in_scripts_menu (FMDirectoryView *view, NautilusDirectory *directory)
{
char *directory_uri;
char *menu_path, *popup_path;
GList *file_list, *node;
gboolean any_scripts;
int i;
NautilusFile *file;
directory_uri = nautilus_directory_get_uri (directory);
menu_path = g_strconcat (FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER,
directory_uri + scripts_directory_uri_length,
NULL);
popup_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER,
directory_uri + scripts_directory_uri_length,
NULL);
g_free (directory_uri);
file_list = nautilus_file_list_sort_by_name
(nautilus_directory_get_file_list (directory));
any_scripts = FALSE;
for (node = all_files, index = 0; node != NULL; node = node->next, ++index) {
i = 0;
for (node = file_list; node != NULL; node = node->next) {
file = node->data;
if (file_is_launchable (file)) {
add_script_to_menus (view, file, index);
add_script_to_script_menus (view, file, i++, menu_path, popup_path);
any_scripts = TRUE;
} else if (nautilus_file_is_directory (file)) {
if (add_directory_to_scripts_directory_list (view, file)) {
add_submenu_to_script_menus (view, file, menu_path, popup_path);
any_scripts = TRUE;
}
}
}
nautilus_file_list_free (file_list);
g_free (popup_path);
g_free (menu_path);
return any_scripts;
}
static void
update_scripts_menu (FMDirectoryView *view)
{
gboolean any_scripts;
GList *sorted_copy, *node;
NautilusDirectory *directory;
char *uri;
nautilus_bonobo_remove_menu_items_and_commands
(view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER);
nautilus_bonobo_remove_menu_items_and_commands
(view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER);
/* As we walk through the directories, remove any that no longer belong. */
any_scripts = FALSE;
sorted_copy = nautilus_directory_list_sort_by_uri
(nautilus_directory_list_copy (view->details->scripts_directory_list));
for (node = sorted_copy; node != NULL; node = node->next) {
directory = node->data;
uri = nautilus_directory_get_uri (directory);
if (!directory_belongs_in_scripts_menu (uri)) {
remove_scripts_directory (view, directory);
} else {
if (update_directory_in_scripts_menu (view, directory)) {
any_scripts = TRUE;
}
}
g_free (uri);
}
nautilus_directory_list_free (sorted_copy);
nautilus_bonobo_set_hidden (view->details->ui,
FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_SEPARATOR,
!any_scripts);
@ -3596,95 +3747,36 @@ reset_scripts_menu (FMDirectoryView *view, GList *all_files)
view->details->scripts_invalid = FALSE;
}
static void
reset_scripts_menu_callback (NautilusDirectory *directory,
GList *files,
gpointer callback_data)
{
FMDirectoryView *view;
view = callback_data;
g_assert (FM_IS_DIRECTORY_VIEW (view));
g_assert (view->details->scripts_directory == directory);
reset_scripts_menu (view, files);
}
static void
call_when_ready_on_scripts_directory (FMDirectoryView *view,
NautilusDirectoryCallback scripts_directory_callback)
{
GList *attributes;
if (view->details->scripts_directory == NULL) {
return;
}
nautilus_directory_cancel_callback (view->details->scripts_directory,
scripts_directory_callback,
view);
/* Later we may want to add more attributes here to get icon, etc. */
attributes = nautilus_icon_factory_get_required_file_attributes ();
attributes = g_list_prepend (attributes, NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES);
attributes = g_list_prepend (attributes, NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT);
nautilus_directory_call_when_ready (view->details->scripts_directory,
attributes,
TRUE,
scripts_directory_callback,
view);
g_list_free (attributes);
}
static void
schedule_reset_scripts_menu (FMDirectoryView *view)
{
call_when_ready_on_scripts_directory (view, reset_scripts_menu_callback);
}
static void
open_scripts_folder_callback (BonoboUIComponent *component,
gpointer callback_data,
const char *verb)
{
FMDirectoryView *view;
char *uri;
view = FM_DIRECTORY_VIEW (callback_data);
if (view->details->scripts_directory != NULL) {
uri = nautilus_directory_get_uri (view->details->scripts_directory);
open_location (view, uri, RESPECT_PREFERENCE);
g_free (uri);
eel_show_info_dialog_with_details
(_("All executable files in this folder will appear in the "
"Scripts menu. Choosing a script from the menu will run "
"that script with any selected items as input."),
_("About Scripts"),
_("All executable files in this folder will appear in the "
"Scripts menu. Choosing a script from the menu will run "
"that script.\n\n"
"When executed from a local folder, scripts will be passed "
"the selected file names. When executed from a remote folder "
"(e.g. a folder showing web or ftp content), scripts will "
"be passed no parameters.\n\n"
"In all cases, the following environment variables will be "
"set by Nautilus, which the scripts may use:\n\n"
"NAUTILUS_SCRIPT_SELECTED_FILE_PATHS: newline-delimited paths for selected files (only if local)\n\n"
"NAUTILUS_SCRIPT_SELECTED_URIS: newline-delimited URIs for selected files\n\n"
"NAUTILUS_SCRIPT_CURRENT_URI: URI for current location\n\n"
"NAUTILUS_SCRIPT_WINDOW_GEOMETRY: position and size of current window"),
fm_directory_view_get_containing_window (view));
} else {
/* This shouldn't happen. If it does, get_scripts_directory was unable to
* mkdir the scripts directory, and this case should be debugged.
*/
eel_show_error_dialog (_("Nautilus was unable to create the directory %s."),
_("No Scripts Folder"),
fm_directory_view_get_containing_window (view));
}
open_location (view, scripts_directory_uri, RESPECT_PREFERENCE);
eel_show_info_dialog_with_details
(_("All executable files in this folder will appear in the "
"Scripts menu. Choosing a script from the menu will run "
"that script with any selected items as input."),
_("About Scripts"),
_("All executable files in this folder will appear in the "
"Scripts menu. Choosing a script from the menu will run "
"that script.\n\n"
"When executed from a local folder, scripts will be passed "
"the selected file names. When executed from a remote folder "
"(e.g. a folder showing web or ftp content), scripts will "
"be passed no parameters.\n\n"
"In all cases, the following environment variables will be "
"set by Nautilus, which the scripts may use:\n\n"
"NAUTILUS_SCRIPT_SELECTED_FILE_PATHS: newline-delimited paths for selected files (only if local)\n\n"
"NAUTILUS_SCRIPT_SELECTED_URIS: newline-delimited URIs for selected files\n\n"
"NAUTILUS_SCRIPT_CURRENT_URI: URI for current location\n\n"
"NAUTILUS_SCRIPT_WINDOW_GEOMETRY: position and size of current window"),
fm_directory_view_get_containing_window (view));
}
static BonoboWindow *
@ -4168,7 +4260,7 @@ real_update_menus (FMDirectoryView *view)
nautilus_file_list_free (selection);
if (view->details->scripts_invalid) {
schedule_reset_scripts_menu (view);
update_scripts_menu (view);
}
}
@ -4877,9 +4969,18 @@ disconnect_directory_handler (FMDirectoryView *view, int *id)
}
static void
disconnect_scripts_directory_handler (FMDirectoryView *view, int *id)
remove_scripts_directory (FMDirectoryView *view, NautilusDirectory *directory)
{
disconnect_handler (GTK_OBJECT (view->details->scripts_directory), id);
view->details->scripts_directory_list = g_list_remove
(view->details->scripts_directory_list, directory);
gtk_signal_disconnect_by_func (GTK_OBJECT (directory),
scripts_added_or_changed_callback,
view);
nautilus_directory_file_monitor_remove (directory, &view->details->scripts_directory_list);
nautilus_directory_unref (directory);
}
static void
@ -4911,24 +5012,6 @@ disconnect_model_handlers (FMDirectoryView *view)
&view->details->directory_as_file);
}
static void
disconnect_script_handlers (FMDirectoryView *view)
{
if (view->details->scripts_directory == NULL) {
return;
}
disconnect_scripts_directory_handler (view, &view->details->scripts_added_handler_id);
disconnect_scripts_directory_handler (view, &view->details->scripts_changed_handler_id);
nautilus_directory_file_monitor_remove (view->details->scripts_directory,
&view->details->scripts_directory);
nautilus_directory_cancel_callback (view->details->scripts_directory,
reset_scripts_menu_callback,
view);
}
/**
* fm_directory_view_reset_to_defaults:
*