00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00036 #include "config.h"
00037
00038 #include <gtk/gtk.h>
00039 #include <string.h>
00040 #include "swig-runtime.h"
00041
00042 #include "guile-util.h"
00043 #include "gnc-engine.h"
00044 #include "gnc-main-window.h"
00045 #include "gnc-plugin-menu-additions.h"
00046 #include "gnc-window.h"
00047 #include "gnc-gconf-utils.h"
00048 #include "gnc-ui.h"
00049 #include "gnc-menu-extensions.h"
00050
00051 static GObjectClass *parent_class = NULL;
00052
00053 static void gnc_plugin_menu_additions_class_init (GncPluginMenuAdditionsClass *klass);
00054 static void gnc_plugin_menu_additions_init (GncPluginMenuAdditions *plugin);
00055 static void gnc_plugin_menu_additions_finalize (GObject *object);
00056
00057 static void gnc_plugin_menu_additions_add_to_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
00058 static void gnc_plugin_menu_additions_remove_from_window (GncPlugin *plugin, GncMainWindow *window, GQuark type);
00059
00060
00061
00062
00063 static QofLogModule log_module = GNC_MOD_GUI;
00064
00065 #define PLUGIN_ACTIONS_NAME "gnc-plugin-menu-additions-actions"
00066
00068 typedef struct GncPluginMenuAdditionsPrivate
00069 {
00070 gpointer dummy;
00071 } GncPluginMenuAdditionsPrivate;
00072
00073 #define GNC_PLUGIN_MENU_ADDITIONS_GET_PRIVATE(o) \
00074 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_MENU_ADDITIONS, GncPluginMenuAdditionsPrivate))
00075
00076
00079 typedef struct _GncPluginMenuAdditionsPerWindow
00080 {
00084 GncMainWindow *window;
00085 GtkUIManager *ui_manager;
00086 GtkActionGroup *group;
00087 gint merge_id;
00088 } GncPluginMenuAdditionsPerWindow;
00089
00090
00091
00092
00093
00094 GType
00095 gnc_plugin_menu_additions_get_type (void)
00096 {
00097 static GType gnc_plugin_menu_additions_type = 0;
00098
00099 if (gnc_plugin_menu_additions_type == 0) {
00100 static const GTypeInfo our_info = {
00101 sizeof (GncPluginMenuAdditionsClass),
00102 NULL,
00103 NULL,
00104 (GClassInitFunc) gnc_plugin_menu_additions_class_init,
00105 NULL,
00106 NULL,
00107 sizeof (GncPluginMenuAdditions),
00108 0,
00109 (GInstanceInitFunc) gnc_plugin_menu_additions_init
00110 };
00111
00112 gnc_plugin_menu_additions_type = g_type_register_static (GNC_TYPE_PLUGIN,
00113 "GncPluginMenuAdditions",
00114 &our_info, 0);
00115 }
00116
00117 return gnc_plugin_menu_additions_type;
00118 }
00119
00120 static void
00121 gnc_plugin_menu_additions_class_init (GncPluginMenuAdditionsClass *klass)
00122 {
00123 GObjectClass *object_class = G_OBJECT_CLASS (klass);
00124 GncPluginClass *plugin_class = GNC_PLUGIN_CLASS (klass);
00125
00126 parent_class = g_type_class_peek_parent (klass);
00127
00128 object_class->finalize = gnc_plugin_menu_additions_finalize;
00129
00130
00131 plugin_class->plugin_name = GNC_PLUGIN_MENU_ADDITIONS_NAME;
00132
00133
00134 plugin_class->add_to_window = gnc_plugin_menu_additions_add_to_window;
00135 plugin_class->remove_from_window = gnc_plugin_menu_additions_remove_from_window;
00136
00137 g_type_class_add_private(klass, sizeof(GncPluginMenuAdditionsPrivate));
00138 }
00139
00140 static void
00141 gnc_plugin_menu_additions_init (GncPluginMenuAdditions *plugin)
00142 {
00143 ENTER("plugin %p", plugin);
00144 LEAVE("");
00145 }
00146
00147 static void
00148 gnc_plugin_menu_additions_finalize (GObject *object)
00149 {
00150 GncPluginMenuAdditions *plugin;
00151 GncPluginMenuAdditionsPrivate *priv;
00152
00153 g_return_if_fail (GNC_IS_PLUGIN_MENU_ADDITIONS (object));
00154
00155 ENTER("plugin %p", object);
00156 plugin = GNC_PLUGIN_MENU_ADDITIONS (object);
00157 priv = GNC_PLUGIN_MENU_ADDITIONS_GET_PRIVATE (plugin);
00158
00159 G_OBJECT_CLASS (parent_class)->finalize (object);
00160 LEAVE("");
00161 }
00162
00163
00164
00165
00166
00167
00168
00169 GncPlugin *
00170 gnc_plugin_menu_additions_new (void)
00171 {
00172 GncPlugin *plugin_page = NULL;
00173
00174 ENTER("");
00175 plugin_page = GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_MENU_ADDITIONS, NULL));
00176 LEAVE("plugin %p", plugin_page);
00177 return plugin_page;
00178 }
00179
00180
00181
00182
00183
00184 static SCM
00185 gnc_main_window_to_scm (GncMainWindow *window)
00186 {
00187 static swig_type_info * main_window_type = NULL;
00188
00189 if (!window)
00190 return SCM_BOOL_F;
00191
00192 if (!main_window_type)
00193 main_window_type = SWIG_TypeQuery("_p_GncMainWindow");
00194
00195 return SWIG_NewPointerObj(window, main_window_type, 0);
00196 }
00197
00198
00210 static void
00211 gnc_plugin_menu_additions_action_cb (GtkAction *action,
00212 GncMainWindowActionData *data)
00213 {
00214
00215 g_return_if_fail(GTK_IS_ACTION(action));
00216 g_return_if_fail(data != NULL);
00217
00218 gnc_extension_invoke_cb(data->data, gnc_main_window_to_scm(data->window));
00219 }
00220
00221
00233 static gint
00234 gnc_menu_additions_sort (ExtensionInfo *a, ExtensionInfo *b)
00235 {
00236 if (a->type == b->type)
00237 return strcmp(a->sort_key, b->sort_key);
00238 else if (a->type == GTK_UI_MANAGER_MENU)
00239 return -1;
00240 else if (b->type == GTK_UI_MANAGER_MENU)
00241 return 1;
00242 else
00243 return 0;
00244 }
00245
00246
00252 static gpointer
00253 gnc_menu_additions_init_accel_table (gpointer unused)
00254 {
00255 return g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
00256 }
00257
00258
00269 static void
00270 gnc_menu_additions_do_preassigned_accel (ExtensionInfo *info, GHashTable *table)
00271 {
00272 gchar *map, *new_map, *accel_key;
00273 const gchar *ptr;
00274
00275 ENTER("Checking %s/%s [%s]", info->path, info->ae.label, info->ae.name);
00276 if (info->accel_assigned) {
00277 LEAVE("Already processed");
00278 return;
00279 }
00280
00281 if (!g_utf8_validate(info->ae.label, -1, NULL)) {
00282 g_warning("Extension menu label '%s' is not valid utf8.", info->ae.label);
00283 info->accel_assigned = TRUE;
00284 LEAVE("Label is invalid utf8");
00285 return;
00286 }
00287
00288
00289 ptr = g_utf8_strchr(info->ae.label, -1, '_');
00290 if (ptr == NULL) {
00291 LEAVE("not preassigned");
00292 return;
00293 }
00294
00295 accel_key = g_utf8_strdown(g_utf8_next_char(ptr), 1);
00296 DEBUG("Accelerator preassigned: '%s'", accel_key);
00297
00298
00299 map = g_hash_table_lookup(table, info->path);
00300 if (map == NULL)
00301 map = "";
00302 new_map = g_strconcat(map, accel_key, (gchar *)NULL);
00303 DEBUG("path '%s', map '%s' -> '%s'", info->path, map, new_map);
00304 g_hash_table_replace(table, info->path, new_map);
00305
00306 info->accel_assigned = TRUE;
00307 g_free(accel_key);
00308 LEAVE("preassigned");
00309 }
00310
00311
00323 static void
00324 gnc_menu_additions_assign_accel (ExtensionInfo *info, GHashTable *table)
00325 {
00326 gchar *map, *new_map, *new_label, *start, buf[16];
00327 const gchar *ptr;
00328 gunichar uni;
00329 gint len;
00330
00331 ENTER("Checking %s/%s [%s]", info->path, info->ae.label, info->ae.name);
00332 if (info->accel_assigned) {
00333 LEAVE("Already processed");
00334 return;
00335 }
00336
00337
00338 map = g_hash_table_lookup(table, info->path);
00339 if (map == NULL)
00340 map = g_strdup("");
00341 DEBUG("map '%s', path %s", map, info->path);
00342
00343 for (ptr = info->ae.label; *ptr; ptr = g_utf8_next_char(ptr)) {
00344 uni = g_utf8_get_char(ptr);
00345 if (!g_unichar_isalpha(uni))
00346 continue;
00347 uni = g_unichar_tolower(uni);
00348 len = g_unichar_to_utf8(uni, buf);
00349 buf[len] = '\0';
00350 DEBUG("Testing character '%s'", buf);
00351 if (!g_utf8_strchr(map, -1, uni))
00352 break;
00353 }
00354
00355 if (ptr == NULL) {
00356
00357 info->accel_assigned = TRUE;
00358 LEAVE("All characters already assigned");
00359 return;
00360 }
00361
00362
00363 start = g_strndup(info->ae.label, ptr - info->ae.label);
00364 DEBUG("start %p, len %ld, text '%s'", start, g_utf8_strlen(start, -1), start);
00365 new_label = g_strconcat(start, "_", ptr, (gchar *)NULL);
00366 g_free(start);
00367 DEBUG("label '%s' -> '%s'", info->ae.label, new_label);
00368 g_free((gchar *)info->ae.label);
00369 info->ae.label = new_label;
00370
00371
00372 new_map = g_strconcat(map, buf, (gchar *)NULL);
00373 DEBUG("map '%s' -> '%s'", map, new_map);
00374 g_hash_table_replace(table, info->path, new_map);
00375
00376 info->accel_assigned = TRUE;
00377 LEAVE("assigned");
00378 }
00379
00380
00390 static void
00391 gnc_menu_additions_menu_setup_one (ExtensionInfo *ext_info,
00392 GncPluginMenuAdditionsPerWindow *per_window)
00393 {
00394 GncMainWindowActionData *cb_data;
00395
00396 DEBUG( "Adding %s/%s [%s] as [%s]", ext_info->path, ext_info->ae.label,
00397 ext_info->ae.name, ext_info->typeStr );
00398
00399 cb_data = g_new0 (GncMainWindowActionData, 1);
00400 cb_data->window = per_window->window;
00401 cb_data->data = ext_info->extension;
00402
00403 if (ext_info->type == GTK_UI_MANAGER_MENUITEM)
00404 ext_info->ae.callback = (GCallback)gnc_plugin_menu_additions_action_cb;
00405
00406 gtk_action_group_add_actions_full(per_window->group, &ext_info->ae, 1,
00407 cb_data, g_free);
00408 gtk_ui_manager_add_ui(per_window->ui_manager, per_window->merge_id,
00409 ext_info->path, ext_info->ae.label, ext_info->ae.name,
00410 ext_info->type, FALSE);
00411 gtk_ui_manager_ensure_update(per_window->ui_manager);
00412 }
00413
00414
00427 static void
00428 gnc_plugin_menu_additions_add_to_window (GncPlugin *plugin,
00429 GncMainWindow *window,
00430 GQuark type)
00431 {
00432 GncPluginMenuAdditionsPerWindow per_window;
00433 static GOnce accel_table_init = G_ONCE_INIT;
00434 static GHashTable *table;
00435 GSList *menu_list;
00436
00437 ENTER(" ");
00438
00439 per_window.window = window;
00440 per_window.ui_manager = window->ui_merge;
00441 per_window.group = gtk_action_group_new ("MenuAdditions" );
00442 gnc_gtk_action_group_set_translation_domain (per_window.group, GETTEXT_PACKAGE);
00443 per_window.merge_id = gtk_ui_manager_new_merge_id(window->ui_merge);
00444 gtk_ui_manager_insert_action_group(window->ui_merge, per_window.group, 0);
00445
00446 menu_list = g_slist_sort(gnc_extensions_get_menu_list(),
00447 (GCompareFunc)gnc_menu_additions_sort);
00448
00449
00450 table = g_once(&accel_table_init, gnc_menu_additions_init_accel_table, NULL);
00451 g_slist_foreach(menu_list,
00452 (GFunc)gnc_menu_additions_do_preassigned_accel, table);
00453 g_slist_foreach(menu_list, (GFunc)gnc_menu_additions_assign_accel, table);
00454
00455
00456 g_slist_foreach(menu_list, (GFunc)gnc_menu_additions_menu_setup_one,
00457 &per_window);
00458
00459
00460
00461 gnc_main_window_manual_merge_actions (window, PLUGIN_ACTIONS_NAME,
00462 per_window.group, per_window.merge_id);
00463
00464 LEAVE(" ");
00465 }
00466
00467
00479 static void
00480 gnc_plugin_menu_additions_remove_from_window (GncPlugin *plugin,
00481 GncMainWindow *window,
00482 GQuark type)
00483 {
00484 GtkActionGroup *group;
00485
00486 ENTER(" ");
00487
00488
00489
00490 group = gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME);
00491 if (group)
00492 gtk_ui_manager_remove_action_group(window->ui_merge, group);
00493
00494
00495
00496
00497
00498 LEAVE(" ");
00499 }
00500