diff --git a/ChangeLog b/ChangeLog index 14958777..6f6689ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,13 @@ src/interface.c: Improve usage of "Unfold all children" option and add some basic documentation for folding support. * plugins/filebrowser.c: Fix display of double slash in path entry. + * src/document.c, src/ui_utils.c: + Deny "(Un)Fold All" actions when folding is disabled. + Hide "(Un)Fold All" menu items instead of just disabling them. + * src/dialogs.c, src/dialogs.h, src/document.c: + Add dialogs_show_msgbox_with_secondary(). + Add line and column number in charset conversion error dialog when + saving a file and improve display of the failed character. 2007-11-27 Enrico Tröger diff --git a/src/dialogs.c b/src/dialogs.c index 499fabd1..0cb33d30 100644 --- a/src/dialogs.c +++ b/src/dialogs.c @@ -570,6 +570,28 @@ void dialogs_show_msgbox(gint type, const gchar *text, ...) } +void dialogs_show_msgbox_with_secondary(gint type, const gchar *text, const gchar *secondary) +{ +#ifndef G_OS_WIN32 + GtkWidget *dialog; +#endif + +#ifdef G_OS_WIN32 + // put the two strings together because Windows message boxes don't support secondary texts + gchar *string = g_strconcat(text, "\n", secondary, NULL); + win32_message_dialog(NULL, type, string); + g_free(string); +#else + dialog = gtk_message_dialog_new(GTK_WINDOW(app->window), GTK_DIALOG_DESTROY_WITH_PARENT, + type, GTK_BUTTONS_OK, "%s", text); + gtk_widget_set_name(dialog, "GeanyDialog"); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", secondary); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +#endif +} + + gboolean dialogs_show_unsaved_file(gint idx) { #ifndef G_OS_WIN32 diff --git a/src/dialogs.h b/src/dialogs.h index f168c10c..b09962d6 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -55,4 +55,6 @@ gboolean dialogs_show_question_full(GtkWidget *parent, const gchar *yes_btn, con void dialogs_show_msgbox(gint type, const gchar *text, ...) G_GNUC_PRINTF (2, 3); +void dialogs_show_msgbox_with_secondary(gint type, const gchar *text, const gchar *secondary); + #endif diff --git a/src/document.c b/src/document.c index b1b0e4b7..c1a0e297 100644 --- a/src/document.c +++ b/src/document.c @@ -1132,6 +1132,32 @@ static gboolean document_update_timestamp(gint idx) } +/* Sets line and column to the given position byte_pos in the document. + * byte_pos is the position counted in bytes, not characters */ +static void get_line_column_from_pos(gint idx, guint byte_pos, gint *line, gint *column) +{ + gint i; + gint line_start; + + // for some reason we can use byte count instead of character count here + *line = sci_get_line_from_position(doc_list[idx].sci, byte_pos); + line_start = sci_get_position_from_line(doc_list[idx].sci, *line); + // get the column in the line + *column = byte_pos - line_start; + + // any non-ASCII characters are encoded with two bytes(UTF-8, always in Scintilla), so + // skip one byte(i++) and decrease the column number which is based on byte count + for (i = line_start; i < (line_start + *column); i++) + { + if (sci_get_char_at(doc_list[idx].sci, i) < 0) + { + (*column)--; + i++; + } + } +} + + /* This saves the file. * When force is set then it is always saved, even if it is unchanged(useful when using Save As) * It returns whether the file could be saved or not. */ @@ -1143,7 +1169,7 @@ gboolean document_save_file(gint idx, gboolean force) gchar *locale_filename = NULL; if (! DOC_IDX_VALID(idx)) return FALSE; - // the changed flag should exclude the readonly flag, but check it anyway for safety + // the "changed" flag should exclude the "readonly" flag, but check it anyway for safety if (! force && (! doc_list[idx].changed || doc_list[idx].readonly)) return FALSE; if (doc_list[idx].file_name == NULL) @@ -1195,22 +1221,41 @@ gboolean document_save_file(gint idx, gboolean force) if (conv_error != NULL) { - gchar *context = NULL; + gchar *text = g_strdup_printf( + _("An error occurred while converting the file from UTF-8 in \"%s\". The file remains unsaved."), + doc_list[idx].encoding); + gchar *error_text; if (conv_error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE) { - context = g_malloc(4); // read 3 bytes from Sci + '\0' - sci_get_text_range(doc_list[idx].sci, bytes_read, bytes_read + 3, context); + gchar *context = NULL; + gint line, column; + gint context_len; + gunichar unic; + gint max_len = MIN((gint)bytes_read + 6, len - 1); // don't read over the doc length + context = g_malloc(7); // read 6 bytes from Sci + '\0' + sci_get_text_range(doc_list[idx].sci, bytes_read, max_len, context); + + // take only one valid Unicode character from the context and discard the leftover + unic = g_utf8_get_char_validated(context, -1); + context_len = g_unichar_to_utf8(unic, context); + context[context_len] = '\0'; + get_line_column_from_pos(idx, bytes_read, &line, &column); + + error_text = g_strdup_printf( + _("Error message: %s\nThe error occurred at \"%s\" (line: %d, column: %d)."), + conv_error->message, context, line + 1, column); + g_free(context); } - dialogs_show_msgbox(GTK_MESSAGE_ERROR, - _("An error occurred while converting the file from UTF-8 in \"%s\". The file remains unsaved." - "\nError message: %s\nThe error occurred at \"%s\"."), - doc_list[idx].encoding, conv_error->message, - (context != NULL) ? context : _("unknown")); + else + error_text = g_strdup_printf(_("Error message: %s."), conv_error->message); + geany_debug("encoding error: %s", conv_error->message); + dialogs_show_msgbox_with_secondary(GTK_MESSAGE_ERROR, text, error_text); g_error_free(conv_error); - g_free(context); g_free(data); + g_free(text); + g_free(error_text); return FALSE; } else @@ -1926,7 +1971,7 @@ static void fold_all(gint idx, gboolean want_fold) { gint lines, first, i; - if (! DOC_IDX_VALID(idx)) return; + if (! DOC_IDX_VALID(idx) || ! editor_prefs.folding) return; lines = sci_get_line_count(doc_list[idx].sci); first = sci_get_first_visible_line(doc_list[idx].sci); diff --git a/src/ui_utils.c b/src/ui_utils.c index eab486f3..3919d956 100644 --- a/src/ui_utils.c +++ b/src/ui_utils.c @@ -363,8 +363,9 @@ void ui_update_insert_include_item(gint idx, gint item) void ui_update_fold_items() { - gtk_widget_set_sensitive(lookup_widget(app->window, "menu_fold_all1"), editor_prefs.folding); - gtk_widget_set_sensitive(lookup_widget(app->window, "menu_unfold_all1"), editor_prefs.folding); + ui_widget_show_hide(lookup_widget(app->window, "menu_fold_all1"), editor_prefs.folding); + ui_widget_show_hide(lookup_widget(app->window, "menu_unfold_all1"), editor_prefs.folding); + ui_widget_show_hide(lookup_widget(app->window, "separator22"), editor_prefs.folding); }