gnc-main-window.c

Go to the documentation of this file.
00001 /* 
00002  * gnc-main-window.c -- GtkWindow which represents the
00003  *      GnuCash main window.
00004  *
00005  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
00006  * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, contact:
00020  *
00021  * Free Software Foundation           Voice:  +1-617-542-5942
00022  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00023  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00024  */
00025 
00036 #include "config.h"
00037 
00038 #include <gnome.h>
00039 #include <glib/gi18n.h>
00040 #include <libguile.h>
00041 #include "guile-mappings.h"
00042 
00043 #include "gnc-plugin.h"
00044 #include "gnc-plugin-manager.h"
00045 #include "gnc-main-window.h"
00046 
00047 #include "dialog-preferences.h"
00048 #include "dialog-reset-warnings.h"
00049 #include "dialog-transfer.h"
00050 #include "dialog-utils.h"
00051 #include "file-utils.h"
00052 #include "gnc-component-manager.h"
00053 #include "gnc-engine.h"
00054 #include "gnc-file.h"
00055 #include "gnc-gkeyfile-utils.h"
00056 #include "gnc-gnome-utils.h"
00057 #include "gnc-gobject-utils.h"
00058 #include "gnc-gui-query.h"
00059 #include "gnc-hooks.h"
00060 #include "gnc-session.h"
00061 #include "gnc-ui.h"
00062 #include "gnc-ui-util.h"
00063 #include "gnc-version.h"
00064 #include "gnc-window.h"
00065 #include "gnc-main.h"
00066 #include "gnc-gconf-utils.h"
00067 // +JSLED
00068 #include "gnc-html.h"
00069 #include "gnc-autosave.h"
00070 
00072 enum {
00073   PAGE_ADDED,
00074   PAGE_CHANGED,
00075   LAST_SIGNAL
00076 };
00077 
00080 #define PLUGIN_PAGE_LABEL "plugin-page"
00081 
00082 #define PLUGIN_PAGE_CLOSE_BUTTON "close-button"
00083 #define PLUGIN_PAGE_TAB_LABEL    "label"
00084 
00085 #define KEY_SHOW_CLOSE_BUTTON   "tab_close_buttons"
00086 #define KEY_TAB_NEXT_RECENT     "tab_next_recent"
00087 #define KEY_TAB_POSITION        "tab_position"
00088 #define KEY_TAB_WIDTH           "tab_width"
00089 
00090 #define GNC_MAIN_WINDOW_NAME "GncMainWindow"
00091 
00092 /* Static Globals *******************************************************/
00093 
00095 static QofLogModule log_module = GNC_MOD_GUI;
00097 static GObjectClass *parent_class = NULL;
00099 static GQuark window_type = 0;
00102 static GList *active_windows = NULL;
00103 
00104 /* Declarations *********************************************************/
00105 static void gnc_main_window_class_init (GncMainWindowClass *klass);
00106 static void gnc_main_window_init (GncMainWindow *window, GncMainWindowClass *klass);
00107 static void gnc_main_window_finalize (GObject *object);
00108 static void gnc_main_window_destroy (GtkObject *object);
00109 
00110 static void gnc_main_window_setup_window (GncMainWindow *window);
00111 static void gnc_window_main_window_init (GncWindowIface *iface);
00112 static void gnc_main_window_update_all_menu_items (void);
00113 
00114 /* Callbacks */
00115 static void gnc_main_window_add_widget (GtkUIManager *merge, GtkWidget *widget, GncMainWindow *window);
00116 static void gnc_main_window_switch_page (GtkNotebook *notebook, GtkNotebookPage *notebook_page, gint pos, GncMainWindow *window);
00117 #ifdef HAVE_GTK_2_10
00118 static void gnc_main_window_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint pos, GncMainWindow *window);
00119 #endif
00120 static void gnc_main_window_plugin_added (GncPlugin *manager, GncPlugin *plugin, GncMainWindow *window);
00121 static void gnc_main_window_plugin_removed (GncPlugin *manager, GncPlugin *plugin, GncMainWindow *window);
00122 
00123 /* Command callbacks */
00124 static void gnc_main_window_cmd_file_properties (GtkAction *action, GncMainWindow *window);
00125 static void gnc_main_window_cmd_file_close (GtkAction *action, GncMainWindow *window);
00126 static void gnc_main_window_cmd_file_quit (GtkAction *action, GncMainWindow *window);
00127 static void gnc_main_window_cmd_edit_cut (GtkAction *action, GncMainWindow *window);
00128 static void gnc_main_window_cmd_edit_copy (GtkAction *action, GncMainWindow *window);
00129 static void gnc_main_window_cmd_edit_paste (GtkAction *action, GncMainWindow *window);
00130 static void gnc_main_window_cmd_edit_preferences (GtkAction *action, GncMainWindow *window);
00131 static void gnc_main_window_cmd_view_refresh (GtkAction *action, GncMainWindow *window);
00132 static void gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window);
00133 static void gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window);
00134 static void gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window);
00135 static void gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window);
00136 static void gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window);
00137 static void gnc_main_window_cmd_window_new (GtkAction *action, GncMainWindow *window);
00138 static void gnc_main_window_cmd_window_move_page (GtkAction *action, GncMainWindow *window);
00139 static void gnc_main_window_cmd_window_raise (GtkAction *action, GtkRadioAction *current, GncMainWindow *window);
00140 static void gnc_main_window_cmd_help_tutorial (GtkAction *action, GncMainWindow *window);
00141 static void gnc_main_window_cmd_help_contents (GtkAction *action, GncMainWindow *window);
00142 static void gnc_main_window_cmd_help_about (GtkAction *action, GncMainWindow *window);
00143 
00144 static void do_popup_menu(GncPluginPage *page, GdkEventButton *event);
00145 static gboolean gnc_main_window_popup_menu_cb (GtkWidget *widget, GncPluginPage *page);
00146 
00147 static GtkAction *gnc_main_window_find_action (GncMainWindow *window, const gchar *name);
00148 
00151 typedef struct GncMainWindowPrivate
00152 {
00157         GtkWidget *menu_dock;
00158         /* The toolbar created by the UI manager.  This pointer
00159          * provides easy access for showing/hiding the toolbar. */
00160         GtkWidget *toolbar;
00162         GtkWidget *notebook;
00166         GtkWidget *statusbar;
00170         GtkWidget *progressbar;
00171 
00175         GtkActionGroup *action_group;
00176 
00178         GList *installed_pages;
00180         GList *usage_order;
00182         GncPluginPage *current_page;
00184         gint event_handler_id;
00185 
00190         GHashTable *merged_actions_table;
00191 } GncMainWindowPrivate;
00192 
00193 #define GNC_MAIN_WINDOW_GET_PRIVATE(o)  \
00194    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_MAIN_WINDOW, GncMainWindowPrivate))
00195 
00198 typedef struct {
00201         guint merge_id;
00204         GtkActionGroup *action_group;
00205 } MergedActionEntry;
00206 
00209 static guint main_window_signals[LAST_SIGNAL] = { 0 };
00210 
00211 
00216 static GtkActionEntry gnc_menu_actions [] =
00217 {
00218         /* Toplevel */
00219 
00220         { "FileAction", NULL, N_("_File"), NULL, NULL, NULL, },
00221         { "EditAction", NULL, N_("_Edit"), NULL, NULL, NULL },
00222         { "ViewAction", NULL, N_("_View"), NULL, NULL, NULL },
00223         { "ActionsAction", NULL, N_("_Actions"), NULL, NULL, NULL },
00224         { "TransactionAction", NULL, N_("Tra_nsaction"), NULL, NULL, NULL },
00225         { "ReportsAction", NULL, N_("_Reports"), NULL, NULL, NULL },
00226         { "ToolsAction", NULL, N_("_Tools"), NULL, NULL, NULL },
00227         { "ExtensionsAction", NULL, N_("E_xtensions"), NULL, NULL, NULL },
00228         { "WindowsAction", NULL, N_("_Windows"), NULL, NULL, NULL },
00229         { "HelpAction", NULL, N_("_Help"), NULL, NULL, NULL },
00230 
00231         /* File menu */
00232 
00233         { "FileNewMenuAction", GTK_STOCK_NEW, N_("_New"), "", NULL, NULL },
00234         { "FileOpenMenuAction", GTK_STOCK_OPEN, N_("_Open"), "", NULL, NULL },
00235         { "FileImportAction", NULL, N_("_Import"), NULL, NULL, NULL },
00236         { "FileExportAction", NULL, N_("_Export"), NULL, NULL, NULL },
00237         { "FilePrintAction", GTK_STOCK_PRINT, N_("_Print..."), "<control>p", 
00238           N_("Print the currently active page"), NULL },
00239         { "FilePropertiesAction", GTK_STOCK_PROPERTIES, N_("Proper_ties"), "<Alt>Return",
00240           N_("Edit the properties of the current file"),
00241           G_CALLBACK (gnc_main_window_cmd_file_properties) },
00242         { "FileCloseAction", GTK_STOCK_CLOSE, N_("_Close"), NULL,
00243           N_("Close the currently active page"),
00244           G_CALLBACK (gnc_main_window_cmd_file_close) },
00245         { "FileQuitAction", GTK_STOCK_QUIT, N_("_Quit"), NULL,
00246           N_("Quit this application"),
00247           G_CALLBACK (gnc_main_window_cmd_file_quit) },
00248 
00249         /* Edit menu */
00250 
00251         { "EditCutAction", GTK_STOCK_CUT, N_("Cu_t"), NULL, 
00252           N_("Cut the current selection and copy it to clipboard"),
00253           G_CALLBACK (gnc_main_window_cmd_edit_cut) },
00254         { "EditCopyAction", GTK_STOCK_COPY, N_("_Copy"), NULL, 
00255           N_("Copy the current selection to clipboard"),
00256           G_CALLBACK (gnc_main_window_cmd_edit_copy) },
00257         { "EditPasteAction", GTK_STOCK_PASTE, N_("_Paste"), NULL,
00258           N_("Paste the clipboard content at the cursor position"),
00259           G_CALLBACK (gnc_main_window_cmd_edit_paste) },
00260         { "EditPreferencesAction", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), NULL,
00261           N_("Edit the global preferences of GnuCash"),
00262           G_CALLBACK (gnc_main_window_cmd_edit_preferences) },
00263 
00264         /* View menu */
00265 
00266         { "ViewSortByAction", NULL, N_("_Sort By..."), NULL, 
00267           N_("Select sorting criteria for this page view"), NULL },
00268         { "ViewFilterByAction", NULL, N_("_Filter By..."), NULL, 
00269           N_("Select the account types that should be displayed."), NULL },
00270         { "ViewRefreshAction", GTK_STOCK_REFRESH, N_("_Refresh"), "<control>r",
00271           N_("Refresh this window"),
00272           G_CALLBACK (gnc_main_window_cmd_view_refresh) },
00273 
00274         /* Actions menu */
00275 
00276         { "ScrubMenuAction", NULL, N_("_Check & Repair"), NULL, NULL, NULL },
00277         { "ActionsForgetWarningsAction", NULL, N_("Reset _Warnings..."), NULL,
00278           N_("Reset the state of all warning messages so they will be shown again."),
00279           G_CALLBACK (gnc_main_window_cmd_actions_reset_warnings) },
00280         { "ActionsRenamePageAction", NULL, N_("Re_name Page"), NULL,
00281           N_("Rename this page."),
00282           G_CALLBACK (gnc_main_window_cmd_actions_rename_page) },
00283 
00284         /* Windows menu */
00285 
00286         { "WindowNewAction", NULL, N_("_New Window"), NULL,
00287           N_("Open a new top-level GnuCash window."),
00288           G_CALLBACK (gnc_main_window_cmd_window_new) },
00289         { "WindowMovePageAction", NULL, N_("New Window with _Page"), NULL,
00290           N_("Move the current page to a new top-level GnuCash window."),
00291           G_CALLBACK (gnc_main_window_cmd_window_move_page) },
00292 
00293         /* Help menu */
00294 
00295         { "HelpTutorialAction", GNOME_STOCK_BOOK_BLUE, N_("Tutorial and Concepts _Guide"), NULL,
00296           N_("Open the GnuCash Tutorial"),
00297           G_CALLBACK (gnc_main_window_cmd_help_tutorial) },
00298         { "HelpContentsAction", GTK_STOCK_HELP, N_("_Contents"), "F1",
00299           N_("Open the GnuCash Help"),
00300           G_CALLBACK (gnc_main_window_cmd_help_contents) },
00301         { "HelpAboutAction", GNOME_STOCK_ABOUT, N_("_About"), NULL,
00302           N_("About GnuCash"),
00303           G_CALLBACK (gnc_main_window_cmd_help_about) },
00304 };
00306 static guint gnc_menu_n_actions = G_N_ELEMENTS (gnc_menu_actions);
00307 
00310 static GtkToggleActionEntry toggle_actions [] =
00311 {
00312         { "ViewToolbarAction", NULL, N_("_Toolbar"), NULL,
00313           N_("Show/hide the toolbar on this window"),
00314           G_CALLBACK (gnc_main_window_cmd_view_toolbar), TRUE },
00315         { "ViewSummaryAction", NULL, N_("Su_mmary Bar"), NULL,
00316           N_("Show/hide the summary bar on this window"),
00317           G_CALLBACK (gnc_main_window_cmd_view_summary), TRUE },
00318         { "ViewStatusbarAction", NULL, N_("Stat_us Bar"), NULL,
00319           N_("Show/hide the status bar on this window"),
00320           G_CALLBACK (gnc_main_window_cmd_view_statusbar), TRUE },
00321 };
00323 static guint n_toggle_actions = G_N_ELEMENTS (toggle_actions);
00324 
00327 static GtkRadioActionEntry radio_entries [] =
00328 {
00329         { "Window0Action", NULL, N_("Window _1"), NULL, NULL, 0 },
00330         { "Window1Action", NULL, N_("Window _2"), NULL, NULL, 1 },
00331         { "Window2Action", NULL, N_("Window _3"), NULL, NULL, 2 },
00332         { "Window3Action", NULL, N_("Window _4"), NULL, NULL, 3 },
00333         { "Window4Action", NULL, N_("Window _5"), NULL, NULL, 4 },
00334         { "Window5Action", NULL, N_("Window _6"), NULL, NULL, 5 },
00335         { "Window6Action", NULL, N_("Window _7"), NULL, NULL, 6 },
00336         { "Window7Action", NULL, N_("Window _8"), NULL, NULL, 7 },
00337         { "Window8Action", NULL, N_("Window _9"), NULL, NULL, 8 },
00338         { "Window9Action", NULL, N_("Window _0"), NULL, NULL, 9 },
00339 };
00341 static guint n_radio_entries = G_N_ELEMENTS (radio_entries);
00342 
00343 
00347 static const gchar *gnc_menu_important_actions[] = {
00348   "FileCloseAction",
00349   NULL,
00350 };
00351 
00352 
00357 static const gchar *always_insensitive_actions[] = {
00358         "FilePrintAction",
00359         NULL
00360 };
00361 
00362 
00366 static const gchar *initially_insensitive_actions[] = {
00367         "FileCloseAction",
00368         NULL
00369 };
00370 
00371 
00376 static const gchar *always_hidden_actions[] = {
00377         "ViewSortByAction",
00378         "ViewFilterByAction",
00379         NULL
00380 };
00381 
00382 
00385 static const gchar *immutable_page_actions[] = {
00386         "FileCloseAction",
00387         NULL
00388 };
00389 
00390 
00393 static const gchar *multiple_page_actions[] = {
00394         "WindowMovePageAction",
00395         NULL
00396 };
00397 
00398 
00399 /* This data structure holds the tooltops for all notebook tabs.
00400  * Typically these are used to provide the full path of a register
00401  * page. */
00402 static GtkTooltips *tips = NULL;
00403 
00404 /************************************************************
00405  *                                                          *
00406  ************************************************************/
00407 #define WINDOW_COUNT            "WindowCount"
00408 #define WINDOW_STRING           "Window %d"
00409 #define WINDOW_GEOMETRY         "WindowGeometry"
00410 #define WINDOW_POSITION         "WindowPosition"
00411 #define WINDOW_MAXIMIZED        "WindowMaximized"
00412 #define TOOLBAR_VISIBLE         "ToolbarVisible"
00413 #define STATUSBAR_VISIBLE       "StatusbarVisible"
00414 #define SUMMARYBAR_VISIBLE      "SummarybarVisible"
00415 #define WINDOW_FIRSTPAGE        "FirstPage"
00416 #define WINDOW_PAGECOUNT        "PageCount"
00417 #define WINDOW_PAGEORDER        "PageOrder"
00418 #define PAGE_TYPE               "PageType"
00419 #define PAGE_NAME               "PageName"
00420 #define PAGE_STRING             "Page %d"
00421 
00422 typedef struct {
00423   GKeyFile *key_file;
00424   const gchar *group_name;
00425   gint window_num;
00426   gint page_num;
00427   gint page_offset;
00428 } GncMainWindowSaveData;
00429 
00430 
00431 /*  Iterator function to walk all pages in all windows, calling the
00432  *  specified function for each page. */
00433 void
00434 gnc_main_window_foreach_page (GncMainWindowPageFunc fn, gpointer user_data)
00435 {
00436   GncMainWindowPrivate *priv;
00437   GncMainWindow *window;
00438   GncPluginPage *page;
00439   GList *w, *p;
00440 
00441   ENTER(" ");
00442   for (w = active_windows; w; w = g_list_next(w)) {
00443     window = w->data;
00444     priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
00445     for (p = priv->installed_pages; p; p = g_list_next(p)) {
00446       page = p->data;
00447       fn(page, user_data);
00448     }
00449   }
00450   LEAVE(" ");
00451 }
00452 
00453 
00465 static void
00466 gnc_main_window_restore_page (GncMainWindow *window, 
00467                               GncMainWindowSaveData *data)
00468 {
00469   GncMainWindowPrivate *priv;
00470   GncPluginPage *page;
00471   gchar *page_group, *page_type = NULL, *name = NULL;
00472   const gchar *class_type;
00473   GError *error = NULL;
00474 
00475   ENTER("window %p, data %p (key file %p, window %d, page start %d, page num %d)",
00476         window, data, data->key_file, data->window_num, data->page_offset, 
00477         data->page_num);
00478 
00479   priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
00480   page_group = g_strdup_printf(PAGE_STRING, 
00481                                data->page_offset + data->page_num);
00482   page_type = g_key_file_get_string(data->key_file, page_group,
00483                                     PAGE_TYPE, &error);
00484   if (error) {
00485     g_warning("error reading group %s key %s: %s",
00486               page_group, PAGE_TYPE, error->message);
00487     goto cleanup;
00488   }
00489 
00490   /* See if the page already exists. */
00491   page = g_list_nth_data(priv->installed_pages, data->page_num);
00492   if (page) {
00493     class_type = GNC_PLUGIN_PAGE_GET_CLASS(page)->plugin_name;
00494     if (strcmp(page_type, class_type) != 0) {
00495       g_warning("error: page types don't match: state %s, existing page %s",
00496                 page_type, class_type);
00497       goto cleanup;
00498     }
00499   } else {
00500     /* create and install the page */
00501     page = gnc_plugin_page_recreate_page(GTK_WIDGET(window), page_type,
00502                                          data->key_file, page_group);
00503     if (page) {
00504       /* Does the page still need to be installed into the window? */
00505       if (page->window == NULL) {
00506         gnc_plugin_page_set_use_new_window(page, FALSE);
00507         gnc_main_window_open_page(window, page);
00508       }
00509 
00510       /* Restore the page name */
00511       name = g_key_file_get_string(data->key_file, page_group,
00512                                        PAGE_NAME, &error);
00513       if (error) {
00514         g_warning("error reading group %s key %s: %s",
00515                   page_group, PAGE_NAME, error->message);
00516         /* Fall through and still show the page. */
00517       } else {
00518         DEBUG("updating page name for %p to %s.", page, name);
00519         main_window_update_page_name(page, name);
00520         g_free(name);
00521       }
00522     }
00523   }
00524 
00525   LEAVE("ok");
00526  cleanup:
00527   if (error)
00528     g_error_free(error);
00529   if (page_type)
00530     g_free(page_type);
00531   g_free(page_group);
00532 }
00533 
00534 
00543 static void
00544 gnc_main_window_restore_window (GncMainWindow *window, GncMainWindowSaveData *data)
00545 {
00546   GncMainWindowPrivate *priv;
00547   GtkAction *action;
00548   gint *pos, *geom, *order;
00549   gsize length;
00550   gboolean max, visible, desired_visibility;
00551   gchar *window_group;
00552   gint page_start, page_count, i;
00553   GError *error = NULL;
00554 
00555   /* Setup */
00556   ENTER("window %p, data %p (key file %p, window %d)",
00557         window, data, data->key_file, data->window_num);
00558   window_group = g_strdup_printf(WINDOW_STRING, data->window_num + 1);
00559 
00560   /* Get this window's notebook info */
00561   page_count = g_key_file_get_integer(data->key_file,
00562                                       window_group, WINDOW_PAGECOUNT, &error);
00563   if (error) {
00564     g_warning("error reading group %s key %s: %s",
00565               window_group, WINDOW_PAGECOUNT, error->message);
00566     goto cleanup;
00567   }
00568   if (page_count == 0) {
00569     /* Shound never happen, but has during alpha testing. Having this
00570      * check doesn't hurt anything. */
00571     goto cleanup;
00572   }
00573   page_start = g_key_file_get_integer(data->key_file,
00574                                       window_group, WINDOW_FIRSTPAGE, &error);
00575   if (error) {
00576     g_warning("error reading group %s key %s: %s",
00577               window_group, WINDOW_FIRSTPAGE, error->message);
00578     goto cleanup;
00579   }
00580 
00581   /* Build a window if we don't already have one */
00582   if (window == NULL) {
00583     DEBUG("Window %d doesn't exist. Creating new window.", data->window_num);
00584     DEBUG("active_windows %p.", active_windows);
00585     if (active_windows)
00586       DEBUG("first window %p.", active_windows->data);
00587     window = gnc_main_window_new();
00588     gtk_widget_show(GTK_WIDGET(window));
00589   }
00590 
00591   priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
00592 
00593   /* Get the window coordinates, etc. */
00594   geom = g_key_file_get_integer_list(data->key_file, window_group,
00595                                      WINDOW_GEOMETRY, &length, &error);
00596   if (error) {
00597     g_warning("error reading group %s key %s: %s",
00598               window_group, WINDOW_GEOMETRY, error->message);
00599     g_error_free(error);
00600     error = NULL;
00601   } else if (length != 2) {
00602     g_warning("invalid number of values for group %s key %s",
00603               window_group, WINDOW_GEOMETRY);
00604   } else {
00605     gtk_window_resize(GTK_WINDOW(window), geom[0], geom[1]);
00606     DEBUG("window (%p) size %dx%d", window, geom[0], geom[1]);
00607   }
00608   /* keep the geometry for a test whether the windows position
00609      is offscreen */
00610 
00611   pos = g_key_file_get_integer_list(data->key_file, window_group,
00612                                     WINDOW_POSITION, &length, &error);
00613   if (error) {
00614     g_warning("error reading group %s key %s: %s",
00615               window_group, WINDOW_POSITION, error->message);
00616     g_error_free(error);
00617     error = NULL;
00618   } else if (length != 2) {
00619     g_warning("invalid number of values for group %s key %s",
00620               window_group, WINDOW_POSITION);
00621   } else if ((pos[0] + (geom ? geom[0] : 0) < 0) ||
00622              (pos[0] > gdk_screen_width()) ||
00623              (pos[1] + (geom ? geom[1] : 0) < 0) ||
00624              (pos[1] > gdk_screen_height())) {
00625 //    g_debug("position %dx%d, size%dx%d is offscreen; will not move",
00626 //          pos[0], pos[1], geom[0], geom[1]);
00627   } else {
00628     gtk_window_move(GTK_WINDOW(window), pos[0], pos[1]);
00629     DEBUG("window (%p) position %dx%d", window, pos[0], pos[1]);
00630   }
00631   if (geom) {
00632     g_free(geom);
00633   }
00634   if (pos) {
00635     g_free(pos);
00636   }
00637 
00638   max = g_key_file_get_boolean(data->key_file, window_group,
00639                                WINDOW_MAXIMIZED, &error);
00640   if (error) {
00641     g_warning("error reading group %s key %s: %s",
00642               window_group, WINDOW_MAXIMIZED, error->message);
00643     g_error_free(error);
00644     error = NULL;
00645   } else if (max) {
00646     gtk_window_maximize(GTK_WINDOW(window));
00647   }
00648 
00649   /* Common view menu items */
00650   action = gnc_main_window_find_action(window, "ViewToolbarAction");
00651   visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
00652   desired_visibility = g_key_file_get_boolean(data->key_file, window_group,
00653                                               TOOLBAR_VISIBLE, &error);
00654   if (error) {
00655     g_warning("error reading group %s key %s: %s",
00656               window_group, TOOLBAR_VISIBLE, error->message);
00657     g_error_free(error);
00658     error = NULL;
00659   } else if (visible != desired_visibility) {
00660     gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action),desired_visibility);
00661   }
00662 
00663   action = gnc_main_window_find_action(window, "ViewSummaryAction");
00664   visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
00665   desired_visibility = g_key_file_get_boolean(data->key_file, window_group,
00666                                               SUMMARYBAR_VISIBLE, &error);
00667   if (error) {
00668     g_warning("error reading group %s key %s: %s",
00669               window_group, TOOLBAR_VISIBLE, error->message);
00670     g_error_free(error);
00671     error = NULL;
00672   } else if (visible != desired_visibility) {
00673     gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action),desired_visibility);
00674   }
00675 
00676   action = gnc_main_window_find_action(window, "ViewStatusbarAction");
00677   visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
00678   desired_visibility = g_key_file_get_boolean(data->key_file, window_group,
00679                                               STATUSBAR_VISIBLE, &error);
00680   if (error) {
00681     g_warning("error reading group %s key %s: %s",
00682               window_group, TOOLBAR_VISIBLE, error->message);
00683     g_error_free(error);
00684     error = NULL;
00685   } else if (visible != desired_visibility) {
00686     gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action),desired_visibility);
00687   }
00688 
00689   /* Now populate the window with pages. */
00690   for (i = 0; i < page_count; i++) {
00691     data->page_offset = page_start;
00692     data->page_num = i;
00693     gnc_main_window_restore_page(window, data);
00694 
00695     /* give the page a chance to display */
00696     while (gtk_events_pending ())
00697       gtk_main_iteration ();
00698   }
00699 
00700   /* Restore page ordering within the notebook. Use +1 notation so the
00701    * numbers in the page order match the page sections, at least for
00702    * the one window case. */
00703   order = g_key_file_get_integer_list(data->key_file, window_group,
00704                                       WINDOW_PAGEORDER, &length, &error);
00705   if (error) {
00706     g_warning("error reading group %s key %s: %s",
00707               window_group, WINDOW_PAGEORDER, error->message);
00708     g_error_free(error);
00709     error = NULL;
00710   } else if (length != page_count) {
00711     g_warning("%s key %s length %" G_GSIZE_FORMAT " differs from window page count %d",
00712               window_group, WINDOW_PAGEORDER, length, page_count);
00713   } else {
00714     /* Dump any list that might exist */
00715     g_list_free(priv->usage_order);
00716     priv->usage_order = NULL;
00717     /* Now rebuild the list from the key file. */
00718     for (i = 0; i < length; i++) {
00719       gpointer page = g_list_nth_data(priv->installed_pages, order[i] - 1);
00720       if (page) {
00721         priv->usage_order = g_list_append(priv->usage_order, page);
00722       }
00723     }
00724     gtk_notebook_set_current_page (GTK_NOTEBOOK(priv->notebook),
00725                                    order[0] - 1);
00726   }
00727   if (order) {
00728     g_free(order);
00729   }
00730 
00731   LEAVE("window %p", window);
00732  cleanup:
00733   if (error)
00734     g_error_free(error);
00735   g_free(window_group);
00736 }
00737 
00738 void
00739 gnc_main_window_restore_all_windows(const GKeyFile *keyfile)
00740 {
00741   gint i, window_count;
00742   GError *error = NULL;
00743   GncMainWindowSaveData data;
00744   GncMainWindow *window;
00745 
00746   /* We use the same struct for reading and for writing, so we cast
00747      away the const. */
00748   data.key_file = (GKeyFile *) keyfile;
00749   window_count = g_key_file_get_integer(data.key_file, STATE_FILE_TOP, 
00750                                         WINDOW_COUNT, &error);
00751   if (error) {
00752     g_warning("error reading group %s key %s: %s",
00753               STATE_FILE_TOP, WINDOW_COUNT, error->message);
00754     g_error_free(error);
00755     LEAVE("can't read count");
00756     return;
00757   }
00758 
00759   /* Restore all state information on the open windows.  Window
00760      numbers in state file are 1-based. GList indices are 0-based. */
00761   gnc_set_busy_cursor (NULL, TRUE);
00762   for (i = 0; i < window_count; i++) {
00763     data.window_num = i;
00764     window = g_list_nth_data(active_windows, i);
00765     gnc_main_window_restore_window(window, &data);
00766   }
00767   gnc_unset_busy_cursor (NULL);
00768 }
00769 
00770 void
00771 gnc_main_window_restore_default_state(void)
00772 {
00773     GtkAction *action;
00774     GncMainWindow *window;
00775     
00776     /* The default state should be to have an Account Tree page open
00777      * in the window. */
00778     DEBUG("no saved state file");
00779     window = g_list_nth_data(active_windows, 0);
00780     action = gnc_main_window_find_action(window, "FileNewAccountTreeAction");
00781     gtk_action_activate(action);
00782 }
00783 
00793 static void
00794 gnc_main_window_save_page (GncPluginPage *page, GncMainWindowSaveData *data)
00795 {
00796   gchar *page_group;
00797   const gchar *plugin_name, *page_name;
00798 
00799   ENTER("page %p, data %p (key file %p, window %d, page %d)",
00800         page, data, data->key_file, data->window_num, data->page_num);
00801   plugin_name = gnc_plugin_page_get_plugin_name(page);
00802   page_name = gnc_plugin_page_get_page_name(page);
00803   if (!plugin_name || !page_name) {
00804       LEAVE("not saving invalid page");
00805       return;
00806   }
00807   page_group = g_strdup_printf(PAGE_STRING, data->page_num++);
00808   g_key_file_set_string(data->key_file, page_group, PAGE_TYPE, plugin_name);
00809   g_key_file_set_string(data->key_file, page_group, PAGE_NAME, page_name);
00810 
00811   gnc_plugin_page_save_page(page, data->key_file, page_group);
00812   g_free(page_group);
00813   LEAVE(" ");
00814 }
00815 
00816 
00825 static void
00826 gnc_main_window_save_window (GncMainWindow *window, GncMainWindowSaveData *data)
00827 {
00828   GncMainWindowPrivate *priv;
00829   GtkAction *action;
00830   gint i, num_pages, coords[4], *order;
00831   gboolean maximized, visible;
00832   gchar *window_group;
00833 
00834   /* Setup */
00835   ENTER("window %p, data %p (key file %p, window %d)",
00836         window, data, data->key_file, data->window_num);
00837   priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
00838 
00839   /* Check for bogus window structures. */
00840   num_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook));
00841   if (0 == num_pages) {
00842     LEAVE("empty window %p", window);
00843     return;
00844   }
00845 
00846   /* Save this window's notebook info */
00847   window_group = g_strdup_printf(WINDOW_STRING, data->window_num++);
00848   g_key_file_set_integer(data->key_file, window_group,
00849                          WINDOW_PAGECOUNT, num_pages);
00850   g_key_file_set_integer(data->key_file, window_group,
00851                          WINDOW_FIRSTPAGE, data->page_num);
00852 
00853   /* Save page ordering within the notebook. Use +1 notation so the
00854    * numbers in the page order match the page sections, at least for
00855    * the one window case. */
00856   order = g_malloc(sizeof(gint) * num_pages);
00857   for (i = 0; i < num_pages; i++) {
00858     gpointer page = g_list_nth_data(priv->usage_order, i);
00859     order[i] = g_list_index(priv->installed_pages, page) + 1;
00860   }
00861   g_key_file_set_integer_list(data->key_file, window_group,
00862                               WINDOW_PAGEORDER, order, num_pages);
00863   g_free(order);
00864 
00865   /* Save the window coordinates, etc. */
00866   gtk_window_get_position(GTK_WINDOW(window), &coords[0], &coords[1]);
00867   gtk_window_get_size(GTK_WINDOW(window), &coords[2], &coords[3]);
00868   maximized = (gdk_window_get_state((GTK_WIDGET(window))->window)
00869                & GDK_WINDOW_STATE_MAXIMIZED) != 0;
00870   g_key_file_set_integer_list(data->key_file, window_group,
00871                               WINDOW_POSITION, &coords[0], 2);
00872   g_key_file_set_integer_list(data->key_file, window_group,
00873                               WINDOW_GEOMETRY, &coords[2], 2);
00874   g_key_file_set_boolean(data->key_file, window_group,
00875                          WINDOW_MAXIMIZED, maximized);
00876   DEBUG("window (%p) position %dx%d, size %dx%d, %s", window,  coords[0], coords[1],
00877         coords[2], coords[3],
00878         maximized ? "maximized" : "not maximized");
00879 
00880   /* Common view menu items */
00881   action = gnc_main_window_find_action(window, "ViewToolbarAction");
00882   visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
00883   g_key_file_set_boolean(data->key_file, window_group,
00884                          TOOLBAR_VISIBLE, visible);
00885   action = gnc_main_window_find_action(window, "ViewSummaryAction");
00886   visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
00887   g_key_file_set_boolean(data->key_file, window_group,
00888                          SUMMARYBAR_VISIBLE, visible);
00889   action = gnc_main_window_find_action(window, "ViewStatusbarAction");
00890   visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
00891   g_key_file_set_boolean(data->key_file, window_group,
00892                          STATUSBAR_VISIBLE, visible);
00893 
00894   /* Save individual pages in this window */
00895   g_list_foreach(priv->installed_pages, (GFunc)gnc_main_window_save_page, data);
00896 
00897   g_free(window_group);
00898   LEAVE("window %p", window);
00899 }
00900 
00901 void
00902 gnc_main_window_save_all_windows(GKeyFile *keyfile)
00903 {
00904     GncMainWindowSaveData data;
00905 
00906     /* Set up the iterator data structures */
00907     data.key_file = keyfile;
00908     data.window_num = 1;
00909     data.page_num = 1;
00910 
00911     g_key_file_set_integer(data.key_file,
00912                            STATE_FILE_TOP, WINDOW_COUNT,
00913                            g_list_length(active_windows));
00914     /* Dump all state information on the open windows */
00915     g_list_foreach(active_windows, (GFunc)gnc_main_window_save_window, &data);
00916 }
00917 
00918 
00919 gboolean
00920 gnc_main_window_finish_pending (GncMainWindow *window)
00921 {
00922         GncMainWindowPrivate *priv;
00923         GList *item;
00924 
00925         g_return_val_if_fail(GNC_IS_MAIN_WINDOW(window), TRUE);
00926 
00927         priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
00928         for (item = priv->installed_pages; item; item = g_list_next(item)) {
00929           if (!gnc_plugin_page_finish_pending(item->data)) {
00930             return FALSE;
00931           }
00932         }
00933         return TRUE;
00934 }
00935 
00936 
00937 gboolean
00938 gnc_main_window_all_finish_pending (void)
00939 {
00940         const GList *windows, *item;
00941 
00942         windows = gnc_gobject_tracking_get_list(GNC_MAIN_WINDOW_NAME);
00943         for (item = windows; item; item = g_list_next(item)) {
00944           if (!gnc_main_window_finish_pending(item->data)) {
00945             return FALSE;
00946           }
00947         }
00948         return TRUE;
00949 }
00950 
00951 
00962 static gboolean
00963 gnc_main_window_page_exists (GncPluginPage *page)
00964 {
00965         GncMainWindow *window;
00966         GncMainWindowPrivate *priv;
00967         GList *walker;
00968 
00969         for (walker = active_windows; walker; walker = g_list_next(walker)) {
00970           window = walker->data;
00971           priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
00972           if (g_list_find(priv->installed_pages, page)) {
00973             return TRUE;
00974           }
00975         }
00976         return FALSE;
00977 }
00978 
00979 
00989 static gboolean
00990 gnc_main_window_prompt_for_save (GtkWidget *window)
00991 {
00992   QofSession *session;
00993   QofBook *book;
00994   GtkWidget *dialog;
00995   gint response;
00996   const gchar *filename, *tmp;
00997   const gchar *title = _("Save changes to file %s before closing?");
00998   /* This should be the same message as in gnc-file.c */
00999   const gchar *message_mins =
01000     _("If you don't save, changes from the past %d minutes will be discarded.");
01001   const gchar *message_hours =
01002     _("If you don't save, changes from the past %d hours and %d minutes will be discarded.");
01003   const gchar *message_days =
01004     _("If you don't save, changes from the past %d days and %d hours will be discarded.");
01005   time_t oldest_change;
01006   gint minutes, hours, days;
01007 
01008   session = gnc_get_current_session();
01009   book = qof_session_get_book(session);
01010   filename = qof_session_get_url(session);
01011   if (filename == NULL)
01012     filename = _("<unknown>");
01013   if ((tmp = strrchr(filename, '/')) != NULL)
01014     filename = tmp + 1;
01015 
01016   /* Remove any pending auto-save timeouts */
01017   gnc_autosave_remove_timer(book);
01018 
01019   dialog = gtk_message_dialog_new(GTK_WINDOW(window),
01020                                   GTK_DIALOG_MODAL,
01021                                   GTK_MESSAGE_WARNING,
01022                                   GTK_BUTTONS_NONE,
01023                                   title,
01024                                   filename);
01025   oldest_change = qof_book_get_dirty_time(book);
01026   minutes = (time(NULL) - oldest_change) / 60 + 1;
01027   hours = minutes / 60;
01028   minutes = minutes % 60;
01029   days = hours / 24;
01030   hours = hours % 24;
01031   if (days > 0) {
01032       gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01033                                                message_days, days, hours);
01034   } else if (hours > 0) {
01035       gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01036                                                message_hours, hours, minutes);
01037   } else {
01038       gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01039                                                message_mins, minutes);
01040   }
01041   gtk_dialog_add_buttons(GTK_DIALOG(dialog),
01042                          _("Close _Without Saving"), GTK_RESPONSE_CLOSE,
01043                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
01044                          GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
01045                          NULL);
01046   gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_APPLY);
01047   response = gtk_dialog_run (GTK_DIALOG (dialog));
01048   gtk_widget_destroy(dialog);
01049 
01050   switch (response) {
01051     case GTK_RESPONSE_APPLY:
01052       gnc_file_save();
01053       return FALSE;
01054 
01055     case GTK_RESPONSE_CLOSE:
01056       qof_book_mark_saved(book);
01057       return FALSE;
01058 
01059     default:
01060       return TRUE;
01061   }
01062 }
01063 
01064 
01065 static void
01066 gnc_main_window_add_plugin (gpointer plugin,
01067                             gpointer window)
01068 {
01069         g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
01070         g_return_if_fail (GNC_IS_PLUGIN (plugin));
01071 
01072         ENTER(" ");
01073         gnc_plugin_add_to_window (GNC_PLUGIN (plugin),
01074                                   GNC_MAIN_WINDOW (window),
01075                                   window_type);
01076         LEAVE(" ");
01077 }
01078 
01079 static void
01080 gnc_main_window_remove_plugin (gpointer plugin,
01081                                gpointer window)
01082 {
01083         g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
01084         g_return_if_fail (GNC_IS_PLUGIN (plugin));
01085 
01086         ENTER(" ");
01087         gnc_plugin_remove_from_window (GNC_PLUGIN (plugin),
01088                                        GNC_MAIN_WINDOW (window),
01089                                        window_type);
01090         LEAVE(" ");
01091 }
01092 
01093 
01094 static gboolean
01095 gnc_main_window_timed_quit (gpointer dummy)
01096 {
01097   if (gnc_file_save_in_progress())
01098     return TRUE;
01099 
01100   gnc_shutdown (0);
01101   return FALSE;
01102 }
01103 
01104 static gboolean
01105 gnc_main_window_quit(GncMainWindow *window)
01106 {
01107     QofSession *session;
01108     gboolean needs_save, do_shutdown;
01109 
01110     session = gnc_get_current_session();
01111     needs_save = qof_book_not_saved(qof_session_get_book(session)) && 
01112         !gnc_file_save_in_progress();
01113     do_shutdown = !needs_save || 
01114         (needs_save && !gnc_main_window_prompt_for_save(GTK_WIDGET(window)));
01115 
01116     if (do_shutdown) {
01117         g_timeout_add(250, gnc_main_window_timed_quit, NULL);
01118         return TRUE;
01119     }
01120     return FALSE;
01121 }
01122 
01123 static gboolean
01124 gnc_main_window_delete_event (GtkWidget *window,
01125                               GdkEvent *event,
01126                               gpointer user_data)
01127 {
01128   static gboolean already_dead = FALSE;
01129 
01130   if (already_dead)
01131     return TRUE;
01132 
01133   if (!gnc_main_window_finish_pending(GNC_MAIN_WINDOW(window))) {
01134     /* Don't close the window. */
01135     return TRUE;
01136   }
01137 
01138   if (g_list_length(active_windows) > 1)
01139     return FALSE;
01140 
01141   already_dead = gnc_main_window_quit(GNC_MAIN_WINDOW(window));
01142   return TRUE;
01143 }
01144 
01145 
01165 static void
01166 gnc_main_window_event_handler (QofInstance *entity,  QofEventId event_type,
01167                                gpointer user_data, gpointer event_data)
01168 {
01169         GncMainWindow *window;
01170         GncMainWindowPrivate *priv;
01171         GncPluginPage *page;
01172         GList *item, *next;
01173 
01174         /* hard failures */
01175         g_return_if_fail(GNC_IS_MAIN_WINDOW(user_data));
01176 
01177         /* soft failures */
01178         if (!QOF_CHECK_TYPE(entity, QOF_ID_BOOK))
01179           return;
01180         if (event_type !=  QOF_EVENT_DESTROY)
01181           return;
01182 
01183         ENTER("entity %p, event %d, window %p, event data %p",
01184               entity, event_type, user_data, event_data);
01185         window = GNC_MAIN_WINDOW(user_data);
01186         priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
01187 
01188         /* This is not a typical list iteration.  We're removing while
01189          * we iterate, so we have to cache the 'next' pointer before
01190          * executing any code in the loop. */
01191         for (item = priv->installed_pages; item; item = next) {
01192           next = g_list_next(item);
01193           page = GNC_PLUGIN_PAGE(item->data);
01194           if (gnc_plugin_page_has_book (page, (QofBook *)entity))
01195               gnc_main_window_close_page (page);
01196         }
01197         LEAVE(" ");
01198 }
01199 
01200 
01216 static gchar *
01217 gnc_main_window_generate_title (GncMainWindow *window)
01218 {
01219   GncMainWindowPrivate *priv;
01220   GncPluginPage *page;
01221   QofBook *book;
01222   const gchar *filename = NULL, *dirty = "";
01223   gchar *title, *ptr;
01224   GtkAction* action;
01225 
01226   /* The save action is sensitive iff the book is dirty */
01227   action = gnc_main_window_find_action (window, "FileSaveAction");
01228   if (action != NULL) {
01229         gtk_action_set_sensitive(action, FALSE);
01230   }
01231   if (gnc_current_session_exist()) {
01232       filename = gnc_session_get_url (gnc_get_current_session ());
01233       book = gnc_get_current_book();
01234       if (qof_instance_is_dirty(QOF_INSTANCE(book))) {
01235                 dirty = "*";
01236                 if (action != NULL) {
01237                   gtk_action_set_sensitive(action, TRUE);
01238                 }
01239           }
01240   }
01241 
01242   if (!filename)
01243     filename = _("<no file>");
01244   else {
01245     /* The Gnome HIG 2.0 recommends only the file name (no path) be used. (p15) */
01246     ptr = g_utf8_strrchr(filename, -1, G_DIR_SEPARATOR);
01247     if (ptr != NULL)
01248       filename = g_utf8_next_char(ptr);
01249   }
01250 
01251   priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
01252   page = priv->current_page;
01253   if (page) {
01254     /* The Gnome HIG 2.0 recommends the application name not be used. (p16) */
01255     title = g_strdup_printf("%s%s - %s", dirty, filename,
01256                             gnc_plugin_page_get_page_name(page));
01257   } else {
01258     title = g_strdup_printf("%s%s", dirty, filename);
01259   }
01260   
01261   return title;
01262 }
01263 
01264 
01274 static void
01275 gnc_main_window_update_title (GncMainWindow *window)
01276 {
01277   gchar *title;
01278 
01279   title = gnc_main_window_generate_title(window);
01280   gtk_window_set_title(GTK_WINDOW(window), title);
01281   g_free(title);
01282 }
01283 
01284 static void
01285 gnc_main_window_update_all_titles (void)
01286 {
01287   g_list_foreach(active_windows,
01288                  (GFunc)gnc_main_window_update_title,
01289                  NULL);
01290 }
01291 
01292 static void
01293 gnc_main_window_book_dirty_cb (QofBook *book,
01294                                gboolean dirty,
01295                                gpointer user_data)
01296 {
01297   gnc_main_window_update_all_titles();
01298 
01299   /* Auto-save feature */
01300   gnc_autosave_dirty_handler(book, dirty);
01301 }
01302 
01303 static void
01304 gnc_main_window_attach_to_book (QofSession *session)
01305 {
01306   QofBook *book;
01307 
01308   g_return_if_fail(session);
01309 
01310   book = qof_session_get_book(session);
01311   qof_book_set_dirty_cb(book, gnc_main_window_book_dirty_cb, NULL);
01312   gnc_main_window_update_all_titles();
01313   gnc_main_window_update_all_menu_items();
01314 }
01315 
01316 
01320 struct menu_update {
01322   gchar    *action_name;
01323 
01325   gchar    *label;
01326 
01328   gboolean  visible;
01329 };
01330 
01331 
01345 static void
01346 gnc_main_window_update_one_menu_action (GncMainWindow *window,
01347                                         struct menu_update *data)
01348 {
01349   GncMainWindowPrivate *priv;
01350   GtkAction* action;
01351 
01352   ENTER("window %p, action %s, label %s, visible %d", window,
01353         data->action_name, data->label, data->visible);
01354   priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
01355   action = gtk_action_group_get_action(priv->action_group, data->action_name);
01356   if (action)
01357     g_object_set(G_OBJECT(action),
01358                  "label", data->label,
01359                  "visible", data->visible,
01360                  (char *)NULL);
01361   LEAVE(" ");
01362 }
01363 
01364 
01377 static void
01378 gnc_main_window_update_radio_button (GncMainWindow *window)
01379 {
01380   GncMainWindowPrivate *priv;
01381   GtkAction *action, *first_action;
01382   GSList *action_list;
01383   gchar *action_name;
01384   gint index;
01385 
01386   ENTER("window %p", window);
01387 
01388   /* Show the new entry in all windows. */
01389   index = g_list_index(active_windows, window);
01390   if (index >= n_radio_entries) {
01391     LEAVE("window %d, only %d actions", index, n_radio_entries);
01392     return;
01393   }
01394 
01395   priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
01396   action_name = g_strdup_printf("Window%dAction", index);
01397   action = gtk_action_group_get_action(priv->action_group, action_name);
01398 
01399   /* Block the signal so as not to affect window ordering (top to
01400    * bottom) on the screen */
01401   action_list = gtk_radio_action_get_group(GTK_RADIO_ACTION(action));
01402   first_action = g_slist_last(action_list)->data;
01403   g_signal_handlers_block_by_func(G_OBJECT(first_action),
01404                                   G_CALLBACK(gnc_main_window_cmd_window_raise), window);
01405   DEBUG("blocked signal on %p, set %p active, window %p", first_action, action, window);
01406   gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
01407   g_signal_handlers_unblock_by_func(G_OBJECT(first_action),
01408                                     G_CALLBACK(gnc_main_window_cmd_window_raise), window);
01409   g_free(action_name);
01410   LEAVE(" ");
01411 }
01412 
01413 
01427 static void
01428 gnc_main_window_update_menu_item (GncMainWindow *window)
01429 {
01430   struct menu_update data;
01431   gchar **strings, *title, *expanded;
01432   gint index;
01433 
01434