diff --git a/moo/mooedit/mooeditdialogs.c b/moo/mooedit/mooeditdialogs.c index 6733e70c..e289a992 100644 --- a/moo/mooedit/mooeditdialogs.c +++ b/moo/mooedit/mooeditdialogs.c @@ -22,7 +22,9 @@ #include "mooutils/mooglade.h" #include "mooutils/eggregex.h" #include "mooutils/mooi18n.h" +#include "mooutils/mooencodings.h" #include +#include static void @@ -39,7 +41,7 @@ _moo_edit_open_dialog (GtkWidget *widget, MooFilterMgr *mgr) { MooFileDialog *dialog; - const char *start; + const char *start, *encoding; char *new_start; GSList *filenames, *infos = NULL, *l; @@ -48,6 +50,7 @@ _moo_edit_open_dialog (GtkWidget *widget, dialog = moo_file_dialog_new (MOO_FILE_DIALOG_OPEN, widget, TRUE, "Open", start, NULL); + g_object_set (dialog, "enable-encodings", TRUE, NULL); g_signal_connect (dialog, "dialog-created", G_CALLBACK (open_dialog_created), NULL); if (mgr) @@ -59,11 +62,16 @@ _moo_edit_open_dialog (GtkWidget *widget, return NULL; } + encoding = moo_file_dialog_get_encoding (dialog); + + if (encoding && !strcmp (encoding, MOO_ENCODING_AUTO)) + encoding = NULL; + filenames = moo_file_dialog_get_filenames (dialog); g_return_val_if_fail (filenames != NULL, NULL); for (l = filenames; l != NULL; l = l->next) - infos = g_slist_prepend (infos, moo_edit_file_info_new (l->data, NULL)); + infos = g_slist_prepend (infos, moo_edit_file_info_new (l->data, encoding)); infos = g_slist_reverse (infos); new_start = g_path_get_dirname (filenames->data); @@ -85,6 +93,7 @@ _moo_edit_save_as_dialog (MooEdit *edit, const char *title = _("Save As"); const char *start = NULL; const char *filename = NULL; + const char *encoding; char *new_start; MooFileDialog *dialog; MooEditFileInfo *file_info; @@ -95,6 +104,8 @@ _moo_edit_save_as_dialog (MooEdit *edit, dialog = moo_file_dialog_new (MOO_FILE_DIALOG_SAVE, GTK_WIDGET (edit), FALSE, title, start, display_basename); + g_object_set (dialog, "enable-encodings", TRUE, NULL); + moo_file_dialog_set_encoding (dialog, moo_edit_get_encoding (edit)); if (mgr) moo_file_dialog_set_filter_mgr (dialog, mgr, "MooEdit"); @@ -105,9 +116,10 @@ _moo_edit_save_as_dialog (MooEdit *edit, return NULL; } + encoding = moo_file_dialog_get_encoding (dialog); filename = moo_file_dialog_get_filename (dialog); g_return_val_if_fail (filename != NULL, NULL); - file_info = moo_edit_file_info_new (filename, NULL); + file_info = moo_edit_file_info_new (filename, encoding); new_start = g_path_get_dirname (filename); moo_prefs_set_filename (moo_edit_setting (MOO_EDIT_PREFS_LAST_DIR), new_start); diff --git a/moo/moopython/pygtk/mooutils-pygtk.defs b/moo/moopython/pygtk/mooutils-pygtk.defs index fcffc704..39f189f5 100644 --- a/moo/moopython/pygtk/mooutils-pygtk.defs +++ b/moo/moopython/pygtk/mooutils-pygtk.defs @@ -612,15 +612,15 @@ ) ) -(define-method attach - (of-object "MooFilterMgr") - (c-name "moo_filter_mgr_attach") - (return-type "none") - (parameters - '("GtkFileChooser*" "filechooser") - '("const-char*" "user_id") - ) -) +; (define-method attach +; (of-object "MooFilterMgr") +; (c-name "moo_filter_mgr_attach") +; (return-type "none") +; (parameters +; '("GtkFileChooser*" "filechooser") +; '("const-char*" "user_id") +; ) +; ) (define-method get_filter (of-object "MooFilterMgr") diff --git a/moo/mooutils/Makefile.am b/moo/mooutils/Makefile.am index db006eec..4a8c3daa 100644 --- a/moo/mooutils/Makefile.am +++ b/moo/mooutils/Makefile.am @@ -84,6 +84,9 @@ mooutils_sources = \ moocompat.h \ moodialogs.c \ moodialogs.h \ + mooencodings.c \ + mooencodings.h \ + mooencodings-data.h \ mooentry.c \ moofiledialog.c \ moofiledialog.h \ diff --git a/moo/mooutils/mooencodings-data.h b/moo/mooutils/mooencodings-data.h new file mode 100644 index 00000000..94d92f42 --- /dev/null +++ b/moo/mooutils/mooencodings-data.h @@ -0,0 +1,127 @@ +enum { + ENCODING_GROUP_WEST_EUROPEAN, + ENCODING_GROUP_EAST_EUROPEAN, + ENCODING_GROUP_EAST_ASIAN, + ENCODING_GROUP_SE_SW_ASIAN, + ENCODING_GROUP_MIDDLE_EASTERN, + ENCODING_GROUP_UNICODE, + N_ENCODING_GROUPS +}; + +static const char * const moo_encoding_groups_names[] = { + N_("West European"), + N_("East European"), + N_("East Asian"), + N_("SE & SW Asian"), + N_("Middle Eastern"), + N_("Unicode") +}; + +static const struct { + const char *name; + const char *alias; +} const moo_encoding_aliases[] = { + {"UTF-8", "UTF8"} +}; + +/* The stuff below if from profterm: + * + * Copyright (C) 2002 Red Hat, Inc. + * + * This 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. + * + */ + +static const struct { + const char *name; + const char *display_subgroup; + const char *short_display_name; + guint group : 3; +} const moo_encodings_data[] = +{ + { "ISO-8859-1", N_("Western"), "ISO-8859-1", ENCODING_GROUP_WEST_EUROPEAN }, + { "ISO-8859-2", N_("Central European"), "ISO-8859-2", ENCODING_GROUP_EAST_EUROPEAN }, + { "ISO-8859-3", N_("South European"), "ISO-8859-3", ENCODING_GROUP_WEST_EUROPEAN }, + { "ISO-8859-4", N_("Baltic"), "ISO-8859-4", ENCODING_GROUP_EAST_EUROPEAN }, + { "ISO-8859-5", N_("Cyrillic"), "ISO-8859-5", ENCODING_GROUP_EAST_EUROPEAN }, + { "ISO-8859-6", N_("Arabic"), "ISO-8859-6", ENCODING_GROUP_MIDDLE_EASTERN }, + { "ISO-8859-7", N_("Greek"), "ISO-8859-7", ENCODING_GROUP_WEST_EUROPEAN }, + { "ISO-8859-8", N_("Hebrew Visual"), "ISO-8859-8", ENCODING_GROUP_MIDDLE_EASTERN }, + { "ISO-8859-8-I", N_("Hebrew"), "ISO-8859-8-I", ENCODING_GROUP_MIDDLE_EASTERN }, + { "ISO-8859-9", N_("Turkish"), "ISO-8859-9", ENCODING_GROUP_SE_SW_ASIAN }, + { "ISO-8859-10", N_("Nordic"), "ISO-8859-10", ENCODING_GROUP_WEST_EUROPEAN }, + { "ISO-8859-13", N_("Baltic"), "ISO-8859-13", ENCODING_GROUP_EAST_EUROPEAN }, + { "ISO-8859-14", N_("Celtic"), "ISO-8859-14", ENCODING_GROUP_WEST_EUROPEAN }, + { "ISO-8859-15", N_("Western"), "ISO-8859-15", ENCODING_GROUP_WEST_EUROPEAN }, + { "ISO-8859-16", N_("Romanian"), "ISO-8859-16", ENCODING_GROUP_EAST_EUROPEAN }, + + { "UTF-7", N_("Unicode"), "UTF-7", ENCODING_GROUP_UNICODE }, + { "UTF-8", N_("Unicode"), "UTF-8", ENCODING_GROUP_UNICODE }, + { "UTF-16", N_("Unicode"), "UTF-16", ENCODING_GROUP_UNICODE }, + { "UCS-2", N_("Unicode"), "UCS-2", ENCODING_GROUP_UNICODE }, + { "UCS-4", N_("Unicode"), "UCS-4", ENCODING_GROUP_UNICODE }, + + { "ARMSCII-8", N_("Armenian"), "ARMSCII-8", ENCODING_GROUP_SE_SW_ASIAN }, + { "BIG5", N_("Chinese Traditional"), "Big5", ENCODING_GROUP_EAST_ASIAN }, + { "BIG5-HKSCS", N_("Chinese Traditional"), "Big5-HKSCS", ENCODING_GROUP_EAST_ASIAN }, + { "CP866", N_("Cyrillic/Russian"), "CP866", ENCODING_GROUP_EAST_EUROPEAN }, + + { "EUC-JP", N_("Japanese"), "EUC-JP", ENCODING_GROUP_EAST_ASIAN }, + { "EUC-KR", N_("Korean"), "EUC-KR", ENCODING_GROUP_EAST_ASIAN }, + { "EUC-TW", N_("Chinese Traditional"), "EUC-TW", ENCODING_GROUP_EAST_ASIAN }, + + { "GB18030", N_("Chinese Simplified"), "GB18030", ENCODING_GROUP_EAST_ASIAN }, + { "GB2312", N_("Chinese Simplified"), "GB2312", ENCODING_GROUP_EAST_ASIAN }, + { "GBK", N_("Chinese Simplified"), "GBK", ENCODING_GROUP_EAST_ASIAN }, + { "GEORGIAN-PS", N_("Georgian"), "GEORGIAN-PS", ENCODING_GROUP_SE_SW_ASIAN }, + { "HZ", N_("Chinese Simplified"), "HZ", ENCODING_GROUP_EAST_ASIAN }, + + { "IBM850", N_("Western"), "IBM850", ENCODING_GROUP_WEST_EUROPEAN }, + { "IBM852", N_("Central European"), "IBM852", ENCODING_GROUP_EAST_EUROPEAN }, + { "IBM855", N_("Cyrillic"), "IBM855", ENCODING_GROUP_EAST_EUROPEAN }, + { "IBM857", N_("Turkish"), "IBM857", ENCODING_GROUP_SE_SW_ASIAN }, + { "IBM862", N_("Hebrew"), "IBM862", ENCODING_GROUP_MIDDLE_EASTERN }, + { "IBM864", N_("Arabic"), "IBM864", ENCODING_GROUP_MIDDLE_EASTERN }, + + { "ISO2022JP", N_("Japanese"), "ISO2022JP", ENCODING_GROUP_EAST_ASIAN }, + { "ISO2022KR", N_("Korean"), "ISO2022KR", ENCODING_GROUP_EAST_ASIAN }, + { "ISO-IR-111", N_("Cyrillic"), "ISO-IR-111", ENCODING_GROUP_EAST_EUROPEAN }, + { "JOHAB", N_("Korean"), "JOHAB", ENCODING_GROUP_EAST_ASIAN }, + { "KOI8-R", N_("Cyrillic"), "KOI8-R", ENCODING_GROUP_EAST_EUROPEAN }, + { "KOI8-U", N_("Cyrillic/Ukrainian"), "KOI8-U", ENCODING_GROUP_EAST_EUROPEAN }, + + { "MAC_ARABIC", N_("Arabic"), "MacArabic", ENCODING_GROUP_MIDDLE_EASTERN }, + { "MAC_CE", N_("Central European"), "MacCE", ENCODING_GROUP_EAST_EUROPEAN }, + { "MAC_CROATIAN", N_("Croatian"), "MacCroatian", ENCODING_GROUP_EAST_EUROPEAN }, + { "MAC-CYRILLIC", N_("Cyrillic"), "MacCyrillic", ENCODING_GROUP_EAST_EUROPEAN }, + { "MAC_DEVANAGARI", N_("Hindi"), "MacDevanagari", ENCODING_GROUP_SE_SW_ASIAN }, + { "MAC_FARSI", N_("Persian"), "MacFarsi", ENCODING_GROUP_MIDDLE_EASTERN }, + { "MAC_GREEK", N_("Greek"), "MacGreek", ENCODING_GROUP_WEST_EUROPEAN }, + { "MAC_GUJARATI", N_("Gujarati"), "MacGujarati", ENCODING_GROUP_SE_SW_ASIAN }, + { "MAC_GURMUKHI", N_("Gurmukhi"), "MacGurmukhi", ENCODING_GROUP_SE_SW_ASIAN }, + { "MAC_HEBREW", N_("Hebrew"), "MacHebrew", ENCODING_GROUP_MIDDLE_EASTERN }, + { "MAC_ICELANDIC", N_("Icelandic"), "MacIcelandic", ENCODING_GROUP_WEST_EUROPEAN }, + { "MAC_ROMAN", N_("Western"), "MacRoman", ENCODING_GROUP_WEST_EUROPEAN }, + { "MAC_ROMANIAN", N_("Romanian"), "MacRomanian", ENCODING_GROUP_EAST_EUROPEAN }, + { "MAC_TURKISH", N_("Turkish"), "MacTurkish", ENCODING_GROUP_SE_SW_ASIAN }, + { "MAC_UKRAINIAN", N_("Cyrillic/Ukrainian"), "MacUkrainian", ENCODING_GROUP_EAST_EUROPEAN }, + + { "SHIFT-JIS", N_("Japanese"), "Shift_JIS", ENCODING_GROUP_EAST_ASIAN }, + { "TCVN", N_("Vietnamese"), "TCVN", ENCODING_GROUP_EAST_ASIAN }, + { "TIS-620", N_("Thai"), "TIS-620", ENCODING_GROUP_SE_SW_ASIAN }, + { "UHC", N_("Korean"), "UHC", ENCODING_GROUP_EAST_ASIAN }, + { "VISCII", N_("Vietnamese"), "VISCII", ENCODING_GROUP_EAST_ASIAN }, + + { "WINDOWS-1250", N_("Central European"), "Windows-1250", ENCODING_GROUP_EAST_EUROPEAN }, + { "WINDOWS-1251", N_("Cyrillic"), "Windows-1251", ENCODING_GROUP_EAST_EUROPEAN }, + { "WINDOWS-1252", N_("Western"), "Windows-1252", ENCODING_GROUP_WEST_EUROPEAN }, + { "WINDOWS-1253", N_("Greek"), "Windows-1253", ENCODING_GROUP_WEST_EUROPEAN }, + { "WINDOWS-1254", N_("Turkish"), "Windows-1254", ENCODING_GROUP_SE_SW_ASIAN }, + { "WINDOWS-1255", N_("Hebrew"), "Windows-1255", ENCODING_GROUP_MIDDLE_EASTERN }, + { "WINDOWS-1256", N_("Arabic"), "Windows-1256", ENCODING_GROUP_MIDDLE_EASTERN }, + { "WINDOWS-1257", N_("Baltic"), "Windows-1257", ENCODING_GROUP_EAST_EUROPEAN }, + { "WINDOWS-1258", N_("Vietnamese"), "Windows-1258", ENCODING_GROUP_EAST_ASIAN } +}; diff --git a/moo/mooutils/mooencodings.c b/moo/mooutils/mooencodings.c new file mode 100644 index 00000000..b2d8dfaf --- /dev/null +++ b/moo/mooutils/mooencodings.c @@ -0,0 +1,680 @@ +/* + * mooencodings.c + * + * Copyright (C) 2004-2006 by Yevgen Muntyan + * + * 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. + * + * See COPYING file that comes with this distribution. + */ + +#include "mooutils/mooencodings.h" +#include "mooutils/mooi18n.h" +#include "mooutils/mooencodings-data.h" +#include +#include +#include + +#define MAX_RECENT_ENCODINGS 5 +#define ROW_RECENT(save_mode) ((save_mode) ? 1 : 3) +#define ROW_LOCALE(save_mode) ((save_mode) ? 0 : 2) +#define ROW_AUTO 0 + + +typedef struct { + const char *name; + const char *short_display_name; + char *display_name; + char *subgroup_name; +} Encoding; + +typedef struct { + Encoding **encodings; + guint n_encodings; + char *name; +} EncodingGroup; + +typedef struct { + GSList *recent; + EncodingGroup *groups; + guint n_groups; + Encoding *locale_encoding; + GSList *user_defined; + char *last_open; + char *last_save; + GHashTable *encodings; +} EncodingsManager; + +enum { + COLUMN_DISPLAY, + COLUMN_ENCODING +}; + + +static void combo_changed (GtkComboBox *combo, + gpointer save_mode); + + +static Encoding * +find_encoding (EncodingsManager *mgr, + const char *name) +{ + Encoding *enc; + char *upper; + + g_return_val_if_fail (name != NULL, NULL); + + upper = g_ascii_strup (name, -1); + enc = g_hash_table_lookup (mgr->encodings, upper); + + if (!enc) + { + enc = g_new0 (Encoding, 1); + enc->name = g_strdup (upper); + enc->short_display_name = enc->name; + enc->display_name = g_strdup (name); + mgr->user_defined = g_slist_prepend (mgr->user_defined, enc); + g_hash_table_insert (mgr->encodings, (char*) enc->name, enc); + } + + g_free (upper); + return enc; +} + + +static gboolean +validate_encoding_name (const char *name) +{ + return name && name[0]; +} + + +static int +compare_encodings (Encoding **enc1, + Encoding **enc2) +{ + int result; + + result = g_utf8_collate ((*enc1)->subgroup_name, (*enc2)->subgroup_name); + + if (!result) + result = g_utf8_collate ((*enc1)->short_display_name, (*enc2)->short_display_name); + + return result; +} + +static void +fill_encoding_group (EncodingGroup *group, + GSList *encodings) +{ + guint i; + + if (!encodings) + return; + + group->n_encodings = g_slist_length (encodings); + group->encodings = g_new0 (Encoding*, group->n_encodings); + + for (i = 0; encodings != NULL; encodings = encodings->next, ++i) + group->encodings[i] = encodings->data; + + qsort (group->encodings, group->n_encodings, sizeof (Encoding*), + (int(*)(const void *, const void *)) compare_encodings); +} + +static void +sort_encoding_groups (EncodingsManager *mgr) +{ + const char *order = N_("012345"); + const char *new_order_s; + int new_order[N_ENCODING_GROUPS] = {0, 0, 0, 0, 0, 0}; + guint i; + EncodingGroup *new_array; + + g_return_if_fail (strlen (order) == N_ENCODING_GROUPS); + g_return_if_fail (mgr->n_groups == N_ENCODING_GROUPS); + + new_order_s = _(order); + + if (!strcmp (order, new_order_s)) + return; + + for (i = 0; new_order_s[i]; ++i) + { + int n = new_order_s[i] - '0'; + + if (n < 0 || n >= (int) mgr->n_groups) + { + g_critical ("invalid order string %s", new_order_s); + return; + } + + new_order[i] = n; + } + + for (i = 0; i < mgr->n_groups; ++i) + { + if (!new_order[i]) + { + g_critical ("invalid order string %s", new_order_s); + return; + } + } + + new_array = g_new (EncodingGroup, mgr->n_groups); + + for (i = 0; i < mgr->n_groups; ++i) + new_array[i] = mgr->groups[new_order[i]]; + + g_free (mgr->groups); + mgr->groups = new_array; +} + +static EncodingsManager * +get_enc_mgr (void) +{ + static EncodingsManager *mgr; + + if (!mgr) + { + guint i; + const char *locale_charset; + GSList *enc_groups[N_ENCODING_GROUPS] = {NULL, NULL, NULL, NULL, NULL, NULL}; + + mgr = g_new0 (EncodingsManager, 1); + + mgr->n_groups = N_ENCODING_GROUPS; + mgr->groups = g_new0 (EncodingGroup, N_ENCODING_GROUPS); + + for (i = 0; i < mgr->n_groups; ++i) + mgr->groups[i].name = g_strdup (_(moo_encoding_groups_names[i])); + + mgr->encodings = g_hash_table_new (g_str_hash, g_str_equal); + + for (i = 0; i < G_N_ELEMENTS (moo_encodings_data); ++i) + { + Encoding *enc; + + enc = g_new0 (Encoding, 1); + enc->name = moo_encodings_data[i].name; + enc->subgroup_name = g_strdup (_(moo_encodings_data[i].display_subgroup)); + enc->short_display_name = moo_encodings_data[i].short_display_name; + enc->display_name = g_strdup_printf ("%s (%s)", enc->subgroup_name, + enc->short_display_name); + + enc_groups[moo_encodings_data[i].group] = + g_slist_prepend (enc_groups[moo_encodings_data[i].group], enc); + g_hash_table_insert (mgr->encodings, (char*) moo_encodings_data[i].name, enc); + } + + for (i = 0; i < G_N_ELEMENTS (moo_encoding_aliases); ++i) + { + Encoding *enc; + + enc = g_hash_table_lookup (mgr->encodings, moo_encoding_aliases[i].name); + + if (!enc) + g_critical ("%s: oops", G_STRLOC); + else + g_hash_table_insert (mgr->encodings, (char*) + moo_encoding_aliases[i].alias, + enc); + } + + for (i = 0; i < N_ENCODING_GROUPS; ++i) + { + fill_encoding_group (&mgr->groups[i], enc_groups[i]); + g_slist_free (enc_groups[i]); + } + + sort_encoding_groups (mgr); + + if (!g_get_charset (&locale_charset)) + locale_charset = MOO_ENCODING_UTF8; + + mgr->locale_encoding = find_encoding (mgr, locale_charset); + } + + return mgr; +} + + +static void +enc_mgr_save (EncodingsManager *enc_mgr) +{ +} + + +static const char * +current_locale_name (EncodingsManager *enc_mgr) +{ + static char *display_name; + + if (!display_name) + { + if (enc_mgr->locale_encoding) + display_name = g_strdup_printf (_("Current locale (%s)"), + enc_mgr->locale_encoding->short_display_name); + else + display_name = g_strdup (_("Current locale")); + } + + return display_name; +} + + +typedef struct { + const char *name; + GtkTreeIter iter; + gboolean found; +} FindEncodingData; + +static gboolean +find_encoding_func (GtkTreeModel *model, + G_GNUC_UNUSED GtkTreePath *path, + GtkTreeIter *iter, + FindEncodingData *data) +{ + char *name; + + gtk_tree_model_get (model, iter, COLUMN_ENCODING, &name, -1); + + if (name && !strcmp (name, data->name)) + { + data->iter = *iter; + data->found = TRUE; + } + + g_free (name); + return data->found; +} + +static gboolean +find_encoding_iter (GtkTreeModel *model, + GtkTreeIter *iter, + const char *name) +{ + FindEncodingData data; + + data.found = FALSE; + data.name = name; + + gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) find_encoding_func, &data); + + if (data.found && iter) + *iter = data.iter; + + return data.found; +} + + +static void +sync_recent_list (GtkTreeStore *store, + guint n_old_items, + GSList *list, + gboolean save_mode) +{ + GtkTreeIter iter; + guint i; + + for (i = 0; i < n_old_items; ++i) + { + gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, + NULL, ROW_RECENT (save_mode)); + gtk_tree_store_remove (store, &iter); + } + + while (list) + { + Encoding *enc = list->data; + gtk_tree_store_insert (store, &iter, NULL, ROW_RECENT (save_mode)); + gtk_tree_store_set (store, &iter, + COLUMN_DISPLAY, enc->display_name, + COLUMN_ENCODING, enc->name, -1); + list = list->next; + } +} + +static void +set_last (EncodingsManager *mgr, + const char *name, + gboolean save_mode) +{ + char **ptr = save_mode ? &mgr->last_save : &mgr->last_open; + char *tmp = *ptr; + *ptr = g_strdup (name); + g_free (tmp); +} + +static void +encoding_combo_set_active (GtkComboBox *combo, + const char *enc_name, + gboolean save_mode) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GSList *l, *recent_copy; + EncodingsManager *mgr; + gboolean found_recent; + guint n_recent; + Encoding *new_enc; + + mgr = get_enc_mgr (); + + if (!strcmp (enc_name, mgr->locale_encoding->name)) + enc_name = MOO_ENCODING_LOCALE; + + set_last (mgr, enc_name, save_mode); + + model = gtk_combo_box_get_model (combo); + g_signal_handlers_block_by_func (combo, (gpointer) combo_changed, + GINT_TO_POINTER (save_mode)); + + if (!strcmp (enc_name, MOO_ENCODING_AUTO)) + { + gtk_tree_model_iter_nth_child (model, &iter, NULL, ROW_AUTO); + gtk_combo_box_set_active_iter (combo, &iter); + goto out; + } + + if (!strcmp (enc_name, MOO_ENCODING_LOCALE)) + { + gtk_tree_model_iter_nth_child (model, &iter, NULL, ROW_LOCALE (save_mode)); + gtk_combo_box_set_active_iter (combo, &iter); + goto out; + } + + new_enc = find_encoding (mgr, enc_name); + g_return_if_fail (new_enc != NULL); + + set_last (mgr, new_enc->name, save_mode); + + n_recent = g_slist_length (mgr->recent); + + for (l = mgr->recent, found_recent = FALSE; l != NULL; l = l->next) + { + Encoding *enc = l->data; + + if (!strcmp (new_enc->name, enc->name)) + { + found_recent = TRUE; + + if (l != mgr->recent) + { + mgr->recent = g_slist_remove_link (mgr->recent, l); + l->next = mgr->recent; + mgr->recent = l; + } + } + } + + if (!found_recent) + { + mgr->recent = g_slist_prepend (mgr->recent, new_enc); + + if (g_slist_length (mgr->recent) > MAX_RECENT_ENCODINGS) + mgr->recent = g_slist_delete_link (mgr->recent, g_slist_last (mgr->recent)); + } + + recent_copy = g_slist_reverse (g_slist_copy (mgr->recent)); + sync_recent_list (GTK_TREE_STORE (model), n_recent, recent_copy, save_mode); + g_slist_free (recent_copy); + + if (find_encoding_iter (model, &iter, new_enc->name)) + gtk_combo_box_set_active_iter (combo, &iter); + +out: + g_signal_handlers_unblock_by_func (combo, (gpointer) combo_changed, + GINT_TO_POINTER (save_mode)); +} + +static void +combo_changed (GtkComboBox *combo, + gpointer save_mode) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *enc_name; + + if (!gtk_combo_box_get_active_iter (combo, &iter)) + return; + + model = gtk_combo_box_get_model (combo); + + if (gtk_tree_model_iter_has_child (model, &iter)) + return; + + gtk_tree_model_get (model, &iter, COLUMN_ENCODING, &enc_name, -1); + + if (!enc_name) + return; + + encoding_combo_set_active (combo, enc_name, GPOINTER_TO_INT (save_mode)); + g_free (enc_name); +} + + +static gboolean +row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter) +{ + char *text; + gboolean separator; + + gtk_tree_model_get (model, iter, COLUMN_DISPLAY, &text, -1); + separator = text == NULL; + + g_free (text); + return separator; +} + +static void +cell_data_func (G_GNUC_UNUSED GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gboolean sensitive; + sensitive = !gtk_tree_model_iter_has_child (model, iter); + g_object_set (cell, "sensitive", sensitive, NULL); +} + +static void +setup_combo (GtkComboBox *combo, + EncodingsManager *enc_mgr, + gboolean save_mode) +{ + GtkCellRenderer *cell; + GtkTreeStore *store; + GtkTreeIter iter; + GSList *l; + guint i; + char *start; + + store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + + if (!save_mode) + { + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, + COLUMN_DISPLAY, _("Auto Detected"), + COLUMN_ENCODING, MOO_ENCODING_AUTO, + -1); + + gtk_tree_store_append (store, &iter, NULL); + } + + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, + COLUMN_DISPLAY, current_locale_name (enc_mgr), + COLUMN_ENCODING, MOO_ENCODING_LOCALE, + -1); + + for (l = enc_mgr->recent; l != NULL; l = l->next) + { + Encoding *enc = l->data; + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, + COLUMN_DISPLAY, enc->display_name, + COLUMN_ENCODING, enc->name, + -1); + } + + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, COLUMN_DISPLAY, "Other", -1); + + for (i = 0; i < enc_mgr->n_groups; ++i) + { + guint j; + GtkTreeIter child, group_iter; + EncodingGroup *group; + + group = &enc_mgr->groups[i]; + gtk_tree_store_append (store, &group_iter, &iter); + gtk_tree_store_set (store, &group_iter, COLUMN_DISPLAY, group->name, -1); + + for (j = 0; j < group->n_encodings; ++j) + { + gtk_tree_store_append (store, &child, &group_iter); + gtk_tree_store_set (store, &child, + COLUMN_DISPLAY, group->encodings[j]->display_name, + COLUMN_ENCODING, group->encodings[j]->name, + -1); + } + } + + gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store)); + gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (combo), COLUMN_DISPLAY); + gtk_combo_box_set_row_separator_func (combo, + (GtkTreeViewRowSeparatorFunc) row_separator_func, + NULL, NULL); + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo)); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell, + "text", COLUMN_DISPLAY, NULL); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell, + (GtkCellLayoutDataFunc) cell_data_func, + NULL, NULL); + + if (save_mode) + { + if (enc_mgr->last_save) + start = g_strdup (enc_mgr->last_save); + else + start = g_strdup (MOO_ENCODING_UTF8); + } + else + { + if (enc_mgr->last_open) + start = g_strdup (enc_mgr->last_open); + else + start = g_strdup (MOO_ENCODING_AUTO); + } + + g_signal_connect (combo, "changed", G_CALLBACK (combo_changed), + GINT_TO_POINTER (save_mode)); + encoding_combo_set_active (GTK_COMBO_BOX (combo), start, save_mode); + + g_free (start); + g_object_unref (store); +} + + +void +_moo_encodings_attach_combo (GtkWidget *dialog, + GtkWidget *parent, + gboolean save_mode, + const char *encoding) +{ + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *combo; + + g_return_if_fail (GTK_IS_FILE_CHOOSER (dialog)); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic (_("Charact_er encoding:")); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + combo = gtk_combo_box_entry_new (); + gtk_widget_show (combo); + gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0); + + setup_combo (GTK_COMBO_BOX (combo), get_enc_mgr (), save_mode); + + if (save_mode && encoding) + { + if (!validate_encoding_name (encoding)) + encoding = MOO_ENCODING_UTF8; + encoding_combo_set_active (GTK_COMBO_BOX (combo), encoding, save_mode); + } + + g_object_set_data (G_OBJECT (dialog), "moo-encodings-combo", combo); +} + + +void +_moo_encodings_sync_combo (GtkWidget *dialog, + gboolean save_mode) +{ + GtkComboBox *combo; + const char *enc_name; + GtkTreeIter dummy; + + combo = g_object_get_data (G_OBJECT (dialog), "moo-encodings-combo"); + g_return_if_fail (combo != NULL); + + if (gtk_combo_box_get_active_iter (combo, &dummy)) + return; + + enc_name = gtk_entry_get_text (GTK_ENTRY (GTK_BIN (combo)->child)); + + if (!validate_encoding_name (enc_name)) + enc_name = save_mode ? MOO_ENCODING_UTF8 : MOO_ENCODING_AUTO; + + encoding_combo_set_active (combo, enc_name, save_mode); +} + + +const char * +_moo_encodings_combo_get (GtkWidget *dialog, + gboolean save_mode) +{ + const char *enc_name; + EncodingsManager *mgr; + + _moo_encodings_sync_combo (dialog, save_mode); + + mgr = get_enc_mgr (); + enc_mgr_save (mgr); + + if (save_mode) + { + if (mgr->last_save) + enc_name = mgr->last_save; + else + enc_name = MOO_ENCODING_UTF8; + } + else + { + if (mgr->last_open) + enc_name = mgr->last_open; + else + enc_name = MOO_ENCODING_AUTO; + } + + if (!strcmp (enc_name, MOO_ENCODING_LOCALE)) + enc_name = mgr->locale_encoding->name; + + g_print ("encoding: %s\n", enc_name); + return enc_name; +} diff --git a/moo/mooutils/mooencodings.h b/moo/mooutils/mooencodings.h new file mode 100644 index 00000000..aa32baf4 --- /dev/null +++ b/moo/mooutils/mooencodings.h @@ -0,0 +1,38 @@ +/* + * mooencodings.h + * + * Copyright (C) 2004-2006 by Yevgen Muntyan + * + * 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. + * + * See COPYING file that comes with this distribution. + */ + +#ifndef __MOO_ENCODINGS_H__ +#define __MOO_ENCODINGS_H__ + +#include + +G_BEGIN_DECLS + + +#define MOO_ENCODING_LOCALE "locale" +#define MOO_ENCODING_AUTO "auto" +#define MOO_ENCODING_UTF8 "UTF-8" + +void _moo_encodings_attach_combo (GtkWidget *dialog, + GtkWidget *box, + gboolean save_mode, + const char *encoding); +void _moo_encodings_sync_combo (GtkWidget *dialog, + gboolean save_mode); +const char *_moo_encodings_combo_get (GtkWidget *dialog, + gboolean save_mode); + + +G_END_DECLS + +#endif /* __MOO_ENCODINGS_H__ */ diff --git a/moo/mooutils/moofiledialog.c b/moo/mooutils/moofiledialog.c index e96f0643..23e6002b 100644 --- a/moo/mooutils/moofiledialog.c +++ b/moo/mooutils/moofiledialog.c @@ -17,6 +17,7 @@ #include "mooutils/mooutils-misc.h" #include "mooutils/moocompat.h" #include "mooutils/moomarshals.h" +#include "mooutils/mooencodings.h" #include @@ -29,9 +30,11 @@ struct _MooFileDialogPrivate { GtkWidget *parent; MooFilterMgr *filter_mgr; char *filter_mgr_id; + gboolean enable_encodings; GSList *filenames; char *filename; + char *encoding; }; @@ -47,7 +50,8 @@ enum { PROP_TYPE, PROP_PARENT, PROP_FILTER_MGR, - PROP_FILTER_MGR_ID + PROP_FILTER_MGR_ID, + PROP_ENABLE_ENCODINGS }; enum { @@ -115,6 +119,11 @@ moo_file_dialog_set_property (GObject *object, g_object_notify (object, "filter-mgr-id"); break; + case PROP_ENABLE_ENCODINGS: + dialog->priv->enable_encodings = g_value_get_boolean (value); + g_object_notify (object, "enable-encodings"); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -164,6 +173,10 @@ moo_file_dialog_get_property (GObject *object, g_value_set_string (value, dialog->priv->filter_mgr_id); break; + case PROP_ENABLE_ENCODINGS: + g_value_set_boolean (value, dialog->priv->enable_encodings); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -189,6 +202,7 @@ moo_file_dialog_finalize (GObject *object) g_free (dialog->priv->name); g_free (dialog->priv->filter_mgr_id); g_free (dialog->priv->filename); + g_free (dialog->priv->encoding); string_slist_free (dialog->priv->filenames); @@ -226,6 +240,14 @@ moo_file_dialog_class_init (MooFileDialogClass *klass) FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_ENABLE_ENCODINGS, + g_param_spec_boolean ("enable-encodings", + "enable-encodings", + "enable-encodings", + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_TITLE, g_param_spec_string ("title", @@ -394,6 +416,7 @@ moo_file_dialog_create_widget (MooFileDialog *dialog) { GtkFileChooserAction chooser_action; GtkWidget *widget = NULL; + GtkWidget *extra_box = NULL; switch (dialog->priv->type) { @@ -431,11 +454,23 @@ moo_file_dialog_create_widget (MooFileDialog *dialog) gtk_dialog_set_default_response (GTK_DIALOG (widget), GTK_RESPONSE_OK); + if (dialog->priv->filter_mgr || dialog->priv->enable_encodings) + { + extra_box = gtk_hbox_new (FALSE, 0); + gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (widget), extra_box); + gtk_widget_show (extra_box); + } + if (dialog->priv->filter_mgr) moo_filter_mgr_attach (dialog->priv->filter_mgr, - GTK_FILE_CHOOSER (widget), + GTK_FILE_CHOOSER (widget), extra_box, dialog->priv->filter_mgr_id); + if (dialog->priv->enable_encodings) + _moo_encodings_attach_combo (widget, extra_box, + dialog->priv->type == MOO_FILE_DIALOG_SAVE, + dialog->priv->encoding); + if (dialog->priv->parent) moo_window_set_parent (widget, dialog->priv->parent); @@ -476,6 +511,24 @@ set_filenames (MooFileDialog *dialog, } +static void +set_encoding (MooFileDialog *dialog, + const char *encoding) +{ + char *tmp = dialog->priv->encoding; + dialog->priv->encoding = g_strdup (encoding); + g_free (tmp); +} + +void +moo_file_dialog_set_encoding (MooFileDialog *dialog, + const char *encoding) +{ + g_return_if_fail (MOO_IS_FILE_DIALOG (dialog)); + set_encoding (dialog, encoding); +} + + static gboolean filename_is_valid (G_GNUC_UNUSED const char *filename, G_GNUC_UNUSED char **msg) @@ -540,6 +593,7 @@ moo_file_dialog_run (MooFileDialog *dialog) set_filename (dialog, NULL); set_filenames (dialog, NULL); + set_encoding (dialog, NULL); filechooser = moo_file_dialog_create_widget (dialog); @@ -622,6 +676,10 @@ moo_file_dialog_run (MooFileDialog *dialog) } out: + if (result && dialog->priv->enable_encodings) + set_encoding (dialog, _moo_encodings_combo_get (filechooser, + dialog->priv->type == MOO_FILE_DIALOG_SAVE)); + gtk_widget_destroy (filechooser); return result; } @@ -643,6 +701,14 @@ moo_file_dialog_get_filenames (MooFileDialog *dialog) } +const char * +moo_file_dialog_get_encoding (MooFileDialog *dialog) +{ + g_return_val_if_fail (MOO_IS_FILE_DIALOG (dialog), NULL); + return dialog->priv->encoding ? dialog->priv->encoding : MOO_ENCODING_UTF8; +} + + const char * moo_file_dialogp (GtkWidget *parent, MooFileDialogType type, diff --git a/moo/mooutils/moofiledialog.h b/moo/mooutils/moofiledialog.h index a2f6715c..6c231eb3 100644 --- a/moo/mooutils/moofiledialog.h +++ b/moo/mooutils/moofiledialog.h @@ -75,6 +75,10 @@ gboolean moo_file_dialog_run (MooFileDialog *dialog); const char *moo_file_dialog_get_filename (MooFileDialog *dialog); GSList *moo_file_dialog_get_filenames (MooFileDialog *dialog); +void moo_file_dialog_set_encoding (MooFileDialog *dialog, + const char *encoding); +const char *moo_file_dialog_get_encoding (MooFileDialog *dialog); + const char *moo_file_dialog (GtkWidget *parent, MooFileDialogType type, const char *title, diff --git a/moo/mooutils/moofiltermgr.c b/moo/mooutils/moofiltermgr.c index a55a773e..8c691a8a 100644 --- a/moo/mooutils/moofiltermgr.c +++ b/moo/mooutils/moofiltermgr.c @@ -511,9 +511,9 @@ combo_changed (MooCombo *combo, void moo_filter_mgr_attach (MooFilterMgr *mgr, GtkFileChooser *dialog, + GtkWidget *parent, const char *user_id) { - GtkWidget *alignment; GtkWidget *hbox; GtkWidget *label; GtkWidget *combo; @@ -525,13 +525,9 @@ moo_filter_mgr_attach (MooFilterMgr *mgr, mgr_load (mgr); - alignment = gtk_alignment_new (1, 0.5, 0, 1); - gtk_widget_show (alignment); - gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), alignment); - hbox = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (alignment), hbox); + gtk_box_pack_end (GTK_BOX (parent), hbox, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic ("_Filter:"); gtk_widget_show (label); diff --git a/moo/mooutils/moofiltermgr.h b/moo/mooutils/moofiltermgr.h index 2c54ccc3..bae67683 100644 --- a/moo/mooutils/moofiltermgr.h +++ b/moo/mooutils/moofiltermgr.h @@ -55,6 +55,7 @@ void moo_filter_mgr_init_filter_combo (MooFilterMgr *mgr, const char *user_id); void moo_filter_mgr_attach (MooFilterMgr *mgr, GtkFileChooser *filechooser, + GtkWidget *box, const char *user_id); GtkFileFilter *moo_filter_mgr_get_filter (MooFilterMgr *mgr, diff --git a/po/POTFILES.in b/po/POTFILES.in index 33ab8d6d..82f92d89 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,6 +12,8 @@ moo/mooedit/mooeditwindow.c moo/mooedit/mootextstylescheme.c moo/mooedit/moousertools.c moo/mooedit/moousertools-prefs.c +moo/mooutils/mooencodings-data.h +moo/mooutils/mooencodings.c moo/mooedit/glade/mooeditprefs.glade moo/mooedit/glade/mooeditprogress.glade diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 7bfcc33d..cfd73a8b 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -50,6 +50,8 @@ moo/mooedit/language-specs/verilog.lang moo/mooedit/language-specs/vhdl.lang moo/mooedit/language-specs/xml.lang moo/mooedit/language-specs/yacc.lang +moo/mooedit/language-specs/boo.lang +moo/mooedit/language-specs/d.lang moo/moopython/plugins/pyproject/project-plugin.ini.desktop.in.in moo/moopython/plugins/pyproject/mprj/manager.py