diff options
author | Alexander Larsson <alexl@redhat.com> | 2003-12-12 17:55:47 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2003-12-12 17:55:47 +0000 |
commit | 00b39e067c148c5eed16691a3b103e1b6219bb27 (patch) | |
tree | 11351765c343d3a7ba2a997919baf6d86ff3fb31 | |
parent | 1e841b24202d3f0cc880f75a1af961da22d22bc2 (diff) | |
download | nautilus-00b39e067c148c5eed16691a3b103e1b6219bb27.tar.gz |
New function nautilus_file_operations_new_file.
2003-12-12 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/nautilus-file-operations.[ch]:
New function nautilus_file_operations_new_file.
* libnautilus-private/nautilus-file-utilities.[ch]:
New template directory functions
* src/nautilus-navigation-window-ui.xml:
* src/nautilus-spatial-window-ui.xml:
* src/nautilus-window-menus.c:
Add Templates in location menu
* src/file-manager/fm-directory-view.[ch]:
* src/file-manager/nautilus-directory-view-ui.xml:
Implement the templates menu.
Fix issue that affected create new folder too,
sometimes the file has already been added before
we get the done callback.
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-operations.c | 204 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-operations.h | 36 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-utilities.c | 29 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-utilities.h | 4 | ||||
-rw-r--r-- | src/file-manager/fm-directory-view.c | 534 | ||||
-rw-r--r-- | src/file-manager/fm-directory-view.h | 2 | ||||
-rw-r--r-- | src/file-manager/nautilus-directory-view-ui.xml | 23 | ||||
-rw-r--r-- | src/nautilus-navigation-window-ui.xml | 5 | ||||
-rw-r--r-- | src/nautilus-spatial-window-ui.xml | 5 | ||||
-rw-r--r-- | src/nautilus-window-menus.c | 15 |
11 files changed, 806 insertions, 71 deletions
@@ -1,3 +1,23 @@ +2003-12-12 Alexander Larsson <alexl@redhat.com> + + * libnautilus-private/nautilus-file-operations.[ch]: + New function nautilus_file_operations_new_file. + + * libnautilus-private/nautilus-file-utilities.[ch]: + New template directory functions + + * src/nautilus-navigation-window-ui.xml: + * src/nautilus-spatial-window-ui.xml: + * src/nautilus-window-menus.c: + Add Templates in location menu + + * src/file-manager/fm-directory-view.[ch]: + * src/file-manager/nautilus-directory-view-ui.xml: + Implement the templates menu. + Fix issue that affected create new folder too, + sometimes the file has already been added before + we get the done callback. + 2003-12-12 Christian Neumair <chris@gnome-de.org> * components/Makefile.am diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c index fe64cef28..395ae9a76 100644 --- a/libnautilus-private/nautilus-file-operations.c +++ b/libnautilus-private/nautilus-file-operations.c @@ -2089,7 +2089,7 @@ new_folder_transfer_callback (GnomeVFSAsyncHandle *handle, case GNOME_VFS_XFER_PROGRESS_STATUS_OK: nautilus_file_changes_consume_changes (TRUE); (* state->done_callback) (progress_info->target_name, state->data); - return 0; + return 1; case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE: @@ -2165,6 +2165,208 @@ nautilus_file_operations_new_folder (GtkWidget *parent_view, gnome_vfs_uri_unref (parent_uri); } +typedef struct { + GnomeVFSAsyncHandle *handle; + void (* done_callback)(const char *new_folder_uri, gpointer data); + gpointer data; + GtkWidget *parent_view; + char *empty_file; + GHashTable *debuting_uris; +} NewFileTransferState; + + +static int +handle_new_file_vfs_error (const GnomeVFSXferProgressInfo *progress_info, NewFileTransferState *state) +{ + const char *error_string; + char *error_string_to_free; + + error_string_to_free = NULL; + + if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED) { + error_string = _("You do not have permissions to write to the destination."); + } else if (progress_info->vfs_status == GNOME_VFS_ERROR_NO_SPACE) { + error_string = _("There is no space on the destination."); + } else { + error_string = g_strdup_printf (_("Error \"%s\" creating new document."), + gnome_vfs_result_to_string (progress_info->vfs_status)); + error_string_to_free = (char *)error_string; + } + + eel_show_error_dialog (_("Error creating new document."), error_string, _("Error Creating New Document"), + GTK_WINDOW (gtk_widget_get_toplevel (state->parent_view))); + + g_free (error_string_to_free); + + return GNOME_VFS_XFER_ERROR_ACTION_ABORT; +} + +static void +get_new_file_uri (gpointer key, + gpointer value, + gpointer user_data) +{ + char *uri; + char **uri_out; + + uri = key; + uri_out = user_data; + + *uri_out = uri; +} + + +static int +new_file_transfer_callback (GnomeVFSAsyncHandle *handle, + GnomeVFSXferProgressInfo *progress_info, + gpointer data) +{ + NewFileTransferState *state; + char *temp_string; + char *uri; + + state = (NewFileTransferState *) data; + + switch (progress_info->phase) { + + case GNOME_VFS_XFER_PHASE_COMPLETED: + uri = NULL; + g_hash_table_foreach (state->debuting_uris, + get_new_file_uri, &uri); + + (* state->done_callback) (uri, state->data); + /* uri is owned by hashtable, don't free */ + + if (state->empty_file != NULL) { + unlink (state->empty_file); + g_free (state->empty_file); + } + eel_remove_weak_pointer (&state->parent_view); + g_hash_table_destroy (state->debuting_uris); + g_free (state); + return 0; + + default: + switch (progress_info->status) { + case GNOME_VFS_XFER_PROGRESS_STATUS_OK: + nautilus_file_changes_consume_changes (TRUE); + return 1; + + case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE: + + temp_string = progress_info->duplicate_name; + + if (progress_info->vfs_status == GNOME_VFS_ERROR_NAME_TOO_LONG) { + /* special case an 8.3 file system */ + progress_info->duplicate_name = g_strndup (temp_string, 8); + progress_info->duplicate_name[8] = '\0'; + g_free (temp_string); + temp_string = progress_info->duplicate_name; + progress_info->duplicate_name = g_strdup_printf + ("%s.%d", + progress_info->duplicate_name, + progress_info->duplicate_count); + } else { + progress_info->duplicate_name = g_strdup_printf + ("%s%%20%d", + progress_info->duplicate_name, + progress_info->duplicate_count); + } + g_free (temp_string); + return GNOME_VFS_XFER_ERROR_ACTION_SKIP; + + case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: + return handle_new_file_vfs_error (progress_info, state); + + + + default: + g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), + progress_info->status); + return 0; + } + } +} + +void +nautilus_file_operations_new_file (GtkWidget *parent_view, + const char *parent_dir, + const char *source_uri_text, + void (*done_callback) (const char *, gpointer), + gpointer data) +{ + GList *target_uri_list; + GList *source_uri_list; + GnomeVFSURI *target_uri, *parent_uri, *source_uri; + char *filename; + NewFileTransferState *state; + SyncTransferInfo *sync_transfer_info; + + state = g_new (NewFileTransferState, 1); + state->done_callback = done_callback; + state->data = data; + state->parent_view = parent_view; + state->empty_file = NULL; + + /* pass in the target directory and the new folder name as a destination URI */ + parent_uri = gnome_vfs_uri_new (parent_dir); + + if (source_uri_text != NULL) { + source_uri = gnome_vfs_uri_new (source_uri_text); + if (source_uri == NULL) { + (*done_callback) (NULL, data); + g_free (state); + return; + } + filename = gnome_vfs_uri_extract_short_path_name (source_uri); + target_uri = gnome_vfs_uri_append_string (parent_uri, filename); + g_free (filename); + } else { + char empty_file[] = "/tmp/emptyXXXXXX"; + char *empty_uri; + int fd; + + fd = mkstemp (empty_file); + if (fd == -1) { + (*done_callback) (NULL, data); + g_free (state); + } + close (fd); + + empty_uri = gnome_vfs_get_uri_from_local_path (empty_file); + source_uri = gnome_vfs_uri_new (empty_uri); + g_free (empty_uri); + + state->empty_file = g_strdup (empty_file); + + filename = g_filename_from_utf8 (_("new file"), -1, NULL, NULL, NULL); + target_uri = gnome_vfs_uri_append_file_name (parent_uri, filename); + g_free (filename); + } + + state->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + eel_add_weak_pointer (&state->parent_view); + + target_uri_list = g_list_prepend (NULL, target_uri); + source_uri_list = g_list_prepend (NULL, source_uri); + + sync_transfer_info = g_new (SyncTransferInfo, 1); + sync_transfer_info->iterator = NULL; + sync_transfer_info->debuting_uris = state->debuting_uris; + + gnome_vfs_async_xfer (&state->handle, source_uri_list, target_uri_list, + GNOME_VFS_XFER_USE_UNIQUE_NAMES, + GNOME_VFS_XFER_ERROR_MODE_QUERY, + GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, + GNOME_VFS_PRIORITY_DEFAULT, + new_file_transfer_callback, state, + sync_transfer_callback, sync_transfer_info); + + gnome_vfs_uri_list_free (target_uri_list); + gnome_vfs_uri_list_free (source_uri_list); + gnome_vfs_uri_unref (parent_uri); +} + void nautilus_file_operations_delete (const GList *item_uris, GtkWidget *parent_view) diff --git a/libnautilus-private/nautilus-file-operations.h b/libnautilus-private/nautilus-file-operations.h index 3fe6918ca..ead8f44ad 100644 --- a/libnautilus-private/nautilus-file-operations.h +++ b/libnautilus-private/nautilus-file-operations.h @@ -34,22 +34,30 @@ typedef void (* NautilusCopyCallback) (GHashTable *debuting_uris, gpointer callback_data); typedef void (* NautilusNewFolderCallback) (const char *new_folder_uri, gpointer callback_data); +typedef void (* NautilusNewFileCallback) (const char *new_file_uri, + gpointer callback_data); /* FIXME: int copy_action should be an enum */ -void nautilus_file_operations_copy_move (const GList *item_uris, - GArray *target_item_points, - const char *target_dir_uri, - GdkDragAction copy_action, - GtkWidget *parent_view, - NautilusCopyCallback done_callback, - gpointer done_callback_data); -void nautilus_file_operations_empty_trash (GtkWidget *parent_view); -void nautilus_file_operations_new_folder (GtkWidget *parent_view, - const char *parent_dir_uri, - NautilusNewFolderCallback done_callback, - gpointer done_callback_data); -void nautilus_file_operations_delete (const GList *item_uris, - GtkWidget *parent_view); +void nautilus_file_operations_copy_move (const GList *item_uris, + GArray *target_item_points, + const char *target_dir_uri, + GdkDragAction copy_action, + GtkWidget *parent_view, + NautilusCopyCallback done_callback, + gpointer done_callback_data); +void nautilus_file_operations_empty_trash (GtkWidget *parent_view); +void nautilus_file_operations_new_folder (GtkWidget *parent_view, + const char *parent_dir_uri, + NautilusNewFolderCallback done_callback, + gpointer done_callback_data); +void nautilus_file_operations_new_file (GtkWidget *parent_view, + const char *parent_dir, + const char *source_uri_text, + NautilusNewFileCallback done_callback, + gpointer data); +void nautilus_file_operations_delete (const GList *item_uris, + GtkWidget *parent_view); + #endif /* NAUTILUS_FILE_OPERATIONS_H */ diff --git a/libnautilus-private/nautilus-file-utilities.c b/libnautilus-private/nautilus-file-utilities.c index 1e6bd302c..94b25e135 100644 --- a/libnautilus-private/nautilus-file-utilities.c +++ b/libnautilus-private/nautilus-file-utilities.c @@ -166,6 +166,35 @@ nautilus_get_desktop_directory_uri_no_create (void) return desktop_uri; } +char * +nautilus_get_templates_directory (void) +{ + return g_build_filename (g_get_home_dir(), + "Templates", NULL); +} + +void +nautilus_create_templates_directory (void) +{ + char *dir; + + dir = nautilus_get_templates_directory (); + if (!g_file_test (dir, G_FILE_TEST_EXISTS)) { + mkdir (dir, DEFAULT_NAUTILUS_DIRECTORY_MODE); + } + g_free (dir); +} + +char * +nautilus_get_templates_directory_uri (void) +{ + char *directory, *uri; + + directory = nautilus_get_templates_directory (); + uri = gnome_vfs_get_uri_from_local_path (directory); + g_free (directory); + return uri; +} /* These need to be reset to NULL when desktop_is_home_dir changes */ static char *escaped_desktop_dir = NULL; diff --git a/libnautilus-private/nautilus-file-utilities.h b/libnautilus-private/nautilus-file-utilities.h index 9f83dd565..831e353b6 100644 --- a/libnautilus-private/nautilus-file-utilities.h +++ b/libnautilus-private/nautilus-file-utilities.h @@ -43,6 +43,10 @@ gboolean nautilus_is_desktop_directory_escaped (char *escaped_dir); char * nautilus_get_gmc_desktop_directory (void); char * nautilus_get_pixmap_directory (void); +char * nautilus_get_templates_directory (void); +char * nautilus_get_templates_directory_uri (void); +void nautilus_create_templates_directory (void); + /* This function returns something that needs to be freed with g_free, * is not NULL, but is not garaunteed to exist */ char * nautilus_get_desktop_directory_uri_no_create (void); diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index 29e204357..7c8c74866 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -139,6 +139,8 @@ #define FM_DIRECTORY_VIEW_COMMAND_MEDIA_PROPERTIES_VOLUME_CONDITIONAL "/commands/Media Properties Conditional" #define FM_DIRECTORY_VIEW_MENU_PATH_OPEN_WITH "/menu/File/Open Placeholder/Open With" +#define FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS "/menu/File/New Items Placeholder/New Documents" +#define FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_NO_TEMPLATES "/menu/File/New Items Placeholder/New Documents/No Templates" #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS "/menu/File/Open Placeholder/Scripts" #define FM_DIRECTORY_VIEW_MENU_PATH_TRASH "/menu/Edit/Dangerous File Items Placeholder/Trash" #define FM_DIRECTORY_VIEW_MENU_PATH_DELETE "/menu/Edit/Dangerous File Items Placeholder/Delete" @@ -151,6 +153,8 @@ #define FM_DIRECTORY_VIEW_MENU_PATH_OTHER_VIEWER "/menu/File/Open Placeholder/Open With/OtherViewer" #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER "/menu/File/Open Placeholder/Scripts/Scripts Placeholder" #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_SEPARATOR "/menu/File/Open Placeholder/Scripts/After Scripts" +#define FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER "/menu/File/New Items Placeholder/New Documents/New Documents Placeholder" +#define FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_SEPARATOR "/menu/File/New Items Placeholder/New Documents/After New Documents" #define FM_DIRECTORY_VIEW_MENU_PATH_CUT_FILES "/menu/Edit/Cut" #define FM_DIRECTORY_VIEW_MENU_PATH_COPY_FILES "/menu/Edit/Copy" #define FM_DIRECTORY_VIEW_MENU_PATH_PASTE_FILES "/menu/File/Paste" @@ -161,6 +165,10 @@ #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS "/popups/background/Before Zoom Items/Scripts" #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER "/popups/background/Before Zoom Items/Scripts/Scripts Placeholder" #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_SEPARATOR "/popups/background/Before Zoom Items/Scripts/After Scripts" +#define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS "/popups/background/Before Zoom Items/New Documents" +#define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_NO_TEMPLATES "/popups/background/Before Zoom Items/New Documents/No Templates" +#define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER "/popups/background/Before Zoom Items/New Documents/New Documents Placeholder" +#define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_SEPARATOR "/popups/background/Before Zoom Items/New Documents/After New Documents" #define FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER "/popups/selection/Open Placeholder/Open With/Applications Placeholder" #define FM_DIRECTORY_VIEW_POPUP_PATH_BEFORE_VIEWERS_SEPARATOR "/popups/selection/Open Placeholder/Open With/Before Viewers" @@ -198,6 +206,9 @@ static gboolean confirm_trash_auto_value; static char *scripts_directory_uri; static int scripts_directory_uri_length; +static char *templates_directory_uri; +static int templates_directory_uri_length; + struct FMDirectoryViewDetails { NautilusView *nautilus_view; @@ -208,6 +219,7 @@ struct FMDirectoryViewDetails BonoboUIComponent *ui; GList *scripts_directory_list; + GList *templates_directory_list; guint display_selection_idle_id; guint update_menus_timeout_id; @@ -234,6 +246,7 @@ struct FMDirectoryViewDetails gboolean menus_merged; gboolean menu_states_untrustworthy; gboolean scripts_invalid; + gboolean templates_invalid; gboolean reported_load_error; gboolean sort_directories_first; @@ -389,6 +402,12 @@ typedef struct { FMDirectoryView *directory_view; } ScriptLaunchParameters; +typedef struct { + NautilusFile *file; + FMDirectoryView *directory_view; +} CreateTemplateParameters; + + static ApplicationLaunchParameters * application_launch_parameters_new (GnomeVFSMimeApplication *application, NautilusFile *file, @@ -463,6 +482,30 @@ script_launch_parameters_free (ScriptLaunchParameters *parameters) g_free (parameters); } +static CreateTemplateParameters * +create_template_parameters_new (NautilusFile *file, + FMDirectoryView *directory_view) +{ + CreateTemplateParameters *result; + + result = g_new0 (CreateTemplateParameters, 1); + g_object_ref (directory_view); + result->directory_view = directory_view; + nautilus_file_ref (file); + result->file = file; + + return result; +} + +static void +create_templates_parameters_free (CreateTemplateParameters *parameters) +{ + g_object_unref (parameters->directory_view); + nautilus_file_unref (parameters->file); + g_free (parameters); +} + + /* Returns the GtkWindow that this directory view occupies, or NULL * if at the moment this directory view is not in a GtkWindow or the * GtkWindow cannot be determined. Primarily used for parenting dialogs. @@ -1072,6 +1115,14 @@ new_folder_callback (BonoboUIComponent *component, gpointer callback_data, const } static void +new_empty_file_callback (BonoboUIComponent *component, gpointer callback_data, const char *verb) +{ + g_assert (FM_IS_DIRECTORY_VIEW (callback_data)); + + fm_directory_view_new_file (FM_DIRECTORY_VIEW (callback_data), NULL); +} + +static void new_launcher_callback (BonoboUIComponent *component, gpointer callback_data, const char *verb) { char *parent_uri; @@ -1285,6 +1336,17 @@ set_up_scripts_directory_global (void) } static void +set_up_templates_directory_global (void) +{ + if (templates_directory_uri != NULL) { + return; + } + + templates_directory_uri = nautilus_get_templates_directory_uri (); + templates_directory_uri_length = strlen (templates_directory_uri); +} + +static void create_scripts_directory (void) { char *gnome1_path, *gnome1_uri_str; @@ -1330,6 +1392,19 @@ scripts_added_or_changed_callback (NautilusDirectory *directory, } static void +templates_added_or_changed_callback (NautilusDirectory *directory, + GList *files, + gpointer callback_data) +{ + FMDirectoryView *view; + + view = FM_DIRECTORY_VIEW (callback_data); + + view->details->templates_invalid = TRUE; + schedule_update_menus (view); +} + +static void icons_changed_callback (gpointer callback_data) { FMDirectoryView *view; @@ -1337,57 +1412,100 @@ icons_changed_callback (gpointer callback_data) view = FM_DIRECTORY_VIEW (callback_data); view->details->scripts_invalid = TRUE; + view->details->templates_invalid = TRUE; schedule_update_menus (view); } static void -add_directory_to_scripts_directory_list (FMDirectoryView *view, - NautilusDirectory *directory) +add_directory_to_directory_list (FMDirectoryView *view, + NautilusDirectory *directory, + GList **directory_list, + GCallback changed_callback) { NautilusFileAttributes attributes; - if (g_list_find (view->details->scripts_directory_list, directory) == NULL) { + if (g_list_find (*directory_list, directory) == NULL) { nautilus_directory_ref (directory); attributes = nautilus_icon_factory_get_required_file_attributes (); attributes |= NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES | NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT; - nautilus_directory_file_monitor_add (directory, &view->details->scripts_directory_list, + nautilus_directory_file_monitor_add (directory, directory_list, FALSE, FALSE, attributes, - scripts_added_or_changed_callback, view); + (NautilusDirectoryCallback)changed_callback, view); g_signal_connect_object (directory, "files_added", - G_CALLBACK (scripts_added_or_changed_callback), view, 0); + G_CALLBACK (changed_callback), view, 0); g_signal_connect_object (directory, "files_changed", - G_CALLBACK (scripts_added_or_changed_callback), view, 0); + G_CALLBACK (changed_callback), view, 0); - view->details->scripts_directory_list = g_list_append - (view->details->scripts_directory_list, directory); + *directory_list = g_list_append (*directory_list, directory); } } static void -remove_directory_from_scripts_directory_list (FMDirectoryView *view, - NautilusDirectory *directory) +remove_directory_from_directory_list (FMDirectoryView *view, + NautilusDirectory *directory, + GList **directory_list, + GCallback changed_callback) { - view->details->scripts_directory_list = g_list_remove - (view->details->scripts_directory_list, directory); + *directory_list = g_list_remove (*directory_list, directory); g_signal_handlers_disconnect_by_func (directory, - G_CALLBACK (scripts_added_or_changed_callback), + G_CALLBACK (changed_callback), view); - nautilus_directory_file_monitor_remove (directory, &view->details->scripts_directory_list); + nautilus_directory_file_monitor_remove (directory, directory_list); nautilus_directory_unref (directory); } + +static void +add_directory_to_scripts_directory_list (FMDirectoryView *view, + NautilusDirectory *directory) +{ + add_directory_to_directory_list (view, directory, + &view->details->scripts_directory_list, + G_CALLBACK (scripts_added_or_changed_callback)); +} + +static void +remove_directory_from_scripts_directory_list (FMDirectoryView *view, + NautilusDirectory *directory) +{ + remove_directory_from_directory_list (view, directory, + &view->details->scripts_directory_list, + G_CALLBACK (scripts_added_or_changed_callback)); +} + +static void +add_directory_to_templates_directory_list (FMDirectoryView *view, + NautilusDirectory *directory) +{ + add_directory_to_directory_list (view, directory, + &view->details->templates_directory_list, + G_CALLBACK (templates_added_or_changed_callback)); +} + +static void +remove_directory_from_templates_directory_list (FMDirectoryView *view, + NautilusDirectory *directory) +{ + remove_directory_from_directory_list (view, directory, + &view->details->templates_directory_list, + G_CALLBACK (templates_added_or_changed_callback)); +} + + + static void fm_directory_view_init (FMDirectoryView *view) { static gboolean setup_autos = FALSE; NautilusDirectory *scripts_directory; + NautilusDirectory *templates_directory; if (!setup_autos) { setup_autos = TRUE; @@ -1410,11 +1528,15 @@ fm_directory_view_init (FMDirectoryView *view) view->details->nautilus_view = nautilus_view_new (GTK_WIDGET (view)); set_up_scripts_directory_global (); - scripts_directory = nautilus_directory_get (scripts_directory_uri); add_directory_to_scripts_directory_list (view, scripts_directory); nautilus_directory_unref (scripts_directory); + set_up_templates_directory_global (); + templates_directory = nautilus_directory_get (templates_directory_uri); + add_directory_to_templates_directory_list (view, templates_directory); + nautilus_directory_unref (templates_directory); + view->details->zoomable = bonobo_zoomable_new (); bonobo_zoomable_set_parameters_full (view->details->zoomable, 0.0, .25, 4.0, TRUE, TRUE, FALSE, @@ -1512,6 +1634,12 @@ fm_directory_view_finalize (GObject *object) remove_directory_from_scripts_directory_list (view, node->data); } + for (node = view->details->templates_directory_list; node != NULL; node = next) { + next = node->next; + remove_directory_from_templates_directory_list (view, node->data); + } + + nautilus_directory_unref (view->details->model); view->details->model = NULL; nautilus_file_unref (view->details->directory_as_file); @@ -3246,29 +3374,58 @@ start_renaming_file (FMDirectoryView *view, NautilusFile *file) } static void +rename_file (FMDirectoryView *view, NautilusFile *new_file) +{ + /* no need to select because start_renaming_file selects + * fm_directory_view_select_file (view, new_file); + */ + EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view, start_renaming_file, (view, new_file)); + fm_directory_view_reveal_selection (view); +} + +static void reveal_newly_added_folder (FMDirectoryView *view, NautilusFile *new_file, const char *target_uri) { if (nautilus_file_matches_uri (new_file, target_uri)) { g_signal_handlers_disconnect_by_func (view, G_CALLBACK (reveal_newly_added_folder), (void *) target_uri); - /* no need to select because start_renaming_file selects - * fm_directory_view_select_file (view, new_file); - */ - EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view, start_renaming_file, (view, new_file)); - fm_directory_view_reveal_selection (view); + rename_file (view, new_file); } } +typedef struct { + FMDirectoryView *directory_view; + GHashTable *added_uris; +} NewFolderData; + + static void -new_folder_done (const char *new_folder_uri, gpointer data) +track_newly_added_uris (FMDirectoryView *view, NautilusFile *new_file, gpointer user_data) +{ + NewFolderData *data; + + data = user_data; + + g_hash_table_insert (data->added_uris, nautilus_file_get_uri (new_file), NULL); +} + +static void +new_folder_done (const char *new_folder_uri, gpointer user_data) { FMDirectoryView *directory_view; NautilusFile *file; char *screen_string; GdkScreen *screen; + NewFolderData *data; - directory_view = (FMDirectoryView *) data; + data = (NewFolderData *)user_data; + + if (new_folder_uri == NULL) { + goto fail; + } + + directory_view = data->directory_view; g_assert (FM_IS_DIRECTORY_VIEW (directory_view)); screen = gtk_widget_get_screen (GTK_WIDGET (directory_view)); @@ -3281,31 +3438,92 @@ new_folder_done (const char *new_folder_uri, gpointer data) screen_string); g_free (screen_string); - /* We need to run after the default handler adds the folder we want to - * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we - * must use connect_after. - */ - g_signal_connect_data (directory_view, - "add_file", - G_CALLBACK (reveal_newly_added_folder), - g_strdup (new_folder_uri), - (GClosureNotify)g_free, - G_CONNECT_AFTER); + g_signal_handlers_disconnect_by_func (directory_view, + G_CALLBACK (track_newly_added_uris), + (void *) data); + + if (g_hash_table_lookup_extended (data->added_uris, new_folder_uri, NULL, NULL)) { + /* The file was already added */ + rename_file (directory_view, file); + } else { + /* We need to run after the default handler adds the folder we want to + * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we + * must use connect_after. + */ + g_signal_connect_data (directory_view, + "add_file", + G_CALLBACK (reveal_newly_added_folder), + g_strdup (new_folder_uri), + (GClosureNotify)g_free, + G_CONNECT_AFTER); + } + + fail: + g_hash_table_destroy (data->added_uris); + g_free (data); } void fm_directory_view_new_folder (FMDirectoryView *directory_view) { char *parent_uri; + NewFolderData *data; + + data = g_new (NewFolderData, 1); + data->directory_view = directory_view; + data->added_uris = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + g_signal_connect_data (directory_view, + "add_file", + G_CALLBACK (track_newly_added_uris), + data, + (GClosureNotify)NULL, + G_CONNECT_AFTER); parent_uri = fm_directory_view_get_backing_uri (directory_view); nautilus_file_operations_new_folder (GTK_WIDGET (directory_view), parent_uri, - new_folder_done, directory_view); + new_folder_done, data); g_free (parent_uri); } +void +fm_directory_view_new_file (FMDirectoryView *directory_view, + NautilusFile *source) +{ + char *parent_uri; + char *source_uri; + NewFolderData *data; + + data = g_new (NewFolderData, 1); + data->directory_view = directory_view; + data->added_uris = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + g_signal_connect_data (directory_view, + "add_file", + G_CALLBACK (track_newly_added_uris), + data, + (GClosureNotify)NULL, + G_CONNECT_AFTER); + + + source_uri = NULL; + if (source != NULL) { + source_uri = nautilus_file_get_uri (source); + } + parent_uri = fm_directory_view_get_backing_uri (directory_view); + nautilus_file_operations_new_file (GTK_WIDGET (directory_view), + parent_uri, + source_uri, + new_folder_done, data); + g_free (parent_uri); + g_free (source_uri); +} + + /* handle the open command */ static void @@ -3364,6 +3582,10 @@ add_numbered_menu_item (BonoboUIComponent *ui, GDestroyNotify destroy_notify) { char *escaped_parent_path, *escaped_label, *verb_name, *item_path; + + if (parent_path == NULL) { + return; + } escaped_parent_path = eel_str_double_underscores (parent_path); @@ -3399,11 +3621,13 @@ add_submenu (BonoboUIComponent *ui, { char *escaped_parent_path, *escaped_label; - escaped_parent_path = eel_str_double_underscores (parent_path); - escaped_label = eel_str_double_underscores (label); - nautilus_bonobo_add_submenu (ui, escaped_parent_path, escaped_label, pixbuf); - g_free (escaped_label); - g_free (escaped_parent_path); + if (parent_path != NULL) { + escaped_parent_path = eel_str_double_underscores (parent_path); + escaped_label = eel_str_double_underscores (label); + nautilus_bonobo_add_submenu (ui, escaped_parent_path, escaped_label, pixbuf); + g_free (escaped_label); + g_free (escaped_parent_path); + } } static void @@ -4170,12 +4394,12 @@ run_script_callback (BonoboUIComponent *component, gpointer callback_data, const } static void -add_script_to_script_menus (FMDirectoryView *directory_view, - NautilusFile *file, - int index, - const char *menu_path, - const char *popup_path, - const char *popup_bg_path) +add_script_to_scripts_menus (FMDirectoryView *directory_view, + NautilusFile *file, + int index, + const char *menu_path, + const char *popup_path, + const char *popup_bg_path) { ScriptLaunchParameters *launch_parameters; char *tip; @@ -4227,11 +4451,11 @@ add_script_to_script_menus (FMDirectoryView *directory_view, } static void -add_submenu_to_script_menus (FMDirectoryView *directory_view, - NautilusFile *file, - const char *menu_path, - const char *popup_path, - const char *popup_bg_path) +add_submenu_to_directory_menus (FMDirectoryView *directory_view, + NautilusFile *file, + const char *menu_path, + const char *popup_path, + const char *popup_bg_path) { char *name; GdkPixbuf *pixbuf; @@ -4279,19 +4503,22 @@ update_directory_in_scripts_menu (FMDirectoryView *view, NautilusDirectory *dire NautilusFile *file; NautilusDirectory *dir; char *uri; + char *escaped_path; int i; uri = nautilus_directory_get_uri (directory); + escaped_path = gnome_vfs_escape_path_string (uri + scripts_directory_uri_length); + g_free (uri); menu_path = g_strconcat (FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER, - uri + scripts_directory_uri_length, + escaped_path, NULL); popup_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER, - uri + scripts_directory_uri_length, + escaped_path, NULL); popup_bg_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER, - uri + scripts_directory_uri_length, + escaped_path, NULL); - g_free (uri); + g_free (escaped_path); file_list = nautilus_directory_get_file_list (directory); filtered = nautilus_file_list_filter_hidden_and_backup (file_list, FALSE, FALSE); @@ -4305,7 +4532,7 @@ update_directory_in_scripts_menu (FMDirectoryView *view, NautilusDirectory *dire file = node->data; if (file_is_launchable (file)) { - add_script_to_script_menus (view, file, i++, menu_path, popup_path, popup_bg_path); + add_script_to_scripts_menus (view, file, i++, menu_path, popup_path, popup_bg_path); any_scripts = TRUE; } else if (nautilus_file_is_directory (file)) { uri = nautilus_file_get_uri (file); @@ -4314,7 +4541,7 @@ update_directory_in_scripts_menu (FMDirectoryView *view, NautilusDirectory *dire add_directory_to_scripts_directory_list (view, dir); nautilus_directory_unref (dir); - add_submenu_to_script_menus (view, file, menu_path, popup_path, popup_bg_path); + add_submenu_to_directory_menus (view, file, menu_path, popup_path, popup_bg_path); any_scripts = TRUE; } @@ -4389,6 +4616,196 @@ update_scripts_menu (FMDirectoryView *view) } static void +create_template_callback (BonoboUIComponent *component, gpointer callback_data, const char *path) +{ + CreateTemplateParameters *parameters; + + parameters = callback_data; + + fm_directory_view_new_file (parameters->directory_view, parameters->file); +} + + +static void +add_template_to_templates_menus (FMDirectoryView *directory_view, + NautilusFile *file, + int index, + const char *menu_path, + const char *popup_bg_path) +{ + char *tip; + char *name; + GdkPixbuf *pixbuf; + CreateTemplateParameters *parameters; + + name = nautilus_file_get_display_name (file); + tip = g_strdup_printf (_("Create Document from template \"%s\""), name); + + pixbuf = nautilus_icon_factory_get_pixbuf_for_file + (file, NULL, NAUTILUS_ICON_SIZE_FOR_MENUS); + + parameters = create_template_parameters_new (file, directory_view); + add_numbered_menu_item (directory_view->details->ui, + menu_path, + name, + tip, + index, + pixbuf, + create_template_callback, + parameters, + (GDestroyNotify) create_templates_parameters_free); + + /* Use same uri 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, + popup_bg_path, + name, + tip, + index, + pixbuf, + create_template_callback, + parameters, + NULL); + + g_object_unref (pixbuf); + g_free (name); + g_free (tip); +} + + +static gboolean +directory_belongs_in_templates_menu (const char *uri) +{ + int num_levels; + int i; + + if (!eel_str_has_prefix (uri, templates_directory_uri)) { + return FALSE; + } + + num_levels = 0; + for (i = templates_directory_uri_length; uri[i] != '\0'; i++) { + if (uri[i] == '/') { + num_levels++; + } + } + + if (num_levels > MAX_MENU_LEVELS) { + return FALSE; + } + + return TRUE; +} + +static gboolean +update_directory_in_templates_menu (FMDirectoryView *view, NautilusDirectory *directory) +{ + char *menu_path, *popup_bg_path; + GList *file_list, *filtered, *node; + gboolean any_templates; + NautilusFile *file; + NautilusDirectory *dir; + char *escaped_path; + char *uri; + int i; + + uri = nautilus_directory_get_uri (directory); + escaped_path = gnome_vfs_escape_path_string (uri + templates_directory_uri_length); + g_free (uri); + menu_path = g_strconcat (FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER, + escaped_path, + NULL); + popup_bg_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER, + escaped_path, + NULL);; + + g_free (escaped_path); + + file_list = nautilus_directory_get_file_list (directory); + filtered = nautilus_file_list_filter_hidden_and_backup (file_list, FALSE, FALSE); + nautilus_file_list_free (file_list); + + file_list = nautilus_file_list_sort_by_display_name (filtered); + + any_templates = FALSE; + i = 0; + for (node = file_list; node != NULL; node = node->next) { + file = node->data; + + if (nautilus_file_is_directory (file)) { + uri = nautilus_file_get_uri (file); + if (directory_belongs_in_templates_menu (uri)) { + dir = nautilus_directory_get (uri); + add_directory_to_templates_directory_list (view, dir); + nautilus_directory_unref (dir); + + add_submenu_to_directory_menus (view, file, menu_path, NULL, popup_bg_path); + + any_templates = TRUE; + } + g_free (uri); + } else if (nautilus_file_can_read (file)) { + add_template_to_templates_menus (view, file, i++, menu_path, popup_bg_path); + any_templates = TRUE; + } + } + + nautilus_file_list_free (file_list); + + g_free (popup_bg_path); + g_free (menu_path); + + return any_templates; +} + + + +static void +update_templates_menu (FMDirectoryView *view) +{ + gboolean any_templates; + GList *sorted_copy, *node; + NautilusDirectory *directory; + char *uri; + + /* There is a race condition here. If we don't mark the scripts menu as + valid before we begin our task then we can lose template menu updates that + occur before we finish. */ + view->details->templates_invalid = FALSE; + + nautilus_bonobo_remove_menu_items_and_commands + (view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER); + nautilus_bonobo_remove_menu_items_and_commands + (view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER); + + /* As we walk through the directories, remove any that no longer belong. */ + any_templates = FALSE; + sorted_copy = nautilus_directory_list_sort_by_uri + (nautilus_directory_list_copy (view->details->templates_directory_list)); + for (node = sorted_copy; node != NULL; node = node->next) { + directory = node->data; + + uri = nautilus_directory_get_uri (directory); + if (!directory_belongs_in_templates_menu (uri)) { + remove_directory_from_templates_directory_list (view, directory); + } else if (update_directory_in_templates_menu (view, directory)) { + any_templates = TRUE; + } + g_free (uri); + } + nautilus_directory_list_free (sorted_copy); + + nautilus_bonobo_set_hidden (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_NO_TEMPLATES, + any_templates); + nautilus_bonobo_set_hidden (view->details->ui, + FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_NO_TEMPLATES, + any_templates); +} + + +static void open_scripts_folder_callback (BonoboUIComponent *component, gpointer callback_data, const char *verb) @@ -4860,6 +5277,7 @@ real_merge_menus (FMDirectoryView *view) BONOBO_UI_VERB ("Duplicate", duplicate_callback), BONOBO_UI_VERB ("Empty Trash", bonobo_menu_empty_trash_callback), BONOBO_UI_VERB ("New Folder", new_folder_callback), + BONOBO_UI_VERB ("New Empty File", new_empty_file_callback), BONOBO_UI_VERB ("New Launcher", new_launcher_callback), BONOBO_UI_VERB ("Open Scripts Folder", open_scripts_folder_callback), BONOBO_UI_VERB ("Open", open_callback), @@ -4900,6 +5318,7 @@ real_merge_menus (FMDirectoryView *view) } view->details->scripts_invalid = TRUE; + view->details->templates_invalid = TRUE; } static void @@ -5274,6 +5693,9 @@ real_update_menus (FMDirectoryView *view) if (view->details->scripts_invalid) { update_scripts_menu (view); } + if (view->details->templates_invalid) { + update_templates_menu (view); + } } /** diff --git a/src/file-manager/fm-directory-view.h b/src/file-manager/fm-directory-view.h index 2fa6afaef..3e444f8d5 100644 --- a/src/file-manager/fm-directory-view.h +++ b/src/file-manager/fm-directory-view.h @@ -370,6 +370,8 @@ gboolean fm_directory_view_should_show_file (FMDirect gboolean fm_directory_view_should_sort_directories_first (FMDirectoryView *view); void fm_directory_view_update_menus (FMDirectoryView *view); void fm_directory_view_new_folder (FMDirectoryView *view); +void fm_directory_view_new_file (FMDirectoryView *view, + NautilusFile *source); void fm_directory_view_ignore_hidden_file_preferences (FMDirectoryView *view); #endif /* FM_DIRECTORY_VIEW_H */ diff --git a/src/file-manager/nautilus-directory-view-ui.xml b/src/file-manager/nautilus-directory-view-ui.xml index 35f8a238f..13065cb0e 100644 --- a/src/file-manager/nautilus-directory-view-ui.xml +++ b/src/file-manager/nautilus-directory-view-ui.xml @@ -18,6 +18,9 @@ <cmd name="New Folder" _label="Create _Folder" _tip="Create a new empty folder inside this folder"/> + <cmd name="New Empty File" + _label="_Empty File" + _tip="Create a new empty file inside this folder"/> <cmd name="New Launcher" _label="Create L_auncher" _tip="Create a new launcher"/> @@ -101,6 +104,16 @@ <menuitem name="New Folder" accel="*Shift**Control*n" verb="New Folder"/> + <submenu name="New Documents" + _label="Create _Document"> + <menuitem name="No Templates" + _label="No templates Installed" + sensitive="0"/> + <placeholder name="New Documents Placeholder" delimit="none"/> + <separator name="After New Documents"/> + <menuitem name="New Empty File" + verb="New Empty File"/> + </submenu> <menuitem name="New Launcher" pixtype="stock" pixname="gtk-new" verb="New Launcher"/> @@ -209,6 +222,16 @@ pixtype="stock" pixname="gtk-new" verb="New Launcher"/> </placeholder> + <submenu name="New Documents" + _label="Create _Document"> + <menuitem name="No Templates" + _label="No templates Installed" + sensitive="0"/> + <placeholder name="New Documents Placeholder" delimit="none"/> + <separator name="After New Documents"/> + <menuitem name="New Empty File" + verb="New Empty File"/> + </submenu> <submenu name="Scripts" _label="_Scripts" _tip="Run or manage scripts from ~/Nautilus/scripts" diff --git a/src/nautilus-navigation-window-ui.xml b/src/nautilus-navigation-window-ui.xml index 9bdeb5691..ab3ce0565 100644 --- a/src/nautilus-navigation-window-ui.xml +++ b/src/nautilus-navigation-window-ui.xml @@ -81,6 +81,11 @@ _label="_Computer" pixtype="stock" pixname="gnome-fs-client" verb="Go to Computer"/> + <menuitem name="Go to Templates" + _label="_Templates" + _tip="Go to templates folder" + pixtype="stock" pixname="gnome-fs-client" + verb="Go to Templates"/> <menuitem name="Go to Trash" _label="_Trash" _tip="Go to the trash folder" diff --git a/src/nautilus-spatial-window-ui.xml b/src/nautilus-spatial-window-ui.xml index 4a706a1ad..e789e918d 100644 --- a/src/nautilus-spatial-window-ui.xml +++ b/src/nautilus-spatial-window-ui.xml @@ -44,6 +44,11 @@ _tip="Go to Computer" pixtype="stock" pixname="gnome-fs-client" verb="Go to Computer"/> + <menuitem name="Go to Templates" + _label="_Templates" + _tip="Go to templates folder" + pixtype="stock" pixname="gnome-fs-client" + verb="Go to Templates"/> <menuitem name="Go to Trash" _label="_Trash" _tip="Go to the trash folder" diff --git a/src/nautilus-window-menus.c b/src/nautilus-window-menus.c index 3d5db411f..577ae5059 100644 --- a/src/nautilus-window-menus.c +++ b/src/nautilus-window-menus.c @@ -382,6 +382,20 @@ go_menu_go_to_computer_callback (BonoboUIComponent *component, } static void +go_menu_go_to_templates_callback (BonoboUIComponent *component, + gpointer user_data, + const char *verb) +{ + char *uri; + + nautilus_create_templates_directory (); + uri = nautilus_get_templates_directory_uri (); + nautilus_window_go_to (NAUTILUS_WINDOW (user_data), + uri); + g_free (uri); +} + +static void go_menu_go_to_trash_callback (BonoboUIComponent *component, gpointer user_data, const char *verb) @@ -662,6 +676,7 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window) BONOBO_UI_VERB ("Home", go_menu_home_callback), BONOBO_UI_VERB ("Start Here", go_menu_start_here_callback), BONOBO_UI_VERB ("Go to Computer", go_menu_go_to_computer_callback), + BONOBO_UI_VERB ("Go to Templates", go_menu_go_to_templates_callback), BONOBO_UI_VERB ("Go to Trash", go_menu_go_to_trash_callback), BONOBO_UI_VERB ("Go to Burn CD", go_menu_go_to_burn_cd_callback), BONOBO_UI_VERB ("Go to Location", go_menu_location_callback), |