diff options
author | Pavel Cisler <pavel@eazel.com> | 2000-11-16 03:32:07 +0000 |
---|---|---|
committer | Pavel Cisler <pce@src.gnome.org> | 2000-11-16 03:32:07 +0000 |
commit | 0498767b316c4588f85bc823a15b5471f169f79d (patch) | |
tree | 81f3bb89f72e8b638f54d9f20584569fca1a4bf5 | |
parent | 2803047ec478d3ca91ee27eeea087aa8ff36ec32 (diff) | |
download | nautilus-0498767b316c4588f85bc823a15b5471f169f79d.tar.gz |
reviewed by: John Sullivan <sullivan@eazel.com>
2000-11-15 Pavel Cisler <pavel@eazel.com>
reviewed by: John Sullivan <sullivan@eazel.com>
* libnautilus-extensions/nautilus-gdk-extensions.c:
* libnautilus-extensions/nautilus-gdk-extensions.h:
* libnautilus-extensions/nautilus-file-operations-progress.c:
(set_text_unescaped_trimmed):
(nautilus_string_ellipsize_start):
Turn an existing truncation routine to a public one, giving it
a better name.
Get rid of a questionable optimization (bugzilla 2555).
* libnautilus-extensions/nautilus-gdk-extensions.c:
(nautilus_self_check_ellipsize_start),
(nautilus_self_check_gdk_extensions):
Added tests for the elipsize routine.
* libnautilus-extensions/nautilus-file-operations.c:
* libnautilus-extensions/nautilus-file-operations.h:
(get_label_font), (nautilus_format_name_for_display),
(nautilus_convert_to_formatted_name_for_display),
(handle_xfer_vfs_error), (handle_xfer_overwrite),
(nautilus_file_operations_move_to_trash):
Fix 826: File operation alerts should truncate file names.
Add a convenience call to unescape and truncate a file name,
use it the places that format warning and error dialog strings.
Add some missing quotes in some of the error strings.
* libnautilus-extensions/nautilus-file-operations.c:
(parent_for_error_dialog):
Work on fixing 3093 - file operation error dialogs show up in the
wrong place.
Make the error dialogs use the progress dialog as their parent window,
if available, if not, revert to using the original view as a parent.
* libnautilus-extensions/nautilus-string.c:
Added a comment pointing people to the new ellipsize routines.
-rw-r--r-- | ChangeLog | 39 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-file-operations-progress.c | 32 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-file-operations.c | 90 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-file-operations.h | 5 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-gdk-extensions.c | 101 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-gdk-extensions.h | 5 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-string.c | 8 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-operations-progress.c | 32 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-operations.c | 90 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-operations.h | 5 | ||||
-rw-r--r-- | libnautilus-private/nautilus-gdk-extensions.c | 101 | ||||
-rw-r--r-- | libnautilus-private/nautilus-gdk-extensions.h | 5 | ||||
-rw-r--r-- | libnautilus-private/nautilus-string.c | 8 |
13 files changed, 419 insertions, 102 deletions
@@ -1,3 +1,42 @@ +2000-11-15 Pavel Cisler <pavel@eazel.com> + + reviewed by: John Sullivan <sullivan@eazel.com> + + * libnautilus-extensions/nautilus-gdk-extensions.c: + * libnautilus-extensions/nautilus-gdk-extensions.h: + * libnautilus-extensions/nautilus-file-operations-progress.c: + (set_text_unescaped_trimmed): + (nautilus_string_ellipsize_start): + Turn an existing truncation routine to a public one, giving it + a better name. + Get rid of a questionable optimization (bugzilla 2555). + + * libnautilus-extensions/nautilus-gdk-extensions.c: + (nautilus_self_check_ellipsize_start), + (nautilus_self_check_gdk_extensions): + Added tests for the elipsize routine. + + * libnautilus-extensions/nautilus-file-operations.c: + * libnautilus-extensions/nautilus-file-operations.h: + (get_label_font), (nautilus_format_name_for_display), + (nautilus_convert_to_formatted_name_for_display), + (handle_xfer_vfs_error), (handle_xfer_overwrite), + (nautilus_file_operations_move_to_trash): + Fix 826: File operation alerts should truncate file names. + Add a convenience call to unescape and truncate a file name, + use it the places that format warning and error dialog strings. + Add some missing quotes in some of the error strings. + + * libnautilus-extensions/nautilus-file-operations.c: + (parent_for_error_dialog): + Work on fixing 3093 - file operation error dialogs show up in the + wrong place. + Make the error dialogs use the progress dialog as their parent window, + if available, if not, revert to using the original view as a parent. + + * libnautilus-extensions/nautilus-string.c: + Added a comment pointing people to the new ellipsize routines. + 2000-11-15 Gene Z. Ragan <gzr@eazel.com> Fixed bug 1420, panel splitter drag outline edges are indistinct. diff --git a/libnautilus-extensions/nautilus-file-operations-progress.c b/libnautilus-extensions/nautilus-file-operations-progress.c index b2dee80d3..6547e2b48 100644 --- a/libnautilus-extensions/nautilus-file-operations-progress.c +++ b/libnautilus-extensions/nautilus-file-operations-progress.c @@ -30,6 +30,7 @@ #include <libgnomevfs/gnome-vfs-utils.h> #include "nautilus-file-operations-progress.h" #include "libnautilus-extensions/nautilus-gtk-extensions.h" +#include "libnautilus-extensions/nautilus-gdk-extensions.h" #include "libnautilus-extensions/nautilus-gtk-macros.h" @@ -80,35 +81,6 @@ nautilus_file_operations_progress_update (NautilusFileOperationsProgress *dialog 0.0, dialog->details->bytes_total); } -static char * -truncate_string_from_start (const char *string, GdkFont *font, guint length) -{ - static guint dotdotdot = 0; - int truncate_offset; - - if (gdk_string_width (font, string) <= (int) length) { - /* string is already short enough*/ - return g_strdup (string); - } - - if (!dotdotdot) { - /* FIXME bugzilla.eazel.com 2555: - * This value needs to get updated if a font changes while Nautilus is running - */ - dotdotdot = gdk_string_width (font, "..."); - } - - /* Cut the font length of string to length. */ - length -= dotdotdot; - for (truncate_offset = 0; ; truncate_offset++) { - if (gdk_string_width (font, string + truncate_offset) <= (int) length) { - break; - } - } - - return g_strdup_printf ("...%s", string + truncate_offset); -} - static void set_text_unescaped_trimmed (GtkLabel *label, const char *text, guint max_width) { @@ -121,7 +93,7 @@ set_text_unescaped_trimmed (GtkLabel *label, const char *text, guint max_width) } unescaped_text = gnome_vfs_unescape_string_for_display (text); - trimmed_text = truncate_string_from_start (unescaped_text, + trimmed_text = nautilus_string_ellipsize_start (unescaped_text, GTK_WIDGET (label)->style->font, max_width); gtk_label_set_text (GTK_LABEL (label), trimmed_text); diff --git a/libnautilus-extensions/nautilus-file-operations.c b/libnautilus-extensions/nautilus-file-operations.c index 661421568..af47c3c8d 100644 --- a/libnautilus-extensions/nautilus-file-operations.c +++ b/libnautilus-extensions/nautilus-file-operations.c @@ -26,6 +26,7 @@ #include <config.h> #include <gnome.h> +#include <gtk/gtklabel.h> #include <libgnomevfs/gnome-vfs-find-directory.h> #include <libgnomevfs/gnome-vfs-uri.h> @@ -35,6 +36,7 @@ #include <libnautilus-extensions/nautilus-file-changes-queue.h> #include <libnautilus-extensions/nautilus-file-utilities.h> #include <libnautilus-extensions/nautilus-glib-extensions.h> +#include <libnautilus-extensions/nautilus-gdk-extensions.h> #include <libnautilus-extensions/nautilus-global-preferences.h> #include <libnautilus-extensions/nautilus-stock-dialogs.h> #include <libnautilus-extensions/nautilus-link.h> @@ -110,19 +112,77 @@ icon_position_iterator_free (IconPositionIterator *position_iterator) g_free (position_iterator); } -char * -nautilus_convert_to_unescaped_string_for_display (char *escaped) +/* Hack to get the GdkFont used by a GtkLabel in an error dialog. + * We need to do this because the string truncation needs to be + * done before a dialog is instantiated. + * + * This is probably not super fast but it is not a problem in the + * context we are using it, truncating a string while displaying an + * error dialog. + */ +static GdkFont * +get_label_font (void) { + GtkWidget *label; + GtkStyle *style; + + label = gtk_label_new (""); + style = gtk_widget_get_style (label); + + gdk_font_ref (style->font); + gtk_widget_unref (label); + + return style->font; +} + +static char * +nautilus_format_name_for_display (const char *escaped_uri) +{ + char *unescaped; char *result; + GdkFont *font; + int truncate_to_length; + + unescaped = gnome_vfs_unescape_string_for_display (escaped_uri); + + /* get the font the text will be displayed in */ + font = get_label_font (); + + /* get a nice length to truncate to, based on the current font */ + truncate_to_length = gdk_string_width (font, "MMMMMMMMMMMMMMMMMMMMMM"); + + /* truncate the result */ + result = nautilus_string_ellipsize_start (unescaped, font, truncate_to_length); + + g_free (unescaped); + gdk_font_unref (font); - if (escaped == NULL) { + return result; +} + +static char * +nautilus_convert_to_formatted_name_for_display (char *escaped_uri) +{ + char *result; + + if (escaped_uri == NULL) { return NULL; } - result = gnome_vfs_unescape_string_for_display (escaped); - g_free (escaped); + result = nautilus_format_name_for_display (escaped_uri); + g_free (escaped_uri); return result; } +static GtkWidget * +parent_for_error_dialog (XferInfo *xfer_info) +{ + if (xfer_info->progress_dialog != NULL) { + return xfer_info->progress_dialog; + } + + return xfer_info->parent_view; +} + static void xfer_dialog_clicked_callback (NautilusFileOperationsProgress *dialog, int button_number, @@ -370,7 +430,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, unescaped_name = g_strdup (""); } else { char *name; - name = gnome_vfs_unescape_string_for_display (progress_info->source_name); + name = nautilus_format_name_for_display (progress_info->source_name); unescaped_name = g_strdup_printf (" \"%s\"", name); g_free (name); } @@ -393,7 +453,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, } else { if (progress_info->target_name != NULL) { g_free (unescaped_name); - unescaped_name = gnome_vfs_unescape_string_for_display ( + unescaped_name = nautilus_format_name_for_display ( progress_info->target_name); } text = g_strdup_printf @@ -405,7 +465,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, g_free (unescaped_name); result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Error while Copying"), _("Stop"), NULL); g_free (text); @@ -423,7 +483,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, g_free (unescaped_name); result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Error while Copying"), _("Stop"), NULL); g_free (text); @@ -440,7 +500,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, g_free (unescaped_name); result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Error while Copying"), _("Skip"), _("Retry"), _("Stop"), NULL); g_free (text); @@ -480,8 +540,8 @@ handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, char *text; char *unescaped_name; - unescaped_name = gnome_vfs_unescape_string_for_display (progress_info->target_name); - text = g_strdup_printf (_("File %s already exists.\n" + unescaped_name = nautilus_format_name_for_display (progress_info->target_name); + text = g_strdup_printf (_("File \"%s\" already exists.\n" "Would you like to replace it?"), unescaped_name); g_free (unescaped_name); @@ -491,7 +551,7 @@ handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, * Replace All */ result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Conflict while Copying"), _("Replace"), _("Skip"), NULL); switch (result) { @@ -505,7 +565,7 @@ handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, } } else { result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Conflict while Copying"), _("Replace All"), _("Replace"), _("Skip"), NULL); @@ -1438,7 +1498,7 @@ nautilus_file_operations_move_to_trash (const GList *item_uris, GNOME_STOCK_BUTTON_OK, NULL, NULL); bail = TRUE; } else if (gnome_vfs_uri_is_parent (source_uri, trash_dir_uri, TRUE)) { - item_name = nautilus_convert_to_unescaped_string_for_display + item_name = nautilus_convert_to_formatted_name_for_display (gnome_vfs_uri_extract_short_name (source_uri)); text = g_strdup_printf (_("You cannot throw \"%s\" into the Trash."), diff --git a/libnautilus-extensions/nautilus-file-operations.h b/libnautilus-extensions/nautilus-file-operations.h index 56aa66003..a803c1ffb 100644 --- a/libnautilus-extensions/nautilus-file-operations.h +++ b/libnautilus-extensions/nautilus-file-operations.h @@ -49,10 +49,5 @@ void nautilus_file_operations_new_folder (GtkWidget void nautilus_file_operations_delete (const GList *item_uris, GtkWidget *parent_view); -/* Prepare an escaped string for display. Unescapes a string in place. - * Like gnome_vfs_unescape_string_for_display but frees the original - * string. - */ -char *nautilus_convert_to_unescaped_string_for_display (char *escaped); #endif /* NAUTILUS_FILE_OPERATIONS_H */ diff --git a/libnautilus-extensions/nautilus-gdk-extensions.c b/libnautilus-extensions/nautilus-gdk-extensions.c index 924fac16a..0ba95a7ba 100644 --- a/libnautilus-extensions/nautilus-gdk-extensions.c +++ b/libnautilus-extensions/nautilus-gdk-extensions.c @@ -34,6 +34,7 @@ #include "nautilus-glib-extensions.h" #include "nautilus-lib-self-check-functions.h" #include "nautilus-string.h" +#include "nautilus-font-factory.h" #define GRADIENT_BAND_SIZE 4 @@ -774,6 +775,57 @@ nautilus_gdk_gc_unref_if_not_null (GdkGC *gc_or_null) } /** + * nautilus_string_ellipsize_start: + * + * @string: A a string to be ellipsized. + * @font: A a font used to measure the resulting string width. + * @width: Desired maximum width in pixels. + * Returns: A truncated string at most @width pixels long. + * + * Truncates a string, removing characters from the start and + * replacing them with "..." + * + */ +char * +nautilus_string_ellipsize_start (const char *string, GdkFont *font, int width) +{ + int truncate_offset; + + if (gdk_string_width (font, string) <= (int) width) { + /* String is already short enough. */ + return g_strdup (string); + } + + /* Account for the width of the ellipsis. */ + width -= gdk_string_width (font, "..."); + + + if (width < 0) { + /* No room even for a an ellipsis. */ + return g_strdup (""); + } + + /* We could have the following optimization here: + * check if the desired width and original width are considerably different, + * if so, use a binary stride to figure out the resulting string truncation + * offset. + * For now we assume that we are only truncating by a small number of + * characters, in which a linear scan is faster + */ + for (truncate_offset = 0; ; truncate_offset++) { + if (string[truncate_offset] == '\0') { + break; + } + + if (gdk_string_width (font, string + truncate_offset) <= (int) width) { + break; + } + } + + return g_strdup_printf ("...%s", string + truncate_offset); +} + +/** * nautilus_gdk_window_set_wm_hints_input: * * Set the WM_HINTS.input flag to the passed in value @@ -821,9 +873,43 @@ nautilus_self_check_parse (const char *color_spec) return nautilus_gdk_color_as_hex_string (color); } +/* Testing string truncation is tough because we do not know what font/ + * font metrics to expect on a given system. To work around this we use + * a substring of the original, measure it's length using the given font, + * add the length of the "..." string and use that for truncation. + * The result should then be the substring prepended with a "..." + */ +static char * +nautilus_self_check_ellipsize_start (const char *string, const char *truncate_to_length_string) +{ + GdkFont *font; + int truncation_length; + char *result; + + /* any old font will do */ + font = nautilus_font_factory_get_fallback_font (); + g_assert (font); + + /* measure the length we want to truncate to */ + truncation_length = gdk_string_width (font, truncate_to_length_string); + truncation_length += gdk_string_width (font, "..."); + + result = nautilus_string_ellipsize_start (string, font, truncation_length); + + gdk_font_unref (font); + + return result; +} + void nautilus_self_check_gdk_extensions (void) { + GdkFont *font; + + /* used to test ellipsize routines */ + font = nautilus_font_factory_get_fallback_font (); + g_assert (font); + /* nautilus_interpolate_color */ NAUTILUS_CHECK_INTEGER_RESULT (nautilus_interpolate_color (0.0, 0, 0), 0); NAUTILUS_CHECK_INTEGER_RESULT (nautilus_interpolate_color (0.0, 0, 0xFFFFFF), 0); @@ -923,6 +1009,21 @@ nautilus_self_check_gdk_extensions (void) NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_parse ("white"), "rgb:FFFF/FFFF/FFFF"); NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_parse ("black"), "rgb:0000/0000/0000"); NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_parse ("rgb:0123/4567/89AB"), "rgb:0123/4567/89AB"); + + /* nautilus_string_ellipsize_start */ + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "0012345678"), "012345678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "012345678"), "012345678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "45678"), "...45678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "5678"), "...5678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "678"), "...678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "78"), "...78"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "8"), "...8"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("", font, 100), ""); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("test", font, 0), ""); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("test", font, gdk_string_width (font, "...") - 1), ""); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("test", font, gdk_string_width (font, "...")), "..."); + + gdk_font_unref (font); } #endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-extensions/nautilus-gdk-extensions.h b/libnautilus-extensions/nautilus-gdk-extensions.h index 9050cd28b..690baf0b4 100644 --- a/libnautilus-extensions/nautilus-gdk-extensions.h +++ b/libnautilus-extensions/nautilus-gdk-extensions.h @@ -149,5 +149,8 @@ void nautilus_gdk_gc_unref_if_not_null (GdkGC *gc_o void nautilus_gdk_window_set_wm_hints_input (GdkWindow *w, gboolean status); - +char * nautilus_string_ellipsize_start (const char *original, + GdkFont *font, + int length); + #endif /* NAUTILUS_GDK_EXTENSIONS_H */ diff --git a/libnautilus-extensions/nautilus-string.c b/libnautilus-extensions/nautilus-string.c index 0eae4fc6f..da4b63f0d 100644 --- a/libnautilus-extensions/nautilus-string.c +++ b/libnautilus-extensions/nautilus-string.c @@ -461,6 +461,14 @@ nautilus_str_capitalize (const char *string) return capitalized; } +/* Note: nautilus_string_ellipsize_* that use a length in pixels + * rather than characters can be found in nautilus_gdk_extensions.h + * + * FIXME: + * we should coordinate the names of nautilus_string_ellipsize_* + * and nautilus_str_*_truncate so that they match better and reflect + * their different behavior. + */ char * nautilus_str_middle_truncate (const char *string, guint truncate_length) diff --git a/libnautilus-private/nautilus-file-operations-progress.c b/libnautilus-private/nautilus-file-operations-progress.c index b2dee80d3..6547e2b48 100644 --- a/libnautilus-private/nautilus-file-operations-progress.c +++ b/libnautilus-private/nautilus-file-operations-progress.c @@ -30,6 +30,7 @@ #include <libgnomevfs/gnome-vfs-utils.h> #include "nautilus-file-operations-progress.h" #include "libnautilus-extensions/nautilus-gtk-extensions.h" +#include "libnautilus-extensions/nautilus-gdk-extensions.h" #include "libnautilus-extensions/nautilus-gtk-macros.h" @@ -80,35 +81,6 @@ nautilus_file_operations_progress_update (NautilusFileOperationsProgress *dialog 0.0, dialog->details->bytes_total); } -static char * -truncate_string_from_start (const char *string, GdkFont *font, guint length) -{ - static guint dotdotdot = 0; - int truncate_offset; - - if (gdk_string_width (font, string) <= (int) length) { - /* string is already short enough*/ - return g_strdup (string); - } - - if (!dotdotdot) { - /* FIXME bugzilla.eazel.com 2555: - * This value needs to get updated if a font changes while Nautilus is running - */ - dotdotdot = gdk_string_width (font, "..."); - } - - /* Cut the font length of string to length. */ - length -= dotdotdot; - for (truncate_offset = 0; ; truncate_offset++) { - if (gdk_string_width (font, string + truncate_offset) <= (int) length) { - break; - } - } - - return g_strdup_printf ("...%s", string + truncate_offset); -} - static void set_text_unescaped_trimmed (GtkLabel *label, const char *text, guint max_width) { @@ -121,7 +93,7 @@ set_text_unescaped_trimmed (GtkLabel *label, const char *text, guint max_width) } unescaped_text = gnome_vfs_unescape_string_for_display (text); - trimmed_text = truncate_string_from_start (unescaped_text, + trimmed_text = nautilus_string_ellipsize_start (unescaped_text, GTK_WIDGET (label)->style->font, max_width); gtk_label_set_text (GTK_LABEL (label), trimmed_text); diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c index 661421568..af47c3c8d 100644 --- a/libnautilus-private/nautilus-file-operations.c +++ b/libnautilus-private/nautilus-file-operations.c @@ -26,6 +26,7 @@ #include <config.h> #include <gnome.h> +#include <gtk/gtklabel.h> #include <libgnomevfs/gnome-vfs-find-directory.h> #include <libgnomevfs/gnome-vfs-uri.h> @@ -35,6 +36,7 @@ #include <libnautilus-extensions/nautilus-file-changes-queue.h> #include <libnautilus-extensions/nautilus-file-utilities.h> #include <libnautilus-extensions/nautilus-glib-extensions.h> +#include <libnautilus-extensions/nautilus-gdk-extensions.h> #include <libnautilus-extensions/nautilus-global-preferences.h> #include <libnautilus-extensions/nautilus-stock-dialogs.h> #include <libnautilus-extensions/nautilus-link.h> @@ -110,19 +112,77 @@ icon_position_iterator_free (IconPositionIterator *position_iterator) g_free (position_iterator); } -char * -nautilus_convert_to_unescaped_string_for_display (char *escaped) +/* Hack to get the GdkFont used by a GtkLabel in an error dialog. + * We need to do this because the string truncation needs to be + * done before a dialog is instantiated. + * + * This is probably not super fast but it is not a problem in the + * context we are using it, truncating a string while displaying an + * error dialog. + */ +static GdkFont * +get_label_font (void) { + GtkWidget *label; + GtkStyle *style; + + label = gtk_label_new (""); + style = gtk_widget_get_style (label); + + gdk_font_ref (style->font); + gtk_widget_unref (label); + + return style->font; +} + +static char * +nautilus_format_name_for_display (const char *escaped_uri) +{ + char *unescaped; char *result; + GdkFont *font; + int truncate_to_length; + + unescaped = gnome_vfs_unescape_string_for_display (escaped_uri); + + /* get the font the text will be displayed in */ + font = get_label_font (); + + /* get a nice length to truncate to, based on the current font */ + truncate_to_length = gdk_string_width (font, "MMMMMMMMMMMMMMMMMMMMMM"); + + /* truncate the result */ + result = nautilus_string_ellipsize_start (unescaped, font, truncate_to_length); + + g_free (unescaped); + gdk_font_unref (font); - if (escaped == NULL) { + return result; +} + +static char * +nautilus_convert_to_formatted_name_for_display (char *escaped_uri) +{ + char *result; + + if (escaped_uri == NULL) { return NULL; } - result = gnome_vfs_unescape_string_for_display (escaped); - g_free (escaped); + result = nautilus_format_name_for_display (escaped_uri); + g_free (escaped_uri); return result; } +static GtkWidget * +parent_for_error_dialog (XferInfo *xfer_info) +{ + if (xfer_info->progress_dialog != NULL) { + return xfer_info->progress_dialog; + } + + return xfer_info->parent_view; +} + static void xfer_dialog_clicked_callback (NautilusFileOperationsProgress *dialog, int button_number, @@ -370,7 +430,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, unescaped_name = g_strdup (""); } else { char *name; - name = gnome_vfs_unescape_string_for_display (progress_info->source_name); + name = nautilus_format_name_for_display (progress_info->source_name); unescaped_name = g_strdup_printf (" \"%s\"", name); g_free (name); } @@ -393,7 +453,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, } else { if (progress_info->target_name != NULL) { g_free (unescaped_name); - unescaped_name = gnome_vfs_unescape_string_for_display ( + unescaped_name = nautilus_format_name_for_display ( progress_info->target_name); } text = g_strdup_printf @@ -405,7 +465,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, g_free (unescaped_name); result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Error while Copying"), _("Stop"), NULL); g_free (text); @@ -423,7 +483,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, g_free (unescaped_name); result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Error while Copying"), _("Stop"), NULL); g_free (text); @@ -440,7 +500,7 @@ handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, g_free (unescaped_name); result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Error while Copying"), _("Skip"), _("Retry"), _("Stop"), NULL); g_free (text); @@ -480,8 +540,8 @@ handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, char *text; char *unescaped_name; - unescaped_name = gnome_vfs_unescape_string_for_display (progress_info->target_name); - text = g_strdup_printf (_("File %s already exists.\n" + unescaped_name = nautilus_format_name_for_display (progress_info->target_name); + text = g_strdup_printf (_("File \"%s\" already exists.\n" "Would you like to replace it?"), unescaped_name); g_free (unescaped_name); @@ -491,7 +551,7 @@ handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, * Replace All */ result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Conflict while Copying"), _("Replace"), _("Skip"), NULL); switch (result) { @@ -505,7 +565,7 @@ handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, } } else { result = nautilus_simple_dialog - (xfer_info->parent_view, TRUE, text, + (parent_for_error_dialog (xfer_info), TRUE, text, _("Conflict while Copying"), _("Replace All"), _("Replace"), _("Skip"), NULL); @@ -1438,7 +1498,7 @@ nautilus_file_operations_move_to_trash (const GList *item_uris, GNOME_STOCK_BUTTON_OK, NULL, NULL); bail = TRUE; } else if (gnome_vfs_uri_is_parent (source_uri, trash_dir_uri, TRUE)) { - item_name = nautilus_convert_to_unescaped_string_for_display + item_name = nautilus_convert_to_formatted_name_for_display (gnome_vfs_uri_extract_short_name (source_uri)); text = g_strdup_printf (_("You cannot throw \"%s\" into the Trash."), diff --git a/libnautilus-private/nautilus-file-operations.h b/libnautilus-private/nautilus-file-operations.h index 56aa66003..a803c1ffb 100644 --- a/libnautilus-private/nautilus-file-operations.h +++ b/libnautilus-private/nautilus-file-operations.h @@ -49,10 +49,5 @@ void nautilus_file_operations_new_folder (GtkWidget void nautilus_file_operations_delete (const GList *item_uris, GtkWidget *parent_view); -/* Prepare an escaped string for display. Unescapes a string in place. - * Like gnome_vfs_unescape_string_for_display but frees the original - * string. - */ -char *nautilus_convert_to_unescaped_string_for_display (char *escaped); #endif /* NAUTILUS_FILE_OPERATIONS_H */ diff --git a/libnautilus-private/nautilus-gdk-extensions.c b/libnautilus-private/nautilus-gdk-extensions.c index 924fac16a..0ba95a7ba 100644 --- a/libnautilus-private/nautilus-gdk-extensions.c +++ b/libnautilus-private/nautilus-gdk-extensions.c @@ -34,6 +34,7 @@ #include "nautilus-glib-extensions.h" #include "nautilus-lib-self-check-functions.h" #include "nautilus-string.h" +#include "nautilus-font-factory.h" #define GRADIENT_BAND_SIZE 4 @@ -774,6 +775,57 @@ nautilus_gdk_gc_unref_if_not_null (GdkGC *gc_or_null) } /** + * nautilus_string_ellipsize_start: + * + * @string: A a string to be ellipsized. + * @font: A a font used to measure the resulting string width. + * @width: Desired maximum width in pixels. + * Returns: A truncated string at most @width pixels long. + * + * Truncates a string, removing characters from the start and + * replacing them with "..." + * + */ +char * +nautilus_string_ellipsize_start (const char *string, GdkFont *font, int width) +{ + int truncate_offset; + + if (gdk_string_width (font, string) <= (int) width) { + /* String is already short enough. */ + return g_strdup (string); + } + + /* Account for the width of the ellipsis. */ + width -= gdk_string_width (font, "..."); + + + if (width < 0) { + /* No room even for a an ellipsis. */ + return g_strdup (""); + } + + /* We could have the following optimization here: + * check if the desired width and original width are considerably different, + * if so, use a binary stride to figure out the resulting string truncation + * offset. + * For now we assume that we are only truncating by a small number of + * characters, in which a linear scan is faster + */ + for (truncate_offset = 0; ; truncate_offset++) { + if (string[truncate_offset] == '\0') { + break; + } + + if (gdk_string_width (font, string + truncate_offset) <= (int) width) { + break; + } + } + + return g_strdup_printf ("...%s", string + truncate_offset); +} + +/** * nautilus_gdk_window_set_wm_hints_input: * * Set the WM_HINTS.input flag to the passed in value @@ -821,9 +873,43 @@ nautilus_self_check_parse (const char *color_spec) return nautilus_gdk_color_as_hex_string (color); } +/* Testing string truncation is tough because we do not know what font/ + * font metrics to expect on a given system. To work around this we use + * a substring of the original, measure it's length using the given font, + * add the length of the "..." string and use that for truncation. + * The result should then be the substring prepended with a "..." + */ +static char * +nautilus_self_check_ellipsize_start (const char *string, const char *truncate_to_length_string) +{ + GdkFont *font; + int truncation_length; + char *result; + + /* any old font will do */ + font = nautilus_font_factory_get_fallback_font (); + g_assert (font); + + /* measure the length we want to truncate to */ + truncation_length = gdk_string_width (font, truncate_to_length_string); + truncation_length += gdk_string_width (font, "..."); + + result = nautilus_string_ellipsize_start (string, font, truncation_length); + + gdk_font_unref (font); + + return result; +} + void nautilus_self_check_gdk_extensions (void) { + GdkFont *font; + + /* used to test ellipsize routines */ + font = nautilus_font_factory_get_fallback_font (); + g_assert (font); + /* nautilus_interpolate_color */ NAUTILUS_CHECK_INTEGER_RESULT (nautilus_interpolate_color (0.0, 0, 0), 0); NAUTILUS_CHECK_INTEGER_RESULT (nautilus_interpolate_color (0.0, 0, 0xFFFFFF), 0); @@ -923,6 +1009,21 @@ nautilus_self_check_gdk_extensions (void) NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_parse ("white"), "rgb:FFFF/FFFF/FFFF"); NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_parse ("black"), "rgb:0000/0000/0000"); NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_parse ("rgb:0123/4567/89AB"), "rgb:0123/4567/89AB"); + + /* nautilus_string_ellipsize_start */ + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "0012345678"), "012345678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "012345678"), "012345678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "45678"), "...45678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "5678"), "...5678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "678"), "...678"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "78"), "...78"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_self_check_ellipsize_start ("012345678", "8"), "...8"); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("", font, 100), ""); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("test", font, 0), ""); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("test", font, gdk_string_width (font, "...") - 1), ""); + NAUTILUS_CHECK_STRING_RESULT (nautilus_string_ellipsize_start ("test", font, gdk_string_width (font, "...")), "..."); + + gdk_font_unref (font); } #endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-private/nautilus-gdk-extensions.h b/libnautilus-private/nautilus-gdk-extensions.h index 9050cd28b..690baf0b4 100644 --- a/libnautilus-private/nautilus-gdk-extensions.h +++ b/libnautilus-private/nautilus-gdk-extensions.h @@ -149,5 +149,8 @@ void nautilus_gdk_gc_unref_if_not_null (GdkGC *gc_o void nautilus_gdk_window_set_wm_hints_input (GdkWindow *w, gboolean status); - +char * nautilus_string_ellipsize_start (const char *original, + GdkFont *font, + int length); + #endif /* NAUTILUS_GDK_EXTENSIONS_H */ diff --git a/libnautilus-private/nautilus-string.c b/libnautilus-private/nautilus-string.c index 0eae4fc6f..da4b63f0d 100644 --- a/libnautilus-private/nautilus-string.c +++ b/libnautilus-private/nautilus-string.c @@ -461,6 +461,14 @@ nautilus_str_capitalize (const char *string) return capitalized; } +/* Note: nautilus_string_ellipsize_* that use a length in pixels + * rather than characters can be found in nautilus_gdk_extensions.h + * + * FIXME: + * we should coordinate the names of nautilus_string_ellipsize_* + * and nautilus_str_*_truncate so that they match better and reflect + * their different behavior. + */ char * nautilus_str_middle_truncate (const char *string, guint truncate_length) |