diff options
author | Darin Adler <darin@src.gnome.org> | 2000-03-08 21:16:21 +0000 |
---|---|---|
committer | Darin Adler <darin@src.gnome.org> | 2000-03-08 21:16:21 +0000 |
commit | 6ba4e1e5e3adce6604d0d09563c99923bc9cc97a (patch) | |
tree | 2f253460141e3b059b81134004e932a410d6c23b | |
parent | 886358c4f74f0843ee5d235218e0745c3ea2a64a (diff) | |
download | nautilus-6ba4e1e5e3adce6604d0d09563c99923bc9cc97a.tar.gz |
Broke the file part of nautilus-directory.[ch] into nautilus-file.[ch].
* components/music/nautilus-music-view.c,
components/notes/ntl-notes.c, libnautilus/Makefile.am,
libnautilus/nautilus-directory-private.h,
libnautilus/nautilus-directory.h,
libnautilus/nautilus-directory.c,
libnautilus/nautilus-file-private.h, libnautilus/nautilus-file.h,
libnautilus/nautilus-file.c, libnautilus/nautilus-icon-factory.h,
src/ntl-index-panel.c, src/file-manager/fm-directory-view.h:
Broke the file part of nautilus-directory.[ch] into
nautilus-file.[ch].
* libnautilus/nautilus-string.c (nautilus_strstrip): Added more
tests. Changed algorithm on strstrip so it's linear instead of
n^2.
* libnautilus/gnome-icon-container.c
(gnome_icon_container_initialize): Fixed font for "larger" zoom
level. Also made it assert if the font can't be loaded.
* components/help/hyperbola-nav-index.c (despace):
Fixed warning.
* libnautilus/gnome-icon-container-dnd.c,
libnautilus/nautilus-string.h: Whitespace.
* src/file-manager/Makefile.am,
src/file-manager/fm-directory-view.c,
src/file-manager/fm-properties-window.h,
src/file-manager/fm-properties-window.c: Added properties window
hook, but no window yet. The menu item still needs to be added to
the main menus as well as the context menus.
* src/file-manager/fm-directory-view.c,
src/file-manager/fm-directory-view-icons.c,
src/file-manager/fm-icon-text-window.h,
src/file-manager/fm-icon-text-window.c: A little cleanup. Shorter
names.
52 files changed, 4341 insertions, 3747 deletions
diff --git a/ChangeLog-20000414 b/ChangeLog-20000414 index 2a22185dc..9ab27f408 100644 --- a/ChangeLog-20000414 +++ b/ChangeLog-20000414 @@ -1,13 +1,53 @@ +2000-03-07 Darin Adler <darin@eazel.com> + + * components/music/nautilus-music-view.c, + components/notes/ntl-notes.c, libnautilus/Makefile.am, + libnautilus/nautilus-directory-private.h, + libnautilus/nautilus-directory.h, + libnautilus/nautilus-directory.c, + libnautilus/nautilus-file-private.h, libnautilus/nautilus-file.h, + libnautilus/nautilus-file.c, libnautilus/nautilus-icon-factory.h, + src/ntl-index-panel.c, src/file-manager/fm-directory-view.h: + Broke the file part of nautilus-directory.[ch] into + nautilus-file.[ch]. + + * libnautilus/nautilus-string.c (nautilus_strstrip): Added more + tests. Changed algorithm on strstrip so it's linear instead of + n^2. + + * libnautilus/gnome-icon-container.c + (gnome_icon_container_initialize): Fixed font for "larger" zoom + level. Also made it assert if the font can't be loaded. + + * components/help/hyperbola-nav-index.c (despace): + Fixed warning. + + * libnautilus/gnome-icon-container-dnd.c, + libnautilus/nautilus-string.h: Whitespace. + + * src/file-manager/Makefile.am, + src/file-manager/fm-directory-view.c, + src/file-manager/fm-properties-window.h, + src/file-manager/fm-properties-window.c: Added properties window + hook, but no window yet. The menu item still needs to be added to + the main menus as well as the context menus. + + * src/file-manager/fm-directory-view.c, + src/file-manager/fm-directory-view-icons.c, + src/file-manager/fm-icon-text-window.h, + src/file-manager/fm-icon-text-window.c: A little cleanup. Shorter + names. + 2000-03-08 Ramiro Estrugo <ramiro@eazel.com> * src/nautilus-prefs-group-radio.h, src/nautilus-prefs-group-radio.h: Make the radio group emit proper - signals on changes. + signals on changes. + + * src/nautilus-prefs-pane.c, src/nautilus-prefs-group.c + src/nautilus-prefs-box.c: Make everything prettier by using nice + offsets. - * src/nautilus-prefs-pane.c, - src/nautilus-prefs-group.c - src/nautilus-prefs-box.c: Make everything prettier by using nice offsets. - 2000-03-08 Ramiro Estrugo <ramiro@eazel.com> Added macros to check, assert and invoke class methods @@ -17,9 +57,10 @@ (NAUTILUS_KLASS) Access the class for a given object (NAUTILUS_INVOKE_METHOD) Invoke a method for a given object (NAUTILUS_ACCESS_METHOD) Access a method. - (NAUTILUS_ASSERT_METHOD) Assert the non-nullness of a method for a given object + (NAUTILUS_ASSERT_METHOD) Assert the non-nullness of a method + for a given object (NAUTILUS_INVOKE_METHOD_IF) Invoke a method if it aint null. - + 2000-03-08 Ramiro Estrugo <ramiro@eazel.com> First whack at having a better preferences ui. diff --git a/components/help/hyperbola-nav-index.c b/components/help/hyperbola-nav-index.c index 6df6a109e..33535de9b 100644 --- a/components/help/hyperbola-nav-index.c +++ b/components/help/hyperbola-nav-index.c @@ -366,7 +366,7 @@ despace(GString *s) ctmp = ctmp_s + 2; i--; if(i != strlen(ctmp)) - g_error("i (%d) != strlen(ctmp) (%ld)", i, strlen(ctmp)); + g_error("i (%d) != strlen(ctmp) (%ld)", i, (long)strlen(ctmp)); } ctmp_s = NULL; } diff --git a/components/music/nautilus-music-view.c b/components/music/nautilus-music-view.c index 00cf191f1..11ce76912 100644 --- a/components/music/nautilus-music-view.c +++ b/components/music/nautilus-music-view.c @@ -33,6 +33,7 @@ #include <libnautilus/libnautilus.h> #include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-file.h> #include <libnautilus/nautilus-file-utilities.h> #include <libnautilus/nautilus-glib-extensions.h> #include <libnautilus/nautilus-gtk-macros.h> diff --git a/components/notes/nautilus-notes.c b/components/notes/nautilus-notes.c index 165def4b0..d89412230 100644 --- a/components/notes/nautilus-notes.c +++ b/components/notes/nautilus-notes.c @@ -24,7 +24,8 @@ */ /* annotation metaview - allows you to annotate a directory or file */ -#include "config.h" + +#include <config.h> #include <libnautilus/libnautilus.h> #include <libnautilus/nautilus-metadata.h> @@ -34,8 +35,9 @@ #include <limits.h> #include <ctype.h> #include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-file.h> -#define NOTES_DEFAULT_BACKGROUND_COLOR "rgb:FFFF/FFFF/BBBB" +#define NOTES_DEFAULT_BACKGROUND_COLOR "rgb:FFFF/FFFF/BBBB" typedef struct { diff --git a/components/notes/ntl-notes.c b/components/notes/ntl-notes.c index 165def4b0..d89412230 100644 --- a/components/notes/ntl-notes.c +++ b/components/notes/ntl-notes.c @@ -24,7 +24,8 @@ */ /* annotation metaview - allows you to annotate a directory or file */ -#include "config.h" + +#include <config.h> #include <libnautilus/libnautilus.h> #include <libnautilus/nautilus-metadata.h> @@ -34,8 +35,9 @@ #include <limits.h> #include <ctype.h> #include <libnautilus/nautilus-background.h> +#include <libnautilus/nautilus-file.h> -#define NOTES_DEFAULT_BACKGROUND_COLOR "rgb:FFFF/FFFF/BBBB" +#define NOTES_DEFAULT_BACKGROUND_COLOR "rgb:FFFF/FFFF/BBBB" typedef struct { diff --git a/libnautilus-extensions/Makefile.am b/libnautilus-extensions/Makefile.am index 4e65cefad..002601a80 100644 --- a/libnautilus-extensions/Makefile.am +++ b/libnautilus-extensions/Makefile.am @@ -27,8 +27,6 @@ libnautilusincludedir=$(includedir)/libnautilus libnautilusinclude_HEADERS= \ bonobo-stream-vfs.h \ gdk-extensions.h \ - gnome-icon-container-dnd.h \ - gnome-icon-container-private.h \ gnome-icon-container.h \ gtkflist.h \ gtkscrollframe.h \ @@ -38,13 +36,13 @@ libnautilusinclude_HEADERS= \ nautilus-bookmark.h \ nautilus-debug.h \ nautilus-directory.h \ + nautilus-file.h \ nautilus-file-utilities.h \ nautilus-glib-extensions.h \ nautilus-gtk-extensions.h \ nautilus-icon-factory.h \ nautilus-icons-controller.h \ nautilus-icons-view-icon-item.h \ - nautilus-lib-self-check-functions.h \ nautilus-metadata.h \ nautilus-mime-type.h \ nautilus-self-checks.h \ @@ -68,6 +66,7 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ nautilus-default-file-icon.c \ nautilus-default-file-icon.h \ nautilus-directory.c \ + nautilus-file.c \ nautilus-file-utilities.c \ nautilus-glib-extensions.c \ nautilus-gtk-extensions.c \ diff --git a/libnautilus-extensions/gnome-icon-container-dnd.c b/libnautilus-extensions/gnome-icon-container-dnd.c index 987556da1..1057c984d 100644 --- a/libnautilus-extensions/gnome-icon-container-dnd.c +++ b/libnautilus-extensions/gnome-icon-container-dnd.c @@ -816,12 +816,12 @@ gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, gtk_object_getv (GTK_OBJECT (item), 1, &pixbuf_arg); pixbuf = GTK_VALUE_BOXED (pixbuf_arg); - transparent_pixbuf = make_semi_transparent(pixbuf); + transparent_pixbuf = make_semi_transparent (pixbuf); gdk_pixbuf_render_pixmap_and_mask (transparent_pixbuf, &pixmap_for_dragged_file, &mask_for_dragged_file, 128); - gdk_pixbuf_unref(transparent_pixbuf); + gdk_pixbuf_unref (transparent_pixbuf); /* compute the image's offset */ nautilus_icons_view_icon_item_get_icon_window_rectangle diff --git a/libnautilus-extensions/gnome-icon-container.c b/libnautilus-extensions/gnome-icon-container.c index 20ada54d2..ddf28423e 100644 --- a/libnautilus-extensions/gnome-icon-container.c +++ b/libnautilus-extensions/gnome-icon-container.c @@ -724,15 +724,17 @@ make_icon_visible (GnomeIconContainer *container, icon_get_bounding_box (icon, &x1, &y1, &x2, &y2); - if (y1 < vadj->value) + if (y1 < vadj->value) { gtk_adjustment_set_value (vadj, y1); - else if (y2 > vadj->value + allocation->height) + } else if (y2 > vadj->value + allocation->height) { gtk_adjustment_set_value (vadj, y2 - allocation->height); + } - if (x1 < hadj->value) + if (x1 < hadj->value) { gtk_adjustment_set_value (hadj, x1); - else if (x2 > hadj->value + allocation->width) + } else if (x2 > hadj->value + allocation->width) { gtk_adjustment_set_value (hadj, x2 - allocation->width); + } } static gboolean @@ -2145,6 +2147,17 @@ gnome_icon_container_initialize_class (GnomeIconContainerClass *class) stipple = gdk_bitmap_create_from_data (NULL, stipple_bits, 2, 2); } +static GdkFont * +load_font (const char *name) +{ + GdkFont *font; + + /* FIXME: Eventually we need a runtime check, but an assert is better than nothing. */ + font = gdk_font_load (name); + g_assert (font != NULL); + return font; +} + static void gnome_icon_container_initialize (GnomeIconContainer *container) { @@ -2159,15 +2172,15 @@ gnome_icon_container_initialize (GnomeIconContainer *container) details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD; - /* font table - this isnt exactly proportional, but it looks better than computed */ + /* font table - this isn't exactly proportional, but it looks better than computed */ /* FIXME: read font from metadata and/or preferences */ - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLEST] = gdk_font_load("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLER] = gdk_font_load("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALL] = gdk_font_load("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_STANDARD] = gdk_font_load("-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGE] = gdk_font_load("-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGER] = gdk_font_load("-*-helveticar-medium-r-normal-*-18-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGEST] = gdk_font_load("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLEST] = load_font ("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLER] = load_font ("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALL] = load_font ("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_STANDARD] = load_font ("-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGE] = load_font ("-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGER] = load_font ("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGEST] = load_font ("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); /* FIXME: Read these from preferences. */ details->linger_selection_mode = FALSE; diff --git a/libnautilus-extensions/nautilus-directory-private.h b/libnautilus-extensions/nautilus-directory-private.h new file mode 100644 index 000000000..12496a3f6 --- /dev/null +++ b/libnautilus-extensions/nautilus-directory-private.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include "nautilus-directory.h" + +#include <libgnomevfs/gnome-vfs-types.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-file-info.h> + +#include <gnome-xml/tree.h> + +#include "nautilus-file.h" + +struct NautilusDirectoryDetails +{ + char *uri_text; + GnomeVFSURI *uri; + + GnomeVFSURI *metafile_uri; + GnomeVFSURI *alternate_metafile_uri; + gboolean use_alternate_metafile; + + xmlDoc *metafile_tree; + guint write_metafile_idle_id; + + GnomeVFSAsyncHandle *directory_load_in_progress; + GnomeVFSDirectoryListPosition directory_load_list_last_handled; + + GList *pending_file_info; + guint dequeue_pending_idle_id; + + gboolean directory_loaded; + + GList *files; +}; + +NautilusFile *nautilus_directory_new_file (NautilusDirectory *directory, + GnomeVFSFileInfo *info); +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata); +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata, + const char *metadata); +xmlNode * nautilus_directory_get_file_metadata_node (NautilusDirectory *directory, + const char *file_name); +void nautilus_directory_files_removed (NautilusDirectory *directory, + GList *removed_files); diff --git a/libnautilus-extensions/nautilus-directory.c b/libnautilus-extensions/nautilus-directory.c index 643c290db..eaa37ac68 100644 --- a/libnautilus-extensions/nautilus-directory.c +++ b/libnautilus-extensions/nautilus-directory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - nautilus-directory.c: Mautilus directory model. + nautilus-directory.c: Nautilus directory model. Copyright (C) 1999, 2000 Eazel, Inc. @@ -23,33 +23,20 @@ */ #include <config.h> -#include "nautilus-directory.h" +#include "nautilus-directory-private.h" -#include <grp.h> -#include <pwd.h> #include <stdlib.h> #include <gtk/gtksignal.h> #include <gtk/gtkmain.h> -#include <libgnome/gnome-defs.h> -#include <libgnome/gnome-i18n.h> - -#include <libgnomevfs/gnome-vfs-types.h> -#include <libgnomevfs/gnome-vfs-uri.h> -#include <libgnomevfs/gnome-vfs-file-info.h> -#include <libgnomevfs/gnome-vfs-ops.h> -#include <libgnomevfs/gnome-vfs-async-ops.h> - #include <gnome-xml/parser.h> -#include <gnome-xml/tree.h> #include <gnome-xml/xmlmemory.h> -#include "nautilus-alloc.h" -#include "nautilus-glib-extensions.h" #include "nautilus-gtk-macros.h" -#include "nautilus-lib-self-check-functions.h" #include "nautilus-string.h" +#include "nautilus-lib-self-check-functions.h" +#include "nautilus-file-private.h" #define METAFILE_NAME ".nautilus-metafile.xml" #define METAFILE_PERMISSIONS (GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE \ @@ -67,12 +54,6 @@ #define DIRECTORY_LOAD_ITEMS_PER_CB 1 -typedef enum { - NAUTILUS_DATE_TYPE_MODIFIED, - NAUTILUS_DATE_TYPE_CHANGED, - NAUTILUS_DATE_TYPE_ACCESSED -} NautilusDateType; - enum { FILES_ADDED, @@ -80,79 +61,25 @@ enum LAST_SIGNAL }; -/* FIXME: This hack needs to die eventually. See comments with function */ -static int get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items); - - static guint nautilus_directory_signals[LAST_SIGNAL]; -static void nautilus_directory_initialize_class (gpointer klass); -static void nautilus_directory_initialize (gpointer object, gpointer klass); -static void nautilus_directory_finalize (GtkObject *object); - -static NautilusDirectory *nautilus_directory_new (const char* uri); - -static void nautilus_directory_read_metafile (NautilusDirectory *directory); -static void nautilus_directory_write_metafile (NautilusDirectory *directory); -static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); -static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); - -static void nautilus_file_free (NautilusFile *file); -static int nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2); -static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type, - gboolean reversed); - -static char * nautilus_file_get_date_as_string (NautilusFile *file, - NautilusDateType date_type); -static char *nautilus_file_get_owner_as_string (NautilusFile *file); -static char *nautilus_file_get_group_as_string (NautilusFile *file); -static char *nautilus_file_get_permissions_as_string (NautilusFile *file); -static char * nautilus_file_get_size_as_string (NautilusFile *file); -static char * nautilus_file_get_type_as_string (NautilusFile *file); -static void nautilus_directory_load_cb (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GnomeVFSDirectoryList *list, - guint entries_read, - gpointer callback_data); -static NautilusFile *nautilus_directory_new_file (NautilusDirectory *directory, - GnomeVFSFileInfo *info); +static void nautilus_directory_initialize_class (gpointer klass); +static void nautilus_directory_initialize (gpointer object, + gpointer klass); +static void nautilus_directory_finalize (GtkObject *object); +static NautilusDirectory *nautilus_directory_new (const char *uri); +static void nautilus_directory_read_metafile (NautilusDirectory *directory); +static void nautilus_directory_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); +static void nautilus_directory_load_cb (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + GnomeVFSDirectoryList *list, + guint entries_read, + gpointer callback_data); NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusDirectory, nautilus_directory, GTK_TYPE_OBJECT) -struct NautilusDirectoryDetails -{ - char *uri_text; - GnomeVFSURI *uri; - - GnomeVFSURI *metafile_uri; - GnomeVFSURI *alternate_metafile_uri; - gboolean use_alternate_metafile; - - xmlDoc *metafile_tree; - guint write_metafile_idle_id; - - GnomeVFSAsyncHandle *directory_load_in_progress; - GnomeVFSDirectoryListPosition directory_load_list_last_handled; - - GList *pending_file_info; - guint dequeue_pending_idle_id; - - gboolean directory_loaded; - - GList *files; -}; - -struct NautilusFile -{ - guint ref_count; - - NautilusDirectory *directory; - GnomeVFSFileInfo *info; - gboolean is_gone; -}; - static GHashTable* directory_objects; static void @@ -1005,9 +932,9 @@ nautilus_directory_set_integer_metadata (NautilusDirectory *directory, g_free (default_as_string); } -static xmlNode * -get_file_metadata_node (NautilusDirectory *directory, - const char *file_name) +xmlNode * +nautilus_directory_get_file_metadata_node (NautilusDirectory *directory, + const char *file_name) { xmlNode *root, *child; xmlChar *property; @@ -1038,18 +965,18 @@ get_file_metadata_node (NautilusDirectory *directory, return NULL; } -static char * +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, const char *file_name, const char *tag, const char *default_metadata) { return nautilus_directory_get_metadata_from_node - (get_file_metadata_node (directory, file_name), + (nautilus_directory_get_file_metadata_node (directory, file_name), tag, default_metadata); } -static void +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, const char *file_name, const char *tag, @@ -1118,7 +1045,7 @@ nautilus_directory_set_file_metadata (NautilusDirectory *directory, nautilus_directory_request_write_metafile (directory); } -static NautilusFile * +NautilusFile * nautilus_directory_new_file (NautilusDirectory *directory, GnomeVFSFileInfo *info) { NautilusFile *file; @@ -1135,973 +1062,13 @@ nautilus_directory_new_file (NautilusDirectory *directory, GnomeVFSFileInfo *inf return file; } -/** - * nautilus_file_get: - * @uri: URI of file to get. - * - * Get a file given a uri. - * Returns a referenced object. Unref when finished. - * If two windows are viewing the same uri, the file object is shared. - */ -NautilusFile * -nautilus_file_get (const char *uri) -{ - GnomeVFSResult result; - GnomeVFSFileInfo *file_info; - GnomeVFSURI *vfs_uri, *directory_vfs_uri; - char *directory_uri; - NautilusDirectory *directory; - NautilusFile *file; - - /* Get info on the file. */ - file_info = gnome_vfs_file_info_new (); - result = gnome_vfs_get_file_info (uri, file_info, - GNOME_VFS_FILE_INFO_GETMIMETYPE - | GNOME_VFS_FILE_INFO_FASTMIMETYPE - | GNOME_VFS_FILE_INFO_FOLLOWLINKS, NULL); - if (result != GNOME_VFS_OK) - return NULL; - - /* Make VFS version of URI. */ - vfs_uri = gnome_vfs_uri_new (uri); - if (vfs_uri == NULL) - return NULL; - - /* Make VFS version of directory URI. */ - directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); - gnome_vfs_uri_unref (vfs_uri); - if (directory_vfs_uri == NULL) - return NULL; - - /* Make text version of directory URI. */ - directory_uri = gnome_vfs_uri_to_string (directory_vfs_uri, - GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (directory_vfs_uri); - - /* Get object that represents the directory. */ - directory = nautilus_directory_get (directory_uri); - g_free (directory_uri); - if (directory == NULL) - return NULL; - - file = nautilus_directory_new_file (directory, file_info); - - gnome_vfs_file_info_unref (file_info); - nautilus_file_ref (file); - gtk_object_unref (GTK_OBJECT (directory)); - - return file; -} - -void -nautilus_file_ref (NautilusFile *file) -{ - g_return_if_fail (file != NULL); - - g_assert (file->ref_count < G_MAXINT); - g_assert (file->directory != NULL); - - /* Increment the ref count. */ - if (file->ref_count++ != 0) { - return; - } - - /* As soon as someone other than the directory holds a ref, - * we need to hold the directory too. */ - gtk_object_ref (GTK_OBJECT (file->directory)); -} - -void -nautilus_file_unref (NautilusFile *file) -{ - g_return_if_fail (file != NULL); - - g_assert (file->ref_count != 0); - g_assert (file->directory != NULL); - - /* Decrement the ref count. */ - if (--file->ref_count != 0) { - return; - } - - /* No references left, so it's time to release our hold on the directory. */ - gtk_object_unref (GTK_OBJECT (file->directory)); - if (file->is_gone) { - nautilus_file_free (file); - } -} - -static void -nautilus_file_free (NautilusFile *file) -{ - g_assert (file->ref_count == 0); - - /* Destroy the file object. */ - gnome_vfs_file_info_unref (file->info); - g_free (file); -} - -static int -nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2) -{ - gboolean is_directory_1; - gboolean is_directory_2; - int item_count_1; - int item_count_2; - - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && !is_directory_2) - return -1; - - if (is_directory_2 && !is_directory_1) - return +1; - - if (!is_directory_1 && !is_directory_2) - return 0; - - /* Both are directories, compare by item count. */ - /* FIXME: get_directory_item_count_hack is slow, and calling - * it for every pairwise comparison here is nasty. Need to - * change this to (not-yet-existent) architecture where the - * item count can be calculated once in a deferred way, and - * then stored or cached. - */ - item_count_1 = get_directory_item_count_hack (file_1, FALSE); - item_count_2 = get_directory_item_count_hack (file_2, FALSE); - - if (item_count_1 < item_count_2) - return -1; - - if (item_count_2 < item_count_1) - return +1; - - return 0; -} - -static int -nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2) -{ - gboolean is_directory_1; - gboolean is_directory_2; - char * type_string_1; - char * type_string_2; - int result; - - /* Directories go first. Then, if mime types are identical, - * don't bother getting strings (for speed). This assumes - * that the string is dependent entirely on the mime type, - * which is true now but might not be later. - */ - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && is_directory_2) - return 0; - - if (is_directory_1) - return -1; - - if (is_directory_2) - return +1; - - if (nautilus_strcmp (file_1->info->mime_type, file_2->info->mime_type) == 0) - return 0; - - type_string_1 = nautilus_file_get_type_as_string (file_1); - type_string_2 = nautilus_file_get_type_as_string (file_2); - - result = nautilus_strcmp (type_string_1, type_string_2); - - g_free (type_string_1); - g_free (type_string_2); - - return result; -} - -static int -nautilus_file_compare_for_sort_internal (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type, - gboolean reversed) -{ - GnomeVFSDirectorySortRule *rules; - - g_return_val_if_fail (file_1 != NULL, 0); - g_return_val_if_fail (file_2 != NULL, 0); - g_return_val_if_fail (sort_type != NAUTILUS_FILE_SORT_NONE, 0); - -#define ALLOC_RULES(n) alloca ((n) * sizeof (GnomeVFSDirectorySortRule)) - - switch (sort_type) { - case NAUTILUS_FILE_SORT_BY_NAME: - rules = ALLOC_RULES (2); - /* Note: This used to put directories first. I - * thought that was counterintuitive and removed it, - * but I can imagine discussing this further. - * John Sullivan <sullivan@eazel.com> - */ - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_SIZE: - /* Compare directory sizes ourselves, then if necessary - * use GnomeVFS to compare file sizes. - */ - { - int size_compare; - - size_compare = nautilus_file_compare_by_size_with_directories (file_1, file_2); - if (size_compare != 0) - return size_compare; - } - rules = ALLOC_RULES (3); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYSIZE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_TYPE: - /* GnomeVFS doesn't know about our special text for certain - * mime types, so we handle the mime-type sorting ourselves. - */ - { - int type_compare; - - type_compare = nautilus_file_compare_by_type (file_1, file_2); - if (type_compare != 0) - return type_compare; - } - rules = ALLOC_RULES (2); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_MTIME: - rules = ALLOC_RULES (3); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYMTIME; - rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - default: - g_assert_not_reached (); - return 0; - } - - if (reversed) - return gnome_vfs_file_info_compare_for_sort_reversed (file_1->info, - file_2->info, - rules); - else - return gnome_vfs_file_info_compare_for_sort (file_1->info, - file_2->info, - rules); - -#undef ALLOC_RULES -} - -/** - * nautilus_file_compare_for_sort: - * @file_1: A file object - * @file_2: Another file object - * @sort_type: Sort criterion - * - * Return value: int < 0 if @file_1 should come before file_2 in a smallest-to-largest - * sorted list; int > 0 if @file_2 should come before file_1 in a smallest-to-largest - * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note - * that each named sort type may actually break ties several ways, with the name - * of the sort criterion being the primary but not only differentiator. - **/ -int -nautilus_file_compare_for_sort (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type) -{ - return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, FALSE); -} - -/** - * nautilus_file_compare_for_sort_reversed: - * @file_1: A file object - * @file_2: Another file object - * @sort_type: Sort criterion - * - * Return value: The opposite of nautilus_file_compare_for_sort: int > 0 if @file_1 - * should come before file_2 in a smallest-to-largest sorted list; int < 0 if @file_2 - * should come before file_1 in a smallest-to-largest sorted list; 0 if @file_1 - * and @file_2 are equal for this sort criterion. Note that each named sort type - * may actually break ties several ways, with the name of the sort criterion - * being the primary but not only differentiator. - **/ -int -nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type) -{ - return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, TRUE); -} - -char * -nautilus_file_get_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata) -{ - g_return_val_if_fail (file != NULL, NULL); - - return nautilus_directory_get_file_metadata (file->directory, - file->info->name, - tag, - default_metadata); -} - void -nautilus_file_set_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata, - const char *metadata) +nautilus_directory_files_removed (NautilusDirectory *directory, + GList *removed_files) { - g_return_if_fail (file != NULL); - - nautilus_directory_set_file_metadata (file->directory, - file->info->name, - tag, - default_metadata, - metadata); -} - -char * -nautilus_file_get_name (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - g_assert (file->directory == NULL || NAUTILUS_IS_DIRECTORY (file->directory)); - g_assert (file->info->name != NULL); - g_assert (file->info->name[0] != '\0'); - - return g_strdup (file->info->name); -} - -char * -nautilus_file_get_uri (NautilusFile *file) -{ - GnomeVFSURI *uri; - char *uri_text; - - g_return_val_if_fail (file != NULL, NULL); - g_return_val_if_fail (file->directory != NULL, NULL); - - uri = gnome_vfs_uri_append_path (file->directory->details->uri, file->info->name); - uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (uri); - return uri_text; -} - -/** - * nautilus_file_get_date_as_string: - * - * Get a user-displayable string representing a file modification date. - * The caller is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type) -{ - struct tm *file_time; - const char *format; - GDate *today; - GDate *file_date; - guint32 file_date_age; - - g_return_val_if_fail (file != NULL, NULL); - - switch (date_type) - { - case NAUTILUS_DATE_TYPE_CHANGED: - file_time = localtime(&file->info->ctime); - break; - case NAUTILUS_DATE_TYPE_ACCESSED: - file_time = localtime(&file->info->atime); - break; - case NAUTILUS_DATE_TYPE_MODIFIED: - file_time = localtime(&file->info->mtime); - break; - default: - g_assert_not_reached (); - } - file_date = nautilus_g_date_new_tm (file_time); - - today = g_date_new (); - g_date_set_time (today, time (NULL)); - - /* Overflow results in a large number; fine for our purposes. */ - file_date_age = g_date_julian (today) - g_date_julian (file_date); - - g_date_free (file_date); - g_date_free (today); - - /* Format varies depending on how old the date is. This minimizes - * the length (and thus clutter & complication) of typical dates - * while providing sufficient detail for recent dates to make - * them maximally understandable at a glance. Keep all format - * strings separate rather than combining bits & pieces for - * internationalization's sake. - */ - - if (file_date_age == 0) - { - /* today, use special word */ - format = _("today %-I:%M %p"); - } - else if (file_date_age == 1) - { - /* yesterday, use special word */ - format = _("yesterday %-I:%M %p"); - } - else if (file_date_age < 7) - { - /* current week, include day of week */ - format = _("%A %-m/%-d/%y %-I:%M %p"); - } - else - { - format = _("%-m/%-d/%y %-I:%M %p"); - } - - return nautilus_strdup_strftime (format, file_time); -} - -/** - * nautilus_file_get_directory_item_count - * - * Get the number of items in a directory. - * @file: NautilusFile representing a directory. It is an error to - * call this function on a file that is not a directory. - * @ignore_invisible_items: TRUE if invisible items should not be - * included in count. - * - * Returns: item count for this directory. - * - **/ -guint -nautilus_file_get_directory_item_count (NautilusFile *file, - gboolean ignore_invisible_items) -{ - g_return_val_if_fail (nautilus_file_is_directory (file), 0); - - return get_directory_item_count_hack (file, ignore_invisible_items); -} - -/** - * nautilus_file_get_size - * - * Get the file size. - * @file: NautilusFile representing the file in question. - * - * Returns: Size in bytes. - * - **/ -GnomeVFSFileSize -nautilus_file_get_size (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, 0); - - return file->info->size; -} - -/** - * nautilus_file_get_permissions_as_string: - * - * Get a user-displayable string representing a file's permissions. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_permissions_as_string (NautilusFile *file) -{ - GnomeVFSFilePermissions permissions; - gboolean is_directory; - gboolean is_link; - - permissions = file->info->permissions; - is_directory = nautilus_file_is_directory (file); - is_link = GNOME_VFS_FILE_INFO_SYMLINK(file->info); - - return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", - is_link ? 'l' : is_directory ? 'd' : '-', - permissions & GNOME_VFS_PERM_USER_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_USER_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_USER_EXEC ? 'x' : '-', - permissions & GNOME_VFS_PERM_GROUP_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_GROUP_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_GROUP_EXEC ? 'x' : '-', - permissions & GNOME_VFS_PERM_OTHER_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_OTHER_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_OTHER_EXEC ? 'x' : '-'); -} - -/** - * nautilus_file_get_owner_as_string: - * - * Get a user-displayable string representing a file's owner. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_owner_as_string (NautilusFile *file) -{ - struct passwd *password_info; - - /* FIXME: Can we trust the uid in the file info? Might - * there be garbage there? What will it do for non-local files? - */ - /* No need to free result of getpwuid */ - password_info = getpwuid (file->info->uid); - - g_print ("pointer to password info is %p\n", password_info); - - if (password_info == NULL) - { - return g_strdup (_("unknown owner")); - } - - return g_strdup (password_info->pw_name); -} - -/** - * nautilus_file_get_group_as_string: - * - * Get a user-displayable string representing a file's group. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_group_as_string (NautilusFile *file) -{ - struct group *group_info; - - /* FIXME: Can we trust the gid in the file info? Might - * there be garbage there? What will it do for non-local files? - */ - /* No need to free result of getgrgid */ - group_info = getgrgid (file->info->gid); - - if (group_info == NULL) - { - return g_strdup (_("unknown group")); - } - - return g_strdup (group_info->gr_name); -} - - -/* This #include is part of the following hack, and should be removed with it */ -#include <dirent.h> - -static int -get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items) -{ - /* Code borrowed from Gnomad and hacked into here for now */ - - char * uri; - char * path; - DIR* directory; - int count; - struct dirent * entry; - - g_assert (nautilus_file_is_directory (file)); - - uri = nautilus_file_get_uri (file); - if (nautilus_has_prefix (uri, "file://")) - path = uri + 7; - else - path = uri; - - directory = opendir (path); - - g_free (uri); - - if (!directory) - return 0; - - count = 0; - - while ((entry = readdir(directory)) != NULL) - // Only count invisible items if requested. - if (!ignore_invisible_items || entry->d_name[0] != '.') - count += 1; - - closedir(directory); - - /* This way of getting the count includes . and .., so we subtract those out */ - if (!ignore_invisible_items) { - count -= 2; - } - - return count; -} - -/** - * nautilus_file_get_size_as_string: - * - * Get a user-displayable string representing a file size. The caller - * is responsible for g_free-ing this string. The string is an item - * count for directories. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_size_as_string (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - if (nautilus_file_is_directory (file)) - { - /* FIXME: Since computing the item count is slow, we - * want to do it in a deferred way. However, that - * architecture doesn't exist yet, so we're hacking - * it in for now. - */ - int item_count; - - item_count = get_directory_item_count_hack (file, FALSE); - if (item_count == 0) { - return g_strdup (_("0 items")); - } else if (item_count == 1) { - return g_strdup (_("1 item")); - } else { - return g_strdup_printf (_("%d items"), item_count); - } - } - - return gnome_vfs_file_size_to_string (file->info->size); -} - -/** - * nautilus_file_get_string_attribute: - * - * Get a user-displayable string from a named attribute. Use g_free to - * free this string. - * - * @file: NautilusFile representing the file in question. - * @attribute_name: The name of the desired attribute. The currently supported - * set includes "name", "type", "size", "date_modified", "date_changed", - * "date_accessed", "owner", "group", "permissions". - * - * Returns: Newly allocated string ready to display to the user, or NULL - * if @attribute_name is not supported. - * - **/ -char * -nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) -{ - /* FIXME: Use hash table and switch statement or function pointers for speed? */ - - if (strcmp (attribute_name, "name") == 0) { - return nautilus_file_get_name (file); - } - - if (strcmp (attribute_name, "type") == 0) { - return nautilus_file_get_type_as_string (file); - } - - if (strcmp (attribute_name, "size") == 0) { - return nautilus_file_get_size_as_string (file); - } - - if (strcmp (attribute_name, "date_modified") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_MODIFIED); - } - - if (strcmp (attribute_name, "date_changed") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_CHANGED); - } - - if (strcmp (attribute_name, "date_accessed") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_ACCESSED); - } - - if (strcmp (attribute_name, "permissions") == 0) { - return nautilus_file_get_permissions_as_string (file); - } - - if (strcmp (attribute_name, "owner") == 0) { - return nautilus_file_get_owner_as_string (file); - } - - if (strcmp (attribute_name, "group") == 0) { - return nautilus_file_get_group_as_string (file); - } - - return NULL; -} - -/** - * nautilus_file_get_type_as_string: - * - * Get a user-displayable string representing a file type. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_type_as_string (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - if (nautilus_file_is_directory (file)) { - /* Special-case this so it isn't "special/directory". - * FIXME: Should this be "folder" instead? - */ - return g_strdup (_("directory")); - } - - if (nautilus_strlen (file->info->mime_type) == 0) { - return g_strdup (_("unknown type")); - } - - return g_strdup (file->info->mime_type); -} - -/** - * nautilus_file_get_type - * - * Return this file's type. - * @file: NautilusFile representing the file in question. - * - * Returns: The type. - * - **/ -GnomeVFSFileType -nautilus_file_get_type (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->info->type; -} - -/** - * nautilus_file_get_mime_type - * - * Return this file's mime type. - * @file: NautilusFile representing the file in question. - * - * Returns: The mime type. - * - **/ -const char * -nautilus_file_get_mime_type (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->info->mime_type; -} - -/** - * nautilus_file_get_keywords - * - * Return this file's keywords. - * @file: NautilusFile representing the file in question. - * - * Returns: A list of keywords. - * - **/ -GList * -nautilus_file_get_keywords (NautilusFile *file) -{ - GList *keywords; - xmlNode *file_node, *child; - xmlChar *property; - - g_return_val_if_fail (file != NULL, NULL); - - keywords = NULL; - - /* Put all the keywords into a list. */ - file_node = get_file_metadata_node (file->directory, file->info->name); - if (file_node != NULL) { - for (child = file_node->childs; child != NULL; child = child->next) { - if (strcmp (child->name, "KEYWORD") == 0) { - property = xmlGetProp (child, "NAME"); - if (property != NULL) { - keywords = g_list_prepend (keywords, - g_strdup (property)); - } - } - } - } - - return g_list_reverse (keywords); -} - -/** - * nautilus_file_is_symbolic_link - * - * Check if this file is a symbolic link. - * @file: NautilusFile representing the file in question. - * - * Returns: True if the file is a symbolic link. - * - **/ -gboolean -nautilus_file_is_symbolic_link (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return GNOME_VFS_FILE_INFO_SYMLINK (file->info); -} - -/** - * nautilus_file_is_directory - * - * Check if this file is a directory. - * @file: NautilusFile representing the file in question. - * - * Returns: TRUE if @file is a directory. - * - **/ -gboolean -nautilus_file_is_directory (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return nautilus_file_get_type (file) == GNOME_VFS_FILE_TYPE_DIRECTORY; -} - -/** - * nautilus_file_is_executable - * - * Check if this file is executable at all. - * @file: NautilusFile representing the file in question. - * - * Returns: True if any of the execute bits are set. - * - **/ -gboolean -nautilus_file_is_executable (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return (file->info->flags & (GNOME_VFS_PERM_USER_EXEC - | GNOME_VFS_PERM_GROUP_EXEC - | GNOME_VFS_PERM_OTHER_EXEC)) != 0; -} - -/** - * nautilus_file_delete - * - * Delete this file. - * @file: NautilusFile representing the file in question. - **/ -void -nautilus_file_delete (NautilusFile *file) -{ - char *text_uri; - GnomeVFSResult result; - GList *removed_files; - - g_return_if_fail (file != NULL); - - /* Deleting a file that's already gone is easy. */ - if (file->is_gone) { - return; - } - - /* Do the actual deletion. */ - text_uri = nautilus_file_get_uri (file); - if (nautilus_file_is_directory (file)) { - result = gnome_vfs_remove_directory (text_uri); - } else { - result = gnome_vfs_unlink (text_uri); - } - g_free (text_uri); - - /* Mark the file gone. */ - if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_NOTFOUND) { - file->is_gone = TRUE; - - /* Let the directory know it's gone. */ - if (file->directory != NULL) { - g_list_remove (file->directory->details->files, file); - - /* Send out a message. */ - removed_files = g_list_prepend (NULL, file); - gtk_signal_emit (GTK_OBJECT (file->directory), - nautilus_directory_signals[FILES_REMOVED], - removed_files); - g_list_free (removed_files); - } - } -} - -/** - * nautilus_file_is_gone - * - * Check if a file has already been deleted. - * @file: NautilusFile representing the file in question. - * - * Returns: TRUE if the file is already gone. - **/ -gboolean -nautilus_file_is_gone (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->is_gone; -} - -/** - * nautilus_file_list_ref - * - * Ref all the files in a list. - * @file_list: GList of files. - **/ -void -nautilus_file_list_ref (GList *file_list) -{ - g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); -} - -/** - * nautilus_file_list_unref - * - * Unref all the files in a list. - * @file_list: GList of files. - **/ -void -nautilus_file_list_unref (GList *file_list) -{ - g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); -} - -/** - * nautilus_file_list_free - * - * Free a list of files after unrefing them. - * @file_list: GList of files. - **/ -void -nautilus_file_list_free (GList *file_list) -{ - nautilus_file_list_unref (file_list); - g_list_free (file_list); + gtk_signal_emit (GTK_OBJECT (directory), + nautilus_directory_signals[FILES_REMOVED], + removed_files); } #if !defined (NAUTILUS_OMIT_SELF_CHECK) diff --git a/libnautilus-extensions/nautilus-directory.h b/libnautilus-extensions/nautilus-directory.h index 35058f26b..42ea0451b 100644 --- a/libnautilus-extensions/nautilus-directory.h +++ b/libnautilus-extensions/nautilus-directory.h @@ -26,7 +26,6 @@ #define NAUTILUS_DIRECTORY_H #include <gtk/gtkobject.h> -#include <libgnomevfs/gnome-vfs-types.h> /* NautilusDirectory is a class that manages the model for a directory, real or virtual, for Nautilus, mainly the file-manager component. The directory is @@ -57,21 +56,6 @@ typedef struct NautilusDirectoryClass NautilusDirectoryClass; #define NAUTILUS_IS_DIRECTORY_CLASS(klass) \ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DIRECTORY)) -#define NAUTILUS_IS_FILE(object) \ - ((object) != NULL) - -typedef enum { - NAUTILUS_FILE_SORT_NONE, - NAUTILUS_FILE_SORT_BY_NAME, - NAUTILUS_FILE_SORT_BY_SIZE, - NAUTILUS_FILE_SORT_BY_TYPE, - NAUTILUS_FILE_SORT_BY_MTIME -} NautilusFileSortType; - -typedef struct NautilusFile NautilusFile; - -#define NAUTILUS_FILE(file) ((NautilusFile *)(file)) - typedef void (*NautilusFileListCallback) (NautilusDirectory *directory, GList *files, gpointer callback_data); @@ -124,61 +108,6 @@ void nautilus_directory_stop_monitoring (NautilusDirectory */ gboolean nautilus_directory_are_all_files_seen (NautilusDirectory *directory); -/* Getting at a single file. */ -NautilusFile * nautilus_file_get (const char *uri); - -/* Basic operations on file objects. */ -void nautilus_file_ref (NautilusFile *file); -void nautilus_file_unref (NautilusFile *file); -void nautilus_file_delete (NautilusFile *file); - -/* Basic attributes for file objects. */ -char * nautilus_file_get_name (NautilusFile *file); -char * nautilus_file_get_uri (NautilusFile *file); -GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); -GnomeVFSFileType nautilus_file_get_type (NautilusFile *file); -const char * nautilus_file_get_mime_type (NautilusFile *file); -gboolean nautilus_file_is_symbolic_link (NautilusFile *file); -gboolean nautilus_file_is_executable (NautilusFile *file); -gboolean nautilus_file_is_directory (NautilusFile *file); -guint nautilus_file_get_directory_item_count (NautilusFile *file, - gboolean ignore_invisible_items); -GList * nautilus_file_get_keywords (NautilusFile *file); -void nautilus_file_set_keywords (NautilusFile *file, - GList *keywords); - -/* Simple getting and setting top-level metadata. */ -char * nautilus_file_get_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata); -void nautilus_file_set_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata, - const char *metadata); - -/* Attributes for file objects as user-displayable strings. */ -char * nautilus_file_get_string_attribute (NautilusFile *file, - const char *attribute_name); - -/* Comparing two file objects for sorting */ -int nautilus_file_compare_for_sort (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type); -int nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type); - -/* Convenience functions for dealing with a list of NautilusFile objects that each have a ref. */ -void nautilus_file_list_ref (GList *file_list); -void nautilus_file_list_unref (GList *file_list); -void nautilus_file_list_free (GList *file_list); - -/* Return true if this file has already been deleted. - This object will be unref'd after sending the files_removed signal, - but it could hang around longer if someone ref'd it. -*/ -gboolean nautilus_file_is_gone (NautilusFile *file); - typedef struct NautilusDirectoryDetails NautilusDirectoryDetails; struct NautilusDirectory @@ -201,10 +130,10 @@ struct NautilusDirectoryClass this is the last chance to forget about these file objects which are about to be unref'd. */ - void (* files_added) (NautilusDirectory *directory, - GList *added_files); - void (* files_removed) (NautilusDirectory *directory, - GList *removed_files); + void (* files_added) (NautilusDirectory *directory, + GList *added_files); + void (* files_removed) (NautilusDirectory *directory, + GList *removed_files); /* The files_changed signal is emitted as changes occur to existing files that are noticed by the synchronization framework. diff --git a/libnautilus-extensions/nautilus-file-private.h b/libnautilus-extensions/nautilus-file-private.h new file mode 100644 index 000000000..7ee311c9b --- /dev/null +++ b/libnautilus-extensions/nautilus-file-private.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include "nautilus-file.h" +#include "nautilus-directory.h" + +struct NautilusFile +{ + guint ref_count; + + NautilusDirectory *directory; + GnomeVFSFileInfo *info; + gboolean is_gone; +}; + +void nautilus_file_free (NautilusFile *); diff --git a/libnautilus-extensions/nautilus-file.c b/libnautilus-extensions/nautilus-file.c new file mode 100644 index 000000000..56efacead --- /dev/null +++ b/libnautilus-extensions/nautilus-file.c @@ -0,0 +1,1014 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-file.c: Nautilus file model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include <config.h> +#include "nautilus-file-private.h" + +#include <grp.h> +#include <pwd.h> + +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> + +#include "nautilus-glib-extensions.h" +#include "nautilus-string.h" +#include "nautilus-directory-private.h" + +typedef enum { + NAUTILUS_DATE_TYPE_MODIFIED, + NAUTILUS_DATE_TYPE_CHANGED, + NAUTILUS_DATE_TYPE_ACCESSED +} NautilusDateType; + +/* FIXME: This hack needs to die eventually. See comments with function */ +static int get_directory_item_count_hack (NautilusFile *file, + gboolean ignore_invisible_items); + +static int nautilus_file_compare_by_type (NautilusFile *file_1, + NautilusFile *file_2); +static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type, + gboolean reversed); +static char *nautilus_file_get_date_as_string (NautilusFile *file, + NautilusDateType date_type); +static char *nautilus_file_get_owner_as_string (NautilusFile *file); +static char *nautilus_file_get_group_as_string (NautilusFile *file); +static char *nautilus_file_get_permissions_as_string (NautilusFile *file); +static char *nautilus_file_get_size_as_string (NautilusFile *file); +static char *nautilus_file_get_type_as_string (NautilusFile *file); + +/** + * nautilus_file_get: + * @uri: URI of file to get. + * + * Get a file given a uri. + * Returns a referenced object. Unref when finished. + * If two windows are viewing the same uri, the file object is shared. + */ +NautilusFile * +nautilus_file_get (const char *uri) +{ + GnomeVFSResult result; + GnomeVFSFileInfo *file_info; + GnomeVFSURI *vfs_uri, *directory_vfs_uri; + char *directory_uri; + NautilusDirectory *directory; + NautilusFile *file; + + /* Get info on the file. */ + file_info = gnome_vfs_file_info_new (); + result = gnome_vfs_get_file_info (uri, file_info, + GNOME_VFS_FILE_INFO_GETMIMETYPE + | GNOME_VFS_FILE_INFO_FASTMIMETYPE + | GNOME_VFS_FILE_INFO_FOLLOWLINKS, NULL); + if (result != GNOME_VFS_OK) + return NULL; + + /* Make VFS version of URI. */ + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri == NULL) + return NULL; + + /* Make VFS version of directory URI. */ + directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); + gnome_vfs_uri_unref (vfs_uri); + if (directory_vfs_uri == NULL) + return NULL; + + /* Make text version of directory URI. */ + directory_uri = gnome_vfs_uri_to_string (directory_vfs_uri, + GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (directory_vfs_uri); + + /* Get object that represents the directory. */ + directory = nautilus_directory_get (directory_uri); + g_free (directory_uri); + if (directory == NULL) + return NULL; + + file = nautilus_directory_new_file (directory, file_info); + + gnome_vfs_file_info_unref (file_info); + nautilus_file_ref (file); + gtk_object_unref (GTK_OBJECT (directory)); + + return file; +} + +void +nautilus_file_ref (NautilusFile *file) +{ + g_return_if_fail (file != NULL); + + g_assert (file->ref_count < G_MAXINT); + g_assert (file->directory != NULL); + + /* Increment the ref count. */ + if (file->ref_count++ != 0) { + return; + } + + /* As soon as someone other than the directory holds a ref, + * we need to hold the directory too. */ + gtk_object_ref (GTK_OBJECT (file->directory)); +} + +void +nautilus_file_unref (NautilusFile *file) +{ + g_return_if_fail (file != NULL); + + g_assert (file->ref_count != 0); + g_assert (file->directory != NULL); + + /* Decrement the ref count. */ + if (--file->ref_count != 0) { + return; + } + + /* No references left, so it's time to release our hold on the directory. */ + gtk_object_unref (GTK_OBJECT (file->directory)); + if (file->is_gone) { + nautilus_file_free (file); + } +} + +void +nautilus_file_free (NautilusFile *file) +{ + g_assert (file->ref_count == 0); + + /* Destroy the file object. */ + gnome_vfs_file_info_unref (file->info); + g_free (file); +} + +static int +nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2) +{ + gboolean is_directory_1; + gboolean is_directory_2; + int item_count_1; + int item_count_2; + + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && !is_directory_2) + return -1; + + if (is_directory_2 && !is_directory_1) + return +1; + + if (!is_directory_1 && !is_directory_2) + return 0; + + /* Both are directories, compare by item count. */ + /* FIXME: get_directory_item_count_hack is slow, and calling + * it for every pairwise comparison here is nasty. Need to + * change this to (not-yet-existent) architecture where the + * item count can be calculated once in a deferred way, and + * then stored or cached. + */ + item_count_1 = get_directory_item_count_hack (file_1, FALSE); + item_count_2 = get_directory_item_count_hack (file_2, FALSE); + + if (item_count_1 < item_count_2) + return -1; + + if (item_count_2 < item_count_1) + return +1; + + return 0; +} + +static int +nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2) +{ + gboolean is_directory_1; + gboolean is_directory_2; + char * type_string_1; + char * type_string_2; + int result; + + /* Directories go first. Then, if mime types are identical, + * don't bother getting strings (for speed). This assumes + * that the string is dependent entirely on the mime type, + * which is true now but might not be later. + */ + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && is_directory_2) + return 0; + + if (is_directory_1) + return -1; + + if (is_directory_2) + return +1; + + if (nautilus_strcmp (file_1->info->mime_type, file_2->info->mime_type) == 0) + return 0; + + type_string_1 = nautilus_file_get_type_as_string (file_1); + type_string_2 = nautilus_file_get_type_as_string (file_2); + + result = nautilus_strcmp (type_string_1, type_string_2); + + g_free (type_string_1); + g_free (type_string_2); + + return result; +} + +static int +nautilus_file_compare_for_sort_internal (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type, + gboolean reversed) +{ + GnomeVFSDirectorySortRule rules[3]; + int compare; + + g_return_val_if_fail (file_1 != NULL, 0); + g_return_val_if_fail (file_2 != NULL, 0); + g_return_val_if_fail (sort_type != NAUTILUS_FILE_SORT_NONE, 0); + + switch (sort_type) { + case NAUTILUS_FILE_SORT_BY_NAME: + /* Note: This used to put directories first. I + * thought that was counterintuitive and removed it, + * but I can imagine discussing this further. + * John Sullivan <sullivan@eazel.com> + */ + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_SIZE: + /* Compare directory sizes ourselves, then if necessary + * use GnomeVFS to compare file sizes. + */ + compare = nautilus_file_compare_by_size_with_directories (file_1, file_2); + if (compare != 0) { + return compare; + } + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYSIZE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_TYPE: + /* GnomeVFS doesn't know about our special text for certain + * mime types, so we handle the mime-type sorting ourselves. + */ + compare = nautilus_file_compare_by_type (file_1, file_2); + if (compare != 0) { + return compare; + } + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_MTIME: + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYMTIME; + rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + default: + g_assert_not_reached (); + return 0; + } + + if (reversed) + return gnome_vfs_file_info_compare_for_sort_reversed (file_1->info, + file_2->info, + rules); + else + return gnome_vfs_file_info_compare_for_sort (file_1->info, + file_2->info, + rules); +} + +/** + * nautilus_file_compare_for_sort: + * @file_1: A file object + * @file_2: Another file object + * @sort_type: Sort criterion + * + * Return value: int < 0 if @file_1 should come before file_2 in a smallest-to-largest + * sorted list; int > 0 if @file_2 should come before file_1 in a smallest-to-largest + * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note + * that each named sort type may actually break ties several ways, with the name + * of the sort criterion being the primary but not only differentiator. + **/ +int +nautilus_file_compare_for_sort (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type) +{ + return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, FALSE); +} + +/** + * nautilus_file_compare_for_sort_reversed: + * @file_1: A file object + * @file_2: Another file object + * @sort_type: Sort criterion + * + * Return value: The opposite of nautilus_file_compare_for_sort: int > 0 if @file_1 + * should come before file_2 in a smallest-to-largest sorted list; int < 0 if @file_2 + * should come before file_1 in a smallest-to-largest sorted list; 0 if @file_1 + * and @file_2 are equal for this sort criterion. Note that each named sort type + * may actually break ties several ways, with the name of the sort criterion + * being the primary but not only differentiator. + **/ +int +nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type) +{ + return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, TRUE); +} + +char * +nautilus_file_get_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata) +{ + g_return_val_if_fail (file != NULL, NULL); + + return nautilus_directory_get_file_metadata (file->directory, + file->info->name, + tag, + default_metadata); +} + +void +nautilus_file_set_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata, + const char *metadata) +{ + g_return_if_fail (file != NULL); + + nautilus_directory_set_file_metadata (file->directory, + file->info->name, + tag, + default_metadata, + metadata); +} + +char * +nautilus_file_get_name (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + g_assert (file->directory == NULL || NAUTILUS_IS_DIRECTORY (file->directory)); + g_assert (file->info->name != NULL); + g_assert (file->info->name[0] != '\0'); + + return g_strdup (file->info->name); +} + +char * +nautilus_file_get_uri (NautilusFile *file) +{ + GnomeVFSURI *uri; + char *uri_text; + + g_return_val_if_fail (file != NULL, NULL); + g_return_val_if_fail (file->directory != NULL, NULL); + + uri = gnome_vfs_uri_append_path (file->directory->details->uri, file->info->name); + uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (uri); + return uri_text; +} + +/** + * nautilus_file_get_date_as_string: + * + * Get a user-displayable string representing a file modification date. + * The caller is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type) +{ + struct tm *file_time; + const char *format; + GDate *today; + GDate *file_date; + guint32 file_date_age; + + g_return_val_if_fail (file != NULL, NULL); + + switch (date_type) + { + case NAUTILUS_DATE_TYPE_CHANGED: + file_time = localtime(&file->info->ctime); + break; + case NAUTILUS_DATE_TYPE_ACCESSED: + file_time = localtime(&file->info->atime); + break; + case NAUTILUS_DATE_TYPE_MODIFIED: + file_time = localtime(&file->info->mtime); + break; + default: + g_assert_not_reached (); + } + file_date = nautilus_g_date_new_tm (file_time); + + today = g_date_new (); + g_date_set_time (today, time (NULL)); + + /* Overflow results in a large number; fine for our purposes. */ + file_date_age = g_date_julian (today) - g_date_julian (file_date); + + g_date_free (file_date); + g_date_free (today); + + /* Format varies depending on how old the date is. This minimizes + * the length (and thus clutter & complication) of typical dates + * while providing sufficient detail for recent dates to make + * them maximally understandable at a glance. Keep all format + * strings separate rather than combining bits & pieces for + * internationalization's sake. + */ + + if (file_date_age == 0) + { + /* today, use special word */ + format = _("today %-I:%M %p"); + } + else if (file_date_age == 1) + { + /* yesterday, use special word */ + format = _("yesterday %-I:%M %p"); + } + else if (file_date_age < 7) + { + /* current week, include day of week */ + format = _("%A %-m/%-d/%y %-I:%M %p"); + } + else + { + format = _("%-m/%-d/%y %-I:%M %p"); + } + + return nautilus_strdup_strftime (format, file_time); +} + +/** + * nautilus_file_get_directory_item_count + * + * Get the number of items in a directory. + * @file: NautilusFile representing a directory. It is an error to + * call this function on a file that is not a directory. + * @ignore_invisible_items: TRUE if invisible items should not be + * included in count. + * + * Returns: item count for this directory. + * + **/ +guint +nautilus_file_get_directory_item_count (NautilusFile *file, + gboolean ignore_invisible_items) +{ + g_return_val_if_fail (nautilus_file_is_directory (file), 0); + + return get_directory_item_count_hack (file, ignore_invisible_items); +} + +/** + * nautilus_file_get_size + * + * Get the file size. + * @file: NautilusFile representing the file in question. + * + * Returns: Size in bytes. + * + **/ +GnomeVFSFileSize +nautilus_file_get_size (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, 0); + + return file->info->size; +} + +/** + * nautilus_file_get_permissions_as_string: + * + * Get a user-displayable string representing a file's permissions. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_permissions_as_string (NautilusFile *file) +{ + GnomeVFSFilePermissions permissions; + gboolean is_directory; + gboolean is_link; + + permissions = file->info->permissions; + is_directory = nautilus_file_is_directory (file); + is_link = GNOME_VFS_FILE_INFO_SYMLINK(file->info); + + return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", + is_link ? 'l' : is_directory ? 'd' : '-', + permissions & GNOME_VFS_PERM_USER_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_USER_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_USER_EXEC ? 'x' : '-', + permissions & GNOME_VFS_PERM_GROUP_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_GROUP_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_GROUP_EXEC ? 'x' : '-', + permissions & GNOME_VFS_PERM_OTHER_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_OTHER_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_OTHER_EXEC ? 'x' : '-'); +} + +/** + * nautilus_file_get_owner_as_string: + * + * Get a user-displayable string representing a file's owner. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_owner_as_string (NautilusFile *file) +{ + struct passwd *password_info; + + /* FIXME: Can we trust the uid in the file info? Might + * there be garbage there? What will it do for non-local files? + */ + /* No need to free result of getpwuid */ + password_info = getpwuid (file->info->uid); + + g_print ("pointer to password info is %p\n", password_info); + + if (password_info == NULL) + { + return g_strdup (_("unknown owner")); + } + + return g_strdup (password_info->pw_name); +} + +/** + * nautilus_file_get_group_as_string: + * + * Get a user-displayable string representing a file's group. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_group_as_string (NautilusFile *file) +{ + struct group *group_info; + + /* FIXME: Can we trust the gid in the file info? Might + * there be garbage there? What will it do for non-local files? + */ + /* No need to free result of getgrgid */ + group_info = getgrgid (file->info->gid); + + if (group_info == NULL) + { + return g_strdup (_("unknown group")); + } + + return g_strdup (group_info->gr_name); +} + + +/* This #include is part of the following hack, and should be removed with it */ +#include <dirent.h> + +static int +get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items) +{ + /* Code borrowed from Gnomad and hacked into here for now */ + + char * uri; + char * path; + DIR* directory; + int count; + struct dirent * entry; + + g_assert (nautilus_file_is_directory (file)); + + uri = nautilus_file_get_uri (file); + if (nautilus_has_prefix (uri, "file://")) + path = uri + 7; + else + path = uri; + + directory = opendir (path); + + g_free (uri); + + if (!directory) + return 0; + + count = 0; + + while ((entry = readdir(directory)) != NULL) + // Only count invisible items if requested. + if (!ignore_invisible_items || entry->d_name[0] != '.') + count += 1; + + closedir(directory); + + /* This way of getting the count includes . and .., so we subtract those out */ + if (!ignore_invisible_items) { + count -= 2; + } + + return count; +} + +/** + * nautilus_file_get_size_as_string: + * + * Get a user-displayable string representing a file size. The caller + * is responsible for g_free-ing this string. The string is an item + * count for directories. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_size_as_string (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + if (nautilus_file_is_directory (file)) + { + /* FIXME: Since computing the item count is slow, we + * want to do it in a deferred way. However, that + * architecture doesn't exist yet, so we're hacking + * it in for now. + */ + int item_count; + + item_count = get_directory_item_count_hack (file, FALSE); + if (item_count == 0) { + return g_strdup (_("0 items")); + } else if (item_count == 1) { + return g_strdup (_("1 item")); + } else { + return g_strdup_printf (_("%d items"), item_count); + } + } + + return gnome_vfs_file_size_to_string (file->info->size); +} + +/** + * nautilus_file_get_string_attribute: + * + * Get a user-displayable string from a named attribute. Use g_free to + * free this string. + * + * @file: NautilusFile representing the file in question. + * @attribute_name: The name of the desired attribute. The currently supported + * set includes "name", "type", "size", "date_modified", "date_changed", + * "date_accessed", "owner", "group", "permissions". + * + * Returns: Newly allocated string ready to display to the user, or NULL + * if @attribute_name is not supported. + * + **/ +char * +nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) +{ + /* FIXME: Use hash table and switch statement or function pointers for speed? */ + + if (strcmp (attribute_name, "name") == 0) { + return nautilus_file_get_name (file); + } + + if (strcmp (attribute_name, "type") == 0) { + return nautilus_file_get_type_as_string (file); + } + + if (strcmp (attribute_name, "size") == 0) { + return nautilus_file_get_size_as_string (file); + } + + if (strcmp (attribute_name, "date_modified") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_MODIFIED); + } + + if (strcmp (attribute_name, "date_changed") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_CHANGED); + } + + if (strcmp (attribute_name, "date_accessed") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_ACCESSED); + } + + if (strcmp (attribute_name, "permissions") == 0) { + return nautilus_file_get_permissions_as_string (file); + } + + if (strcmp (attribute_name, "owner") == 0) { + return nautilus_file_get_owner_as_string (file); + } + + if (strcmp (attribute_name, "group") == 0) { + return nautilus_file_get_group_as_string (file); + } + + return NULL; +} + +/** + * nautilus_file_get_type_as_string: + * + * Get a user-displayable string representing a file type. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_type_as_string (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + if (nautilus_file_is_directory (file)) { + /* Special-case this so it isn't "special/directory". + * FIXME: Should this be "folder" instead? + */ + return g_strdup (_("directory")); + } + + if (nautilus_strlen (file->info->mime_type) == 0) { + return g_strdup (_("unknown type")); + } + + return g_strdup (file->info->mime_type); +} + +/** + * nautilus_file_get_type + * + * Return this file's type. + * @file: NautilusFile representing the file in question. + * + * Returns: The type. + * + **/ +GnomeVFSFileType +nautilus_file_get_type (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->info->type; +} + +/** + * nautilus_file_get_mime_type + * + * Return this file's mime type. + * @file: NautilusFile representing the file in question. + * + * Returns: The mime type. + * + **/ +const char * +nautilus_file_get_mime_type (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->info->mime_type; +} + +/** + * nautilus_file_get_keywords + * + * Return this file's keywords. + * @file: NautilusFile representing the file in question. + * + * Returns: A list of keywords. + * + **/ +GList * +nautilus_file_get_keywords (NautilusFile *file) +{ + GList *keywords; + xmlNode *file_node, *child; + xmlChar *property; + + g_return_val_if_fail (file != NULL, NULL); + + keywords = NULL; + + /* Put all the keywords into a list. */ + file_node = nautilus_directory_get_file_metadata_node (file->directory, file->info->name); + if (file_node != NULL) { + for (child = file_node->childs; child != NULL; child = child->next) { + if (strcmp (child->name, "KEYWORD") == 0) { + property = xmlGetProp (child, "NAME"); + if (property != NULL) { + keywords = g_list_prepend (keywords, + g_strdup (property)); + } + } + } + } + + return g_list_reverse (keywords); +} + +/** + * nautilus_file_is_symbolic_link + * + * Check if this file is a symbolic link. + * @file: NautilusFile representing the file in question. + * + * Returns: True if the file is a symbolic link. + * + **/ +gboolean +nautilus_file_is_symbolic_link (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return GNOME_VFS_FILE_INFO_SYMLINK (file->info); +} + +/** + * nautilus_file_is_directory + * + * Check if this file is a directory. + * @file: NautilusFile representing the file in question. + * + * Returns: TRUE if @file is a directory. + * + **/ +gboolean +nautilus_file_is_directory (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return nautilus_file_get_type (file) == GNOME_VFS_FILE_TYPE_DIRECTORY; +} + +/** + * nautilus_file_is_executable + * + * Check if this file is executable at all. + * @file: NautilusFile representing the file in question. + * + * Returns: True if any of the execute bits are set. + * + **/ +gboolean +nautilus_file_is_executable (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return (file->info->flags & (GNOME_VFS_PERM_USER_EXEC + | GNOME_VFS_PERM_GROUP_EXEC + | GNOME_VFS_PERM_OTHER_EXEC)) != 0; +} + +/** + * nautilus_file_delete + * + * Delete this file. + * @file: NautilusFile representing the file in question. + **/ +void +nautilus_file_delete (NautilusFile *file) +{ + char *text_uri; + GnomeVFSResult result; + GList *removed_files; + + g_return_if_fail (file != NULL); + + /* Deleting a file that's already gone is easy. */ + if (file->is_gone) { + return; + } + + /* Do the actual deletion. */ + text_uri = nautilus_file_get_uri (file); + if (nautilus_file_is_directory (file)) { + result = gnome_vfs_remove_directory (text_uri); + } else { + result = gnome_vfs_unlink (text_uri); + } + g_free (text_uri); + + /* Mark the file gone. */ + if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_NOTFOUND) { + file->is_gone = TRUE; + + /* Let the directory know it's gone. */ + if (file->directory != NULL) { + g_list_remove (file->directory->details->files, file); + + /* Send out a signal. */ + removed_files = g_list_prepend (NULL, file); + nautilus_directory_files_removed (file->directory, removed_files); + g_list_free (removed_files); + } + } +} + +/** + * nautilus_file_is_gone + * + * Check if a file has already been deleted. + * @file: NautilusFile representing the file in question. + * + * Returns: TRUE if the file is already gone. + **/ +gboolean +nautilus_file_is_gone (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->is_gone; +} + +/** + * nautilus_file_list_ref + * + * Ref all the files in a list. + * @file_list: GList of files. + **/ +void +nautilus_file_list_ref (GList *file_list) +{ + g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); +} + +/** + * nautilus_file_list_unref + * + * Unref all the files in a list. + * @file_list: GList of files. + **/ +void +nautilus_file_list_unref (GList *file_list) +{ + g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); +} + +/** + * nautilus_file_list_free + * + * Free a list of files after unrefing them. + * @file_list: GList of files. + **/ +void +nautilus_file_list_free (GList *file_list) +{ + nautilus_file_list_unref (file_list); + g_list_free (file_list); +} diff --git a/libnautilus-extensions/nautilus-file.h b/libnautilus-extensions/nautilus-file.h new file mode 100644 index 000000000..dc06290b5 --- /dev/null +++ b/libnautilus-extensions/nautilus-file.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-file.h: Nautilus file model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifndef NAUTILUS_FILE_H +#define NAUTILUS_FILE_H + +#include <glib.h> /* gnome-vfs-types.h requires glib.h but doesn't include it */ +#include <libgnomevfs/gnome-vfs-types.h> + +/* NautilusFile is an object used to represent a single element of a + * NautilusDirectory. It's lightweight and relies on NautilusDirectory + * to do most of the work. + */ + +typedef enum { + NAUTILUS_FILE_SORT_NONE, + NAUTILUS_FILE_SORT_BY_NAME, + NAUTILUS_FILE_SORT_BY_SIZE, + NAUTILUS_FILE_SORT_BY_TYPE, + NAUTILUS_FILE_SORT_BY_MTIME +} NautilusFileSortType; + +typedef struct NautilusFile NautilusFile; + +#define NAUTILUS_IS_FILE(object) \ + ((object) != NULL) +#define NAUTILUS_FILE(file) \ + ((NautilusFile *)(file)) + +/* Getting at a single file. */ +NautilusFile * nautilus_file_get (const char *uri); + +/* Basic operations on file objects. */ +void nautilus_file_ref (NautilusFile *file); +void nautilus_file_unref (NautilusFile *file); +void nautilus_file_delete (NautilusFile *file); + +/* Basic attributes for file objects. */ +char * nautilus_file_get_name (NautilusFile *file); +char * nautilus_file_get_uri (NautilusFile *file); +GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); +GnomeVFSFileType nautilus_file_get_type (NautilusFile *file); +const char * nautilus_file_get_mime_type (NautilusFile *file); +gboolean nautilus_file_is_symbolic_link (NautilusFile *file); +gboolean nautilus_file_is_executable (NautilusFile *file); +gboolean nautilus_file_is_directory (NautilusFile *file); +guint nautilus_file_get_directory_item_count (NautilusFile *file, + gboolean ignore_invisible_items); +GList * nautilus_file_get_keywords (NautilusFile *file); +void nautilus_file_set_keywords (NautilusFile *file, + GList *keywords); + +/* Simple getting and setting top-level metadata. */ +char * nautilus_file_get_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata); +void nautilus_file_set_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata, + const char *metadata); + +/* Attributes for file objects as user-displayable strings. */ +char * nautilus_file_get_string_attribute (NautilusFile *file, + const char *attribute_name); + +/* Comparing two file objects for sorting */ +int nautilus_file_compare_for_sort (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type); +int nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type); + +/* Convenience functions for dealing with a list of NautilusFile objects that each have a ref. */ +void nautilus_file_list_ref (GList *file_list); +void nautilus_file_list_unref (GList *file_list); +void nautilus_file_list_free (GList *file_list); + +/* Return true if this file has already been deleted. + This object will be unref'd after sending the files_removed signal, + but it could hang around longer if someone ref'd it. +*/ +gboolean nautilus_file_is_gone (NautilusFile *file); + +#endif /* NAUTILUS_FILE_H */ diff --git a/libnautilus-extensions/nautilus-icon-factory.h b/libnautilus-extensions/nautilus-icon-factory.h index 545211440..3e7bfa903 100644 --- a/libnautilus-extensions/nautilus-icon-factory.h +++ b/libnautilus-extensions/nautilus-icon-factory.h @@ -2,7 +2,7 @@ nautilus-icon-factory.h: Class for obtaining icons for files and other objects. - * Copyright (C) 1999, 2000 Red Hat Inc. + Copyright (C) 1999, 2000 Red Hat Inc. Copyright (C) 1999, 2000 Eazel, Inc. This program is free software; you can redistribute it and/or @@ -27,7 +27,8 @@ #define NAUTILUS_ICON_FACTORY_H #include <gdk-pixbuf/gdk-pixbuf.h> -#include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> +#include <gtk/gtkobject.h> /* NautilusIconFactory is a class that knows how to hand out icons to be * used for representing files and some other objects. It was designed @@ -97,8 +98,8 @@ char * nautilus_icon_factory_get_theme (void); void nautilus_icon_factory_set_theme (const char *theme_name); /* Choose the appropriate icon, but don't render it yet. */ -NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file, - void *controller); +NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file, + void *controller); NautilusScalableIcon *nautilus_icon_factory_get_icon_by_name (const char *icon_name); GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file); diff --git a/libnautilus-extensions/nautilus-string.c b/libnautilus-extensions/nautilus-string.c index d2df8e286..c3ac00d5e 100644 --- a/libnautilus-extensions/nautilus-string.c +++ b/libnautilus-extensions/nautilus-string.c @@ -69,10 +69,12 @@ nautilus_has_prefix (const char *haystack_null_allowed, const char *needle_null_ h = haystack_null_allowed == NULL ? "" : haystack_null_allowed; n = needle_null_allowed == NULL ? "" : needle_null_allowed; do { - if (*n == '\0') + if (*n == '\0') { return TRUE; - if (*h == '\0') + } + if (*h == '\0') { return FALSE; + } } while (*h++ == *n++); return FALSE; } @@ -82,19 +84,23 @@ nautilus_has_suffix (const char *haystack_null_allowed, const char *needle_null_ { const char *h, *n; - if (haystack_null_allowed == NULL) + if (needle_null_allowed == NULL) { return TRUE; - if (needle_null_allowed == NULL) - return FALSE; + } + if (haystack_null_allowed == NULL) { + return needle_null_allowed[0] == '\0'; + } /* Eat one character at a time. */ h = haystack_null_allowed + strlen(haystack_null_allowed); n = needle_null_allowed + strlen(needle_null_allowed); do { - if (n == needle_null_allowed) + if (n == needle_null_allowed) { return TRUE; - if (h == haystack_null_allowed) + } + if (h == haystack_null_allowed) { return FALSE; + } } while (*--h == *--n); return FALSE; } @@ -144,23 +150,28 @@ nautilus_string_to_int (const char *string, int *integer) char *parse_end; /* Check for the case of an empty string. */ - if (string == NULL || *string == '\0') + if (string == NULL || *string == '\0') { return FALSE; + } /* Call the standard library routine to do the conversion. */ errno = 0; result = strtol (string, &parse_end, 0); /* Check that the result is in range. */ - if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) { return FALSE; - if (result < G_MININT || result > G_MAXINT) + } + if (result < G_MININT || result > G_MAXINT) { return FALSE; + } /* Check that all the trailing characters are spaces. */ - while (*parse_end != '\0') - if (!isspace (*parse_end++)) + while (*parse_end != '\0') { + if (!isspace (*parse_end++)) { return FALSE; + } + } /* Return the result. */ *integer = result; @@ -170,27 +181,27 @@ nautilus_string_to_int (const char *string, int *integer) /** * nautilus_strstrip: * Remove all occurrences of a character from a string. The - * original string is modified, and also returned for convenience. + * original string is modified in place, and also returned for convenience. * * @string_null_allowed: The string to be stripped. * @remove_this: The char to remove from @string_null_allowed * * Return value: @string_null_allowed, after removing all occurrences - * of @remove_this. + * of @remove_this. */ char * nautilus_strstrip (char *string_null_allowed, char remove_this) { if (string_null_allowed != NULL) { - char *pos; + char *in, *out; - pos = string_null_allowed; - while (*pos != '\0') { - if (*pos == remove_this) { - g_memmove (pos, pos + 1, strlen (pos)); + in = string_null_allowed; + out = string_null_allowed; + do { + if (*in != remove_this) { + *out++ = *in; } - ++pos; - } + } while (*in++ != '\0'); } return string_null_allowed; @@ -232,7 +243,6 @@ void nautilus_self_check_string (void) { int integer; - char *test_string; NAUTILUS_CHECK_INTEGER_RESULT (nautilus_strlen (NULL), 0); NAUTILUS_CHECK_INTEGER_RESULT (nautilus_strlen (""), 0); @@ -283,6 +293,22 @@ nautilus_self_check_string (void) NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_prefix ("aaa", "aaab"), FALSE); NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_prefix ("aaab", "aaa"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, ""), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("", NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "a"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("aaab", "aaab"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("", "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", ""), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "b"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "ab"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("ab", "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("ab", "b"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("aaa", "baaa"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("baaa", "aaa"), TRUE); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix (NULL, NULL), NULL); NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix (NULL, "foo"), NULL); NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix ("foo", NULL), "foo"); @@ -292,14 +318,11 @@ nautilus_self_check_string (void) NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix ("footle:bar", "tle:"), "foo"); NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (NULL, '_'), NULL); - test_string = g_strdup ("foo"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("_foo"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("foo_"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("_foo_"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("foo"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_foo"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("foo_"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_foo_"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_f_o__o_"), '_'), "foo"); #define TEST_INTEGER_CONVERSION_FUNCTIONS(string, boolean_result, integer_result) \ NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_string_to_int (string, &integer), boolean_result); \ diff --git a/libnautilus-extensions/nautilus-string.h b/libnautilus-extensions/nautilus-string.h index 9d269dcd7..03c778f00 100644 --- a/libnautilus-extensions/nautilus-string.h +++ b/libnautilus-extensions/nautilus-string.h @@ -47,8 +47,8 @@ char * nautilus_strdup_prefix (const char *source_null_allowed, gboolean nautilus_has_suffix (const char *target_null_allowed, const char *suffix_null_allowed); -char * nautilus_strstrip (char *string_null_allowed, - char remove_this); +char * nautilus_strstrip (char *string_null_allowed, + char remove_this); /* Conversions to and from strings. */ diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index 4e65cefad..002601a80 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -27,8 +27,6 @@ libnautilusincludedir=$(includedir)/libnautilus libnautilusinclude_HEADERS= \ bonobo-stream-vfs.h \ gdk-extensions.h \ - gnome-icon-container-dnd.h \ - gnome-icon-container-private.h \ gnome-icon-container.h \ gtkflist.h \ gtkscrollframe.h \ @@ -38,13 +36,13 @@ libnautilusinclude_HEADERS= \ nautilus-bookmark.h \ nautilus-debug.h \ nautilus-directory.h \ + nautilus-file.h \ nautilus-file-utilities.h \ nautilus-glib-extensions.h \ nautilus-gtk-extensions.h \ nautilus-icon-factory.h \ nautilus-icons-controller.h \ nautilus-icons-view-icon-item.h \ - nautilus-lib-self-check-functions.h \ nautilus-metadata.h \ nautilus-mime-type.h \ nautilus-self-checks.h \ @@ -68,6 +66,7 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ nautilus-default-file-icon.c \ nautilus-default-file-icon.h \ nautilus-directory.c \ + nautilus-file.c \ nautilus-file-utilities.c \ nautilus-glib-extensions.c \ nautilus-gtk-extensions.c \ diff --git a/libnautilus-private/gnome-icon-container-dnd.c b/libnautilus-private/gnome-icon-container-dnd.c index 987556da1..1057c984d 100644 --- a/libnautilus-private/gnome-icon-container-dnd.c +++ b/libnautilus-private/gnome-icon-container-dnd.c @@ -816,12 +816,12 @@ gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, gtk_object_getv (GTK_OBJECT (item), 1, &pixbuf_arg); pixbuf = GTK_VALUE_BOXED (pixbuf_arg); - transparent_pixbuf = make_semi_transparent(pixbuf); + transparent_pixbuf = make_semi_transparent (pixbuf); gdk_pixbuf_render_pixmap_and_mask (transparent_pixbuf, &pixmap_for_dragged_file, &mask_for_dragged_file, 128); - gdk_pixbuf_unref(transparent_pixbuf); + gdk_pixbuf_unref (transparent_pixbuf); /* compute the image's offset */ nautilus_icons_view_icon_item_get_icon_window_rectangle diff --git a/libnautilus-private/gnome-icon-container.c b/libnautilus-private/gnome-icon-container.c index 20ada54d2..ddf28423e 100644 --- a/libnautilus-private/gnome-icon-container.c +++ b/libnautilus-private/gnome-icon-container.c @@ -724,15 +724,17 @@ make_icon_visible (GnomeIconContainer *container, icon_get_bounding_box (icon, &x1, &y1, &x2, &y2); - if (y1 < vadj->value) + if (y1 < vadj->value) { gtk_adjustment_set_value (vadj, y1); - else if (y2 > vadj->value + allocation->height) + } else if (y2 > vadj->value + allocation->height) { gtk_adjustment_set_value (vadj, y2 - allocation->height); + } - if (x1 < hadj->value) + if (x1 < hadj->value) { gtk_adjustment_set_value (hadj, x1); - else if (x2 > hadj->value + allocation->width) + } else if (x2 > hadj->value + allocation->width) { gtk_adjustment_set_value (hadj, x2 - allocation->width); + } } static gboolean @@ -2145,6 +2147,17 @@ gnome_icon_container_initialize_class (GnomeIconContainerClass *class) stipple = gdk_bitmap_create_from_data (NULL, stipple_bits, 2, 2); } +static GdkFont * +load_font (const char *name) +{ + GdkFont *font; + + /* FIXME: Eventually we need a runtime check, but an assert is better than nothing. */ + font = gdk_font_load (name); + g_assert (font != NULL); + return font; +} + static void gnome_icon_container_initialize (GnomeIconContainer *container) { @@ -2159,15 +2172,15 @@ gnome_icon_container_initialize (GnomeIconContainer *container) details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD; - /* font table - this isnt exactly proportional, but it looks better than computed */ + /* font table - this isn't exactly proportional, but it looks better than computed */ /* FIXME: read font from metadata and/or preferences */ - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLEST] = gdk_font_load("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLER] = gdk_font_load("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALL] = gdk_font_load("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_STANDARD] = gdk_font_load("-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGE] = gdk_font_load("-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGER] = gdk_font_load("-*-helveticar-medium-r-normal-*-18-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGEST] = gdk_font_load("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLEST] = load_font ("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLER] = load_font ("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALL] = load_font ("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_STANDARD] = load_font ("-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGE] = load_font ("-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGER] = load_font ("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGEST] = load_font ("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); /* FIXME: Read these from preferences. */ details->linger_selection_mode = FALSE; diff --git a/libnautilus-private/nautilus-directory-private.h b/libnautilus-private/nautilus-directory-private.h new file mode 100644 index 000000000..12496a3f6 --- /dev/null +++ b/libnautilus-private/nautilus-directory-private.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include "nautilus-directory.h" + +#include <libgnomevfs/gnome-vfs-types.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-file-info.h> + +#include <gnome-xml/tree.h> + +#include "nautilus-file.h" + +struct NautilusDirectoryDetails +{ + char *uri_text; + GnomeVFSURI *uri; + + GnomeVFSURI *metafile_uri; + GnomeVFSURI *alternate_metafile_uri; + gboolean use_alternate_metafile; + + xmlDoc *metafile_tree; + guint write_metafile_idle_id; + + GnomeVFSAsyncHandle *directory_load_in_progress; + GnomeVFSDirectoryListPosition directory_load_list_last_handled; + + GList *pending_file_info; + guint dequeue_pending_idle_id; + + gboolean directory_loaded; + + GList *files; +}; + +NautilusFile *nautilus_directory_new_file (NautilusDirectory *directory, + GnomeVFSFileInfo *info); +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata); +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata, + const char *metadata); +xmlNode * nautilus_directory_get_file_metadata_node (NautilusDirectory *directory, + const char *file_name); +void nautilus_directory_files_removed (NautilusDirectory *directory, + GList *removed_files); diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c index 643c290db..eaa37ac68 100644 --- a/libnautilus-private/nautilus-directory.c +++ b/libnautilus-private/nautilus-directory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - nautilus-directory.c: Mautilus directory model. + nautilus-directory.c: Nautilus directory model. Copyright (C) 1999, 2000 Eazel, Inc. @@ -23,33 +23,20 @@ */ #include <config.h> -#include "nautilus-directory.h" +#include "nautilus-directory-private.h" -#include <grp.h> -#include <pwd.h> #include <stdlib.h> #include <gtk/gtksignal.h> #include <gtk/gtkmain.h> -#include <libgnome/gnome-defs.h> -#include <libgnome/gnome-i18n.h> - -#include <libgnomevfs/gnome-vfs-types.h> -#include <libgnomevfs/gnome-vfs-uri.h> -#include <libgnomevfs/gnome-vfs-file-info.h> -#include <libgnomevfs/gnome-vfs-ops.h> -#include <libgnomevfs/gnome-vfs-async-ops.h> - #include <gnome-xml/parser.h> -#include <gnome-xml/tree.h> #include <gnome-xml/xmlmemory.h> -#include "nautilus-alloc.h" -#include "nautilus-glib-extensions.h" #include "nautilus-gtk-macros.h" -#include "nautilus-lib-self-check-functions.h" #include "nautilus-string.h" +#include "nautilus-lib-self-check-functions.h" +#include "nautilus-file-private.h" #define METAFILE_NAME ".nautilus-metafile.xml" #define METAFILE_PERMISSIONS (GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE \ @@ -67,12 +54,6 @@ #define DIRECTORY_LOAD_ITEMS_PER_CB 1 -typedef enum { - NAUTILUS_DATE_TYPE_MODIFIED, - NAUTILUS_DATE_TYPE_CHANGED, - NAUTILUS_DATE_TYPE_ACCESSED -} NautilusDateType; - enum { FILES_ADDED, @@ -80,79 +61,25 @@ enum LAST_SIGNAL }; -/* FIXME: This hack needs to die eventually. See comments with function */ -static int get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items); - - static guint nautilus_directory_signals[LAST_SIGNAL]; -static void nautilus_directory_initialize_class (gpointer klass); -static void nautilus_directory_initialize (gpointer object, gpointer klass); -static void nautilus_directory_finalize (GtkObject *object); - -static NautilusDirectory *nautilus_directory_new (const char* uri); - -static void nautilus_directory_read_metafile (NautilusDirectory *directory); -static void nautilus_directory_write_metafile (NautilusDirectory *directory); -static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); -static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); - -static void nautilus_file_free (NautilusFile *file); -static int nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2); -static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type, - gboolean reversed); - -static char * nautilus_file_get_date_as_string (NautilusFile *file, - NautilusDateType date_type); -static char *nautilus_file_get_owner_as_string (NautilusFile *file); -static char *nautilus_file_get_group_as_string (NautilusFile *file); -static char *nautilus_file_get_permissions_as_string (NautilusFile *file); -static char * nautilus_file_get_size_as_string (NautilusFile *file); -static char * nautilus_file_get_type_as_string (NautilusFile *file); -static void nautilus_directory_load_cb (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GnomeVFSDirectoryList *list, - guint entries_read, - gpointer callback_data); -static NautilusFile *nautilus_directory_new_file (NautilusDirectory *directory, - GnomeVFSFileInfo *info); +static void nautilus_directory_initialize_class (gpointer klass); +static void nautilus_directory_initialize (gpointer object, + gpointer klass); +static void nautilus_directory_finalize (GtkObject *object); +static NautilusDirectory *nautilus_directory_new (const char *uri); +static void nautilus_directory_read_metafile (NautilusDirectory *directory); +static void nautilus_directory_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); +static void nautilus_directory_load_cb (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + GnomeVFSDirectoryList *list, + guint entries_read, + gpointer callback_data); NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusDirectory, nautilus_directory, GTK_TYPE_OBJECT) -struct NautilusDirectoryDetails -{ - char *uri_text; - GnomeVFSURI *uri; - - GnomeVFSURI *metafile_uri; - GnomeVFSURI *alternate_metafile_uri; - gboolean use_alternate_metafile; - - xmlDoc *metafile_tree; - guint write_metafile_idle_id; - - GnomeVFSAsyncHandle *directory_load_in_progress; - GnomeVFSDirectoryListPosition directory_load_list_last_handled; - - GList *pending_file_info; - guint dequeue_pending_idle_id; - - gboolean directory_loaded; - - GList *files; -}; - -struct NautilusFile -{ - guint ref_count; - - NautilusDirectory *directory; - GnomeVFSFileInfo *info; - gboolean is_gone; -}; - static GHashTable* directory_objects; static void @@ -1005,9 +932,9 @@ nautilus_directory_set_integer_metadata (NautilusDirectory *directory, g_free (default_as_string); } -static xmlNode * -get_file_metadata_node (NautilusDirectory *directory, - const char *file_name) +xmlNode * +nautilus_directory_get_file_metadata_node (NautilusDirectory *directory, + const char *file_name) { xmlNode *root, *child; xmlChar *property; @@ -1038,18 +965,18 @@ get_file_metadata_node (NautilusDirectory *directory, return NULL; } -static char * +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, const char *file_name, const char *tag, const char *default_metadata) { return nautilus_directory_get_metadata_from_node - (get_file_metadata_node (directory, file_name), + (nautilus_directory_get_file_metadata_node (directory, file_name), tag, default_metadata); } -static void +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, const char *file_name, const char *tag, @@ -1118,7 +1045,7 @@ nautilus_directory_set_file_metadata (NautilusDirectory *directory, nautilus_directory_request_write_metafile (directory); } -static NautilusFile * +NautilusFile * nautilus_directory_new_file (NautilusDirectory *directory, GnomeVFSFileInfo *info) { NautilusFile *file; @@ -1135,973 +1062,13 @@ nautilus_directory_new_file (NautilusDirectory *directory, GnomeVFSFileInfo *inf return file; } -/** - * nautilus_file_get: - * @uri: URI of file to get. - * - * Get a file given a uri. - * Returns a referenced object. Unref when finished. - * If two windows are viewing the same uri, the file object is shared. - */ -NautilusFile * -nautilus_file_get (const char *uri) -{ - GnomeVFSResult result; - GnomeVFSFileInfo *file_info; - GnomeVFSURI *vfs_uri, *directory_vfs_uri; - char *directory_uri; - NautilusDirectory *directory; - NautilusFile *file; - - /* Get info on the file. */ - file_info = gnome_vfs_file_info_new (); - result = gnome_vfs_get_file_info (uri, file_info, - GNOME_VFS_FILE_INFO_GETMIMETYPE - | GNOME_VFS_FILE_INFO_FASTMIMETYPE - | GNOME_VFS_FILE_INFO_FOLLOWLINKS, NULL); - if (result != GNOME_VFS_OK) - return NULL; - - /* Make VFS version of URI. */ - vfs_uri = gnome_vfs_uri_new (uri); - if (vfs_uri == NULL) - return NULL; - - /* Make VFS version of directory URI. */ - directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); - gnome_vfs_uri_unref (vfs_uri); - if (directory_vfs_uri == NULL) - return NULL; - - /* Make text version of directory URI. */ - directory_uri = gnome_vfs_uri_to_string (directory_vfs_uri, - GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (directory_vfs_uri); - - /* Get object that represents the directory. */ - directory = nautilus_directory_get (directory_uri); - g_free (directory_uri); - if (directory == NULL) - return NULL; - - file = nautilus_directory_new_file (directory, file_info); - - gnome_vfs_file_info_unref (file_info); - nautilus_file_ref (file); - gtk_object_unref (GTK_OBJECT (directory)); - - return file; -} - -void -nautilus_file_ref (NautilusFile *file) -{ - g_return_if_fail (file != NULL); - - g_assert (file->ref_count < G_MAXINT); - g_assert (file->directory != NULL); - - /* Increment the ref count. */ - if (file->ref_count++ != 0) { - return; - } - - /* As soon as someone other than the directory holds a ref, - * we need to hold the directory too. */ - gtk_object_ref (GTK_OBJECT (file->directory)); -} - -void -nautilus_file_unref (NautilusFile *file) -{ - g_return_if_fail (file != NULL); - - g_assert (file->ref_count != 0); - g_assert (file->directory != NULL); - - /* Decrement the ref count. */ - if (--file->ref_count != 0) { - return; - } - - /* No references left, so it's time to release our hold on the directory. */ - gtk_object_unref (GTK_OBJECT (file->directory)); - if (file->is_gone) { - nautilus_file_free (file); - } -} - -static void -nautilus_file_free (NautilusFile *file) -{ - g_assert (file->ref_count == 0); - - /* Destroy the file object. */ - gnome_vfs_file_info_unref (file->info); - g_free (file); -} - -static int -nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2) -{ - gboolean is_directory_1; - gboolean is_directory_2; - int item_count_1; - int item_count_2; - - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && !is_directory_2) - return -1; - - if (is_directory_2 && !is_directory_1) - return +1; - - if (!is_directory_1 && !is_directory_2) - return 0; - - /* Both are directories, compare by item count. */ - /* FIXME: get_directory_item_count_hack is slow, and calling - * it for every pairwise comparison here is nasty. Need to - * change this to (not-yet-existent) architecture where the - * item count can be calculated once in a deferred way, and - * then stored or cached. - */ - item_count_1 = get_directory_item_count_hack (file_1, FALSE); - item_count_2 = get_directory_item_count_hack (file_2, FALSE); - - if (item_count_1 < item_count_2) - return -1; - - if (item_count_2 < item_count_1) - return +1; - - return 0; -} - -static int -nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2) -{ - gboolean is_directory_1; - gboolean is_directory_2; - char * type_string_1; - char * type_string_2; - int result; - - /* Directories go first. Then, if mime types are identical, - * don't bother getting strings (for speed). This assumes - * that the string is dependent entirely on the mime type, - * which is true now but might not be later. - */ - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && is_directory_2) - return 0; - - if (is_directory_1) - return -1; - - if (is_directory_2) - return +1; - - if (nautilus_strcmp (file_1->info->mime_type, file_2->info->mime_type) == 0) - return 0; - - type_string_1 = nautilus_file_get_type_as_string (file_1); - type_string_2 = nautilus_file_get_type_as_string (file_2); - - result = nautilus_strcmp (type_string_1, type_string_2); - - g_free (type_string_1); - g_free (type_string_2); - - return result; -} - -static int -nautilus_file_compare_for_sort_internal (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type, - gboolean reversed) -{ - GnomeVFSDirectorySortRule *rules; - - g_return_val_if_fail (file_1 != NULL, 0); - g_return_val_if_fail (file_2 != NULL, 0); - g_return_val_if_fail (sort_type != NAUTILUS_FILE_SORT_NONE, 0); - -#define ALLOC_RULES(n) alloca ((n) * sizeof (GnomeVFSDirectorySortRule)) - - switch (sort_type) { - case NAUTILUS_FILE_SORT_BY_NAME: - rules = ALLOC_RULES (2); - /* Note: This used to put directories first. I - * thought that was counterintuitive and removed it, - * but I can imagine discussing this further. - * John Sullivan <sullivan@eazel.com> - */ - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_SIZE: - /* Compare directory sizes ourselves, then if necessary - * use GnomeVFS to compare file sizes. - */ - { - int size_compare; - - size_compare = nautilus_file_compare_by_size_with_directories (file_1, file_2); - if (size_compare != 0) - return size_compare; - } - rules = ALLOC_RULES (3); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYSIZE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_TYPE: - /* GnomeVFS doesn't know about our special text for certain - * mime types, so we handle the mime-type sorting ourselves. - */ - { - int type_compare; - - type_compare = nautilus_file_compare_by_type (file_1, file_2); - if (type_compare != 0) - return type_compare; - } - rules = ALLOC_RULES (2); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_MTIME: - rules = ALLOC_RULES (3); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYMTIME; - rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - default: - g_assert_not_reached (); - return 0; - } - - if (reversed) - return gnome_vfs_file_info_compare_for_sort_reversed (file_1->info, - file_2->info, - rules); - else - return gnome_vfs_file_info_compare_for_sort (file_1->info, - file_2->info, - rules); - -#undef ALLOC_RULES -} - -/** - * nautilus_file_compare_for_sort: - * @file_1: A file object - * @file_2: Another file object - * @sort_type: Sort criterion - * - * Return value: int < 0 if @file_1 should come before file_2 in a smallest-to-largest - * sorted list; int > 0 if @file_2 should come before file_1 in a smallest-to-largest - * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note - * that each named sort type may actually break ties several ways, with the name - * of the sort criterion being the primary but not only differentiator. - **/ -int -nautilus_file_compare_for_sort (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type) -{ - return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, FALSE); -} - -/** - * nautilus_file_compare_for_sort_reversed: - * @file_1: A file object - * @file_2: Another file object - * @sort_type: Sort criterion - * - * Return value: The opposite of nautilus_file_compare_for_sort: int > 0 if @file_1 - * should come before file_2 in a smallest-to-largest sorted list; int < 0 if @file_2 - * should come before file_1 in a smallest-to-largest sorted list; 0 if @file_1 - * and @file_2 are equal for this sort criterion. Note that each named sort type - * may actually break ties several ways, with the name of the sort criterion - * being the primary but not only differentiator. - **/ -int -nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type) -{ - return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, TRUE); -} - -char * -nautilus_file_get_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata) -{ - g_return_val_if_fail (file != NULL, NULL); - - return nautilus_directory_get_file_metadata (file->directory, - file->info->name, - tag, - default_metadata); -} - void -nautilus_file_set_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata, - const char *metadata) +nautilus_directory_files_removed (NautilusDirectory *directory, + GList *removed_files) { - g_return_if_fail (file != NULL); - - nautilus_directory_set_file_metadata (file->directory, - file->info->name, - tag, - default_metadata, - metadata); -} - -char * -nautilus_file_get_name (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - g_assert (file->directory == NULL || NAUTILUS_IS_DIRECTORY (file->directory)); - g_assert (file->info->name != NULL); - g_assert (file->info->name[0] != '\0'); - - return g_strdup (file->info->name); -} - -char * -nautilus_file_get_uri (NautilusFile *file) -{ - GnomeVFSURI *uri; - char *uri_text; - - g_return_val_if_fail (file != NULL, NULL); - g_return_val_if_fail (file->directory != NULL, NULL); - - uri = gnome_vfs_uri_append_path (file->directory->details->uri, file->info->name); - uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (uri); - return uri_text; -} - -/** - * nautilus_file_get_date_as_string: - * - * Get a user-displayable string representing a file modification date. - * The caller is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type) -{ - struct tm *file_time; - const char *format; - GDate *today; - GDate *file_date; - guint32 file_date_age; - - g_return_val_if_fail (file != NULL, NULL); - - switch (date_type) - { - case NAUTILUS_DATE_TYPE_CHANGED: - file_time = localtime(&file->info->ctime); - break; - case NAUTILUS_DATE_TYPE_ACCESSED: - file_time = localtime(&file->info->atime); - break; - case NAUTILUS_DATE_TYPE_MODIFIED: - file_time = localtime(&file->info->mtime); - break; - default: - g_assert_not_reached (); - } - file_date = nautilus_g_date_new_tm (file_time); - - today = g_date_new (); - g_date_set_time (today, time (NULL)); - - /* Overflow results in a large number; fine for our purposes. */ - file_date_age = g_date_julian (today) - g_date_julian (file_date); - - g_date_free (file_date); - g_date_free (today); - - /* Format varies depending on how old the date is. This minimizes - * the length (and thus clutter & complication) of typical dates - * while providing sufficient detail for recent dates to make - * them maximally understandable at a glance. Keep all format - * strings separate rather than combining bits & pieces for - * internationalization's sake. - */ - - if (file_date_age == 0) - { - /* today, use special word */ - format = _("today %-I:%M %p"); - } - else if (file_date_age == 1) - { - /* yesterday, use special word */ - format = _("yesterday %-I:%M %p"); - } - else if (file_date_age < 7) - { - /* current week, include day of week */ - format = _("%A %-m/%-d/%y %-I:%M %p"); - } - else - { - format = _("%-m/%-d/%y %-I:%M %p"); - } - - return nautilus_strdup_strftime (format, file_time); -} - -/** - * nautilus_file_get_directory_item_count - * - * Get the number of items in a directory. - * @file: NautilusFile representing a directory. It is an error to - * call this function on a file that is not a directory. - * @ignore_invisible_items: TRUE if invisible items should not be - * included in count. - * - * Returns: item count for this directory. - * - **/ -guint -nautilus_file_get_directory_item_count (NautilusFile *file, - gboolean ignore_invisible_items) -{ - g_return_val_if_fail (nautilus_file_is_directory (file), 0); - - return get_directory_item_count_hack (file, ignore_invisible_items); -} - -/** - * nautilus_file_get_size - * - * Get the file size. - * @file: NautilusFile representing the file in question. - * - * Returns: Size in bytes. - * - **/ -GnomeVFSFileSize -nautilus_file_get_size (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, 0); - - return file->info->size; -} - -/** - * nautilus_file_get_permissions_as_string: - * - * Get a user-displayable string representing a file's permissions. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_permissions_as_string (NautilusFile *file) -{ - GnomeVFSFilePermissions permissions; - gboolean is_directory; - gboolean is_link; - - permissions = file->info->permissions; - is_directory = nautilus_file_is_directory (file); - is_link = GNOME_VFS_FILE_INFO_SYMLINK(file->info); - - return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", - is_link ? 'l' : is_directory ? 'd' : '-', - permissions & GNOME_VFS_PERM_USER_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_USER_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_USER_EXEC ? 'x' : '-', - permissions & GNOME_VFS_PERM_GROUP_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_GROUP_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_GROUP_EXEC ? 'x' : '-', - permissions & GNOME_VFS_PERM_OTHER_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_OTHER_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_OTHER_EXEC ? 'x' : '-'); -} - -/** - * nautilus_file_get_owner_as_string: - * - * Get a user-displayable string representing a file's owner. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_owner_as_string (NautilusFile *file) -{ - struct passwd *password_info; - - /* FIXME: Can we trust the uid in the file info? Might - * there be garbage there? What will it do for non-local files? - */ - /* No need to free result of getpwuid */ - password_info = getpwuid (file->info->uid); - - g_print ("pointer to password info is %p\n", password_info); - - if (password_info == NULL) - { - return g_strdup (_("unknown owner")); - } - - return g_strdup (password_info->pw_name); -} - -/** - * nautilus_file_get_group_as_string: - * - * Get a user-displayable string representing a file's group. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_group_as_string (NautilusFile *file) -{ - struct group *group_info; - - /* FIXME: Can we trust the gid in the file info? Might - * there be garbage there? What will it do for non-local files? - */ - /* No need to free result of getgrgid */ - group_info = getgrgid (file->info->gid); - - if (group_info == NULL) - { - return g_strdup (_("unknown group")); - } - - return g_strdup (group_info->gr_name); -} - - -/* This #include is part of the following hack, and should be removed with it */ -#include <dirent.h> - -static int -get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items) -{ - /* Code borrowed from Gnomad and hacked into here for now */ - - char * uri; - char * path; - DIR* directory; - int count; - struct dirent * entry; - - g_assert (nautilus_file_is_directory (file)); - - uri = nautilus_file_get_uri (file); - if (nautilus_has_prefix (uri, "file://")) - path = uri + 7; - else - path = uri; - - directory = opendir (path); - - g_free (uri); - - if (!directory) - return 0; - - count = 0; - - while ((entry = readdir(directory)) != NULL) - // Only count invisible items if requested. - if (!ignore_invisible_items || entry->d_name[0] != '.') - count += 1; - - closedir(directory); - - /* This way of getting the count includes . and .., so we subtract those out */ - if (!ignore_invisible_items) { - count -= 2; - } - - return count; -} - -/** - * nautilus_file_get_size_as_string: - * - * Get a user-displayable string representing a file size. The caller - * is responsible for g_free-ing this string. The string is an item - * count for directories. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_size_as_string (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - if (nautilus_file_is_directory (file)) - { - /* FIXME: Since computing the item count is slow, we - * want to do it in a deferred way. However, that - * architecture doesn't exist yet, so we're hacking - * it in for now. - */ - int item_count; - - item_count = get_directory_item_count_hack (file, FALSE); - if (item_count == 0) { - return g_strdup (_("0 items")); - } else if (item_count == 1) { - return g_strdup (_("1 item")); - } else { - return g_strdup_printf (_("%d items"), item_count); - } - } - - return gnome_vfs_file_size_to_string (file->info->size); -} - -/** - * nautilus_file_get_string_attribute: - * - * Get a user-displayable string from a named attribute. Use g_free to - * free this string. - * - * @file: NautilusFile representing the file in question. - * @attribute_name: The name of the desired attribute. The currently supported - * set includes "name", "type", "size", "date_modified", "date_changed", - * "date_accessed", "owner", "group", "permissions". - * - * Returns: Newly allocated string ready to display to the user, or NULL - * if @attribute_name is not supported. - * - **/ -char * -nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) -{ - /* FIXME: Use hash table and switch statement or function pointers for speed? */ - - if (strcmp (attribute_name, "name") == 0) { - return nautilus_file_get_name (file); - } - - if (strcmp (attribute_name, "type") == 0) { - return nautilus_file_get_type_as_string (file); - } - - if (strcmp (attribute_name, "size") == 0) { - return nautilus_file_get_size_as_string (file); - } - - if (strcmp (attribute_name, "date_modified") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_MODIFIED); - } - - if (strcmp (attribute_name, "date_changed") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_CHANGED); - } - - if (strcmp (attribute_name, "date_accessed") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_ACCESSED); - } - - if (strcmp (attribute_name, "permissions") == 0) { - return nautilus_file_get_permissions_as_string (file); - } - - if (strcmp (attribute_name, "owner") == 0) { - return nautilus_file_get_owner_as_string (file); - } - - if (strcmp (attribute_name, "group") == 0) { - return nautilus_file_get_group_as_string (file); - } - - return NULL; -} - -/** - * nautilus_file_get_type_as_string: - * - * Get a user-displayable string representing a file type. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_type_as_string (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - if (nautilus_file_is_directory (file)) { - /* Special-case this so it isn't "special/directory". - * FIXME: Should this be "folder" instead? - */ - return g_strdup (_("directory")); - } - - if (nautilus_strlen (file->info->mime_type) == 0) { - return g_strdup (_("unknown type")); - } - - return g_strdup (file->info->mime_type); -} - -/** - * nautilus_file_get_type - * - * Return this file's type. - * @file: NautilusFile representing the file in question. - * - * Returns: The type. - * - **/ -GnomeVFSFileType -nautilus_file_get_type (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->info->type; -} - -/** - * nautilus_file_get_mime_type - * - * Return this file's mime type. - * @file: NautilusFile representing the file in question. - * - * Returns: The mime type. - * - **/ -const char * -nautilus_file_get_mime_type (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->info->mime_type; -} - -/** - * nautilus_file_get_keywords - * - * Return this file's keywords. - * @file: NautilusFile representing the file in question. - * - * Returns: A list of keywords. - * - **/ -GList * -nautilus_file_get_keywords (NautilusFile *file) -{ - GList *keywords; - xmlNode *file_node, *child; - xmlChar *property; - - g_return_val_if_fail (file != NULL, NULL); - - keywords = NULL; - - /* Put all the keywords into a list. */ - file_node = get_file_metadata_node (file->directory, file->info->name); - if (file_node != NULL) { - for (child = file_node->childs; child != NULL; child = child->next) { - if (strcmp (child->name, "KEYWORD") == 0) { - property = xmlGetProp (child, "NAME"); - if (property != NULL) { - keywords = g_list_prepend (keywords, - g_strdup (property)); - } - } - } - } - - return g_list_reverse (keywords); -} - -/** - * nautilus_file_is_symbolic_link - * - * Check if this file is a symbolic link. - * @file: NautilusFile representing the file in question. - * - * Returns: True if the file is a symbolic link. - * - **/ -gboolean -nautilus_file_is_symbolic_link (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return GNOME_VFS_FILE_INFO_SYMLINK (file->info); -} - -/** - * nautilus_file_is_directory - * - * Check if this file is a directory. - * @file: NautilusFile representing the file in question. - * - * Returns: TRUE if @file is a directory. - * - **/ -gboolean -nautilus_file_is_directory (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return nautilus_file_get_type (file) == GNOME_VFS_FILE_TYPE_DIRECTORY; -} - -/** - * nautilus_file_is_executable - * - * Check if this file is executable at all. - * @file: NautilusFile representing the file in question. - * - * Returns: True if any of the execute bits are set. - * - **/ -gboolean -nautilus_file_is_executable (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return (file->info->flags & (GNOME_VFS_PERM_USER_EXEC - | GNOME_VFS_PERM_GROUP_EXEC - | GNOME_VFS_PERM_OTHER_EXEC)) != 0; -} - -/** - * nautilus_file_delete - * - * Delete this file. - * @file: NautilusFile representing the file in question. - **/ -void -nautilus_file_delete (NautilusFile *file) -{ - char *text_uri; - GnomeVFSResult result; - GList *removed_files; - - g_return_if_fail (file != NULL); - - /* Deleting a file that's already gone is easy. */ - if (file->is_gone) { - return; - } - - /* Do the actual deletion. */ - text_uri = nautilus_file_get_uri (file); - if (nautilus_file_is_directory (file)) { - result = gnome_vfs_remove_directory (text_uri); - } else { - result = gnome_vfs_unlink (text_uri); - } - g_free (text_uri); - - /* Mark the file gone. */ - if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_NOTFOUND) { - file->is_gone = TRUE; - - /* Let the directory know it's gone. */ - if (file->directory != NULL) { - g_list_remove (file->directory->details->files, file); - - /* Send out a message. */ - removed_files = g_list_prepend (NULL, file); - gtk_signal_emit (GTK_OBJECT (file->directory), - nautilus_directory_signals[FILES_REMOVED], - removed_files); - g_list_free (removed_files); - } - } -} - -/** - * nautilus_file_is_gone - * - * Check if a file has already been deleted. - * @file: NautilusFile representing the file in question. - * - * Returns: TRUE if the file is already gone. - **/ -gboolean -nautilus_file_is_gone (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->is_gone; -} - -/** - * nautilus_file_list_ref - * - * Ref all the files in a list. - * @file_list: GList of files. - **/ -void -nautilus_file_list_ref (GList *file_list) -{ - g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); -} - -/** - * nautilus_file_list_unref - * - * Unref all the files in a list. - * @file_list: GList of files. - **/ -void -nautilus_file_list_unref (GList *file_list) -{ - g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); -} - -/** - * nautilus_file_list_free - * - * Free a list of files after unrefing them. - * @file_list: GList of files. - **/ -void -nautilus_file_list_free (GList *file_list) -{ - nautilus_file_list_unref (file_list); - g_list_free (file_list); + gtk_signal_emit (GTK_OBJECT (directory), + nautilus_directory_signals[FILES_REMOVED], + removed_files); } #if !defined (NAUTILUS_OMIT_SELF_CHECK) diff --git a/libnautilus-private/nautilus-directory.h b/libnautilus-private/nautilus-directory.h index 35058f26b..42ea0451b 100644 --- a/libnautilus-private/nautilus-directory.h +++ b/libnautilus-private/nautilus-directory.h @@ -26,7 +26,6 @@ #define NAUTILUS_DIRECTORY_H #include <gtk/gtkobject.h> -#include <libgnomevfs/gnome-vfs-types.h> /* NautilusDirectory is a class that manages the model for a directory, real or virtual, for Nautilus, mainly the file-manager component. The directory is @@ -57,21 +56,6 @@ typedef struct NautilusDirectoryClass NautilusDirectoryClass; #define NAUTILUS_IS_DIRECTORY_CLASS(klass) \ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DIRECTORY)) -#define NAUTILUS_IS_FILE(object) \ - ((object) != NULL) - -typedef enum { - NAUTILUS_FILE_SORT_NONE, - NAUTILUS_FILE_SORT_BY_NAME, - NAUTILUS_FILE_SORT_BY_SIZE, - NAUTILUS_FILE_SORT_BY_TYPE, - NAUTILUS_FILE_SORT_BY_MTIME -} NautilusFileSortType; - -typedef struct NautilusFile NautilusFile; - -#define NAUTILUS_FILE(file) ((NautilusFile *)(file)) - typedef void (*NautilusFileListCallback) (NautilusDirectory *directory, GList *files, gpointer callback_data); @@ -124,61 +108,6 @@ void nautilus_directory_stop_monitoring (NautilusDirectory */ gboolean nautilus_directory_are_all_files_seen (NautilusDirectory *directory); -/* Getting at a single file. */ -NautilusFile * nautilus_file_get (const char *uri); - -/* Basic operations on file objects. */ -void nautilus_file_ref (NautilusFile *file); -void nautilus_file_unref (NautilusFile *file); -void nautilus_file_delete (NautilusFile *file); - -/* Basic attributes for file objects. */ -char * nautilus_file_get_name (NautilusFile *file); -char * nautilus_file_get_uri (NautilusFile *file); -GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); -GnomeVFSFileType nautilus_file_get_type (NautilusFile *file); -const char * nautilus_file_get_mime_type (NautilusFile *file); -gboolean nautilus_file_is_symbolic_link (NautilusFile *file); -gboolean nautilus_file_is_executable (NautilusFile *file); -gboolean nautilus_file_is_directory (NautilusFile *file); -guint nautilus_file_get_directory_item_count (NautilusFile *file, - gboolean ignore_invisible_items); -GList * nautilus_file_get_keywords (NautilusFile *file); -void nautilus_file_set_keywords (NautilusFile *file, - GList *keywords); - -/* Simple getting and setting top-level metadata. */ -char * nautilus_file_get_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata); -void nautilus_file_set_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata, - const char *metadata); - -/* Attributes for file objects as user-displayable strings. */ -char * nautilus_file_get_string_attribute (NautilusFile *file, - const char *attribute_name); - -/* Comparing two file objects for sorting */ -int nautilus_file_compare_for_sort (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type); -int nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type); - -/* Convenience functions for dealing with a list of NautilusFile objects that each have a ref. */ -void nautilus_file_list_ref (GList *file_list); -void nautilus_file_list_unref (GList *file_list); -void nautilus_file_list_free (GList *file_list); - -/* Return true if this file has already been deleted. - This object will be unref'd after sending the files_removed signal, - but it could hang around longer if someone ref'd it. -*/ -gboolean nautilus_file_is_gone (NautilusFile *file); - typedef struct NautilusDirectoryDetails NautilusDirectoryDetails; struct NautilusDirectory @@ -201,10 +130,10 @@ struct NautilusDirectoryClass this is the last chance to forget about these file objects which are about to be unref'd. */ - void (* files_added) (NautilusDirectory *directory, - GList *added_files); - void (* files_removed) (NautilusDirectory *directory, - GList *removed_files); + void (* files_added) (NautilusDirectory *directory, + GList *added_files); + void (* files_removed) (NautilusDirectory *directory, + GList *removed_files); /* The files_changed signal is emitted as changes occur to existing files that are noticed by the synchronization framework. diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h new file mode 100644 index 000000000..7ee311c9b --- /dev/null +++ b/libnautilus-private/nautilus-file-private.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include "nautilus-file.h" +#include "nautilus-directory.h" + +struct NautilusFile +{ + guint ref_count; + + NautilusDirectory *directory; + GnomeVFSFileInfo *info; + gboolean is_gone; +}; + +void nautilus_file_free (NautilusFile *); diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c new file mode 100644 index 000000000..56efacead --- /dev/null +++ b/libnautilus-private/nautilus-file.c @@ -0,0 +1,1014 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-file.c: Nautilus file model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include <config.h> +#include "nautilus-file-private.h" + +#include <grp.h> +#include <pwd.h> + +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> + +#include "nautilus-glib-extensions.h" +#include "nautilus-string.h" +#include "nautilus-directory-private.h" + +typedef enum { + NAUTILUS_DATE_TYPE_MODIFIED, + NAUTILUS_DATE_TYPE_CHANGED, + NAUTILUS_DATE_TYPE_ACCESSED +} NautilusDateType; + +/* FIXME: This hack needs to die eventually. See comments with function */ +static int get_directory_item_count_hack (NautilusFile *file, + gboolean ignore_invisible_items); + +static int nautilus_file_compare_by_type (NautilusFile *file_1, + NautilusFile *file_2); +static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type, + gboolean reversed); +static char *nautilus_file_get_date_as_string (NautilusFile *file, + NautilusDateType date_type); +static char *nautilus_file_get_owner_as_string (NautilusFile *file); +static char *nautilus_file_get_group_as_string (NautilusFile *file); +static char *nautilus_file_get_permissions_as_string (NautilusFile *file); +static char *nautilus_file_get_size_as_string (NautilusFile *file); +static char *nautilus_file_get_type_as_string (NautilusFile *file); + +/** + * nautilus_file_get: + * @uri: URI of file to get. + * + * Get a file given a uri. + * Returns a referenced object. Unref when finished. + * If two windows are viewing the same uri, the file object is shared. + */ +NautilusFile * +nautilus_file_get (const char *uri) +{ + GnomeVFSResult result; + GnomeVFSFileInfo *file_info; + GnomeVFSURI *vfs_uri, *directory_vfs_uri; + char *directory_uri; + NautilusDirectory *directory; + NautilusFile *file; + + /* Get info on the file. */ + file_info = gnome_vfs_file_info_new (); + result = gnome_vfs_get_file_info (uri, file_info, + GNOME_VFS_FILE_INFO_GETMIMETYPE + | GNOME_VFS_FILE_INFO_FASTMIMETYPE + | GNOME_VFS_FILE_INFO_FOLLOWLINKS, NULL); + if (result != GNOME_VFS_OK) + return NULL; + + /* Make VFS version of URI. */ + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri == NULL) + return NULL; + + /* Make VFS version of directory URI. */ + directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); + gnome_vfs_uri_unref (vfs_uri); + if (directory_vfs_uri == NULL) + return NULL; + + /* Make text version of directory URI. */ + directory_uri = gnome_vfs_uri_to_string (directory_vfs_uri, + GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (directory_vfs_uri); + + /* Get object that represents the directory. */ + directory = nautilus_directory_get (directory_uri); + g_free (directory_uri); + if (directory == NULL) + return NULL; + + file = nautilus_directory_new_file (directory, file_info); + + gnome_vfs_file_info_unref (file_info); + nautilus_file_ref (file); + gtk_object_unref (GTK_OBJECT (directory)); + + return file; +} + +void +nautilus_file_ref (NautilusFile *file) +{ + g_return_if_fail (file != NULL); + + g_assert (file->ref_count < G_MAXINT); + g_assert (file->directory != NULL); + + /* Increment the ref count. */ + if (file->ref_count++ != 0) { + return; + } + + /* As soon as someone other than the directory holds a ref, + * we need to hold the directory too. */ + gtk_object_ref (GTK_OBJECT (file->directory)); +} + +void +nautilus_file_unref (NautilusFile *file) +{ + g_return_if_fail (file != NULL); + + g_assert (file->ref_count != 0); + g_assert (file->directory != NULL); + + /* Decrement the ref count. */ + if (--file->ref_count != 0) { + return; + } + + /* No references left, so it's time to release our hold on the directory. */ + gtk_object_unref (GTK_OBJECT (file->directory)); + if (file->is_gone) { + nautilus_file_free (file); + } +} + +void +nautilus_file_free (NautilusFile *file) +{ + g_assert (file->ref_count == 0); + + /* Destroy the file object. */ + gnome_vfs_file_info_unref (file->info); + g_free (file); +} + +static int +nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2) +{ + gboolean is_directory_1; + gboolean is_directory_2; + int item_count_1; + int item_count_2; + + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && !is_directory_2) + return -1; + + if (is_directory_2 && !is_directory_1) + return +1; + + if (!is_directory_1 && !is_directory_2) + return 0; + + /* Both are directories, compare by item count. */ + /* FIXME: get_directory_item_count_hack is slow, and calling + * it for every pairwise comparison here is nasty. Need to + * change this to (not-yet-existent) architecture where the + * item count can be calculated once in a deferred way, and + * then stored or cached. + */ + item_count_1 = get_directory_item_count_hack (file_1, FALSE); + item_count_2 = get_directory_item_count_hack (file_2, FALSE); + + if (item_count_1 < item_count_2) + return -1; + + if (item_count_2 < item_count_1) + return +1; + + return 0; +} + +static int +nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2) +{ + gboolean is_directory_1; + gboolean is_directory_2; + char * type_string_1; + char * type_string_2; + int result; + + /* Directories go first. Then, if mime types are identical, + * don't bother getting strings (for speed). This assumes + * that the string is dependent entirely on the mime type, + * which is true now but might not be later. + */ + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && is_directory_2) + return 0; + + if (is_directory_1) + return -1; + + if (is_directory_2) + return +1; + + if (nautilus_strcmp (file_1->info->mime_type, file_2->info->mime_type) == 0) + return 0; + + type_string_1 = nautilus_file_get_type_as_string (file_1); + type_string_2 = nautilus_file_get_type_as_string (file_2); + + result = nautilus_strcmp (type_string_1, type_string_2); + + g_free (type_string_1); + g_free (type_string_2); + + return result; +} + +static int +nautilus_file_compare_for_sort_internal (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type, + gboolean reversed) +{ + GnomeVFSDirectorySortRule rules[3]; + int compare; + + g_return_val_if_fail (file_1 != NULL, 0); + g_return_val_if_fail (file_2 != NULL, 0); + g_return_val_if_fail (sort_type != NAUTILUS_FILE_SORT_NONE, 0); + + switch (sort_type) { + case NAUTILUS_FILE_SORT_BY_NAME: + /* Note: This used to put directories first. I + * thought that was counterintuitive and removed it, + * but I can imagine discussing this further. + * John Sullivan <sullivan@eazel.com> + */ + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_SIZE: + /* Compare directory sizes ourselves, then if necessary + * use GnomeVFS to compare file sizes. + */ + compare = nautilus_file_compare_by_size_with_directories (file_1, file_2); + if (compare != 0) { + return compare; + } + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYSIZE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_TYPE: + /* GnomeVFS doesn't know about our special text for certain + * mime types, so we handle the mime-type sorting ourselves. + */ + compare = nautilus_file_compare_by_type (file_1, file_2); + if (compare != 0) { + return compare; + } + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_MTIME: + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYMTIME; + rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + default: + g_assert_not_reached (); + return 0; + } + + if (reversed) + return gnome_vfs_file_info_compare_for_sort_reversed (file_1->info, + file_2->info, + rules); + else + return gnome_vfs_file_info_compare_for_sort (file_1->info, + file_2->info, + rules); +} + +/** + * nautilus_file_compare_for_sort: + * @file_1: A file object + * @file_2: Another file object + * @sort_type: Sort criterion + * + * Return value: int < 0 if @file_1 should come before file_2 in a smallest-to-largest + * sorted list; int > 0 if @file_2 should come before file_1 in a smallest-to-largest + * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note + * that each named sort type may actually break ties several ways, with the name + * of the sort criterion being the primary but not only differentiator. + **/ +int +nautilus_file_compare_for_sort (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type) +{ + return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, FALSE); +} + +/** + * nautilus_file_compare_for_sort_reversed: + * @file_1: A file object + * @file_2: Another file object + * @sort_type: Sort criterion + * + * Return value: The opposite of nautilus_file_compare_for_sort: int > 0 if @file_1 + * should come before file_2 in a smallest-to-largest sorted list; int < 0 if @file_2 + * should come before file_1 in a smallest-to-largest sorted list; 0 if @file_1 + * and @file_2 are equal for this sort criterion. Note that each named sort type + * may actually break ties several ways, with the name of the sort criterion + * being the primary but not only differentiator. + **/ +int +nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type) +{ + return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, TRUE); +} + +char * +nautilus_file_get_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata) +{ + g_return_val_if_fail (file != NULL, NULL); + + return nautilus_directory_get_file_metadata (file->directory, + file->info->name, + tag, + default_metadata); +} + +void +nautilus_file_set_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata, + const char *metadata) +{ + g_return_if_fail (file != NULL); + + nautilus_directory_set_file_metadata (file->directory, + file->info->name, + tag, + default_metadata, + metadata); +} + +char * +nautilus_file_get_name (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + g_assert (file->directory == NULL || NAUTILUS_IS_DIRECTORY (file->directory)); + g_assert (file->info->name != NULL); + g_assert (file->info->name[0] != '\0'); + + return g_strdup (file->info->name); +} + +char * +nautilus_file_get_uri (NautilusFile *file) +{ + GnomeVFSURI *uri; + char *uri_text; + + g_return_val_if_fail (file != NULL, NULL); + g_return_val_if_fail (file->directory != NULL, NULL); + + uri = gnome_vfs_uri_append_path (file->directory->details->uri, file->info->name); + uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (uri); + return uri_text; +} + +/** + * nautilus_file_get_date_as_string: + * + * Get a user-displayable string representing a file modification date. + * The caller is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type) +{ + struct tm *file_time; + const char *format; + GDate *today; + GDate *file_date; + guint32 file_date_age; + + g_return_val_if_fail (file != NULL, NULL); + + switch (date_type) + { + case NAUTILUS_DATE_TYPE_CHANGED: + file_time = localtime(&file->info->ctime); + break; + case NAUTILUS_DATE_TYPE_ACCESSED: + file_time = localtime(&file->info->atime); + break; + case NAUTILUS_DATE_TYPE_MODIFIED: + file_time = localtime(&file->info->mtime); + break; + default: + g_assert_not_reached (); + } + file_date = nautilus_g_date_new_tm (file_time); + + today = g_date_new (); + g_date_set_time (today, time (NULL)); + + /* Overflow results in a large number; fine for our purposes. */ + file_date_age = g_date_julian (today) - g_date_julian (file_date); + + g_date_free (file_date); + g_date_free (today); + + /* Format varies depending on how old the date is. This minimizes + * the length (and thus clutter & complication) of typical dates + * while providing sufficient detail for recent dates to make + * them maximally understandable at a glance. Keep all format + * strings separate rather than combining bits & pieces for + * internationalization's sake. + */ + + if (file_date_age == 0) + { + /* today, use special word */ + format = _("today %-I:%M %p"); + } + else if (file_date_age == 1) + { + /* yesterday, use special word */ + format = _("yesterday %-I:%M %p"); + } + else if (file_date_age < 7) + { + /* current week, include day of week */ + format = _("%A %-m/%-d/%y %-I:%M %p"); + } + else + { + format = _("%-m/%-d/%y %-I:%M %p"); + } + + return nautilus_strdup_strftime (format, file_time); +} + +/** + * nautilus_file_get_directory_item_count + * + * Get the number of items in a directory. + * @file: NautilusFile representing a directory. It is an error to + * call this function on a file that is not a directory. + * @ignore_invisible_items: TRUE if invisible items should not be + * included in count. + * + * Returns: item count for this directory. + * + **/ +guint +nautilus_file_get_directory_item_count (NautilusFile *file, + gboolean ignore_invisible_items) +{ + g_return_val_if_fail (nautilus_file_is_directory (file), 0); + + return get_directory_item_count_hack (file, ignore_invisible_items); +} + +/** + * nautilus_file_get_size + * + * Get the file size. + * @file: NautilusFile representing the file in question. + * + * Returns: Size in bytes. + * + **/ +GnomeVFSFileSize +nautilus_file_get_size (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, 0); + + return file->info->size; +} + +/** + * nautilus_file_get_permissions_as_string: + * + * Get a user-displayable string representing a file's permissions. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_permissions_as_string (NautilusFile *file) +{ + GnomeVFSFilePermissions permissions; + gboolean is_directory; + gboolean is_link; + + permissions = file->info->permissions; + is_directory = nautilus_file_is_directory (file); + is_link = GNOME_VFS_FILE_INFO_SYMLINK(file->info); + + return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", + is_link ? 'l' : is_directory ? 'd' : '-', + permissions & GNOME_VFS_PERM_USER_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_USER_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_USER_EXEC ? 'x' : '-', + permissions & GNOME_VFS_PERM_GROUP_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_GROUP_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_GROUP_EXEC ? 'x' : '-', + permissions & GNOME_VFS_PERM_OTHER_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_OTHER_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_OTHER_EXEC ? 'x' : '-'); +} + +/** + * nautilus_file_get_owner_as_string: + * + * Get a user-displayable string representing a file's owner. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_owner_as_string (NautilusFile *file) +{ + struct passwd *password_info; + + /* FIXME: Can we trust the uid in the file info? Might + * there be garbage there? What will it do for non-local files? + */ + /* No need to free result of getpwuid */ + password_info = getpwuid (file->info->uid); + + g_print ("pointer to password info is %p\n", password_info); + + if (password_info == NULL) + { + return g_strdup (_("unknown owner")); + } + + return g_strdup (password_info->pw_name); +} + +/** + * nautilus_file_get_group_as_string: + * + * Get a user-displayable string representing a file's group. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_group_as_string (NautilusFile *file) +{ + struct group *group_info; + + /* FIXME: Can we trust the gid in the file info? Might + * there be garbage there? What will it do for non-local files? + */ + /* No need to free result of getgrgid */ + group_info = getgrgid (file->info->gid); + + if (group_info == NULL) + { + return g_strdup (_("unknown group")); + } + + return g_strdup (group_info->gr_name); +} + + +/* This #include is part of the following hack, and should be removed with it */ +#include <dirent.h> + +static int +get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items) +{ + /* Code borrowed from Gnomad and hacked into here for now */ + + char * uri; + char * path; + DIR* directory; + int count; + struct dirent * entry; + + g_assert (nautilus_file_is_directory (file)); + + uri = nautilus_file_get_uri (file); + if (nautilus_has_prefix (uri, "file://")) + path = uri + 7; + else + path = uri; + + directory = opendir (path); + + g_free (uri); + + if (!directory) + return 0; + + count = 0; + + while ((entry = readdir(directory)) != NULL) + // Only count invisible items if requested. + if (!ignore_invisible_items || entry->d_name[0] != '.') + count += 1; + + closedir(directory); + + /* This way of getting the count includes . and .., so we subtract those out */ + if (!ignore_invisible_items) { + count -= 2; + } + + return count; +} + +/** + * nautilus_file_get_size_as_string: + * + * Get a user-displayable string representing a file size. The caller + * is responsible for g_free-ing this string. The string is an item + * count for directories. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_size_as_string (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + if (nautilus_file_is_directory (file)) + { + /* FIXME: Since computing the item count is slow, we + * want to do it in a deferred way. However, that + * architecture doesn't exist yet, so we're hacking + * it in for now. + */ + int item_count; + + item_count = get_directory_item_count_hack (file, FALSE); + if (item_count == 0) { + return g_strdup (_("0 items")); + } else if (item_count == 1) { + return g_strdup (_("1 item")); + } else { + return g_strdup_printf (_("%d items"), item_count); + } + } + + return gnome_vfs_file_size_to_string (file->info->size); +} + +/** + * nautilus_file_get_string_attribute: + * + * Get a user-displayable string from a named attribute. Use g_free to + * free this string. + * + * @file: NautilusFile representing the file in question. + * @attribute_name: The name of the desired attribute. The currently supported + * set includes "name", "type", "size", "date_modified", "date_changed", + * "date_accessed", "owner", "group", "permissions". + * + * Returns: Newly allocated string ready to display to the user, or NULL + * if @attribute_name is not supported. + * + **/ +char * +nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) +{ + /* FIXME: Use hash table and switch statement or function pointers for speed? */ + + if (strcmp (attribute_name, "name") == 0) { + return nautilus_file_get_name (file); + } + + if (strcmp (attribute_name, "type") == 0) { + return nautilus_file_get_type_as_string (file); + } + + if (strcmp (attribute_name, "size") == 0) { + return nautilus_file_get_size_as_string (file); + } + + if (strcmp (attribute_name, "date_modified") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_MODIFIED); + } + + if (strcmp (attribute_name, "date_changed") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_CHANGED); + } + + if (strcmp (attribute_name, "date_accessed") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_ACCESSED); + } + + if (strcmp (attribute_name, "permissions") == 0) { + return nautilus_file_get_permissions_as_string (file); + } + + if (strcmp (attribute_name, "owner") == 0) { + return nautilus_file_get_owner_as_string (file); + } + + if (strcmp (attribute_name, "group") == 0) { + return nautilus_file_get_group_as_string (file); + } + + return NULL; +} + +/** + * nautilus_file_get_type_as_string: + * + * Get a user-displayable string representing a file type. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_type_as_string (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + if (nautilus_file_is_directory (file)) { + /* Special-case this so it isn't "special/directory". + * FIXME: Should this be "folder" instead? + */ + return g_strdup (_("directory")); + } + + if (nautilus_strlen (file->info->mime_type) == 0) { + return g_strdup (_("unknown type")); + } + + return g_strdup (file->info->mime_type); +} + +/** + * nautilus_file_get_type + * + * Return this file's type. + * @file: NautilusFile representing the file in question. + * + * Returns: The type. + * + **/ +GnomeVFSFileType +nautilus_file_get_type (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->info->type; +} + +/** + * nautilus_file_get_mime_type + * + * Return this file's mime type. + * @file: NautilusFile representing the file in question. + * + * Returns: The mime type. + * + **/ +const char * +nautilus_file_get_mime_type (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->info->mime_type; +} + +/** + * nautilus_file_get_keywords + * + * Return this file's keywords. + * @file: NautilusFile representing the file in question. + * + * Returns: A list of keywords. + * + **/ +GList * +nautilus_file_get_keywords (NautilusFile *file) +{ + GList *keywords; + xmlNode *file_node, *child; + xmlChar *property; + + g_return_val_if_fail (file != NULL, NULL); + + keywords = NULL; + + /* Put all the keywords into a list. */ + file_node = nautilus_directory_get_file_metadata_node (file->directory, file->info->name); + if (file_node != NULL) { + for (child = file_node->childs; child != NULL; child = child->next) { + if (strcmp (child->name, "KEYWORD") == 0) { + property = xmlGetProp (child, "NAME"); + if (property != NULL) { + keywords = g_list_prepend (keywords, + g_strdup (property)); + } + } + } + } + + return g_list_reverse (keywords); +} + +/** + * nautilus_file_is_symbolic_link + * + * Check if this file is a symbolic link. + * @file: NautilusFile representing the file in question. + * + * Returns: True if the file is a symbolic link. + * + **/ +gboolean +nautilus_file_is_symbolic_link (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return GNOME_VFS_FILE_INFO_SYMLINK (file->info); +} + +/** + * nautilus_file_is_directory + * + * Check if this file is a directory. + * @file: NautilusFile representing the file in question. + * + * Returns: TRUE if @file is a directory. + * + **/ +gboolean +nautilus_file_is_directory (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return nautilus_file_get_type (file) == GNOME_VFS_FILE_TYPE_DIRECTORY; +} + +/** + * nautilus_file_is_executable + * + * Check if this file is executable at all. + * @file: NautilusFile representing the file in question. + * + * Returns: True if any of the execute bits are set. + * + **/ +gboolean +nautilus_file_is_executable (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return (file->info->flags & (GNOME_VFS_PERM_USER_EXEC + | GNOME_VFS_PERM_GROUP_EXEC + | GNOME_VFS_PERM_OTHER_EXEC)) != 0; +} + +/** + * nautilus_file_delete + * + * Delete this file. + * @file: NautilusFile representing the file in question. + **/ +void +nautilus_file_delete (NautilusFile *file) +{ + char *text_uri; + GnomeVFSResult result; + GList *removed_files; + + g_return_if_fail (file != NULL); + + /* Deleting a file that's already gone is easy. */ + if (file->is_gone) { + return; + } + + /* Do the actual deletion. */ + text_uri = nautilus_file_get_uri (file); + if (nautilus_file_is_directory (file)) { + result = gnome_vfs_remove_directory (text_uri); + } else { + result = gnome_vfs_unlink (text_uri); + } + g_free (text_uri); + + /* Mark the file gone. */ + if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_NOTFOUND) { + file->is_gone = TRUE; + + /* Let the directory know it's gone. */ + if (file->directory != NULL) { + g_list_remove (file->directory->details->files, file); + + /* Send out a signal. */ + removed_files = g_list_prepend (NULL, file); + nautilus_directory_files_removed (file->directory, removed_files); + g_list_free (removed_files); + } + } +} + +/** + * nautilus_file_is_gone + * + * Check if a file has already been deleted. + * @file: NautilusFile representing the file in question. + * + * Returns: TRUE if the file is already gone. + **/ +gboolean +nautilus_file_is_gone (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->is_gone; +} + +/** + * nautilus_file_list_ref + * + * Ref all the files in a list. + * @file_list: GList of files. + **/ +void +nautilus_file_list_ref (GList *file_list) +{ + g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); +} + +/** + * nautilus_file_list_unref + * + * Unref all the files in a list. + * @file_list: GList of files. + **/ +void +nautilus_file_list_unref (GList *file_list) +{ + g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); +} + +/** + * nautilus_file_list_free + * + * Free a list of files after unrefing them. + * @file_list: GList of files. + **/ +void +nautilus_file_list_free (GList *file_list) +{ + nautilus_file_list_unref (file_list); + g_list_free (file_list); +} diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h new file mode 100644 index 000000000..dc06290b5 --- /dev/null +++ b/libnautilus-private/nautilus-file.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-file.h: Nautilus file model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifndef NAUTILUS_FILE_H +#define NAUTILUS_FILE_H + +#include <glib.h> /* gnome-vfs-types.h requires glib.h but doesn't include it */ +#include <libgnomevfs/gnome-vfs-types.h> + +/* NautilusFile is an object used to represent a single element of a + * NautilusDirectory. It's lightweight and relies on NautilusDirectory + * to do most of the work. + */ + +typedef enum { + NAUTILUS_FILE_SORT_NONE, + NAUTILUS_FILE_SORT_BY_NAME, + NAUTILUS_FILE_SORT_BY_SIZE, + NAUTILUS_FILE_SORT_BY_TYPE, + NAUTILUS_FILE_SORT_BY_MTIME +} NautilusFileSortType; + +typedef struct NautilusFile NautilusFile; + +#define NAUTILUS_IS_FILE(object) \ + ((object) != NULL) +#define NAUTILUS_FILE(file) \ + ((NautilusFile *)(file)) + +/* Getting at a single file. */ +NautilusFile * nautilus_file_get (const char *uri); + +/* Basic operations on file objects. */ +void nautilus_file_ref (NautilusFile *file); +void nautilus_file_unref (NautilusFile *file); +void nautilus_file_delete (NautilusFile *file); + +/* Basic attributes for file objects. */ +char * nautilus_file_get_name (NautilusFile *file); +char * nautilus_file_get_uri (NautilusFile *file); +GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); +GnomeVFSFileType nautilus_file_get_type (NautilusFile *file); +const char * nautilus_file_get_mime_type (NautilusFile *file); +gboolean nautilus_file_is_symbolic_link (NautilusFile *file); +gboolean nautilus_file_is_executable (NautilusFile *file); +gboolean nautilus_file_is_directory (NautilusFile *file); +guint nautilus_file_get_directory_item_count (NautilusFile *file, + gboolean ignore_invisible_items); +GList * nautilus_file_get_keywords (NautilusFile *file); +void nautilus_file_set_keywords (NautilusFile *file, + GList *keywords); + +/* Simple getting and setting top-level metadata. */ +char * nautilus_file_get_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata); +void nautilus_file_set_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata, + const char *metadata); + +/* Attributes for file objects as user-displayable strings. */ +char * nautilus_file_get_string_attribute (NautilusFile *file, + const char *attribute_name); + +/* Comparing two file objects for sorting */ +int nautilus_file_compare_for_sort (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type); +int nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type); + +/* Convenience functions for dealing with a list of NautilusFile objects that each have a ref. */ +void nautilus_file_list_ref (GList *file_list); +void nautilus_file_list_unref (GList *file_list); +void nautilus_file_list_free (GList *file_list); + +/* Return true if this file has already been deleted. + This object will be unref'd after sending the files_removed signal, + but it could hang around longer if someone ref'd it. +*/ +gboolean nautilus_file_is_gone (NautilusFile *file); + +#endif /* NAUTILUS_FILE_H */ diff --git a/libnautilus-private/nautilus-icon-factory.h b/libnautilus-private/nautilus-icon-factory.h index 545211440..3e7bfa903 100644 --- a/libnautilus-private/nautilus-icon-factory.h +++ b/libnautilus-private/nautilus-icon-factory.h @@ -2,7 +2,7 @@ nautilus-icon-factory.h: Class for obtaining icons for files and other objects. - * Copyright (C) 1999, 2000 Red Hat Inc. + Copyright (C) 1999, 2000 Red Hat Inc. Copyright (C) 1999, 2000 Eazel, Inc. This program is free software; you can redistribute it and/or @@ -27,7 +27,8 @@ #define NAUTILUS_ICON_FACTORY_H #include <gdk-pixbuf/gdk-pixbuf.h> -#include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> +#include <gtk/gtkobject.h> /* NautilusIconFactory is a class that knows how to hand out icons to be * used for representing files and some other objects. It was designed @@ -97,8 +98,8 @@ char * nautilus_icon_factory_get_theme (void); void nautilus_icon_factory_set_theme (const char *theme_name); /* Choose the appropriate icon, but don't render it yet. */ -NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file, - void *controller); +NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file, + void *controller); NautilusScalableIcon *nautilus_icon_factory_get_icon_by_name (const char *icon_name); GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file); diff --git a/libnautilus-private/nautilus-string.c b/libnautilus-private/nautilus-string.c index d2df8e286..c3ac00d5e 100644 --- a/libnautilus-private/nautilus-string.c +++ b/libnautilus-private/nautilus-string.c @@ -69,10 +69,12 @@ nautilus_has_prefix (const char *haystack_null_allowed, const char *needle_null_ h = haystack_null_allowed == NULL ? "" : haystack_null_allowed; n = needle_null_allowed == NULL ? "" : needle_null_allowed; do { - if (*n == '\0') + if (*n == '\0') { return TRUE; - if (*h == '\0') + } + if (*h == '\0') { return FALSE; + } } while (*h++ == *n++); return FALSE; } @@ -82,19 +84,23 @@ nautilus_has_suffix (const char *haystack_null_allowed, const char *needle_null_ { const char *h, *n; - if (haystack_null_allowed == NULL) + if (needle_null_allowed == NULL) { return TRUE; - if (needle_null_allowed == NULL) - return FALSE; + } + if (haystack_null_allowed == NULL) { + return needle_null_allowed[0] == '\0'; + } /* Eat one character at a time. */ h = haystack_null_allowed + strlen(haystack_null_allowed); n = needle_null_allowed + strlen(needle_null_allowed); do { - if (n == needle_null_allowed) + if (n == needle_null_allowed) { return TRUE; - if (h == haystack_null_allowed) + } + if (h == haystack_null_allowed) { return FALSE; + } } while (*--h == *--n); return FALSE; } @@ -144,23 +150,28 @@ nautilus_string_to_int (const char *string, int *integer) char *parse_end; /* Check for the case of an empty string. */ - if (string == NULL || *string == '\0') + if (string == NULL || *string == '\0') { return FALSE; + } /* Call the standard library routine to do the conversion. */ errno = 0; result = strtol (string, &parse_end, 0); /* Check that the result is in range. */ - if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) { return FALSE; - if (result < G_MININT || result > G_MAXINT) + } + if (result < G_MININT || result > G_MAXINT) { return FALSE; + } /* Check that all the trailing characters are spaces. */ - while (*parse_end != '\0') - if (!isspace (*parse_end++)) + while (*parse_end != '\0') { + if (!isspace (*parse_end++)) { return FALSE; + } + } /* Return the result. */ *integer = result; @@ -170,27 +181,27 @@ nautilus_string_to_int (const char *string, int *integer) /** * nautilus_strstrip: * Remove all occurrences of a character from a string. The - * original string is modified, and also returned for convenience. + * original string is modified in place, and also returned for convenience. * * @string_null_allowed: The string to be stripped. * @remove_this: The char to remove from @string_null_allowed * * Return value: @string_null_allowed, after removing all occurrences - * of @remove_this. + * of @remove_this. */ char * nautilus_strstrip (char *string_null_allowed, char remove_this) { if (string_null_allowed != NULL) { - char *pos; + char *in, *out; - pos = string_null_allowed; - while (*pos != '\0') { - if (*pos == remove_this) { - g_memmove (pos, pos + 1, strlen (pos)); + in = string_null_allowed; + out = string_null_allowed; + do { + if (*in != remove_this) { + *out++ = *in; } - ++pos; - } + } while (*in++ != '\0'); } return string_null_allowed; @@ -232,7 +243,6 @@ void nautilus_self_check_string (void) { int integer; - char *test_string; NAUTILUS_CHECK_INTEGER_RESULT (nautilus_strlen (NULL), 0); NAUTILUS_CHECK_INTEGER_RESULT (nautilus_strlen (""), 0); @@ -283,6 +293,22 @@ nautilus_self_check_string (void) NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_prefix ("aaa", "aaab"), FALSE); NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_prefix ("aaab", "aaa"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, ""), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("", NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "a"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("aaab", "aaab"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("", "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", ""), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "b"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "ab"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("ab", "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("ab", "b"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("aaa", "baaa"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("baaa", "aaa"), TRUE); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix (NULL, NULL), NULL); NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix (NULL, "foo"), NULL); NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix ("foo", NULL), "foo"); @@ -292,14 +318,11 @@ nautilus_self_check_string (void) NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix ("footle:bar", "tle:"), "foo"); NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (NULL, '_'), NULL); - test_string = g_strdup ("foo"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("_foo"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("foo_"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("_foo_"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("foo"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_foo"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("foo_"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_foo_"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_f_o__o_"), '_'), "foo"); #define TEST_INTEGER_CONVERSION_FUNCTIONS(string, boolean_result, integer_result) \ NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_string_to_int (string, &integer), boolean_result); \ diff --git a/libnautilus-private/nautilus-string.h b/libnautilus-private/nautilus-string.h index 9d269dcd7..03c778f00 100644 --- a/libnautilus-private/nautilus-string.h +++ b/libnautilus-private/nautilus-string.h @@ -47,8 +47,8 @@ char * nautilus_strdup_prefix (const char *source_null_allowed, gboolean nautilus_has_suffix (const char *target_null_allowed, const char *suffix_null_allowed); -char * nautilus_strstrip (char *string_null_allowed, - char remove_this); +char * nautilus_strstrip (char *string_null_allowed, + char remove_this); /* Conversions to and from strings. */ diff --git a/libnautilus/Makefile.am b/libnautilus/Makefile.am index 4e65cefad..002601a80 100644 --- a/libnautilus/Makefile.am +++ b/libnautilus/Makefile.am @@ -27,8 +27,6 @@ libnautilusincludedir=$(includedir)/libnautilus libnautilusinclude_HEADERS= \ bonobo-stream-vfs.h \ gdk-extensions.h \ - gnome-icon-container-dnd.h \ - gnome-icon-container-private.h \ gnome-icon-container.h \ gtkflist.h \ gtkscrollframe.h \ @@ -38,13 +36,13 @@ libnautilusinclude_HEADERS= \ nautilus-bookmark.h \ nautilus-debug.h \ nautilus-directory.h \ + nautilus-file.h \ nautilus-file-utilities.h \ nautilus-glib-extensions.h \ nautilus-gtk-extensions.h \ nautilus-icon-factory.h \ nautilus-icons-controller.h \ nautilus-icons-view-icon-item.h \ - nautilus-lib-self-check-functions.h \ nautilus-metadata.h \ nautilus-mime-type.h \ nautilus-self-checks.h \ @@ -68,6 +66,7 @@ libnautilus_la_SOURCES=$(nautilus_idl_sources) \ nautilus-default-file-icon.c \ nautilus-default-file-icon.h \ nautilus-directory.c \ + nautilus-file.c \ nautilus-file-utilities.c \ nautilus-glib-extensions.c \ nautilus-gtk-extensions.c \ diff --git a/libnautilus/gnome-icon-container-dnd.c b/libnautilus/gnome-icon-container-dnd.c index 987556da1..1057c984d 100644 --- a/libnautilus/gnome-icon-container-dnd.c +++ b/libnautilus/gnome-icon-container-dnd.c @@ -816,12 +816,12 @@ gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, gtk_object_getv (GTK_OBJECT (item), 1, &pixbuf_arg); pixbuf = GTK_VALUE_BOXED (pixbuf_arg); - transparent_pixbuf = make_semi_transparent(pixbuf); + transparent_pixbuf = make_semi_transparent (pixbuf); gdk_pixbuf_render_pixmap_and_mask (transparent_pixbuf, &pixmap_for_dragged_file, &mask_for_dragged_file, 128); - gdk_pixbuf_unref(transparent_pixbuf); + gdk_pixbuf_unref (transparent_pixbuf); /* compute the image's offset */ nautilus_icons_view_icon_item_get_icon_window_rectangle diff --git a/libnautilus/gnome-icon-container.c b/libnautilus/gnome-icon-container.c index 20ada54d2..ddf28423e 100644 --- a/libnautilus/gnome-icon-container.c +++ b/libnautilus/gnome-icon-container.c @@ -724,15 +724,17 @@ make_icon_visible (GnomeIconContainer *container, icon_get_bounding_box (icon, &x1, &y1, &x2, &y2); - if (y1 < vadj->value) + if (y1 < vadj->value) { gtk_adjustment_set_value (vadj, y1); - else if (y2 > vadj->value + allocation->height) + } else if (y2 > vadj->value + allocation->height) { gtk_adjustment_set_value (vadj, y2 - allocation->height); + } - if (x1 < hadj->value) + if (x1 < hadj->value) { gtk_adjustment_set_value (hadj, x1); - else if (x2 > hadj->value + allocation->width) + } else if (x2 > hadj->value + allocation->width) { gtk_adjustment_set_value (hadj, x2 - allocation->width); + } } static gboolean @@ -2145,6 +2147,17 @@ gnome_icon_container_initialize_class (GnomeIconContainerClass *class) stipple = gdk_bitmap_create_from_data (NULL, stipple_bits, 2, 2); } +static GdkFont * +load_font (const char *name) +{ + GdkFont *font; + + /* FIXME: Eventually we need a runtime check, but an assert is better than nothing. */ + font = gdk_font_load (name); + g_assert (font != NULL); + return font; +} + static void gnome_icon_container_initialize (GnomeIconContainer *container) { @@ -2159,15 +2172,15 @@ gnome_icon_container_initialize (GnomeIconContainer *container) details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD; - /* font table - this isnt exactly proportional, but it looks better than computed */ + /* font table - this isn't exactly proportional, but it looks better than computed */ /* FIXME: read font from metadata and/or preferences */ - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLEST] = gdk_font_load("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLER] = gdk_font_load("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_SMALL] = gdk_font_load("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_STANDARD] = gdk_font_load("-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGE] = gdk_font_load("-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGER] = gdk_font_load("-*-helveticar-medium-r-normal-*-18-*-*-*-*-*-*-*"); - details->label_font[NAUTILUS_ZOOM_LEVEL_LARGEST] = gdk_font_load("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLEST] = load_font ("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALLER] = load_font ("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_SMALL] = load_font ("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_STANDARD] = load_font ("-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGE] = load_font ("-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGER] = load_font ("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); + details->label_font[NAUTILUS_ZOOM_LEVEL_LARGEST] = load_font ("-*-helvetica-medium-r-normal-*-18-*-*-*-*-*-*-*"); /* FIXME: Read these from preferences. */ details->linger_selection_mode = FALSE; diff --git a/libnautilus/nautilus-directory-private.h b/libnautilus/nautilus-directory-private.h new file mode 100644 index 000000000..12496a3f6 --- /dev/null +++ b/libnautilus/nautilus-directory-private.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include "nautilus-directory.h" + +#include <libgnomevfs/gnome-vfs-types.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <libgnomevfs/gnome-vfs-file-info.h> + +#include <gnome-xml/tree.h> + +#include "nautilus-file.h" + +struct NautilusDirectoryDetails +{ + char *uri_text; + GnomeVFSURI *uri; + + GnomeVFSURI *metafile_uri; + GnomeVFSURI *alternate_metafile_uri; + gboolean use_alternate_metafile; + + xmlDoc *metafile_tree; + guint write_metafile_idle_id; + + GnomeVFSAsyncHandle *directory_load_in_progress; + GnomeVFSDirectoryListPosition directory_load_list_last_handled; + + GList *pending_file_info; + guint dequeue_pending_idle_id; + + gboolean directory_loaded; + + GList *files; +}; + +NautilusFile *nautilus_directory_new_file (NautilusDirectory *directory, + GnomeVFSFileInfo *info); +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata); +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, + const char *file_name, + const char *tag, + const char *default_metadata, + const char *metadata); +xmlNode * nautilus_directory_get_file_metadata_node (NautilusDirectory *directory, + const char *file_name); +void nautilus_directory_files_removed (NautilusDirectory *directory, + GList *removed_files); diff --git a/libnautilus/nautilus-directory.c b/libnautilus/nautilus-directory.c index 643c290db..eaa37ac68 100644 --- a/libnautilus/nautilus-directory.c +++ b/libnautilus/nautilus-directory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - nautilus-directory.c: Mautilus directory model. + nautilus-directory.c: Nautilus directory model. Copyright (C) 1999, 2000 Eazel, Inc. @@ -23,33 +23,20 @@ */ #include <config.h> -#include "nautilus-directory.h" +#include "nautilus-directory-private.h" -#include <grp.h> -#include <pwd.h> #include <stdlib.h> #include <gtk/gtksignal.h> #include <gtk/gtkmain.h> -#include <libgnome/gnome-defs.h> -#include <libgnome/gnome-i18n.h> - -#include <libgnomevfs/gnome-vfs-types.h> -#include <libgnomevfs/gnome-vfs-uri.h> -#include <libgnomevfs/gnome-vfs-file-info.h> -#include <libgnomevfs/gnome-vfs-ops.h> -#include <libgnomevfs/gnome-vfs-async-ops.h> - #include <gnome-xml/parser.h> -#include <gnome-xml/tree.h> #include <gnome-xml/xmlmemory.h> -#include "nautilus-alloc.h" -#include "nautilus-glib-extensions.h" #include "nautilus-gtk-macros.h" -#include "nautilus-lib-self-check-functions.h" #include "nautilus-string.h" +#include "nautilus-lib-self-check-functions.h" +#include "nautilus-file-private.h" #define METAFILE_NAME ".nautilus-metafile.xml" #define METAFILE_PERMISSIONS (GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE \ @@ -67,12 +54,6 @@ #define DIRECTORY_LOAD_ITEMS_PER_CB 1 -typedef enum { - NAUTILUS_DATE_TYPE_MODIFIED, - NAUTILUS_DATE_TYPE_CHANGED, - NAUTILUS_DATE_TYPE_ACCESSED -} NautilusDateType; - enum { FILES_ADDED, @@ -80,79 +61,25 @@ enum LAST_SIGNAL }; -/* FIXME: This hack needs to die eventually. See comments with function */ -static int get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items); - - static guint nautilus_directory_signals[LAST_SIGNAL]; -static void nautilus_directory_initialize_class (gpointer klass); -static void nautilus_directory_initialize (gpointer object, gpointer klass); -static void nautilus_directory_finalize (GtkObject *object); - -static NautilusDirectory *nautilus_directory_new (const char* uri); - -static void nautilus_directory_read_metafile (NautilusDirectory *directory); -static void nautilus_directory_write_metafile (NautilusDirectory *directory); -static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); -static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); - -static void nautilus_file_free (NautilusFile *file); -static int nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2); -static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type, - gboolean reversed); - -static char * nautilus_file_get_date_as_string (NautilusFile *file, - NautilusDateType date_type); -static char *nautilus_file_get_owner_as_string (NautilusFile *file); -static char *nautilus_file_get_group_as_string (NautilusFile *file); -static char *nautilus_file_get_permissions_as_string (NautilusFile *file); -static char * nautilus_file_get_size_as_string (NautilusFile *file); -static char * nautilus_file_get_type_as_string (NautilusFile *file); -static void nautilus_directory_load_cb (GnomeVFSAsyncHandle *handle, - GnomeVFSResult result, - GnomeVFSDirectoryList *list, - guint entries_read, - gpointer callback_data); -static NautilusFile *nautilus_directory_new_file (NautilusDirectory *directory, - GnomeVFSFileInfo *info); +static void nautilus_directory_initialize_class (gpointer klass); +static void nautilus_directory_initialize (gpointer object, + gpointer klass); +static void nautilus_directory_finalize (GtkObject *object); +static NautilusDirectory *nautilus_directory_new (const char *uri); +static void nautilus_directory_read_metafile (NautilusDirectory *directory); +static void nautilus_directory_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_request_write_metafile (NautilusDirectory *directory); +static void nautilus_directory_remove_write_metafile_idle (NautilusDirectory *directory); +static void nautilus_directory_load_cb (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + GnomeVFSDirectoryList *list, + guint entries_read, + gpointer callback_data); NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusDirectory, nautilus_directory, GTK_TYPE_OBJECT) -struct NautilusDirectoryDetails -{ - char *uri_text; - GnomeVFSURI *uri; - - GnomeVFSURI *metafile_uri; - GnomeVFSURI *alternate_metafile_uri; - gboolean use_alternate_metafile; - - xmlDoc *metafile_tree; - guint write_metafile_idle_id; - - GnomeVFSAsyncHandle *directory_load_in_progress; - GnomeVFSDirectoryListPosition directory_load_list_last_handled; - - GList *pending_file_info; - guint dequeue_pending_idle_id; - - gboolean directory_loaded; - - GList *files; -}; - -struct NautilusFile -{ - guint ref_count; - - NautilusDirectory *directory; - GnomeVFSFileInfo *info; - gboolean is_gone; -}; - static GHashTable* directory_objects; static void @@ -1005,9 +932,9 @@ nautilus_directory_set_integer_metadata (NautilusDirectory *directory, g_free (default_as_string); } -static xmlNode * -get_file_metadata_node (NautilusDirectory *directory, - const char *file_name) +xmlNode * +nautilus_directory_get_file_metadata_node (NautilusDirectory *directory, + const char *file_name) { xmlNode *root, *child; xmlChar *property; @@ -1038,18 +965,18 @@ get_file_metadata_node (NautilusDirectory *directory, return NULL; } -static char * +char * nautilus_directory_get_file_metadata (NautilusDirectory *directory, const char *file_name, const char *tag, const char *default_metadata) { return nautilus_directory_get_metadata_from_node - (get_file_metadata_node (directory, file_name), + (nautilus_directory_get_file_metadata_node (directory, file_name), tag, default_metadata); } -static void +void nautilus_directory_set_file_metadata (NautilusDirectory *directory, const char *file_name, const char *tag, @@ -1118,7 +1045,7 @@ nautilus_directory_set_file_metadata (NautilusDirectory *directory, nautilus_directory_request_write_metafile (directory); } -static NautilusFile * +NautilusFile * nautilus_directory_new_file (NautilusDirectory *directory, GnomeVFSFileInfo *info) { NautilusFile *file; @@ -1135,973 +1062,13 @@ nautilus_directory_new_file (NautilusDirectory *directory, GnomeVFSFileInfo *inf return file; } -/** - * nautilus_file_get: - * @uri: URI of file to get. - * - * Get a file given a uri. - * Returns a referenced object. Unref when finished. - * If two windows are viewing the same uri, the file object is shared. - */ -NautilusFile * -nautilus_file_get (const char *uri) -{ - GnomeVFSResult result; - GnomeVFSFileInfo *file_info; - GnomeVFSURI *vfs_uri, *directory_vfs_uri; - char *directory_uri; - NautilusDirectory *directory; - NautilusFile *file; - - /* Get info on the file. */ - file_info = gnome_vfs_file_info_new (); - result = gnome_vfs_get_file_info (uri, file_info, - GNOME_VFS_FILE_INFO_GETMIMETYPE - | GNOME_VFS_FILE_INFO_FASTMIMETYPE - | GNOME_VFS_FILE_INFO_FOLLOWLINKS, NULL); - if (result != GNOME_VFS_OK) - return NULL; - - /* Make VFS version of URI. */ - vfs_uri = gnome_vfs_uri_new (uri); - if (vfs_uri == NULL) - return NULL; - - /* Make VFS version of directory URI. */ - directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); - gnome_vfs_uri_unref (vfs_uri); - if (directory_vfs_uri == NULL) - return NULL; - - /* Make text version of directory URI. */ - directory_uri = gnome_vfs_uri_to_string (directory_vfs_uri, - GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (directory_vfs_uri); - - /* Get object that represents the directory. */ - directory = nautilus_directory_get (directory_uri); - g_free (directory_uri); - if (directory == NULL) - return NULL; - - file = nautilus_directory_new_file (directory, file_info); - - gnome_vfs_file_info_unref (file_info); - nautilus_file_ref (file); - gtk_object_unref (GTK_OBJECT (directory)); - - return file; -} - -void -nautilus_file_ref (NautilusFile *file) -{ - g_return_if_fail (file != NULL); - - g_assert (file->ref_count < G_MAXINT); - g_assert (file->directory != NULL); - - /* Increment the ref count. */ - if (file->ref_count++ != 0) { - return; - } - - /* As soon as someone other than the directory holds a ref, - * we need to hold the directory too. */ - gtk_object_ref (GTK_OBJECT (file->directory)); -} - -void -nautilus_file_unref (NautilusFile *file) -{ - g_return_if_fail (file != NULL); - - g_assert (file->ref_count != 0); - g_assert (file->directory != NULL); - - /* Decrement the ref count. */ - if (--file->ref_count != 0) { - return; - } - - /* No references left, so it's time to release our hold on the directory. */ - gtk_object_unref (GTK_OBJECT (file->directory)); - if (file->is_gone) { - nautilus_file_free (file); - } -} - -static void -nautilus_file_free (NautilusFile *file) -{ - g_assert (file->ref_count == 0); - - /* Destroy the file object. */ - gnome_vfs_file_info_unref (file->info); - g_free (file); -} - -static int -nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2) -{ - gboolean is_directory_1; - gboolean is_directory_2; - int item_count_1; - int item_count_2; - - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && !is_directory_2) - return -1; - - if (is_directory_2 && !is_directory_1) - return +1; - - if (!is_directory_1 && !is_directory_2) - return 0; - - /* Both are directories, compare by item count. */ - /* FIXME: get_directory_item_count_hack is slow, and calling - * it for every pairwise comparison here is nasty. Need to - * change this to (not-yet-existent) architecture where the - * item count can be calculated once in a deferred way, and - * then stored or cached. - */ - item_count_1 = get_directory_item_count_hack (file_1, FALSE); - item_count_2 = get_directory_item_count_hack (file_2, FALSE); - - if (item_count_1 < item_count_2) - return -1; - - if (item_count_2 < item_count_1) - return +1; - - return 0; -} - -static int -nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2) -{ - gboolean is_directory_1; - gboolean is_directory_2; - char * type_string_1; - char * type_string_2; - int result; - - /* Directories go first. Then, if mime types are identical, - * don't bother getting strings (for speed). This assumes - * that the string is dependent entirely on the mime type, - * which is true now but might not be later. - */ - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && is_directory_2) - return 0; - - if (is_directory_1) - return -1; - - if (is_directory_2) - return +1; - - if (nautilus_strcmp (file_1->info->mime_type, file_2->info->mime_type) == 0) - return 0; - - type_string_1 = nautilus_file_get_type_as_string (file_1); - type_string_2 = nautilus_file_get_type_as_string (file_2); - - result = nautilus_strcmp (type_string_1, type_string_2); - - g_free (type_string_1); - g_free (type_string_2); - - return result; -} - -static int -nautilus_file_compare_for_sort_internal (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type, - gboolean reversed) -{ - GnomeVFSDirectorySortRule *rules; - - g_return_val_if_fail (file_1 != NULL, 0); - g_return_val_if_fail (file_2 != NULL, 0); - g_return_val_if_fail (sort_type != NAUTILUS_FILE_SORT_NONE, 0); - -#define ALLOC_RULES(n) alloca ((n) * sizeof (GnomeVFSDirectorySortRule)) - - switch (sort_type) { - case NAUTILUS_FILE_SORT_BY_NAME: - rules = ALLOC_RULES (2); - /* Note: This used to put directories first. I - * thought that was counterintuitive and removed it, - * but I can imagine discussing this further. - * John Sullivan <sullivan@eazel.com> - */ - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_SIZE: - /* Compare directory sizes ourselves, then if necessary - * use GnomeVFS to compare file sizes. - */ - { - int size_compare; - - size_compare = nautilus_file_compare_by_size_with_directories (file_1, file_2); - if (size_compare != 0) - return size_compare; - } - rules = ALLOC_RULES (3); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYSIZE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_TYPE: - /* GnomeVFS doesn't know about our special text for certain - * mime types, so we handle the mime-type sorting ourselves. - */ - { - int type_compare; - - type_compare = nautilus_file_compare_by_type (file_1, file_2); - if (type_compare != 0) - return type_compare; - } - rules = ALLOC_RULES (2); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - case NAUTILUS_FILE_SORT_BY_MTIME: - rules = ALLOC_RULES (3); - rules[0] = GNOME_VFS_DIRECTORY_SORT_BYMTIME; - rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; - rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; - break; - default: - g_assert_not_reached (); - return 0; - } - - if (reversed) - return gnome_vfs_file_info_compare_for_sort_reversed (file_1->info, - file_2->info, - rules); - else - return gnome_vfs_file_info_compare_for_sort (file_1->info, - file_2->info, - rules); - -#undef ALLOC_RULES -} - -/** - * nautilus_file_compare_for_sort: - * @file_1: A file object - * @file_2: Another file object - * @sort_type: Sort criterion - * - * Return value: int < 0 if @file_1 should come before file_2 in a smallest-to-largest - * sorted list; int > 0 if @file_2 should come before file_1 in a smallest-to-largest - * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note - * that each named sort type may actually break ties several ways, with the name - * of the sort criterion being the primary but not only differentiator. - **/ -int -nautilus_file_compare_for_sort (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type) -{ - return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, FALSE); -} - -/** - * nautilus_file_compare_for_sort_reversed: - * @file_1: A file object - * @file_2: Another file object - * @sort_type: Sort criterion - * - * Return value: The opposite of nautilus_file_compare_for_sort: int > 0 if @file_1 - * should come before file_2 in a smallest-to-largest sorted list; int < 0 if @file_2 - * should come before file_1 in a smallest-to-largest sorted list; 0 if @file_1 - * and @file_2 are equal for this sort criterion. Note that each named sort type - * may actually break ties several ways, with the name of the sort criterion - * being the primary but not only differentiator. - **/ -int -nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type) -{ - return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, TRUE); -} - -char * -nautilus_file_get_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata) -{ - g_return_val_if_fail (file != NULL, NULL); - - return nautilus_directory_get_file_metadata (file->directory, - file->info->name, - tag, - default_metadata); -} - void -nautilus_file_set_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata, - const char *metadata) +nautilus_directory_files_removed (NautilusDirectory *directory, + GList *removed_files) { - g_return_if_fail (file != NULL); - - nautilus_directory_set_file_metadata (file->directory, - file->info->name, - tag, - default_metadata, - metadata); -} - -char * -nautilus_file_get_name (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - g_assert (file->directory == NULL || NAUTILUS_IS_DIRECTORY (file->directory)); - g_assert (file->info->name != NULL); - g_assert (file->info->name[0] != '\0'); - - return g_strdup (file->info->name); -} - -char * -nautilus_file_get_uri (NautilusFile *file) -{ - GnomeVFSURI *uri; - char *uri_text; - - g_return_val_if_fail (file != NULL, NULL); - g_return_val_if_fail (file->directory != NULL, NULL); - - uri = gnome_vfs_uri_append_path (file->directory->details->uri, file->info->name); - uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); - gnome_vfs_uri_unref (uri); - return uri_text; -} - -/** - * nautilus_file_get_date_as_string: - * - * Get a user-displayable string representing a file modification date. - * The caller is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type) -{ - struct tm *file_time; - const char *format; - GDate *today; - GDate *file_date; - guint32 file_date_age; - - g_return_val_if_fail (file != NULL, NULL); - - switch (date_type) - { - case NAUTILUS_DATE_TYPE_CHANGED: - file_time = localtime(&file->info->ctime); - break; - case NAUTILUS_DATE_TYPE_ACCESSED: - file_time = localtime(&file->info->atime); - break; - case NAUTILUS_DATE_TYPE_MODIFIED: - file_time = localtime(&file->info->mtime); - break; - default: - g_assert_not_reached (); - } - file_date = nautilus_g_date_new_tm (file_time); - - today = g_date_new (); - g_date_set_time (today, time (NULL)); - - /* Overflow results in a large number; fine for our purposes. */ - file_date_age = g_date_julian (today) - g_date_julian (file_date); - - g_date_free (file_date); - g_date_free (today); - - /* Format varies depending on how old the date is. This minimizes - * the length (and thus clutter & complication) of typical dates - * while providing sufficient detail for recent dates to make - * them maximally understandable at a glance. Keep all format - * strings separate rather than combining bits & pieces for - * internationalization's sake. - */ - - if (file_date_age == 0) - { - /* today, use special word */ - format = _("today %-I:%M %p"); - } - else if (file_date_age == 1) - { - /* yesterday, use special word */ - format = _("yesterday %-I:%M %p"); - } - else if (file_date_age < 7) - { - /* current week, include day of week */ - format = _("%A %-m/%-d/%y %-I:%M %p"); - } - else - { - format = _("%-m/%-d/%y %-I:%M %p"); - } - - return nautilus_strdup_strftime (format, file_time); -} - -/** - * nautilus_file_get_directory_item_count - * - * Get the number of items in a directory. - * @file: NautilusFile representing a directory. It is an error to - * call this function on a file that is not a directory. - * @ignore_invisible_items: TRUE if invisible items should not be - * included in count. - * - * Returns: item count for this directory. - * - **/ -guint -nautilus_file_get_directory_item_count (NautilusFile *file, - gboolean ignore_invisible_items) -{ - g_return_val_if_fail (nautilus_file_is_directory (file), 0); - - return get_directory_item_count_hack (file, ignore_invisible_items); -} - -/** - * nautilus_file_get_size - * - * Get the file size. - * @file: NautilusFile representing the file in question. - * - * Returns: Size in bytes. - * - **/ -GnomeVFSFileSize -nautilus_file_get_size (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, 0); - - return file->info->size; -} - -/** - * nautilus_file_get_permissions_as_string: - * - * Get a user-displayable string representing a file's permissions. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_permissions_as_string (NautilusFile *file) -{ - GnomeVFSFilePermissions permissions; - gboolean is_directory; - gboolean is_link; - - permissions = file->info->permissions; - is_directory = nautilus_file_is_directory (file); - is_link = GNOME_VFS_FILE_INFO_SYMLINK(file->info); - - return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", - is_link ? 'l' : is_directory ? 'd' : '-', - permissions & GNOME_VFS_PERM_USER_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_USER_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_USER_EXEC ? 'x' : '-', - permissions & GNOME_VFS_PERM_GROUP_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_GROUP_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_GROUP_EXEC ? 'x' : '-', - permissions & GNOME_VFS_PERM_OTHER_READ ? 'r' : '-', - permissions & GNOME_VFS_PERM_OTHER_WRITE ? 'w' : '-', - permissions & GNOME_VFS_PERM_OTHER_EXEC ? 'x' : '-'); -} - -/** - * nautilus_file_get_owner_as_string: - * - * Get a user-displayable string representing a file's owner. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_owner_as_string (NautilusFile *file) -{ - struct passwd *password_info; - - /* FIXME: Can we trust the uid in the file info? Might - * there be garbage there? What will it do for non-local files? - */ - /* No need to free result of getpwuid */ - password_info = getpwuid (file->info->uid); - - g_print ("pointer to password info is %p\n", password_info); - - if (password_info == NULL) - { - return g_strdup (_("unknown owner")); - } - - return g_strdup (password_info->pw_name); -} - -/** - * nautilus_file_get_group_as_string: - * - * Get a user-displayable string representing a file's group. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_group_as_string (NautilusFile *file) -{ - struct group *group_info; - - /* FIXME: Can we trust the gid in the file info? Might - * there be garbage there? What will it do for non-local files? - */ - /* No need to free result of getgrgid */ - group_info = getgrgid (file->info->gid); - - if (group_info == NULL) - { - return g_strdup (_("unknown group")); - } - - return g_strdup (group_info->gr_name); -} - - -/* This #include is part of the following hack, and should be removed with it */ -#include <dirent.h> - -static int -get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items) -{ - /* Code borrowed from Gnomad and hacked into here for now */ - - char * uri; - char * path; - DIR* directory; - int count; - struct dirent * entry; - - g_assert (nautilus_file_is_directory (file)); - - uri = nautilus_file_get_uri (file); - if (nautilus_has_prefix (uri, "file://")) - path = uri + 7; - else - path = uri; - - directory = opendir (path); - - g_free (uri); - - if (!directory) - return 0; - - count = 0; - - while ((entry = readdir(directory)) != NULL) - // Only count invisible items if requested. - if (!ignore_invisible_items || entry->d_name[0] != '.') - count += 1; - - closedir(directory); - - /* This way of getting the count includes . and .., so we subtract those out */ - if (!ignore_invisible_items) { - count -= 2; - } - - return count; -} - -/** - * nautilus_file_get_size_as_string: - * - * Get a user-displayable string representing a file size. The caller - * is responsible for g_free-ing this string. The string is an item - * count for directories. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_size_as_string (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - if (nautilus_file_is_directory (file)) - { - /* FIXME: Since computing the item count is slow, we - * want to do it in a deferred way. However, that - * architecture doesn't exist yet, so we're hacking - * it in for now. - */ - int item_count; - - item_count = get_directory_item_count_hack (file, FALSE); - if (item_count == 0) { - return g_strdup (_("0 items")); - } else if (item_count == 1) { - return g_strdup (_("1 item")); - } else { - return g_strdup_printf (_("%d items"), item_count); - } - } - - return gnome_vfs_file_size_to_string (file->info->size); -} - -/** - * nautilus_file_get_string_attribute: - * - * Get a user-displayable string from a named attribute. Use g_free to - * free this string. - * - * @file: NautilusFile representing the file in question. - * @attribute_name: The name of the desired attribute. The currently supported - * set includes "name", "type", "size", "date_modified", "date_changed", - * "date_accessed", "owner", "group", "permissions". - * - * Returns: Newly allocated string ready to display to the user, or NULL - * if @attribute_name is not supported. - * - **/ -char * -nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) -{ - /* FIXME: Use hash table and switch statement or function pointers for speed? */ - - if (strcmp (attribute_name, "name") == 0) { - return nautilus_file_get_name (file); - } - - if (strcmp (attribute_name, "type") == 0) { - return nautilus_file_get_type_as_string (file); - } - - if (strcmp (attribute_name, "size") == 0) { - return nautilus_file_get_size_as_string (file); - } - - if (strcmp (attribute_name, "date_modified") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_MODIFIED); - } - - if (strcmp (attribute_name, "date_changed") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_CHANGED); - } - - if (strcmp (attribute_name, "date_accessed") == 0) { - return nautilus_file_get_date_as_string (file, - NAUTILUS_DATE_TYPE_ACCESSED); - } - - if (strcmp (attribute_name, "permissions") == 0) { - return nautilus_file_get_permissions_as_string (file); - } - - if (strcmp (attribute_name, "owner") == 0) { - return nautilus_file_get_owner_as_string (file); - } - - if (strcmp (attribute_name, "group") == 0) { - return nautilus_file_get_group_as_string (file); - } - - return NULL; -} - -/** - * nautilus_file_get_type_as_string: - * - * Get a user-displayable string representing a file type. The caller - * is responsible for g_free-ing this string. - * @file: NautilusFile representing the file in question. - * - * Returns: Newly allocated string ready to display to the user. - * - **/ -static char * -nautilus_file_get_type_as_string (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, NULL); - - if (nautilus_file_is_directory (file)) { - /* Special-case this so it isn't "special/directory". - * FIXME: Should this be "folder" instead? - */ - return g_strdup (_("directory")); - } - - if (nautilus_strlen (file->info->mime_type) == 0) { - return g_strdup (_("unknown type")); - } - - return g_strdup (file->info->mime_type); -} - -/** - * nautilus_file_get_type - * - * Return this file's type. - * @file: NautilusFile representing the file in question. - * - * Returns: The type. - * - **/ -GnomeVFSFileType -nautilus_file_get_type (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->info->type; -} - -/** - * nautilus_file_get_mime_type - * - * Return this file's mime type. - * @file: NautilusFile representing the file in question. - * - * Returns: The mime type. - * - **/ -const char * -nautilus_file_get_mime_type (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->info->mime_type; -} - -/** - * nautilus_file_get_keywords - * - * Return this file's keywords. - * @file: NautilusFile representing the file in question. - * - * Returns: A list of keywords. - * - **/ -GList * -nautilus_file_get_keywords (NautilusFile *file) -{ - GList *keywords; - xmlNode *file_node, *child; - xmlChar *property; - - g_return_val_if_fail (file != NULL, NULL); - - keywords = NULL; - - /* Put all the keywords into a list. */ - file_node = get_file_metadata_node (file->directory, file->info->name); - if (file_node != NULL) { - for (child = file_node->childs; child != NULL; child = child->next) { - if (strcmp (child->name, "KEYWORD") == 0) { - property = xmlGetProp (child, "NAME"); - if (property != NULL) { - keywords = g_list_prepend (keywords, - g_strdup (property)); - } - } - } - } - - return g_list_reverse (keywords); -} - -/** - * nautilus_file_is_symbolic_link - * - * Check if this file is a symbolic link. - * @file: NautilusFile representing the file in question. - * - * Returns: True if the file is a symbolic link. - * - **/ -gboolean -nautilus_file_is_symbolic_link (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return GNOME_VFS_FILE_INFO_SYMLINK (file->info); -} - -/** - * nautilus_file_is_directory - * - * Check if this file is a directory. - * @file: NautilusFile representing the file in question. - * - * Returns: TRUE if @file is a directory. - * - **/ -gboolean -nautilus_file_is_directory (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return nautilus_file_get_type (file) == GNOME_VFS_FILE_TYPE_DIRECTORY; -} - -/** - * nautilus_file_is_executable - * - * Check if this file is executable at all. - * @file: NautilusFile representing the file in question. - * - * Returns: True if any of the execute bits are set. - * - **/ -gboolean -nautilus_file_is_executable (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return (file->info->flags & (GNOME_VFS_PERM_USER_EXEC - | GNOME_VFS_PERM_GROUP_EXEC - | GNOME_VFS_PERM_OTHER_EXEC)) != 0; -} - -/** - * nautilus_file_delete - * - * Delete this file. - * @file: NautilusFile representing the file in question. - **/ -void -nautilus_file_delete (NautilusFile *file) -{ - char *text_uri; - GnomeVFSResult result; - GList *removed_files; - - g_return_if_fail (file != NULL); - - /* Deleting a file that's already gone is easy. */ - if (file->is_gone) { - return; - } - - /* Do the actual deletion. */ - text_uri = nautilus_file_get_uri (file); - if (nautilus_file_is_directory (file)) { - result = gnome_vfs_remove_directory (text_uri); - } else { - result = gnome_vfs_unlink (text_uri); - } - g_free (text_uri); - - /* Mark the file gone. */ - if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_NOTFOUND) { - file->is_gone = TRUE; - - /* Let the directory know it's gone. */ - if (file->directory != NULL) { - g_list_remove (file->directory->details->files, file); - - /* Send out a message. */ - removed_files = g_list_prepend (NULL, file); - gtk_signal_emit (GTK_OBJECT (file->directory), - nautilus_directory_signals[FILES_REMOVED], - removed_files); - g_list_free (removed_files); - } - } -} - -/** - * nautilus_file_is_gone - * - * Check if a file has already been deleted. - * @file: NautilusFile representing the file in question. - * - * Returns: TRUE if the file is already gone. - **/ -gboolean -nautilus_file_is_gone (NautilusFile *file) -{ - g_return_val_if_fail (file != NULL, FALSE); - - return file->is_gone; -} - -/** - * nautilus_file_list_ref - * - * Ref all the files in a list. - * @file_list: GList of files. - **/ -void -nautilus_file_list_ref (GList *file_list) -{ - g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); -} - -/** - * nautilus_file_list_unref - * - * Unref all the files in a list. - * @file_list: GList of files. - **/ -void -nautilus_file_list_unref (GList *file_list) -{ - g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); -} - -/** - * nautilus_file_list_free - * - * Free a list of files after unrefing them. - * @file_list: GList of files. - **/ -void -nautilus_file_list_free (GList *file_list) -{ - nautilus_file_list_unref (file_list); - g_list_free (file_list); + gtk_signal_emit (GTK_OBJECT (directory), + nautilus_directory_signals[FILES_REMOVED], + removed_files); } #if !defined (NAUTILUS_OMIT_SELF_CHECK) diff --git a/libnautilus/nautilus-directory.h b/libnautilus/nautilus-directory.h index 35058f26b..42ea0451b 100644 --- a/libnautilus/nautilus-directory.h +++ b/libnautilus/nautilus-directory.h @@ -26,7 +26,6 @@ #define NAUTILUS_DIRECTORY_H #include <gtk/gtkobject.h> -#include <libgnomevfs/gnome-vfs-types.h> /* NautilusDirectory is a class that manages the model for a directory, real or virtual, for Nautilus, mainly the file-manager component. The directory is @@ -57,21 +56,6 @@ typedef struct NautilusDirectoryClass NautilusDirectoryClass; #define NAUTILUS_IS_DIRECTORY_CLASS(klass) \ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_DIRECTORY)) -#define NAUTILUS_IS_FILE(object) \ - ((object) != NULL) - -typedef enum { - NAUTILUS_FILE_SORT_NONE, - NAUTILUS_FILE_SORT_BY_NAME, - NAUTILUS_FILE_SORT_BY_SIZE, - NAUTILUS_FILE_SORT_BY_TYPE, - NAUTILUS_FILE_SORT_BY_MTIME -} NautilusFileSortType; - -typedef struct NautilusFile NautilusFile; - -#define NAUTILUS_FILE(file) ((NautilusFile *)(file)) - typedef void (*NautilusFileListCallback) (NautilusDirectory *directory, GList *files, gpointer callback_data); @@ -124,61 +108,6 @@ void nautilus_directory_stop_monitoring (NautilusDirectory */ gboolean nautilus_directory_are_all_files_seen (NautilusDirectory *directory); -/* Getting at a single file. */ -NautilusFile * nautilus_file_get (const char *uri); - -/* Basic operations on file objects. */ -void nautilus_file_ref (NautilusFile *file); -void nautilus_file_unref (NautilusFile *file); -void nautilus_file_delete (NautilusFile *file); - -/* Basic attributes for file objects. */ -char * nautilus_file_get_name (NautilusFile *file); -char * nautilus_file_get_uri (NautilusFile *file); -GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); -GnomeVFSFileType nautilus_file_get_type (NautilusFile *file); -const char * nautilus_file_get_mime_type (NautilusFile *file); -gboolean nautilus_file_is_symbolic_link (NautilusFile *file); -gboolean nautilus_file_is_executable (NautilusFile *file); -gboolean nautilus_file_is_directory (NautilusFile *file); -guint nautilus_file_get_directory_item_count (NautilusFile *file, - gboolean ignore_invisible_items); -GList * nautilus_file_get_keywords (NautilusFile *file); -void nautilus_file_set_keywords (NautilusFile *file, - GList *keywords); - -/* Simple getting and setting top-level metadata. */ -char * nautilus_file_get_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata); -void nautilus_file_set_metadata (NautilusFile *file, - const char *tag, - const char *default_metadata, - const char *metadata); - -/* Attributes for file objects as user-displayable strings. */ -char * nautilus_file_get_string_attribute (NautilusFile *file, - const char *attribute_name); - -/* Comparing two file objects for sorting */ -int nautilus_file_compare_for_sort (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type); -int nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, - NautilusFile *file_2, - NautilusFileSortType sort_type); - -/* Convenience functions for dealing with a list of NautilusFile objects that each have a ref. */ -void nautilus_file_list_ref (GList *file_list); -void nautilus_file_list_unref (GList *file_list); -void nautilus_file_list_free (GList *file_list); - -/* Return true if this file has already been deleted. - This object will be unref'd after sending the files_removed signal, - but it could hang around longer if someone ref'd it. -*/ -gboolean nautilus_file_is_gone (NautilusFile *file); - typedef struct NautilusDirectoryDetails NautilusDirectoryDetails; struct NautilusDirectory @@ -201,10 +130,10 @@ struct NautilusDirectoryClass this is the last chance to forget about these file objects which are about to be unref'd. */ - void (* files_added) (NautilusDirectory *directory, - GList *added_files); - void (* files_removed) (NautilusDirectory *directory, - GList *removed_files); + void (* files_added) (NautilusDirectory *directory, + GList *added_files); + void (* files_removed) (NautilusDirectory *directory, + GList *removed_files); /* The files_changed signal is emitted as changes occur to existing files that are noticed by the synchronization framework. diff --git a/libnautilus/nautilus-file-private.h b/libnautilus/nautilus-file-private.h new file mode 100644 index 000000000..7ee311c9b --- /dev/null +++ b/libnautilus/nautilus-file-private.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-directory.c: Nautilus directory model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include "nautilus-file.h" +#include "nautilus-directory.h" + +struct NautilusFile +{ + guint ref_count; + + NautilusDirectory *directory; + GnomeVFSFileInfo *info; + gboolean is_gone; +}; + +void nautilus_file_free (NautilusFile *); diff --git a/libnautilus/nautilus-file.c b/libnautilus/nautilus-file.c new file mode 100644 index 000000000..56efacead --- /dev/null +++ b/libnautilus/nautilus-file.c @@ -0,0 +1,1014 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-file.c: Nautilus file model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#include <config.h> +#include "nautilus-file-private.h" + +#include <grp.h> +#include <pwd.h> + +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> + +#include "nautilus-glib-extensions.h" +#include "nautilus-string.h" +#include "nautilus-directory-private.h" + +typedef enum { + NAUTILUS_DATE_TYPE_MODIFIED, + NAUTILUS_DATE_TYPE_CHANGED, + NAUTILUS_DATE_TYPE_ACCESSED +} NautilusDateType; + +/* FIXME: This hack needs to die eventually. See comments with function */ +static int get_directory_item_count_hack (NautilusFile *file, + gboolean ignore_invisible_items); + +static int nautilus_file_compare_by_type (NautilusFile *file_1, + NautilusFile *file_2); +static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type, + gboolean reversed); +static char *nautilus_file_get_date_as_string (NautilusFile *file, + NautilusDateType date_type); +static char *nautilus_file_get_owner_as_string (NautilusFile *file); +static char *nautilus_file_get_group_as_string (NautilusFile *file); +static char *nautilus_file_get_permissions_as_string (NautilusFile *file); +static char *nautilus_file_get_size_as_string (NautilusFile *file); +static char *nautilus_file_get_type_as_string (NautilusFile *file); + +/** + * nautilus_file_get: + * @uri: URI of file to get. + * + * Get a file given a uri. + * Returns a referenced object. Unref when finished. + * If two windows are viewing the same uri, the file object is shared. + */ +NautilusFile * +nautilus_file_get (const char *uri) +{ + GnomeVFSResult result; + GnomeVFSFileInfo *file_info; + GnomeVFSURI *vfs_uri, *directory_vfs_uri; + char *directory_uri; + NautilusDirectory *directory; + NautilusFile *file; + + /* Get info on the file. */ + file_info = gnome_vfs_file_info_new (); + result = gnome_vfs_get_file_info (uri, file_info, + GNOME_VFS_FILE_INFO_GETMIMETYPE + | GNOME_VFS_FILE_INFO_FASTMIMETYPE + | GNOME_VFS_FILE_INFO_FOLLOWLINKS, NULL); + if (result != GNOME_VFS_OK) + return NULL; + + /* Make VFS version of URI. */ + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri == NULL) + return NULL; + + /* Make VFS version of directory URI. */ + directory_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); + gnome_vfs_uri_unref (vfs_uri); + if (directory_vfs_uri == NULL) + return NULL; + + /* Make text version of directory URI. */ + directory_uri = gnome_vfs_uri_to_string (directory_vfs_uri, + GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (directory_vfs_uri); + + /* Get object that represents the directory. */ + directory = nautilus_directory_get (directory_uri); + g_free (directory_uri); + if (directory == NULL) + return NULL; + + file = nautilus_directory_new_file (directory, file_info); + + gnome_vfs_file_info_unref (file_info); + nautilus_file_ref (file); + gtk_object_unref (GTK_OBJECT (directory)); + + return file; +} + +void +nautilus_file_ref (NautilusFile *file) +{ + g_return_if_fail (file != NULL); + + g_assert (file->ref_count < G_MAXINT); + g_assert (file->directory != NULL); + + /* Increment the ref count. */ + if (file->ref_count++ != 0) { + return; + } + + /* As soon as someone other than the directory holds a ref, + * we need to hold the directory too. */ + gtk_object_ref (GTK_OBJECT (file->directory)); +} + +void +nautilus_file_unref (NautilusFile *file) +{ + g_return_if_fail (file != NULL); + + g_assert (file->ref_count != 0); + g_assert (file->directory != NULL); + + /* Decrement the ref count. */ + if (--file->ref_count != 0) { + return; + } + + /* No references left, so it's time to release our hold on the directory. */ + gtk_object_unref (GTK_OBJECT (file->directory)); + if (file->is_gone) { + nautilus_file_free (file); + } +} + +void +nautilus_file_free (NautilusFile *file) +{ + g_assert (file->ref_count == 0); + + /* Destroy the file object. */ + gnome_vfs_file_info_unref (file->info); + g_free (file); +} + +static int +nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2) +{ + gboolean is_directory_1; + gboolean is_directory_2; + int item_count_1; + int item_count_2; + + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && !is_directory_2) + return -1; + + if (is_directory_2 && !is_directory_1) + return +1; + + if (!is_directory_1 && !is_directory_2) + return 0; + + /* Both are directories, compare by item count. */ + /* FIXME: get_directory_item_count_hack is slow, and calling + * it for every pairwise comparison here is nasty. Need to + * change this to (not-yet-existent) architecture where the + * item count can be calculated once in a deferred way, and + * then stored or cached. + */ + item_count_1 = get_directory_item_count_hack (file_1, FALSE); + item_count_2 = get_directory_item_count_hack (file_2, FALSE); + + if (item_count_1 < item_count_2) + return -1; + + if (item_count_2 < item_count_1) + return +1; + + return 0; +} + +static int +nautilus_file_compare_by_type (NautilusFile *file_1, NautilusFile *file_2) +{ + gboolean is_directory_1; + gboolean is_directory_2; + char * type_string_1; + char * type_string_2; + int result; + + /* Directories go first. Then, if mime types are identical, + * don't bother getting strings (for speed). This assumes + * that the string is dependent entirely on the mime type, + * which is true now but might not be later. + */ + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && is_directory_2) + return 0; + + if (is_directory_1) + return -1; + + if (is_directory_2) + return +1; + + if (nautilus_strcmp (file_1->info->mime_type, file_2->info->mime_type) == 0) + return 0; + + type_string_1 = nautilus_file_get_type_as_string (file_1); + type_string_2 = nautilus_file_get_type_as_string (file_2); + + result = nautilus_strcmp (type_string_1, type_string_2); + + g_free (type_string_1); + g_free (type_string_2); + + return result; +} + +static int +nautilus_file_compare_for_sort_internal (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type, + gboolean reversed) +{ + GnomeVFSDirectorySortRule rules[3]; + int compare; + + g_return_val_if_fail (file_1 != NULL, 0); + g_return_val_if_fail (file_2 != NULL, 0); + g_return_val_if_fail (sort_type != NAUTILUS_FILE_SORT_NONE, 0); + + switch (sort_type) { + case NAUTILUS_FILE_SORT_BY_NAME: + /* Note: This used to put directories first. I + * thought that was counterintuitive and removed it, + * but I can imagine discussing this further. + * John Sullivan <sullivan@eazel.com> + */ + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_SIZE: + /* Compare directory sizes ourselves, then if necessary + * use GnomeVFS to compare file sizes. + */ + compare = nautilus_file_compare_by_size_with_directories (file_1, file_2); + if (compare != 0) { + return compare; + } + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYSIZE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_TYPE: + /* GnomeVFS doesn't know about our special text for certain + * mime types, so we handle the mime-type sorting ourselves. + */ + compare = nautilus_file_compare_by_type (file_1, file_2); + if (compare != 0) { + return compare; + } + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[1] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + case NAUTILUS_FILE_SORT_BY_MTIME: + rules[0] = GNOME_VFS_DIRECTORY_SORT_BYMTIME; + rules[1] = GNOME_VFS_DIRECTORY_SORT_BYNAME_IGNORECASE; + rules[2] = GNOME_VFS_DIRECTORY_SORT_NONE; + break; + default: + g_assert_not_reached (); + return 0; + } + + if (reversed) + return gnome_vfs_file_info_compare_for_sort_reversed (file_1->info, + file_2->info, + rules); + else + return gnome_vfs_file_info_compare_for_sort (file_1->info, + file_2->info, + rules); +} + +/** + * nautilus_file_compare_for_sort: + * @file_1: A file object + * @file_2: Another file object + * @sort_type: Sort criterion + * + * Return value: int < 0 if @file_1 should come before file_2 in a smallest-to-largest + * sorted list; int > 0 if @file_2 should come before file_1 in a smallest-to-largest + * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note + * that each named sort type may actually break ties several ways, with the name + * of the sort criterion being the primary but not only differentiator. + **/ +int +nautilus_file_compare_for_sort (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type) +{ + return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, FALSE); +} + +/** + * nautilus_file_compare_for_sort_reversed: + * @file_1: A file object + * @file_2: Another file object + * @sort_type: Sort criterion + * + * Return value: The opposite of nautilus_file_compare_for_sort: int > 0 if @file_1 + * should come before file_2 in a smallest-to-largest sorted list; int < 0 if @file_2 + * should come before file_1 in a smallest-to-largest sorted list; 0 if @file_1 + * and @file_2 are equal for this sort criterion. Note that each named sort type + * may actually break ties several ways, with the name of the sort criterion + * being the primary but not only differentiator. + **/ +int +nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type) +{ + return nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type, TRUE); +} + +char * +nautilus_file_get_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata) +{ + g_return_val_if_fail (file != NULL, NULL); + + return nautilus_directory_get_file_metadata (file->directory, + file->info->name, + tag, + default_metadata); +} + +void +nautilus_file_set_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata, + const char *metadata) +{ + g_return_if_fail (file != NULL); + + nautilus_directory_set_file_metadata (file->directory, + file->info->name, + tag, + default_metadata, + metadata); +} + +char * +nautilus_file_get_name (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + g_assert (file->directory == NULL || NAUTILUS_IS_DIRECTORY (file->directory)); + g_assert (file->info->name != NULL); + g_assert (file->info->name[0] != '\0'); + + return g_strdup (file->info->name); +} + +char * +nautilus_file_get_uri (NautilusFile *file) +{ + GnomeVFSURI *uri; + char *uri_text; + + g_return_val_if_fail (file != NULL, NULL); + g_return_val_if_fail (file->directory != NULL, NULL); + + uri = gnome_vfs_uri_append_path (file->directory->details->uri, file->info->name); + uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (uri); + return uri_text; +} + +/** + * nautilus_file_get_date_as_string: + * + * Get a user-displayable string representing a file modification date. + * The caller is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type) +{ + struct tm *file_time; + const char *format; + GDate *today; + GDate *file_date; + guint32 file_date_age; + + g_return_val_if_fail (file != NULL, NULL); + + switch (date_type) + { + case NAUTILUS_DATE_TYPE_CHANGED: + file_time = localtime(&file->info->ctime); + break; + case NAUTILUS_DATE_TYPE_ACCESSED: + file_time = localtime(&file->info->atime); + break; + case NAUTILUS_DATE_TYPE_MODIFIED: + file_time = localtime(&file->info->mtime); + break; + default: + g_assert_not_reached (); + } + file_date = nautilus_g_date_new_tm (file_time); + + today = g_date_new (); + g_date_set_time (today, time (NULL)); + + /* Overflow results in a large number; fine for our purposes. */ + file_date_age = g_date_julian (today) - g_date_julian (file_date); + + g_date_free (file_date); + g_date_free (today); + + /* Format varies depending on how old the date is. This minimizes + * the length (and thus clutter & complication) of typical dates + * while providing sufficient detail for recent dates to make + * them maximally understandable at a glance. Keep all format + * strings separate rather than combining bits & pieces for + * internationalization's sake. + */ + + if (file_date_age == 0) + { + /* today, use special word */ + format = _("today %-I:%M %p"); + } + else if (file_date_age == 1) + { + /* yesterday, use special word */ + format = _("yesterday %-I:%M %p"); + } + else if (file_date_age < 7) + { + /* current week, include day of week */ + format = _("%A %-m/%-d/%y %-I:%M %p"); + } + else + { + format = _("%-m/%-d/%y %-I:%M %p"); + } + + return nautilus_strdup_strftime (format, file_time); +} + +/** + * nautilus_file_get_directory_item_count + * + * Get the number of items in a directory. + * @file: NautilusFile representing a directory. It is an error to + * call this function on a file that is not a directory. + * @ignore_invisible_items: TRUE if invisible items should not be + * included in count. + * + * Returns: item count for this directory. + * + **/ +guint +nautilus_file_get_directory_item_count (NautilusFile *file, + gboolean ignore_invisible_items) +{ + g_return_val_if_fail (nautilus_file_is_directory (file), 0); + + return get_directory_item_count_hack (file, ignore_invisible_items); +} + +/** + * nautilus_file_get_size + * + * Get the file size. + * @file: NautilusFile representing the file in question. + * + * Returns: Size in bytes. + * + **/ +GnomeVFSFileSize +nautilus_file_get_size (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, 0); + + return file->info->size; +} + +/** + * nautilus_file_get_permissions_as_string: + * + * Get a user-displayable string representing a file's permissions. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_permissions_as_string (NautilusFile *file) +{ + GnomeVFSFilePermissions permissions; + gboolean is_directory; + gboolean is_link; + + permissions = file->info->permissions; + is_directory = nautilus_file_is_directory (file); + is_link = GNOME_VFS_FILE_INFO_SYMLINK(file->info); + + return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c", + is_link ? 'l' : is_directory ? 'd' : '-', + permissions & GNOME_VFS_PERM_USER_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_USER_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_USER_EXEC ? 'x' : '-', + permissions & GNOME_VFS_PERM_GROUP_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_GROUP_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_GROUP_EXEC ? 'x' : '-', + permissions & GNOME_VFS_PERM_OTHER_READ ? 'r' : '-', + permissions & GNOME_VFS_PERM_OTHER_WRITE ? 'w' : '-', + permissions & GNOME_VFS_PERM_OTHER_EXEC ? 'x' : '-'); +} + +/** + * nautilus_file_get_owner_as_string: + * + * Get a user-displayable string representing a file's owner. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_owner_as_string (NautilusFile *file) +{ + struct passwd *password_info; + + /* FIXME: Can we trust the uid in the file info? Might + * there be garbage there? What will it do for non-local files? + */ + /* No need to free result of getpwuid */ + password_info = getpwuid (file->info->uid); + + g_print ("pointer to password info is %p\n", password_info); + + if (password_info == NULL) + { + return g_strdup (_("unknown owner")); + } + + return g_strdup (password_info->pw_name); +} + +/** + * nautilus_file_get_group_as_string: + * + * Get a user-displayable string representing a file's group. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_group_as_string (NautilusFile *file) +{ + struct group *group_info; + + /* FIXME: Can we trust the gid in the file info? Might + * there be garbage there? What will it do for non-local files? + */ + /* No need to free result of getgrgid */ + group_info = getgrgid (file->info->gid); + + if (group_info == NULL) + { + return g_strdup (_("unknown group")); + } + + return g_strdup (group_info->gr_name); +} + + +/* This #include is part of the following hack, and should be removed with it */ +#include <dirent.h> + +static int +get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items) +{ + /* Code borrowed from Gnomad and hacked into here for now */ + + char * uri; + char * path; + DIR* directory; + int count; + struct dirent * entry; + + g_assert (nautilus_file_is_directory (file)); + + uri = nautilus_file_get_uri (file); + if (nautilus_has_prefix (uri, "file://")) + path = uri + 7; + else + path = uri; + + directory = opendir (path); + + g_free (uri); + + if (!directory) + return 0; + + count = 0; + + while ((entry = readdir(directory)) != NULL) + // Only count invisible items if requested. + if (!ignore_invisible_items || entry->d_name[0] != '.') + count += 1; + + closedir(directory); + + /* This way of getting the count includes . and .., so we subtract those out */ + if (!ignore_invisible_items) { + count -= 2; + } + + return count; +} + +/** + * nautilus_file_get_size_as_string: + * + * Get a user-displayable string representing a file size. The caller + * is responsible for g_free-ing this string. The string is an item + * count for directories. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_size_as_string (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + if (nautilus_file_is_directory (file)) + { + /* FIXME: Since computing the item count is slow, we + * want to do it in a deferred way. However, that + * architecture doesn't exist yet, so we're hacking + * it in for now. + */ + int item_count; + + item_count = get_directory_item_count_hack (file, FALSE); + if (item_count == 0) { + return g_strdup (_("0 items")); + } else if (item_count == 1) { + return g_strdup (_("1 item")); + } else { + return g_strdup_printf (_("%d items"), item_count); + } + } + + return gnome_vfs_file_size_to_string (file->info->size); +} + +/** + * nautilus_file_get_string_attribute: + * + * Get a user-displayable string from a named attribute. Use g_free to + * free this string. + * + * @file: NautilusFile representing the file in question. + * @attribute_name: The name of the desired attribute. The currently supported + * set includes "name", "type", "size", "date_modified", "date_changed", + * "date_accessed", "owner", "group", "permissions". + * + * Returns: Newly allocated string ready to display to the user, or NULL + * if @attribute_name is not supported. + * + **/ +char * +nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) +{ + /* FIXME: Use hash table and switch statement or function pointers for speed? */ + + if (strcmp (attribute_name, "name") == 0) { + return nautilus_file_get_name (file); + } + + if (strcmp (attribute_name, "type") == 0) { + return nautilus_file_get_type_as_string (file); + } + + if (strcmp (attribute_name, "size") == 0) { + return nautilus_file_get_size_as_string (file); + } + + if (strcmp (attribute_name, "date_modified") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_MODIFIED); + } + + if (strcmp (attribute_name, "date_changed") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_CHANGED); + } + + if (strcmp (attribute_name, "date_accessed") == 0) { + return nautilus_file_get_date_as_string (file, + NAUTILUS_DATE_TYPE_ACCESSED); + } + + if (strcmp (attribute_name, "permissions") == 0) { + return nautilus_file_get_permissions_as_string (file); + } + + if (strcmp (attribute_name, "owner") == 0) { + return nautilus_file_get_owner_as_string (file); + } + + if (strcmp (attribute_name, "group") == 0) { + return nautilus_file_get_group_as_string (file); + } + + return NULL; +} + +/** + * nautilus_file_get_type_as_string: + * + * Get a user-displayable string representing a file type. The caller + * is responsible for g_free-ing this string. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user. + * + **/ +static char * +nautilus_file_get_type_as_string (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, NULL); + + if (nautilus_file_is_directory (file)) { + /* Special-case this so it isn't "special/directory". + * FIXME: Should this be "folder" instead? + */ + return g_strdup (_("directory")); + } + + if (nautilus_strlen (file->info->mime_type) == 0) { + return g_strdup (_("unknown type")); + } + + return g_strdup (file->info->mime_type); +} + +/** + * nautilus_file_get_type + * + * Return this file's type. + * @file: NautilusFile representing the file in question. + * + * Returns: The type. + * + **/ +GnomeVFSFileType +nautilus_file_get_type (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->info->type; +} + +/** + * nautilus_file_get_mime_type + * + * Return this file's mime type. + * @file: NautilusFile representing the file in question. + * + * Returns: The mime type. + * + **/ +const char * +nautilus_file_get_mime_type (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->info->mime_type; +} + +/** + * nautilus_file_get_keywords + * + * Return this file's keywords. + * @file: NautilusFile representing the file in question. + * + * Returns: A list of keywords. + * + **/ +GList * +nautilus_file_get_keywords (NautilusFile *file) +{ + GList *keywords; + xmlNode *file_node, *child; + xmlChar *property; + + g_return_val_if_fail (file != NULL, NULL); + + keywords = NULL; + + /* Put all the keywords into a list. */ + file_node = nautilus_directory_get_file_metadata_node (file->directory, file->info->name); + if (file_node != NULL) { + for (child = file_node->childs; child != NULL; child = child->next) { + if (strcmp (child->name, "KEYWORD") == 0) { + property = xmlGetProp (child, "NAME"); + if (property != NULL) { + keywords = g_list_prepend (keywords, + g_strdup (property)); + } + } + } + } + + return g_list_reverse (keywords); +} + +/** + * nautilus_file_is_symbolic_link + * + * Check if this file is a symbolic link. + * @file: NautilusFile representing the file in question. + * + * Returns: True if the file is a symbolic link. + * + **/ +gboolean +nautilus_file_is_symbolic_link (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return GNOME_VFS_FILE_INFO_SYMLINK (file->info); +} + +/** + * nautilus_file_is_directory + * + * Check if this file is a directory. + * @file: NautilusFile representing the file in question. + * + * Returns: TRUE if @file is a directory. + * + **/ +gboolean +nautilus_file_is_directory (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return nautilus_file_get_type (file) == GNOME_VFS_FILE_TYPE_DIRECTORY; +} + +/** + * nautilus_file_is_executable + * + * Check if this file is executable at all. + * @file: NautilusFile representing the file in question. + * + * Returns: True if any of the execute bits are set. + * + **/ +gboolean +nautilus_file_is_executable (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return (file->info->flags & (GNOME_VFS_PERM_USER_EXEC + | GNOME_VFS_PERM_GROUP_EXEC + | GNOME_VFS_PERM_OTHER_EXEC)) != 0; +} + +/** + * nautilus_file_delete + * + * Delete this file. + * @file: NautilusFile representing the file in question. + **/ +void +nautilus_file_delete (NautilusFile *file) +{ + char *text_uri; + GnomeVFSResult result; + GList *removed_files; + + g_return_if_fail (file != NULL); + + /* Deleting a file that's already gone is easy. */ + if (file->is_gone) { + return; + } + + /* Do the actual deletion. */ + text_uri = nautilus_file_get_uri (file); + if (nautilus_file_is_directory (file)) { + result = gnome_vfs_remove_directory (text_uri); + } else { + result = gnome_vfs_unlink (text_uri); + } + g_free (text_uri); + + /* Mark the file gone. */ + if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_NOTFOUND) { + file->is_gone = TRUE; + + /* Let the directory know it's gone. */ + if (file->directory != NULL) { + g_list_remove (file->directory->details->files, file); + + /* Send out a signal. */ + removed_files = g_list_prepend (NULL, file); + nautilus_directory_files_removed (file->directory, removed_files); + g_list_free (removed_files); + } + } +} + +/** + * nautilus_file_is_gone + * + * Check if a file has already been deleted. + * @file: NautilusFile representing the file in question. + * + * Returns: TRUE if the file is already gone. + **/ +gboolean +nautilus_file_is_gone (NautilusFile *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + return file->is_gone; +} + +/** + * nautilus_file_list_ref + * + * Ref all the files in a list. + * @file_list: GList of files. + **/ +void +nautilus_file_list_ref (GList *file_list) +{ + g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); +} + +/** + * nautilus_file_list_unref + * + * Unref all the files in a list. + * @file_list: GList of files. + **/ +void +nautilus_file_list_unref (GList *file_list) +{ + g_list_foreach (file_list, (GFunc) nautilus_file_ref, NULL); +} + +/** + * nautilus_file_list_free + * + * Free a list of files after unrefing them. + * @file_list: GList of files. + **/ +void +nautilus_file_list_free (GList *file_list) +{ + nautilus_file_list_unref (file_list); + g_list_free (file_list); +} diff --git a/libnautilus/nautilus-file.h b/libnautilus/nautilus-file.h new file mode 100644 index 000000000..dc06290b5 --- /dev/null +++ b/libnautilus/nautilus-file.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + nautilus-file.h: Nautilus file model. + + Copyright (C) 1999, 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Darin Adler <darin@eazel.com> +*/ + +#ifndef NAUTILUS_FILE_H +#define NAUTILUS_FILE_H + +#include <glib.h> /* gnome-vfs-types.h requires glib.h but doesn't include it */ +#include <libgnomevfs/gnome-vfs-types.h> + +/* NautilusFile is an object used to represent a single element of a + * NautilusDirectory. It's lightweight and relies on NautilusDirectory + * to do most of the work. + */ + +typedef enum { + NAUTILUS_FILE_SORT_NONE, + NAUTILUS_FILE_SORT_BY_NAME, + NAUTILUS_FILE_SORT_BY_SIZE, + NAUTILUS_FILE_SORT_BY_TYPE, + NAUTILUS_FILE_SORT_BY_MTIME +} NautilusFileSortType; + +typedef struct NautilusFile NautilusFile; + +#define NAUTILUS_IS_FILE(object) \ + ((object) != NULL) +#define NAUTILUS_FILE(file) \ + ((NautilusFile *)(file)) + +/* Getting at a single file. */ +NautilusFile * nautilus_file_get (const char *uri); + +/* Basic operations on file objects. */ +void nautilus_file_ref (NautilusFile *file); +void nautilus_file_unref (NautilusFile *file); +void nautilus_file_delete (NautilusFile *file); + +/* Basic attributes for file objects. */ +char * nautilus_file_get_name (NautilusFile *file); +char * nautilus_file_get_uri (NautilusFile *file); +GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); +GnomeVFSFileType nautilus_file_get_type (NautilusFile *file); +const char * nautilus_file_get_mime_type (NautilusFile *file); +gboolean nautilus_file_is_symbolic_link (NautilusFile *file); +gboolean nautilus_file_is_executable (NautilusFile *file); +gboolean nautilus_file_is_directory (NautilusFile *file); +guint nautilus_file_get_directory_item_count (NautilusFile *file, + gboolean ignore_invisible_items); +GList * nautilus_file_get_keywords (NautilusFile *file); +void nautilus_file_set_keywords (NautilusFile *file, + GList *keywords); + +/* Simple getting and setting top-level metadata. */ +char * nautilus_file_get_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata); +void nautilus_file_set_metadata (NautilusFile *file, + const char *tag, + const char *default_metadata, + const char *metadata); + +/* Attributes for file objects as user-displayable strings. */ +char * nautilus_file_get_string_attribute (NautilusFile *file, + const char *attribute_name); + +/* Comparing two file objects for sorting */ +int nautilus_file_compare_for_sort (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type); +int nautilus_file_compare_for_sort_reversed (NautilusFile *file_1, + NautilusFile *file_2, + NautilusFileSortType sort_type); + +/* Convenience functions for dealing with a list of NautilusFile objects that each have a ref. */ +void nautilus_file_list_ref (GList *file_list); +void nautilus_file_list_unref (GList *file_list); +void nautilus_file_list_free (GList *file_list); + +/* Return true if this file has already been deleted. + This object will be unref'd after sending the files_removed signal, + but it could hang around longer if someone ref'd it. +*/ +gboolean nautilus_file_is_gone (NautilusFile *file); + +#endif /* NAUTILUS_FILE_H */ diff --git a/libnautilus/nautilus-icon-factory.h b/libnautilus/nautilus-icon-factory.h index 545211440..3e7bfa903 100644 --- a/libnautilus/nautilus-icon-factory.h +++ b/libnautilus/nautilus-icon-factory.h @@ -2,7 +2,7 @@ nautilus-icon-factory.h: Class for obtaining icons for files and other objects. - * Copyright (C) 1999, 2000 Red Hat Inc. + Copyright (C) 1999, 2000 Red Hat Inc. Copyright (C) 1999, 2000 Eazel, Inc. This program is free software; you can redistribute it and/or @@ -27,7 +27,8 @@ #define NAUTILUS_ICON_FACTORY_H #include <gdk-pixbuf/gdk-pixbuf.h> -#include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> +#include <gtk/gtkobject.h> /* NautilusIconFactory is a class that knows how to hand out icons to be * used for representing files and some other objects. It was designed @@ -97,8 +98,8 @@ char * nautilus_icon_factory_get_theme (void); void nautilus_icon_factory_set_theme (const char *theme_name); /* Choose the appropriate icon, but don't render it yet. */ -NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file, - void *controller); +NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file, + void *controller); NautilusScalableIcon *nautilus_icon_factory_get_icon_by_name (const char *icon_name); GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file); diff --git a/libnautilus/nautilus-string.c b/libnautilus/nautilus-string.c index d2df8e286..c3ac00d5e 100644 --- a/libnautilus/nautilus-string.c +++ b/libnautilus/nautilus-string.c @@ -69,10 +69,12 @@ nautilus_has_prefix (const char *haystack_null_allowed, const char *needle_null_ h = haystack_null_allowed == NULL ? "" : haystack_null_allowed; n = needle_null_allowed == NULL ? "" : needle_null_allowed; do { - if (*n == '\0') + if (*n == '\0') { return TRUE; - if (*h == '\0') + } + if (*h == '\0') { return FALSE; + } } while (*h++ == *n++); return FALSE; } @@ -82,19 +84,23 @@ nautilus_has_suffix (const char *haystack_null_allowed, const char *needle_null_ { const char *h, *n; - if (haystack_null_allowed == NULL) + if (needle_null_allowed == NULL) { return TRUE; - if (needle_null_allowed == NULL) - return FALSE; + } + if (haystack_null_allowed == NULL) { + return needle_null_allowed[0] == '\0'; + } /* Eat one character at a time. */ h = haystack_null_allowed + strlen(haystack_null_allowed); n = needle_null_allowed + strlen(needle_null_allowed); do { - if (n == needle_null_allowed) + if (n == needle_null_allowed) { return TRUE; - if (h == haystack_null_allowed) + } + if (h == haystack_null_allowed) { return FALSE; + } } while (*--h == *--n); return FALSE; } @@ -144,23 +150,28 @@ nautilus_string_to_int (const char *string, int *integer) char *parse_end; /* Check for the case of an empty string. */ - if (string == NULL || *string == '\0') + if (string == NULL || *string == '\0') { return FALSE; + } /* Call the standard library routine to do the conversion. */ errno = 0; result = strtol (string, &parse_end, 0); /* Check that the result is in range. */ - if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) { return FALSE; - if (result < G_MININT || result > G_MAXINT) + } + if (result < G_MININT || result > G_MAXINT) { return FALSE; + } /* Check that all the trailing characters are spaces. */ - while (*parse_end != '\0') - if (!isspace (*parse_end++)) + while (*parse_end != '\0') { + if (!isspace (*parse_end++)) { return FALSE; + } + } /* Return the result. */ *integer = result; @@ -170,27 +181,27 @@ nautilus_string_to_int (const char *string, int *integer) /** * nautilus_strstrip: * Remove all occurrences of a character from a string. The - * original string is modified, and also returned for convenience. + * original string is modified in place, and also returned for convenience. * * @string_null_allowed: The string to be stripped. * @remove_this: The char to remove from @string_null_allowed * * Return value: @string_null_allowed, after removing all occurrences - * of @remove_this. + * of @remove_this. */ char * nautilus_strstrip (char *string_null_allowed, char remove_this) { if (string_null_allowed != NULL) { - char *pos; + char *in, *out; - pos = string_null_allowed; - while (*pos != '\0') { - if (*pos == remove_this) { - g_memmove (pos, pos + 1, strlen (pos)); + in = string_null_allowed; + out = string_null_allowed; + do { + if (*in != remove_this) { + *out++ = *in; } - ++pos; - } + } while (*in++ != '\0'); } return string_null_allowed; @@ -232,7 +243,6 @@ void nautilus_self_check_string (void) { int integer; - char *test_string; NAUTILUS_CHECK_INTEGER_RESULT (nautilus_strlen (NULL), 0); NAUTILUS_CHECK_INTEGER_RESULT (nautilus_strlen (""), 0); @@ -283,6 +293,22 @@ nautilus_self_check_string (void) NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_prefix ("aaa", "aaab"), FALSE); NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_prefix ("aaab", "aaa"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, ""), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("", NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "a"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("aaab", "aaab"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix (NULL, "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", NULL), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("", "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", ""), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "b"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("a", "ab"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("ab", "a"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("ab", "b"), TRUE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("aaa", "baaa"), FALSE); + NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_has_suffix ("baaa", "aaa"), TRUE); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix (NULL, NULL), NULL); NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix (NULL, "foo"), NULL); NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix ("foo", NULL), "foo"); @@ -292,14 +318,11 @@ nautilus_self_check_string (void) NAUTILUS_CHECK_STRING_RESULT (nautilus_strdup_prefix ("footle:bar", "tle:"), "foo"); NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (NULL, '_'), NULL); - test_string = g_strdup ("foo"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("_foo"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("foo_"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); - test_string = g_strdup ("_foo_"); - NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (test_string, '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("foo"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_foo"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("foo_"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_foo_"), '_'), "foo"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_strstrip (g_strdup ("_f_o__o_"), '_'), "foo"); #define TEST_INTEGER_CONVERSION_FUNCTIONS(string, boolean_result, integer_result) \ NAUTILUS_CHECK_BOOLEAN_RESULT (nautilus_string_to_int (string, &integer), boolean_result); \ diff --git a/libnautilus/nautilus-string.h b/libnautilus/nautilus-string.h index 9d269dcd7..03c778f00 100644 --- a/libnautilus/nautilus-string.h +++ b/libnautilus/nautilus-string.h @@ -47,8 +47,8 @@ char * nautilus_strdup_prefix (const char *source_null_allowed, gboolean nautilus_has_suffix (const char *target_null_allowed, const char *suffix_null_allowed); -char * nautilus_strstrip (char *string_null_allowed, - char remove_this); +char * nautilus_strstrip (char *string_null_allowed, + char remove_this); /* Conversions to and from strings. */ diff --git a/src/file-manager/Makefile.am b/src/file-manager/Makefile.am index de6d20e66..36412e10d 100644 --- a/src/file-manager/Makefile.am +++ b/src/file-manager/Makefile.am @@ -33,6 +33,8 @@ libntl_file_manager_la_SOURCES= \ fm-icon-text-window.h \ fm-icons-controller.c \ fm-icons-controller.h \ + fm-properties-window.c \ + fm-properties-window.h \ fm-signaller.c \ fm-signaller.h diff --git a/src/file-manager/fm-directory-view-icons.c b/src/file-manager/fm-directory-view-icons.c index 561602c4d..4c1940c7c 100644 --- a/src/file-manager/fm-directory-view-icons.c +++ b/src/file-manager/fm-directory-view-icons.c @@ -49,11 +49,11 @@ #define DEFAULT_BACKGROUND_COLOR "rgb:FFFF/FFFF/FFFF" /* Paths to use when creating & referring to bonobo menu items */ -#define FM_DIRECTORY_VIEW_ICONS_MENU_PATH_BEFORE_STRETCH_SEPARATOR "/Settings/Before Stretch Separator" -#define FM_DIRECTORY_VIEW_ICONS_MENU_PATH_STRETCH_ICON "/Settings/Stretch" -#define FM_DIRECTORY_VIEW_ICONS_MENU_PATH_RESTORE_STRETCHED_ICONS "/Settings/Restore" -#define FM_DIRECTORY_VIEW_ICONS_MENU_PATH_AFTER_STRETCH_SEPARATOR "/Settings/After Stretch Separator" -#define FM_DIRECTORY_VIEW_ICONS_MENU_PATH_CUSTOMIZE_ICON_TEXT "/Settings/Icon Text" +#define MENU_PATH_BEFORE_STRETCH_SEPARATOR "/Settings/Before Stretch Separator" +#define MENU_PATH_STRETCH_ICON "/Settings/Stretch" +#define MENU_PATH_RESTORE_STRETCHED_ICONS "/Settings/Restore" +#define MENU_PATH_AFTER_STRETCH_SEPARATOR "/Settings/After Stretch Separator" +#define MENU_PATH_CUSTOMIZE_ICON_TEXT "/Settings/Icon Text" /* forward declarations */ @@ -367,14 +367,14 @@ fm_directory_view_icons_compute_menu_item_info (FMDirectoryViewIcons *view, icon_container = get_icon_container (view); - if (strcmp (FM_DIRECTORY_VIEW_ICONS_MENU_PATH_STRETCH_ICON, menu_path) == 0) { + if (strcmp (MENU_PATH_STRETCH_ICON, menu_path) == 0) { *return_name = g_strdup (_("_Stretch Icon")); /* Current stretching UI only works on one item at a time, so we'll * desensitize the menu item if that's not the case. */ *sensitive_return = g_list_length (files) == 1 && !gnome_icon_container_has_stretch_handles (icon_container); - } else if (strcmp (FM_DIRECTORY_VIEW_ICONS_MENU_PATH_RESTORE_STRETCHED_ICONS, menu_path) == 0) { + } else if (strcmp (MENU_PATH_RESTORE_STRETCHED_ICONS, menu_path) == 0) { if (g_list_length (files) > 1) { *return_name = g_strdup (_("_Restore Icons to Unstretched Size")); } else { @@ -383,7 +383,7 @@ fm_directory_view_icons_compute_menu_item_info (FMDirectoryViewIcons *view, *sensitive_return = gnome_icon_container_is_stretched (icon_container); - } else if (strcmp (FM_DIRECTORY_VIEW_ICONS_MENU_PATH_CUSTOMIZE_ICON_TEXT, menu_path) == 0) { + } else if (strcmp (MENU_PATH_CUSTOMIZE_ICON_TEXT, menu_path) == 0) { *return_name = g_strdup (_("Customize _Icon Text...")); *sensitive_return = TRUE; } else { @@ -433,26 +433,20 @@ fm_directory_view_icons_append_selection_context_menu_items (FMDirectoryView *vi (view, menu, files)); append_one_context_menu_item (FM_DIRECTORY_VIEW_ICONS (view), menu, files, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_STRETCH_ICON, + MENU_PATH_STRETCH_ICON, GTK_SIGNAL_FUNC (show_stretch_handles_cb)); append_one_context_menu_item (FM_DIRECTORY_VIEW_ICONS (view), menu, files, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_RESTORE_STRETCHED_ICONS, + MENU_PATH_RESTORE_STRETCHED_ICONS, GTK_SIGNAL_FUNC (unstretch_icons_cb)); } -/** - * Note that this is used both as a Bonobo menu callback and a signal callback. +/* Note that this is used both as a Bonobo menu callback and a signal callback. * The first parameter is different in these cases, but we just ignore it anyway. */ static void -customize_icon_text_cb (gpointer ignored, gpointer view) +customize_icon_text_cb (gpointer ignored1, gpointer ignored2) { - GtkWindow *window; - - g_assert (FM_IS_DIRECTORY_VIEW_ICONS (view)); - - window = GTK_WINDOW (fm_icon_text_window_get_or_create ()); - nautilus_gtk_window_present (window); + nautilus_gtk_window_present (fm_icon_text_window_get_or_create ()); } static void @@ -476,7 +470,7 @@ fm_directory_view_icons_append_background_context_menu_items (FMDirectoryView *v gtk_menu_append (menu, menu_item); append_one_context_menu_item (FM_DIRECTORY_VIEW_ICONS (view), menu, NULL, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_CUSTOMIZE_ICON_TEXT, + MENU_PATH_CUSTOMIZE_ICON_TEXT, GTK_SIGNAL_FUNC (customize_icon_text_cb)); } @@ -791,26 +785,26 @@ fm_directory_view_icons_merge_menus (FMDirectoryView *view) ui_handler = fm_directory_view_get_bonobo_ui_handler (view); bonobo_ui_handler_menu_new_separator (ui_handler, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_BEFORE_STRETCH_SEPARATOR, + MENU_PATH_BEFORE_STRETCH_SEPARATOR, -1); append_bonobo_menu_item (FM_DIRECTORY_VIEW_ICONS (view), ui_handler, selection, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_STRETCH_ICON, + MENU_PATH_STRETCH_ICON, _("Make the selected icon stretchable"), - (BonoboUIHandlerCallbackFunc)show_stretch_handles_cb, view); + (BonoboUIHandlerCallbackFunc) show_stretch_handles_cb, view); append_bonobo_menu_item (FM_DIRECTORY_VIEW_ICONS (view), ui_handler, selection, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_RESTORE_STRETCHED_ICONS, + MENU_PATH_RESTORE_STRETCHED_ICONS, _("Restore each selected icon to its original size"), - (BonoboUIHandlerCallbackFunc)unstretch_icons_cb, view); + (BonoboUIHandlerCallbackFunc) unstretch_icons_cb, view); bonobo_ui_handler_menu_new_separator (ui_handler, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_AFTER_STRETCH_SEPARATOR, + MENU_PATH_AFTER_STRETCH_SEPARATOR, -1); append_bonobo_menu_item (FM_DIRECTORY_VIEW_ICONS (view), ui_handler, selection, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_CUSTOMIZE_ICON_TEXT, + MENU_PATH_CUSTOMIZE_ICON_TEXT, _("Choose which information appears beneath each icon's name"), - (BonoboUIHandlerCallbackFunc)customize_icon_text_cb, view); + (BonoboUIHandlerCallbackFunc) customize_icon_text_cb, view); nautilus_file_list_free (selection); } @@ -842,9 +836,9 @@ fm_directory_view_icons_update_menus (FMDirectoryView *view) selection = fm_directory_view_get_selection (view); update_bonobo_menu_item (FM_DIRECTORY_VIEW_ICONS (view), ui_handler, selection, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_STRETCH_ICON); + MENU_PATH_STRETCH_ICON); update_bonobo_menu_item (FM_DIRECTORY_VIEW_ICONS (view), ui_handler, selection, - FM_DIRECTORY_VIEW_ICONS_MENU_PATH_RESTORE_STRETCHED_ICONS); + MENU_PATH_RESTORE_STRETCHED_ICONS); nautilus_file_list_free (selection); } diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index ce8dfa3a2..80ef16a14 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -45,15 +45,18 @@ #include <libnautilus/nautilus-icon-factory.h> #include <libnautilus/nautilus-string.h> +#include "fm-properties-window.h" + #define DISPLAY_TIMEOUT_INTERVAL_MSECS 500 /* Paths to use when creating & referring to bonobo menu items */ -#define FM_DIRECTORY_VIEW_MENU_PATH_OPEN "/File/Open" -#define FM_DIRECTORY_VIEW_MENU_PATH_OPEN_IN_NEW_WINDOW "/File/OpenNew" -#define FM_DIRECTORY_VIEW_MENU_PATH_DELETE "/File/Delete" -#define FM_DIRECTORY_VIEW_MENU_PATH_SELECT_ALL "/Edit/Select All" +#define MENU_PATH_OPEN "/File/Open" +#define MENU_PATH_OPEN_IN_NEW_WINDOW "/File/OpenNew" +#define MENU_PATH_DELETE "/File/Delete" +#define MENU_PATH_SELECT_ALL "/Edit/Select All" +#define MENU_PATH_SET_PROPERTIES "/Edit/Set Properties" -enum +enum { ADD_ENTRY, APPEND_BACKGROUND_CONTEXT_MENU_ITEMS, @@ -88,48 +91,51 @@ struct _FMDirectoryViewDetails }; /* forward declarations */ -static void delete_cb (GtkMenuItem *item, GList *files); -static int display_selection_info_idle_cb (gpointer data); -static void display_selection_info (FMDirectoryView *view); -static void fm_directory_view_initialize_class (FMDirectoryViewClass *klass); -static void fm_directory_view_initialize (FMDirectoryView *view); -static void fm_directory_view_delete_with_confirm (FMDirectoryView *view, GList *files); -static void fm_directory_view_destroy (GtkObject *object); -static void fm_directory_view_append_background_context_menu_items - (FMDirectoryView *view, - GtkMenu *menu); -static void fm_directory_view_merge_menus (FMDirectoryView *view); -static void fm_directory_view_real_append_background_context_menu_items - (FMDirectoryView *view, - GtkMenu *menu); -static void fm_directory_view_real_append_selection_context_menu_items - (FMDirectoryView *view, - GtkMenu *menu, - GList *files); -static void fm_directory_view_real_merge_menus (FMDirectoryView *view); -static void fm_directory_view_real_update_menus (FMDirectoryView *view); -static GtkMenu *create_selection_context_menu (FMDirectoryView *view); -static GtkMenu *create_background_context_menu (FMDirectoryView *view); -static BonoboControl *get_bonobo_control (FMDirectoryView *view); -static void stop_location_change_cb (NautilusViewFrame *view_frame, - FMDirectoryView *directory_view); -static void notify_location_change_cb (NautilusViewFrame *view_frame, - Nautilus_NavigationInfo *nav_context, - FMDirectoryView *directory_view); -static void open_cb (GtkMenuItem *item, NautilusFile *file); -static void open_in_new_window_cb (GtkMenuItem *item, GList *files); -static void open_one_in_new_window (gpointer data, gpointer user_data); -static void select_all_cb (GtkMenuItem *item, FMDirectoryView *directory_view); -static void zoom_in_cb (GtkMenuItem *item, FMDirectoryView *directory_view); -static void zoom_out_cb (GtkMenuItem *item, FMDirectoryView *directory_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 delete_cb (GtkMenuItem *item, + GList *files); +static int display_selection_info_idle_cb (gpointer data); +static void display_selection_info (FMDirectoryView *view); +static void fm_directory_view_initialize_class (FMDirectoryViewClass *klass); +static void fm_directory_view_initialize (FMDirectoryView *view); +static void fm_directory_view_delete_with_confirm (FMDirectoryView *view, + GList *files); +static void fm_directory_view_destroy (GtkObject *object); +static void fm_directory_view_append_background_context_menu_items (FMDirectoryView *view, + GtkMenu *menu); +static void fm_directory_view_merge_menus (FMDirectoryView *view); +static void fm_directory_view_real_append_background_context_menu_items (FMDirectoryView *view, + GtkMenu *menu); +static void fm_directory_view_real_append_selection_context_menu_items (FMDirectoryView *view, + GtkMenu *menu, + GList *files); +static void fm_directory_view_real_merge_menus (FMDirectoryView *view); +static void fm_directory_view_real_update_menus (FMDirectoryView *view); +static GtkMenu * create_selection_context_menu (FMDirectoryView *view); +static GtkMenu * create_background_context_menu (FMDirectoryView *view); +static BonoboControl *get_bonobo_control (FMDirectoryView *view); +static void stop_location_change_cb (NautilusViewFrame *view_frame, + FMDirectoryView *directory_view); +static void notify_location_change_cb (NautilusViewFrame *view_frame, + Nautilus_NavigationInfo *nav_context, + FMDirectoryView *directory_view); +static void open_cb (GtkMenuItem *item, + GList *files); +static void open_in_new_window_cb (GtkMenuItem *item, + GList *files); +static void open_one_in_new_window (gpointer data, + gpointer user_data); +static void select_all_cb (GtkMenuItem *item, + FMDirectoryView *directory_view); +static void zoom_in_cb (GtkMenuItem *item, + FMDirectoryView *directory_view); +static void zoom_out_cb (GtkMenuItem *item, + FMDirectoryView *directory_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); NAUTILUS_DEFINE_CLASS_BOILERPLATE (FMDirectoryView, fm_directory_view, GTK_TYPE_SCROLLED_WINDOW) NAUTILUS_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, add_entry) @@ -292,8 +298,8 @@ bonobo_menu_delete_cb (BonoboUIHandler *ui_handler, gpointer user_data, const ch static BonoboControl * get_bonobo_control (FMDirectoryView *view) { - return BONOBO_CONTROL (nautilus_view_frame_get_bonobo_control ( - NAUTILUS_VIEW_FRAME (view->details->view_frame))); + return BONOBO_CONTROL (nautilus_view_frame_get_bonobo_control + (NAUTILUS_VIEW_FRAME (view->details->view_frame))); } static void @@ -423,10 +429,11 @@ display_selection_info (FMDirectoryView *view) non_folder_size += nautilus_file_get_size (file); } - if (first_item_name == NULL) + if (first_item_name == NULL) { first_item_name = nautilus_file_get_name (file); + } } - + nautilus_file_list_free (selection); memset (&request, 0, sizeof (request)); @@ -1090,13 +1097,16 @@ delete_cb (GtkMenuItem *item, GList *files) /* handle the open command */ static void -open_cb (GtkMenuItem *item, NautilusFile *file) +open_cb (GtkMenuItem *item, GList *files) { FMDirectoryView *directory_view; + g_assert (g_list_length (files) == 1); + g_assert (NAUTILUS_IS_FILE (files->data)); + directory_view = FM_DIRECTORY_VIEW (gtk_object_get_data (GTK_OBJECT (item), "directory_view")); - fm_directory_view_activate_entry (directory_view, file, FALSE); + fm_directory_view_activate_entry (directory_view, files->data, FALSE); } static void @@ -1119,6 +1129,25 @@ open_in_new_window_cb (GtkMenuItem *item, GList *files) } static void +open_one_properties_window (gpointer data, gpointer user_data) +{ + g_assert (NAUTILUS_IS_FILE (data)); + g_assert (FM_IS_DIRECTORY_VIEW (user_data)); + + nautilus_gtk_window_present (fm_properties_window_get_or_create (data)); +} + +static void +open_properties_window_cb (GtkMenuItem *item, GList *files) +{ + FMDirectoryView *directory_view; + + directory_view = FM_DIRECTORY_VIEW (gtk_object_get_data (GTK_OBJECT (item), "directory_view")); + + g_list_foreach (files, open_one_properties_window, directory_view); +} + +static void finish_adding_menu_item (GtkMenu *menu, GtkWidget *menu_item, gboolean sensitive) { gtk_widget_set_sensitive (menu_item, sensitive); @@ -1157,19 +1186,22 @@ compute_menu_item_info (const char *path, char **return_name, gboolean *return_sensitivity) { - if (strcmp (path, FM_DIRECTORY_VIEW_MENU_PATH_OPEN) == 0) { + if (strcmp (path, MENU_PATH_OPEN) == 0) { *return_name = g_strdup_printf (_("_Open")); *return_sensitivity = selection_length == 1; - } else if (strcmp (path, FM_DIRECTORY_VIEW_MENU_PATH_OPEN_IN_NEW_WINDOW) == 0) { + } else if (strcmp (path, MENU_PATH_OPEN_IN_NEW_WINDOW) == 0) { if (selection_length <= 1) { *return_name = g_strdup (_("Open in _New Window")); } else { *return_name = g_strdup_printf (_("Open in %d _New Windows"), selection_length); } *return_sensitivity = selection_length > 0; - } else if (strcmp (path, FM_DIRECTORY_VIEW_MENU_PATH_DELETE) == 0) { + } else if (strcmp (path, MENU_PATH_DELETE) == 0) { *return_name = g_strdup (_("_Delete...")); *return_sensitivity = selection_length > 0; + } else if (strcmp (path, MENU_PATH_SET_PROPERTIES) == 0) { + *return_name = g_strdup (_("Set _Properties...")); + *return_sensitivity = selection_length > 0; } else { g_assert_not_reached (); } @@ -1180,84 +1212,52 @@ compute_menu_item_info (const char *path, } static void -append_one_selection_context_menu_item (GtkMenu *menu, - const char *path, - int item_count, - const char *item_data_id, - gpointer item_data, - GtkDestroyNotify item_data_destroy_func, - gboolean ref_item_data, - GtkSignalFunc callback, - gpointer callback_data) +append_selection_menu_item (FMDirectoryView *view, + GtkMenu *menu, + GList *files, + const char *path, + GtkSignalFunc callback) { GtkWidget *menu_item; char *label_string; gboolean sensitive; - compute_menu_item_info (path, item_count, FALSE, &label_string, &sensitive); + compute_menu_item_info (path, g_list_length (files), FALSE, &label_string, &sensitive); menu_item = gtk_menu_item_new_with_label (label_string); g_free (label_string); + if (sensitive) { - if (item_data != NULL) { - gtk_object_set_data_full (GTK_OBJECT (menu_item), - item_data_id, - item_data, - item_data_destroy_func); - if (ref_item_data) { - gtk_object_ref (GTK_OBJECT (item_data)); - } - } - + /* Attach directory view to item. */ + gtk_object_ref (GTK_OBJECT (view)); + gtk_object_set_data_full (GTK_OBJECT (menu_item), + "directory_view", + view, + (GtkDestroyNotify) gtk_object_unref); + + /* Attack callback function to item. */ gtk_signal_connect (GTK_OBJECT (menu_item), "activate", callback, - callback_data); + files); } finish_adding_menu_item (menu, menu_item, sensitive); -} +} static void fm_directory_view_real_append_selection_context_menu_items (FMDirectoryView *view, GtkMenu *menu, GList *files) { - int item_count; - - item_count = g_list_length (files); - - g_assert (item_count >= 1); - - append_one_selection_context_menu_item (menu, - FM_DIRECTORY_VIEW_MENU_PATH_OPEN, - item_count, - "directory_view", - view, - (GtkDestroyNotify) gtk_object_unref, - TRUE, - open_cb, - files->data); - - append_one_selection_context_menu_item (menu, - FM_DIRECTORY_VIEW_MENU_PATH_OPEN_IN_NEW_WINDOW, - item_count, - "directory_view", - view, - (GtkDestroyNotify) gtk_object_unref, - TRUE, - open_in_new_window_cb, - files); - - append_one_selection_context_menu_item (menu, - FM_DIRECTORY_VIEW_MENU_PATH_DELETE, - item_count, - "directory_view", - view, - (GtkDestroyNotify) gtk_object_unref, - TRUE, - delete_cb, - files); + append_selection_menu_item (view, menu, files, + MENU_PATH_OPEN, open_cb); + append_selection_menu_item (view, menu, files, + MENU_PATH_OPEN_IN_NEW_WINDOW, open_in_new_window_cb); + append_selection_menu_item (view, menu, files, + MENU_PATH_DELETE, delete_cb); + append_selection_menu_item (view, menu, files, + MENU_PATH_SET_PROPERTIES, open_properties_window_cb); } static void @@ -1273,7 +1273,7 @@ fm_directory_view_real_merge_menus (FMDirectoryView *view) * right places without special knowledge like this. */ bonobo_ui_handler_menu_new_item (ui_handler, - FM_DIRECTORY_VIEW_MENU_PATH_OPEN, + MENU_PATH_OPEN, _("_Open"), _("Open the selected item in this window"), 1, @@ -1284,7 +1284,7 @@ fm_directory_view_real_merge_menus (FMDirectoryView *view) bonobo_menu_open_cb, view); bonobo_ui_handler_menu_new_item (ui_handler, - FM_DIRECTORY_VIEW_MENU_PATH_OPEN_IN_NEW_WINDOW, + MENU_PATH_OPEN_IN_NEW_WINDOW, _("Open in New Window"), _("Open each selected item in a new window"), 2, @@ -1295,7 +1295,7 @@ fm_directory_view_real_merge_menus (FMDirectoryView *view) bonobo_menu_open_in_new_window_cb, view); bonobo_ui_handler_menu_new_item (ui_handler, - FM_DIRECTORY_VIEW_MENU_PATH_DELETE, + MENU_PATH_DELETE, _("Delete..."), _("Delete all selected items"), 3, @@ -1306,15 +1306,15 @@ fm_directory_view_real_merge_menus (FMDirectoryView *view) bonobo_menu_delete_cb, view); bonobo_ui_handler_menu_new_item (ui_handler, - FM_DIRECTORY_VIEW_MENU_PATH_SELECT_ALL, + MENU_PATH_SELECT_ALL, _("Select All"), _("Select all items in this window"), - bonobo_ui_handler_menu_get_pos (ui_handler, FM_DIRECTORY_VIEW_MENU_PATH_SELECT_ALL), + bonobo_ui_handler_menu_get_pos (ui_handler, MENU_PATH_SELECT_ALL), BONOBO_UI_HANDLER_PIXMAP_NONE, NULL, 0, 0, - (BonoboUIHandlerCallbackFunc)select_all_cb, + (BonoboUIHandlerCallbackFunc) select_all_cb, view); } @@ -1342,9 +1342,9 @@ fm_directory_view_real_update_menus (FMDirectoryView *view) count = g_list_length (selection); nautilus_file_list_free (selection); - update_one_menu_item (handler, FM_DIRECTORY_VIEW_MENU_PATH_OPEN, count); - update_one_menu_item (handler, FM_DIRECTORY_VIEW_MENU_PATH_OPEN_IN_NEW_WINDOW, count); - update_one_menu_item (handler, FM_DIRECTORY_VIEW_MENU_PATH_DELETE, count); + update_one_menu_item (handler, MENU_PATH_OPEN, count); + update_one_menu_item (handler, MENU_PATH_OPEN_IN_NEW_WINDOW, count); + update_one_menu_item (handler, MENU_PATH_DELETE, count); } static GtkMenu * @@ -1410,8 +1410,6 @@ fm_directory_view_append_background_context_menu_items (FMDirectoryView *view, } -/* FIXME - need a way for specific views to add custom commands here. */ - static GtkMenu * create_background_context_menu (FMDirectoryView *view) { @@ -1462,7 +1460,6 @@ fm_directory_view_pop_up_background_context_menu (FMDirectoryView *view) NAUTILUS_DEFAULT_POPUP_MENU_DISPLACEMENT); } - /** * fm_directory_view_notify_selection_changed: * @@ -1581,7 +1578,6 @@ fm_directory_view_load_uri (FMDirectoryView *view, view); } - /** * fm_directory_view_merge_menus: * diff --git a/src/file-manager/fm-directory-view.h b/src/file-manager/fm-directory-view.h index b18c274f7..f240d60b4 100644 --- a/src/file-manager/fm-directory-view.h +++ b/src/file-manager/fm-directory-view.h @@ -30,6 +30,7 @@ #include <gtk/gtkscrolledwindow.h> #include <libnautilus/ntl-content-view-frame.h> #include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> typedef struct _FMDirectoryView FMDirectoryView; typedef struct _FMDirectoryViewClass FMDirectoryViewClass; diff --git a/src/file-manager/fm-icon-text-window.c b/src/file-manager/fm-icon-text-window.c index 030fb230e..66e0057cf 100644 --- a/src/file-manager/fm-icon-text-window.c +++ b/src/file-manager/fm-icon-text-window.c @@ -36,8 +36,10 @@ #include <gtk/gtktext.h> #include <gtk/gtkradiobutton.h> #include <gtk/gtkvbox.h> +#include <libgnome/gnome-defs.h> #include <libgnome/gnome-i18n.h> #include <libgnomeui/gnome-uidefs.h> +#include "fm-directory-view-icons.h" static void ensure_unique_attributes (int menu_index); static gboolean fm_icon_text_window_delete_event_cb (GtkWidget *widget, @@ -288,14 +290,14 @@ fm_icon_text_window_delete_event_cb (GtkWidget *widget, * beneath icons. * **/ -GtkWidget * +GtkWindow * fm_icon_text_window_get_or_create (void) { static GtkWidget *icon_text_window = NULL; - if (icon_text_window == NULL) + if (icon_text_window == NULL) { icon_text_window = create_icon_text_window (); + } - g_assert (GTK_IS_WINDOW (icon_text_window)); - return icon_text_window; + return GTK_WINDOW (icon_text_window); } diff --git a/src/file-manager/fm-icon-text-window.h b/src/file-manager/fm-icon-text-window.h index 55f18444d..6ef905db5 100644 --- a/src/file-manager/fm-icon-text-window.h +++ b/src/file-manager/fm-icon-text-window.h @@ -26,9 +26,8 @@ #ifndef FM_ICON_TEXT_WINDOW_H #define FM_ICON_TEXT_WINDOW_H -#include "fm-directory-view-icons.h" #include <gtk/gtkwindow.h> -GtkWidget * fm_icon_text_window_get_or_create (void); +GtkWindow *fm_icon_text_window_get_or_create (void); #endif /* FM_ICON_TEXT_WINDOW_H */ diff --git a/src/file-manager/fm-properties-window.c b/src/file-manager/fm-properties-window.c new file mode 100644 index 000000000..afdc95476 --- /dev/null +++ b/src/file-manager/fm-properties-window.c @@ -0,0 +1,34 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* fm-properties-window.c - window that lets user modify file properties + + Copyright (C) 2000 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <darin@eazel.com> +*/ + +#include <config.h> +#include "fm-properties-window.h" + +/* static GHashTable *windows; */ + +GtkWindow * +fm_properties_window_get_or_create (NautilusFile *file) +{ + return NULL; +} diff --git a/src/file-manager/fm-properties-window.h b/src/file-manager/fm-properties-window.h new file mode 100644 index 000000000..db57c6642 --- /dev/null +++ b/src/file-manager/fm-properties-window.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* fm-properties-window.h - interface for window that lets user modify + icon properties + + Copyright (C) 2000 Eazel, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <darin@eazel.com> +*/ + +#ifndef FM_PROPERTIES_WINDOW_H +#define FM_PROPERTIES_WINDOW_H + +#include <gtk/gtkwindow.h> +#include <libnautilus/nautilus-file.h> + +GtkWindow *fm_properties_window_get_or_create (NautilusFile *); + +#endif /* FM_PROPERTIES_WINDOW_H */ diff --git a/src/nautilus-information-panel.c b/src/nautilus-information-panel.c index c3652a053..54d2b46e7 100644 --- a/src/nautilus-information-panel.c +++ b/src/nautilus-information-panel.c @@ -37,6 +37,7 @@ #include <libgnomevfs/gnome-vfs-uri.h> #include <libnautilus/nautilus-background.h> #include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> #include <libnautilus/nautilus-glib-extensions.h> #include <libnautilus/nautilus-gtk-macros.h> #include <libnautilus/nautilus-metadata.h> diff --git a/src/nautilus-sidebar.c b/src/nautilus-sidebar.c index c3652a053..54d2b46e7 100644 --- a/src/nautilus-sidebar.c +++ b/src/nautilus-sidebar.c @@ -37,6 +37,7 @@ #include <libgnomevfs/gnome-vfs-uri.h> #include <libnautilus/nautilus-background.h> #include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> #include <libnautilus/nautilus-glib-extensions.h> #include <libnautilus/nautilus-gtk-macros.h> #include <libnautilus/nautilus-metadata.h> diff --git a/src/ntl-index-panel.c b/src/ntl-index-panel.c index c3652a053..54d2b46e7 100644 --- a/src/ntl-index-panel.c +++ b/src/ntl-index-panel.c @@ -37,6 +37,7 @@ #include <libgnomevfs/gnome-vfs-uri.h> #include <libnautilus/nautilus-background.h> #include <libnautilus/nautilus-directory.h> +#include <libnautilus/nautilus-file.h> #include <libnautilus/nautilus-glib-extensions.h> #include <libnautilus/nautilus-gtk-macros.h> #include <libnautilus/nautilus-metadata.h> |