|
GnuCash 2.4.99
|
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 00035 #include "config.h" 00036 00037 #include <gnome.h> 00038 #include <glib/gi18n.h> 00039 #include <libguile.h> 00040 #include "guile-mappings.h" 00041 00042 #include "gnc-plugin.h" 00043 #include "gnc-plugin-manager.h" 00044 #include "gnc-main-window.h" 00045 00046 #include "dialog-preferences.h" 00047 #include "dialog-reset-warnings.h" 00048 #include "dialog-transfer.h" 00049 #include "dialog-utils.h" 00050 #include "file-utils.h" 00051 #include "gnc-component-manager.h" 00052 #include "gnc-engine.h" 00053 #include "gnc-file.h" 00054 #include "gnc-gkeyfile-utils.h" 00055 #include "gnc-gnome-utils.h" 00056 #include "gnc-gobject-utils.h" 00057 #include "gnc-gui-query.h" 00058 #include "gnc-hooks.h" 00059 #include "gnc-session.h" 00060 #include "gnc-ui.h" 00061 #include "gnc-ui-util.h" 00062 #include "gnc-uri-utils.h" 00063 #include "core-utils/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 #include "print-session.h" 00071 #ifdef MAC_INTEGRATION 00072 #include <gtkmacintegration/gtkosxapplication.h> 00073 #endif 00074 00076 enum 00077 { 00078 PAGE_ADDED, 00079 PAGE_CHANGED, 00080 LAST_SIGNAL 00081 }; 00082 00085 #define PLUGIN_PAGE_LABEL "plugin-page" 00086 00087 #define PLUGIN_PAGE_CLOSE_BUTTON "close-button" 00088 #define PLUGIN_PAGE_TAB_LABEL "label" 00089 00090 #define KEY_SHOW_CLOSE_BUTTON "tab_close_buttons" 00091 #define KEY_TAB_NEXT_RECENT "tab_next_recent" 00092 #define KEY_TAB_POSITION "tab_position" 00093 #define KEY_TAB_WIDTH "tab_width" 00094 00095 #define GNC_MAIN_WINDOW_NAME "GncMainWindow" 00096 00097 00098 /* Static Globals *******************************************************/ 00099 00101 static QofLogModule log_module = GNC_MOD_GUI; 00103 static GObjectClass *parent_class = NULL; 00105 static GQuark window_type = 0; 00108 static GList *active_windows = NULL; 00109 00110 /* Declarations *********************************************************/ 00111 static void gnc_main_window_class_init (GncMainWindowClass *klass); 00112 static void gnc_main_window_init (GncMainWindow *window, GncMainWindowClass *klass); 00113 static void gnc_main_window_finalize (GObject *object); 00114 static void gnc_main_window_destroy (GtkObject *object); 00115 00116 static void gnc_main_window_setup_window (GncMainWindow *window); 00117 static void gnc_window_main_window_init (GncWindowIface *iface); 00118 static void gnc_main_window_update_all_menu_items (void); 00119 00120 /* Callbacks */ 00121 static void gnc_main_window_add_widget (GtkUIManager *merge, GtkWidget *widget, GncMainWindow *window); 00122 static void gnc_main_window_switch_page (GtkNotebook *notebook, GtkNotebookPage *notebook_page, gint pos, GncMainWindow *window); 00123 static void gnc_main_window_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint pos, GncMainWindow *window); 00124 static void gnc_main_window_plugin_added (GncPlugin *manager, GncPlugin *plugin, GncMainWindow *window); 00125 static void gnc_main_window_plugin_removed (GncPlugin *manager, GncPlugin *plugin, GncMainWindow *window); 00126 static void gnc_main_window_engine_commit_error_callback( gpointer data, QofBackendError errcode ); 00127 00128 /* Command callbacks */ 00129 static void gnc_main_window_cmd_page_setup (GtkAction *action, GncMainWindow *window); 00130 static void gnc_main_window_cmd_file_properties (GtkAction *action, GncMainWindow *window); 00131 static void gnc_main_window_cmd_file_close (GtkAction *action, GncMainWindow *window); 00132 static void gnc_main_window_cmd_file_quit (GtkAction *action, GncMainWindow *window); 00133 static void gnc_main_window_cmd_edit_cut (GtkAction *action, GncMainWindow *window); 00134 static void gnc_main_window_cmd_edit_copy (GtkAction *action, GncMainWindow *window); 00135 static void gnc_main_window_cmd_edit_paste (GtkAction *action, GncMainWindow *window); 00136 static void gnc_main_window_cmd_edit_preferences (GtkAction *action, GncMainWindow *window); 00137 static void gnc_main_window_cmd_view_refresh (GtkAction *action, GncMainWindow *window); 00138 static void gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window); 00139 static void gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window); 00140 static void gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window); 00141 static void gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window); 00142 static void gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window); 00143 static void gnc_main_window_cmd_window_new (GtkAction *action, GncMainWindow *window); 00144 static void gnc_main_window_cmd_window_move_page (GtkAction *action, GncMainWindow *window); 00145 static void gnc_main_window_cmd_window_raise (GtkAction *action, GtkRadioAction *current, GncMainWindow *window); 00146 static void gnc_main_window_cmd_help_tutorial (GtkAction *action, GncMainWindow *window); 00147 static void gnc_main_window_cmd_help_contents (GtkAction *action, GncMainWindow *window); 00148 static void gnc_main_window_cmd_help_about (GtkAction *action, GncMainWindow *window); 00149 00150 static void do_popup_menu(GncPluginPage *page, GdkEventButton *event); 00151 static gboolean gnc_main_window_popup_menu_cb (GtkWidget *widget, GncPluginPage *page); 00152 00153 #ifdef MAC_INTEGRATION 00154 static void gnc_quartz_shutdown(GtkOSXApplication *theApp, gpointer data); 00155 static gboolean gnc_quartz_should_quit(GtkOSXApplication *theApp, GncMainWindow *window); 00156 static void gnc_quartz_set_menu(GncMainWindow* window); 00157 #endif 00158 00161 typedef struct GncMainWindowPrivate 00162 { 00167 GtkWidget *menu_dock; 00170 GtkWidget *toolbar; 00172 GtkWidget *notebook; 00176 GtkWidget *statusbar; 00180 GtkWidget *progressbar; 00181 00185 GtkActionGroup *action_group; 00186 00188 GList *installed_pages; 00190 GList *usage_order; 00192 GncPluginPage *current_page; 00194 gint event_handler_id; 00195 00200 GHashTable *merged_actions_table; 00201 } GncMainWindowPrivate; 00202 00203 #define GNC_MAIN_WINDOW_GET_PRIVATE(o) \ 00204 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_MAIN_WINDOW, GncMainWindowPrivate)) 00205 00208 typedef struct 00209 { 00212 guint merge_id; 00215 GtkActionGroup *action_group; 00216 } MergedActionEntry; 00217 00220 static guint main_window_signals[LAST_SIGNAL] = { 0 }; 00221 00222 00227 static GtkActionEntry gnc_menu_actions [] = 00228 { 00229 /* Toplevel */ 00230 00231 { "FileAction", NULL, N_("_File"), NULL, NULL, NULL, }, 00232 { "EditAction", NULL, N_("_Edit"), NULL, NULL, NULL }, 00233 { "ViewAction", NULL, N_("_View"), NULL, NULL, NULL }, 00234 { "ActionsAction", NULL, N_("_Actions"), NULL, NULL, NULL }, 00235 { "TransactionAction", NULL, N_("Tra_nsaction"), NULL, NULL, NULL }, 00236 { "ReportsAction", NULL, N_("_Reports"), NULL, NULL, NULL }, 00237 { "ToolsAction", NULL, N_("_Tools"), NULL, NULL, NULL }, 00238 { "ExtensionsAction", NULL, N_("E_xtensions"), NULL, NULL, NULL }, 00239 { "WindowsAction", NULL, N_("_Windows"), NULL, NULL, NULL }, 00240 { "HelpAction", NULL, N_("_Help"), NULL, NULL, NULL }, 00241 00242 /* File menu */ 00243 00244 { "FileImportAction", NULL, N_("_Import"), NULL, NULL, NULL }, 00245 { "FileExportAction", NULL, N_("_Export"), NULL, NULL, NULL }, 00246 { 00247 "FilePrintAction", GTK_STOCK_PRINT, N_("_Print..."), "<control>p", 00248 N_("Print the currently active page"), NULL 00249 }, 00250 #ifndef GTK_STOCK_PAGE_SETUP 00251 # define GTK_STOCK_PAGE_SETUP NULL 00252 #endif 00253 { 00254 "FilePageSetupAction", GTK_STOCK_PAGE_SETUP, N_("Pa_ge Setup..."), "<control><shift>p", 00255 N_("Specify the page size and orientation for printing"), 00256 G_CALLBACK (gnc_main_window_cmd_page_setup) 00257 }, 00258 { 00259 "FilePropertiesAction", GTK_STOCK_PROPERTIES, N_("Proper_ties"), "<Alt>Return", 00260 N_("Edit the properties of the current file"), 00261 G_CALLBACK (gnc_main_window_cmd_file_properties) 00262 }, 00263 { 00264 "FileCloseAction", GTK_STOCK_CLOSE, N_("_Close"), NULL, 00265 N_("Close the currently active page"), 00266 G_CALLBACK (gnc_main_window_cmd_file_close) 00267 }, 00268 { 00269 "FileQuitAction", GTK_STOCK_QUIT, N_("_Quit"), NULL, 00270 N_("Quit this application"), 00271 G_CALLBACK (gnc_main_window_cmd_file_quit) 00272 }, 00273 00274 /* Edit menu */ 00275 00276 { 00277 "EditCutAction", GTK_STOCK_CUT, N_("Cu_t"), NULL, 00278 N_("Cut the current selection and copy it to clipboard"), 00279 G_CALLBACK (gnc_main_window_cmd_edit_cut) 00280 }, 00281 { 00282 "EditCopyAction", GTK_STOCK_COPY, N_("_Copy"), NULL, 00283 N_("Copy the current selection to clipboard"), 00284 G_CALLBACK (gnc_main_window_cmd_edit_copy) 00285 }, 00286 { 00287 "EditPasteAction", GTK_STOCK_PASTE, N_("_Paste"), NULL, 00288 N_("Paste the clipboard content at the cursor position"), 00289 G_CALLBACK (gnc_main_window_cmd_edit_paste) 00290 }, 00291 { 00292 "EditPreferencesAction", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), NULL, 00293 N_("Edit the global preferences of GnuCash"), 00294 G_CALLBACK (gnc_main_window_cmd_edit_preferences) 00295 }, 00296 00297 /* View menu */ 00298 00299 { 00300 "ViewSortByAction", NULL, N_("_Sort By..."), NULL, 00301 N_("Select sorting criteria for this page view"), NULL 00302 }, 00303 { 00304 "ViewFilterByAction", NULL, N_("_Filter By..."), NULL, 00305 N_("Select the account types that should be displayed."), NULL 00306 }, 00307 { 00308 "ViewRefreshAction", GTK_STOCK_REFRESH, N_("_Refresh"), "<control>r", 00309 N_("Refresh this window"), 00310 G_CALLBACK (gnc_main_window_cmd_view_refresh) 00311 }, 00312 00313 /* Actions menu */ 00314 00315 { "ScrubMenuAction", NULL, N_("_Check & Repair"), NULL, NULL, NULL }, 00316 { 00317 "ActionsForgetWarningsAction", NULL, N_("Reset _Warnings..."), NULL, 00318 N_("Reset the state of all warning messages so they will be shown again."), 00319 G_CALLBACK (gnc_main_window_cmd_actions_reset_warnings) 00320 }, 00321 { 00322 "ActionsRenamePageAction", NULL, N_("Re_name Page"), NULL, 00323 N_("Rename this page."), 00324 G_CALLBACK (gnc_main_window_cmd_actions_rename_page) 00325 }, 00326 00327 /* Windows menu */ 00328 00329 { 00330 "WindowNewAction", NULL, N_("_New Window"), NULL, 00331 N_("Open a new top-level GnuCash window."), 00332 G_CALLBACK (gnc_main_window_cmd_window_new) 00333 }, 00334 { 00335 "WindowMovePageAction", NULL, N_("New Window with _Page"), NULL, 00336 N_("Move the current page to a new top-level GnuCash window."), 00337 G_CALLBACK (gnc_main_window_cmd_window_move_page) 00338 }, 00339 00340 /* Help menu */ 00341 00342 { 00343 "HelpTutorialAction", GNOME_STOCK_BOOK_BLUE, N_("Tutorial and Concepts _Guide"), NULL, 00344 N_("Open the GnuCash Tutorial"), 00345 G_CALLBACK (gnc_main_window_cmd_help_tutorial) 00346 }, 00347 { 00348 "HelpContentsAction", GTK_STOCK_HELP, N_("_Contents"), "F1", 00349 N_("Open the GnuCash Help"), 00350 G_CALLBACK (gnc_main_window_cmd_help_contents) 00351 }, 00352 { 00353 "HelpAboutAction", GNOME_STOCK_ABOUT, N_("_About"), NULL, 00354 N_("About GnuCash"), 00355 G_CALLBACK (gnc_main_window_cmd_help_about) 00356 }, 00357 }; 00359 static guint gnc_menu_n_actions = G_N_ELEMENTS (gnc_menu_actions); 00360 00363 static GtkToggleActionEntry toggle_actions [] = 00364 { 00365 { 00366 "ViewToolbarAction", NULL, N_("_Toolbar"), NULL, 00367 N_("Show/hide the toolbar on this window"), 00368 G_CALLBACK (gnc_main_window_cmd_view_toolbar), TRUE 00369 }, 00370 { 00371 "ViewSummaryAction", NULL, N_("Su_mmary Bar"), NULL, 00372 N_("Show/hide the summary bar on this window"), 00373 G_CALLBACK (gnc_main_window_cmd_view_summary), TRUE 00374 }, 00375 { 00376 "ViewStatusbarAction", NULL, N_("Stat_us Bar"), NULL, 00377 N_("Show/hide the status bar on this window"), 00378 G_CALLBACK (gnc_main_window_cmd_view_statusbar), TRUE 00379 }, 00380 }; 00382 static guint n_toggle_actions = G_N_ELEMENTS (toggle_actions); 00383 00386 static GtkRadioActionEntry radio_entries [] = 00387 { 00388 { "Window0Action", NULL, N_("Window _1"), NULL, NULL, 0 }, 00389 { "Window1Action", NULL, N_("Window _2"), NULL, NULL, 1 }, 00390 { "Window2Action", NULL, N_("Window _3"), NULL, NULL, 2 }, 00391 { "Window3Action", NULL, N_("Window _4"), NULL, NULL, 3 }, 00392 { "Window4Action", NULL, N_("Window _5"), NULL, NULL, 4 }, 00393 { "Window5Action", NULL, N_("Window _6"), NULL, NULL, 5 }, 00394 { "Window6Action", NULL, N_("Window _7"), NULL, NULL, 6 }, 00395 { "Window7Action", NULL, N_("Window _8"), NULL, NULL, 7 }, 00396 { "Window8Action", NULL, N_("Window _9"), NULL, NULL, 8 }, 00397 { "Window9Action", NULL, N_("Window _0"), NULL, NULL, 9 }, 00398 }; 00400 static guint n_radio_entries = G_N_ELEMENTS (radio_entries); 00401 00402 00406 static const gchar *gnc_menu_important_actions[] = 00407 { 00408 "FileCloseAction", 00409 NULL, 00410 }; 00411 00412 00417 static const gchar *always_insensitive_actions[] = 00418 { 00419 "FilePrintAction", 00420 NULL 00421 }; 00422 00423 00427 static const gchar *initially_insensitive_actions[] = 00428 { 00429 "FileCloseAction", 00430 NULL 00431 }; 00432 00433 00438 static const gchar *always_hidden_actions[] = 00439 { 00440 "ViewSortByAction", 00441 "ViewFilterByAction", 00442 NULL 00443 }; 00444 00445 00448 static const gchar *immutable_page_actions[] = 00449 { 00450 "FileCloseAction", 00451 NULL 00452 }; 00453 00454 00457 static const gchar *multiple_page_actions[] = 00458 { 00459 "WindowMovePageAction", 00460 NULL 00461 }; 00462 00463 00464 /************************************************************ 00465 * * 00466 ************************************************************/ 00467 #define WINDOW_COUNT "WindowCount" 00468 #define WINDOW_STRING "Window %d" 00469 #define WINDOW_GEOMETRY "WindowGeometry" 00470 #define WINDOW_POSITION "WindowPosition" 00471 #define WINDOW_MAXIMIZED "WindowMaximized" 00472 #define TOOLBAR_VISIBLE "ToolbarVisible" 00473 #define STATUSBAR_VISIBLE "StatusbarVisible" 00474 #define SUMMARYBAR_VISIBLE "SummarybarVisible" 00475 #define WINDOW_FIRSTPAGE "FirstPage" 00476 #define WINDOW_PAGECOUNT "PageCount" 00477 #define WINDOW_PAGEORDER "PageOrder" 00478 #define PAGE_TYPE "PageType" 00479 #define PAGE_NAME "PageName" 00480 #define PAGE_STRING "Page %d" 00481 00482 typedef struct 00483 { 00484 GKeyFile *key_file; 00485 const gchar *group_name; 00486 gint window_num; 00487 gint page_num; 00488 gint page_offset; 00489 } GncMainWindowSaveData; 00490 00491 00492 /* Iterator function to walk all pages in all windows, calling the 00493 * specified function for each page. */ 00494 void 00495 gnc_main_window_foreach_page (GncMainWindowPageFunc fn, gpointer user_data) 00496 { 00497 GncMainWindowPrivate *priv; 00498 GncMainWindow *window; 00499 GncPluginPage *page; 00500 GList *w, *p; 00501 00502 ENTER(" "); 00503 for (w = active_windows; w; w = g_list_next(w)) 00504 { 00505 window = w->data; 00506 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 00507 for (p = priv->installed_pages; p; p = g_list_next(p)) 00508 { 00509 page = p->data; 00510 fn(page, user_data); 00511 } 00512 } 00513 LEAVE(" "); 00514 } 00515 00516 00528 static void 00529 gnc_main_window_restore_page (GncMainWindow *window, 00530 GncMainWindowSaveData *data) 00531 { 00532 GncMainWindowPrivate *priv; 00533 GncPluginPage *page; 00534 gchar *page_group, *page_type = NULL, *name = NULL; 00535 const gchar *class_type; 00536 GError *error = NULL; 00537 00538 ENTER("window %p, data %p (key file %p, window %d, page start %d, page num %d)", 00539 window, data, data->key_file, data->window_num, data->page_offset, 00540 data->page_num); 00541 00542 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 00543 page_group = g_strdup_printf(PAGE_STRING, 00544 data->page_offset + data->page_num); 00545 page_type = g_key_file_get_string(data->key_file, page_group, 00546 PAGE_TYPE, &error); 00547 if (error) 00548 { 00549 g_warning("error reading group %s key %s: %s", 00550 page_group, PAGE_TYPE, error->message); 00551 goto cleanup; 00552 } 00553 00554 /* See if the page already exists. */ 00555 page = g_list_nth_data(priv->installed_pages, data->page_num); 00556 if (page) 00557 { 00558 class_type = GNC_PLUGIN_PAGE_GET_CLASS(page)->plugin_name; 00559 if (strcmp(page_type, class_type) != 0) 00560 { 00561 g_warning("error: page types don't match: state %s, existing page %s", 00562 page_type, class_type); 00563 goto cleanup; 00564 } 00565 } 00566 else 00567 { 00568 /* create and install the page */ 00569 page = gnc_plugin_page_recreate_page(GTK_WIDGET(window), page_type, 00570 data->key_file, page_group); 00571 if (page) 00572 { 00573 /* Does the page still need to be installed into the window? */ 00574 if (page->window == NULL) 00575 { 00576 gnc_plugin_page_set_use_new_window(page, FALSE); 00577 gnc_main_window_open_page(window, page); 00578 } 00579 00580 /* Restore the page name */ 00581 name = g_key_file_get_string(data->key_file, page_group, 00582 PAGE_NAME, &error); 00583 if (error) 00584 { 00585 g_warning("error reading group %s key %s: %s", 00586 page_group, PAGE_NAME, error->message); 00587 /* Fall through and still show the page. */ 00588 } 00589 else 00590 { 00591 DEBUG("updating page name for %p to %s.", page, name); 00592 main_window_update_page_name(page, name); 00593 g_free(name); 00594 } 00595 } 00596 } 00597 00598 LEAVE("ok"); 00599 cleanup: 00600 if (error) 00601 g_error_free(error); 00602 if (page_type) 00603 g_free(page_type); 00604 g_free(page_group); 00605 } 00606 00607 00616 static void 00617 gnc_main_window_restore_window (GncMainWindow *window, GncMainWindowSaveData *data) 00618 { 00619 GncMainWindowPrivate *priv; 00620 GtkAction *action; 00621 gint *pos, *geom, *order; 00622 gsize length; 00623 gboolean max, visible, desired_visibility; 00624 gchar *window_group; 00625 gint page_start, page_count, i; 00626 GError *error = NULL; 00627 00628 /* Setup */ 00629 ENTER("window %p, data %p (key file %p, window %d)", 00630 window, data, data->key_file, data->window_num); 00631 window_group = g_strdup_printf(WINDOW_STRING, data->window_num + 1); 00632 00633 /* Get this window's notebook info */ 00634 page_count = g_key_file_get_integer(data->key_file, 00635 window_group, WINDOW_PAGECOUNT, &error); 00636 if (error) 00637 { 00638 g_warning("error reading group %s key %s: %s", 00639 window_group, WINDOW_PAGECOUNT, error->message); 00640 goto cleanup; 00641 } 00642 if (page_count == 0) 00643 { 00644 /* Shound never happen, but has during alpha testing. Having this 00645 * check doesn't hurt anything. */ 00646 goto cleanup; 00647 } 00648 page_start = g_key_file_get_integer(data->key_file, 00649 window_group, WINDOW_FIRSTPAGE, &error); 00650 if (error) 00651 { 00652 g_warning("error reading group %s key %s: %s", 00653 window_group, WINDOW_FIRSTPAGE, error->message); 00654 goto cleanup; 00655 } 00656 00657 /* Build a window if we don't already have one */ 00658 if (window == NULL) 00659 { 00660 DEBUG("Window %d doesn't exist. Creating new window.", data->window_num); 00661 DEBUG("active_windows %p.", active_windows); 00662 if (active_windows) 00663 DEBUG("first window %p.", active_windows->data); 00664 window = gnc_main_window_new(); 00665 gtk_widget_show(GTK_WIDGET(window)); 00666 } 00667 00668 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 00669 00670 /* Get the window coordinates, etc. */ 00671 geom = g_key_file_get_integer_list(data->key_file, window_group, 00672 WINDOW_GEOMETRY, &length, &error); 00673 if (error) 00674 { 00675 g_warning("error reading group %s key %s: %s", 00676 window_group, WINDOW_GEOMETRY, error->message); 00677 g_error_free(error); 00678 error = NULL; 00679 } 00680 else if (length != 2) 00681 { 00682 g_warning("invalid number of values for group %s key %s", 00683 window_group, WINDOW_GEOMETRY); 00684 } 00685 else 00686 { 00687 gtk_window_resize(GTK_WINDOW(window), geom[0], geom[1]); 00688 DEBUG("window (%p) size %dx%d", window, geom[0], geom[1]); 00689 } 00690 /* keep the geometry for a test whether the windows position 00691 is offscreen */ 00692 00693 pos = g_key_file_get_integer_list(data->key_file, window_group, 00694 WINDOW_POSITION, &length, &error); 00695 if (error) 00696 { 00697 g_warning("error reading group %s key %s: %s", 00698 window_group, WINDOW_POSITION, error->message); 00699 g_error_free(error); 00700 error = NULL; 00701 } 00702 else if (length != 2) 00703 { 00704 g_warning("invalid number of values for group %s key %s", 00705 window_group, WINDOW_POSITION); 00706 } 00707 else if ((pos[0] + (geom ? geom[0] : 0) < 0) || 00708 (pos[0] > gdk_screen_width()) || 00709 (pos[1] + (geom ? geom[1] : 0) < 0) || 00710 (pos[1] > gdk_screen_height())) 00711 { 00712 // g_debug("position %dx%d, size%dx%d is offscreen; will not move", 00713 // pos[0], pos[1], geom[0], geom[1]); 00714 } 00715 else 00716 { 00717 gtk_window_move(GTK_WINDOW(window), pos[0], pos[1]); 00718 DEBUG("window (%p) position %dx%d", window, pos[0], pos[1]); 00719 } 00720 if (geom) 00721 { 00722 g_free(geom); 00723 } 00724 if (pos) 00725 { 00726 g_free(pos); 00727 } 00728 00729 max = g_key_file_get_boolean(data->key_file, window_group, 00730 WINDOW_MAXIMIZED, &error); 00731 if (error) 00732 { 00733 g_warning("error reading group %s key %s: %s", 00734 window_group, WINDOW_MAXIMIZED, error->message); 00735 g_error_free(error); 00736 error = NULL; 00737 } 00738 else if (max) 00739 { 00740 gtk_window_maximize(GTK_WINDOW(window)); 00741 } 00742 00743 /* Common view menu items */ 00744 action = gnc_main_window_find_action(window, "ViewToolbarAction"); 00745 visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 00746 desired_visibility = g_key_file_get_boolean(data->key_file, window_group, 00747 TOOLBAR_VISIBLE, &error); 00748 if (error) 00749 { 00750 g_warning("error reading group %s key %s: %s", 00751 window_group, TOOLBAR_VISIBLE, error->message); 00752 g_error_free(error); 00753 error = NULL; 00754 } 00755 else if (visible != desired_visibility) 00756 { 00757 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), desired_visibility); 00758 } 00759 00760 action = gnc_main_window_find_action(window, "ViewSummaryAction"); 00761 visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 00762 desired_visibility = g_key_file_get_boolean(data->key_file, window_group, 00763 SUMMARYBAR_VISIBLE, &error); 00764 if (error) 00765 { 00766 g_warning("error reading group %s key %s: %s", 00767 window_group, TOOLBAR_VISIBLE, error->message); 00768 g_error_free(error); 00769 error = NULL; 00770 } 00771 else if (visible != desired_visibility) 00772 { 00773 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), desired_visibility); 00774 } 00775 00776 action = gnc_main_window_find_action(window, "ViewStatusbarAction"); 00777 visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 00778 desired_visibility = g_key_file_get_boolean(data->key_file, window_group, 00779 STATUSBAR_VISIBLE, &error); 00780 if (error) 00781 { 00782 g_warning("error reading group %s key %s: %s", 00783 window_group, TOOLBAR_VISIBLE, error->message); 00784 g_error_free(error); 00785 error = NULL; 00786 } 00787 else if (visible != desired_visibility) 00788 { 00789 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), desired_visibility); 00790 } 00791 00792 /* Now populate the window with pages. */ 00793 for (i = 0; i < page_count; i++) 00794 { 00795 data->page_offset = page_start; 00796 data->page_num = i; 00797 gnc_main_window_restore_page(window, data); 00798 00799 /* give the page a chance to display */ 00800 while (gtk_events_pending ()) 00801 gtk_main_iteration (); 00802 } 00803 00804 /* Restore page ordering within the notebook. Use +1 notation so the 00805 * numbers in the page order match the page sections, at least for 00806 * the one window case. */ 00807 order = g_key_file_get_integer_list(data->key_file, window_group, 00808 WINDOW_PAGEORDER, &length, &error); 00809 if (error) 00810 { 00811 g_warning("error reading group %s key %s: %s", 00812 window_group, WINDOW_PAGEORDER, error->message); 00813 g_error_free(error); 00814 error = NULL; 00815 } 00816 else if (length != page_count) 00817 { 00818 g_warning("%s key %s length %" G_GSIZE_FORMAT " differs from window page count %d", 00819 window_group, WINDOW_PAGEORDER, length, page_count); 00820 } 00821 else 00822 { 00823 /* Dump any list that might exist */ 00824 g_list_free(priv->usage_order); 00825 priv->usage_order = NULL; 00826 /* Now rebuild the list from the key file. */ 00827 for (i = 0; i < length; i++) 00828 { 00829 gpointer page = g_list_nth_data(priv->installed_pages, order[i] - 1); 00830 if (page) 00831 { 00832 priv->usage_order = g_list_append(priv->usage_order, page); 00833 } 00834 } 00835 gtk_notebook_set_current_page (GTK_NOTEBOOK(priv->notebook), 00836 order[0] - 1); 00837 } 00838 if (order) 00839 { 00840 g_free(order); 00841 } 00842 00843 LEAVE("window %p", window); 00844 cleanup: 00845 if (error) 00846 g_error_free(error); 00847 g_free(window_group); 00848 } 00849 00850 void 00851 gnc_main_window_restore_all_windows(const GKeyFile *keyfile) 00852 { 00853 gint i, window_count; 00854 GError *error = NULL; 00855 GncMainWindowSaveData data; 00856 GncMainWindow *window; 00857 00858 /* We use the same struct for reading and for writing, so we cast 00859 away the const. */ 00860 data.key_file = (GKeyFile *) keyfile; 00861 window_count = g_key_file_get_integer(data.key_file, STATE_FILE_TOP, 00862 WINDOW_COUNT, &error); 00863 if (error) 00864 { 00865 g_warning("error reading group %s key %s: %s", 00866 STATE_FILE_TOP, WINDOW_COUNT, error->message); 00867 g_error_free(error); 00868 LEAVE("can't read count"); 00869 return; 00870 } 00871 00872 /* Restore all state information on the open windows. Window 00873 numbers in state file are 1-based. GList indices are 0-based. */ 00874 gnc_set_busy_cursor (NULL, TRUE); 00875 for (i = 0; i < window_count; i++) 00876 { 00877 data.window_num = i; 00878 window = g_list_nth_data(active_windows, i); 00879 gnc_main_window_restore_window(window, &data); 00880 } 00881 gnc_unset_busy_cursor (NULL); 00882 } 00883 00884 void 00885 gnc_main_window_restore_default_state(void) 00886 { 00887 GtkAction *action; 00888 GncMainWindow *window; 00889 00890 /* The default state should be to have an Account Tree page open 00891 * in the window. */ 00892 DEBUG("no saved state file"); 00893 window = g_list_nth_data(active_windows, 0); 00894 action = gnc_main_window_find_action(window, "ViewAccountTreeAction"); 00895 gtk_action_activate(action); 00896 } 00897 00907 static void 00908 gnc_main_window_save_page (GncPluginPage *page, GncMainWindowSaveData *data) 00909 { 00910 gchar *page_group; 00911 const gchar *plugin_name, *page_name; 00912 00913 ENTER("page %p, data %p (key file %p, window %d, page %d)", 00914 page, data, data->key_file, data->window_num, data->page_num); 00915 plugin_name = gnc_plugin_page_get_plugin_name(page); 00916 page_name = gnc_plugin_page_get_page_name(page); 00917 if (!plugin_name || !page_name) 00918 { 00919 LEAVE("not saving invalid page"); 00920 return; 00921 } 00922 page_group = g_strdup_printf(PAGE_STRING, data->page_num++); 00923 g_key_file_set_string(data->key_file, page_group, PAGE_TYPE, plugin_name); 00924 g_key_file_set_string(data->key_file, page_group, PAGE_NAME, page_name); 00925 00926 gnc_plugin_page_save_page(page, data->key_file, page_group); 00927 g_free(page_group); 00928 LEAVE(" "); 00929 } 00930 00931 00940 static void 00941 gnc_main_window_save_window (GncMainWindow *window, GncMainWindowSaveData *data) 00942 { 00943 GncMainWindowPrivate *priv; 00944 GtkAction *action; 00945 gint i, num_pages, coords[4], *order; 00946 gboolean maximized, visible; 00947 gchar *window_group; 00948 00949 /* Setup */ 00950 ENTER("window %p, data %p (key file %p, window %d)", 00951 window, data, data->key_file, data->window_num); 00952 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 00953 00954 /* Check for bogus window structures. */ 00955 num_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook)); 00956 if (0 == num_pages) 00957 { 00958 LEAVE("empty window %p", window); 00959 return; 00960 } 00961 00962 /* Save this window's notebook info */ 00963 window_group = g_strdup_printf(WINDOW_STRING, data->window_num++); 00964 g_key_file_set_integer(data->key_file, window_group, 00965 WINDOW_PAGECOUNT, num_pages); 00966 g_key_file_set_integer(data->key_file, window_group, 00967 WINDOW_FIRSTPAGE, data->page_num); 00968 00969 /* Save page ordering within the notebook. Use +1 notation so the 00970 * numbers in the page order match the page sections, at least for 00971 * the one window case. */ 00972 order = g_malloc(sizeof(gint) * num_pages); 00973 for (i = 0; i < num_pages; i++) 00974 { 00975 gpointer page = g_list_nth_data(priv->usage_order, i); 00976 order[i] = g_list_index(priv->installed_pages, page) + 1; 00977 } 00978 g_key_file_set_integer_list(data->key_file, window_group, 00979 WINDOW_PAGEORDER, order, num_pages); 00980 g_free(order); 00981 00982 /* Save the window coordinates, etc. */ 00983 gtk_window_get_position(GTK_WINDOW(window), &coords[0], &coords[1]); 00984 gtk_window_get_size(GTK_WINDOW(window), &coords[2], &coords[3]); 00985 maximized = (gdk_window_get_state((GTK_WIDGET(window))->window) 00986 & GDK_WINDOW_STATE_MAXIMIZED) != 0; 00987 g_key_file_set_integer_list(data->key_file, window_group, 00988 WINDOW_POSITION, &coords[0], 2); 00989 g_key_file_set_integer_list(data->key_file, window_group, 00990 WINDOW_GEOMETRY, &coords[2], 2); 00991 g_key_file_set_boolean(data->key_file, window_group, 00992 WINDOW_MAXIMIZED, maximized); 00993 DEBUG("window (%p) position %dx%d, size %dx%d, %s", window, coords[0], coords[1], 00994 coords[2], coords[3], 00995 maximized ? "maximized" : "not maximized"); 00996 00997 /* Common view menu items */ 00998 action = gnc_main_window_find_action(window, "ViewToolbarAction"); 00999 visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 01000 g_key_file_set_boolean(data->key_file, window_group, 01001 TOOLBAR_VISIBLE, visible); 01002 action = gnc_main_window_find_action(window, "ViewSummaryAction"); 01003 visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 01004 g_key_file_set_boolean(data->key_file, window_group, 01005 SUMMARYBAR_VISIBLE, visible); 01006 action = gnc_main_window_find_action(window, "ViewStatusbarAction"); 01007 visible = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 01008 g_key_file_set_boolean(data->key_file, window_group, 01009 STATUSBAR_VISIBLE, visible); 01010 01011 /* Save individual pages in this window */ 01012 g_list_foreach(priv->installed_pages, (GFunc)gnc_main_window_save_page, data); 01013 01014 g_free(window_group); 01015 LEAVE("window %p", window); 01016 } 01017 01018 void 01019 gnc_main_window_save_all_windows(GKeyFile *keyfile) 01020 { 01021 GncMainWindowSaveData data; 01022 01023 /* Set up the iterator data structures */ 01024 data.key_file = keyfile; 01025 data.window_num = 1; 01026 data.page_num = 1; 01027 01028 g_key_file_set_integer(data.key_file, 01029 STATE_FILE_TOP, WINDOW_COUNT, 01030 g_list_length(active_windows)); 01031 /* Dump all state information on the open windows */ 01032 g_list_foreach(active_windows, (GFunc)gnc_main_window_save_window, &data); 01033 } 01034 01035 01036 gboolean 01037 gnc_main_window_finish_pending (GncMainWindow *window) 01038 { 01039 GncMainWindowPrivate *priv; 01040 GList *item; 01041 01042 g_return_val_if_fail(GNC_IS_MAIN_WINDOW(window), TRUE); 01043 01044 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01045 for (item = priv->installed_pages; item; item = g_list_next(item)) 01046 { 01047 if (!gnc_plugin_page_finish_pending(item->data)) 01048 { 01049 return FALSE; 01050 } 01051 } 01052 return TRUE; 01053 } 01054 01055 01056 gboolean 01057 gnc_main_window_all_finish_pending (void) 01058 { 01059 const GList *windows, *item; 01060 01061 windows = gnc_gobject_tracking_get_list(GNC_MAIN_WINDOW_NAME); 01062 for (item = windows; item; item = g_list_next(item)) 01063 { 01064 if (!gnc_main_window_finish_pending(item->data)) 01065 { 01066 return FALSE; 01067 } 01068 } 01069 return TRUE; 01070 } 01071 01072 01083 static gboolean 01084 gnc_main_window_page_exists (GncPluginPage *page) 01085 { 01086 GncMainWindow *window; 01087 GncMainWindowPrivate *priv; 01088 GList *walker; 01089 01090 for (walker = active_windows; walker; walker = g_list_next(walker)) 01091 { 01092 window = walker->data; 01093 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01094 if (g_list_find(priv->installed_pages, page)) 01095 { 01096 return TRUE; 01097 } 01098 } 01099 return FALSE; 01100 } 01101 01102 01112 static gboolean 01113 gnc_main_window_prompt_for_save (GtkWidget *window) 01114 { 01115 QofSession *session; 01116 QofBook *book; 01117 GtkWidget *dialog; 01118 gint response; 01119 const gchar *filename, *tmp; 01120 const gchar *title = _("Save changes to file %s before closing?"); 01121 /* This should be the same message as in gnc-file.c */ 01122 const gchar *message_hours = 01123 _("If you don't save, changes from the past %d hours and %d minutes will be discarded."); 01124 const gchar *message_days = 01125 _("If you don't save, changes from the past %d days and %d hours will be discarded."); 01126 time_t oldest_change; 01127 gint minutes, hours, days; 01128 01129 session = gnc_get_current_session(); 01130 book = qof_session_get_book(session); 01131 filename = qof_session_get_url(session); 01132 if (filename == NULL) 01133 filename = _("<unknown>"); 01134 if ((tmp = strrchr(filename, '/')) != NULL) 01135 filename = tmp + 1; 01136 01137 /* Remove any pending auto-save timeouts */ 01138 gnc_autosave_remove_timer(book); 01139 01140 dialog = gtk_message_dialog_new(GTK_WINDOW(window), 01141 GTK_DIALOG_MODAL, 01142 GTK_MESSAGE_WARNING, 01143 GTK_BUTTONS_NONE, 01144 title, 01145 filename); 01146 oldest_change = qof_book_get_session_dirty_time(book); 01147 minutes = (time(NULL) - oldest_change) / 60 + 1; 01148 hours = minutes / 60; 01149 minutes = minutes % 60; 01150 days = hours / 24; 01151 hours = hours % 24; 01152 if (days > 0) 01153 { 01154 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), 01155 message_days, days, hours); 01156 } 01157 else if (hours > 0) 01158 { 01159 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), 01160 message_hours, hours, minutes); 01161 } 01162 else 01163 { 01164 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), 01165 ngettext("If you don't save, changes from the past %d minute will be discarded.", 01166 "If you don't save, changes from the past %d minutes will be discarded.", 01167 minutes), minutes); 01168 } 01169 gtk_dialog_add_buttons(GTK_DIALOG(dialog), 01170 _("Close _Without Saving"), GTK_RESPONSE_CLOSE, 01171 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 01172 GTK_STOCK_SAVE, GTK_RESPONSE_APPLY, 01173 NULL); 01174 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_APPLY); 01175 response = gtk_dialog_run (GTK_DIALOG (dialog)); 01176 gtk_widget_destroy(dialog); 01177 01178 switch (response) 01179 { 01180 case GTK_RESPONSE_APPLY: 01181 gnc_file_save(); 01182 return FALSE; 01183 01184 case GTK_RESPONSE_CLOSE: 01185 qof_book_mark_session_saved(book); 01186 return FALSE; 01187 01188 default: 01189 return TRUE; 01190 } 01191 } 01192 01193 01194 static void 01195 gnc_main_window_add_plugin (gpointer plugin, 01196 gpointer window) 01197 { 01198 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 01199 g_return_if_fail (GNC_IS_PLUGIN (plugin)); 01200 01201 ENTER(" "); 01202 gnc_plugin_add_to_window (GNC_PLUGIN (plugin), 01203 GNC_MAIN_WINDOW (window), 01204 window_type); 01205 LEAVE(" "); 01206 } 01207 01208 static void 01209 gnc_main_window_remove_plugin (gpointer plugin, 01210 gpointer window) 01211 { 01212 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 01213 g_return_if_fail (GNC_IS_PLUGIN (plugin)); 01214 01215 ENTER(" "); 01216 gnc_plugin_remove_from_window (GNC_PLUGIN (plugin), 01217 GNC_MAIN_WINDOW (window), 01218 window_type); 01219 LEAVE(" "); 01220 } 01221 01222 01223 static gboolean 01224 gnc_main_window_timed_quit (gpointer dummy) 01225 { 01226 if (gnc_file_save_in_progress()) 01227 return TRUE; 01228 01229 gnc_shutdown (0); 01230 return FALSE; 01231 } 01232 01233 static gboolean 01234 gnc_main_window_quit(GncMainWindow *window) 01235 { 01236 QofSession *session; 01237 gboolean needs_save, do_shutdown; 01238 01239 session = gnc_get_current_session(); 01240 needs_save = qof_book_session_not_saved(qof_session_get_book(session)) && 01241 !gnc_file_save_in_progress(); 01242 do_shutdown = !needs_save || 01243 (needs_save && !gnc_main_window_prompt_for_save(GTK_WIDGET(window))); 01244 01245 if (do_shutdown) 01246 { 01247 g_timeout_add(250, gnc_main_window_timed_quit, NULL); 01248 return TRUE; 01249 } 01250 return FALSE; 01251 } 01252 01253 static gboolean 01254 gnc_main_window_delete_event (GtkWidget *window, 01255 GdkEvent *event, 01256 gpointer user_data) 01257 { 01258 static gboolean already_dead = FALSE; 01259 01260 if (already_dead) 01261 return TRUE; 01262 01263 if (!gnc_main_window_finish_pending(GNC_MAIN_WINDOW(window))) 01264 { 01265 /* Don't close the window. */ 01266 return TRUE; 01267 } 01268 01269 if (g_list_length(active_windows) > 1) 01270 return FALSE; 01271 01272 already_dead = gnc_main_window_quit(GNC_MAIN_WINDOW(window)); 01273 return TRUE; 01274 } 01275 01276 01296 static void 01297 gnc_main_window_event_handler (QofInstance *entity, QofEventId event_type, 01298 gpointer user_data, gpointer event_data) 01299 { 01300 GncMainWindow *window; 01301 GncMainWindowPrivate *priv; 01302 GncPluginPage *page; 01303 GList *item, *next; 01304 01305 /* hard failures */ 01306 g_return_if_fail(GNC_IS_MAIN_WINDOW(user_data)); 01307 01308 /* soft failures */ 01309 if (!QOF_CHECK_TYPE(entity, QOF_ID_BOOK)) 01310 return; 01311 if (event_type != QOF_EVENT_DESTROY) 01312 return; 01313 01314 ENTER("entity %p, event %d, window %p, event data %p", 01315 entity, event_type, user_data, event_data); 01316 window = GNC_MAIN_WINDOW(user_data); 01317 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01318 01319 /* This is not a typical list iteration. We're removing while 01320 * we iterate, so we have to cache the 'next' pointer before 01321 * executing any code in the loop. */ 01322 for (item = priv->installed_pages; item; item = next) 01323 { 01324 next = g_list_next(item); 01325 page = GNC_PLUGIN_PAGE(item->data); 01326 if (gnc_plugin_page_has_book (page, (QofBook *)entity)) 01327 gnc_main_window_close_page (page); 01328 } 01329 LEAVE(" "); 01330 } 01331 01332 01348 static gchar * 01349 gnc_main_window_generate_title (GncMainWindow *window) 01350 { 01351 GncMainWindowPrivate *priv; 01352 GncPluginPage *page; 01353 QofBook *book; 01354 gchar *filename = NULL; 01355 const gchar *book_id = NULL; 01356 const gchar *dirty = ""; 01357 const gchar *readonly_text = NULL; 01358 gchar *readonly; 01359 gchar *title; 01360 GtkAction* action; 01361 01362 /* The save action is sensitive if the book is dirty */ 01363 action = gnc_main_window_find_action (window, "FileSaveAction"); 01364 if (action != NULL) 01365 { 01366 gtk_action_set_sensitive(action, FALSE); 01367 } 01368 if (gnc_current_session_exist()) 01369 { 01370 book_id = qof_session_get_url (gnc_get_current_session ()); 01371 book = gnc_get_current_book(); 01372 if (qof_book_session_not_saved (book)) 01373 { 01374 dirty = "*"; 01375 if (action != NULL) 01376 { 01377 gtk_action_set_sensitive(action, TRUE); 01378 } 01379 } 01380 if (qof_book_is_readonly(book)) 01381 { 01382 /* Translators: This string is shown in the window title if this 01383 document is, well, read-only. */ 01384 readonly_text = _("(read-only)"); 01385 } 01386 } 01387 readonly = (readonly_text != NULL) 01388 ? g_strdup_printf(" %s", readonly_text) 01389 : g_strdup(""); 01390 01391 if (!book_id) 01392 filename = g_strdup(_("Unsaved Book")); 01393 else 01394 { 01395 if ( gnc_uri_is_file_uri ( book_id ) ) 01396 { 01397 /* The filename is a true file. 01398 * The Gnome HIG 2.0 recommends only the file name (no path) be used. (p15) */ 01399 gchar *path = gnc_uri_get_path ( book_id ); 01400 filename = g_path_get_basename ( path ); 01401 g_free ( path ); 01402 } 01403 else 01404 { 01405 /* The filename is composed of database connection parameters. 01406 * For this we will show access_method://username@database[:port] */ 01407 filename = gnc_uri_normalize_uri (book_id, FALSE); 01408 } 01409 } 01410 01411 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01412 page = priv->current_page; 01413 if (page) 01414 { 01415 /* The Gnome HIG 2.0 recommends the application name not be used. (p16) 01416 * but several developers prefer to use it anyway. */ 01417 title = g_strdup_printf("%s%s%s - %s - GnuCash", dirty, filename, readonly, 01418 gnc_plugin_page_get_page_name(page)); 01419 } 01420 else 01421 { 01422 title = g_strdup_printf("%s%s%s - GnuCash", dirty, filename, readonly); 01423 } 01424 g_free( filename ); 01425 g_free(readonly); 01426 01427 return title; 01428 } 01429 01430 01440 static void 01441 gnc_main_window_update_title (GncMainWindow *window) 01442 { 01443 gchar *title; 01444 01445 title = gnc_main_window_generate_title(window); 01446 gtk_window_set_title(GTK_WINDOW(window), title); 01447 g_free(title); 01448 } 01449 01450 static void 01451 gnc_main_window_update_all_titles (void) 01452 { 01453 g_list_foreach(active_windows, 01454 (GFunc)gnc_main_window_update_title, 01455 NULL); 01456 } 01457 01458 static void 01459 gnc_main_window_book_dirty_cb (QofBook *book, 01460 gboolean dirty, 01461 gpointer user_data) 01462 { 01463 gnc_main_window_update_all_titles(); 01464 01465 /* Auto-save feature */ 01466 gnc_autosave_dirty_handler(book, dirty); 01467 } 01468 01469 static void 01470 gnc_main_window_attach_to_book (QofSession *session) 01471 { 01472 QofBook *book; 01473 01474 g_return_if_fail(session); 01475 01476 book = qof_session_get_book(session); 01477 qof_book_set_dirty_cb(book, gnc_main_window_book_dirty_cb, NULL); 01478 gnc_main_window_update_all_titles(); 01479 #ifndef MAC_INTEGRATION 01480 gnc_main_window_update_all_menu_items(); 01481 #endif 01482 } 01483 01484 01488 struct menu_update 01489 { 01491 gchar *action_name; 01492 01494 gchar *label; 01495 01497 gboolean visible; 01498 }; 01499 01500 01514 static void 01515 gnc_main_window_update_one_menu_action (GncMainWindow *window, 01516 struct menu_update *data) 01517 { 01518 GncMainWindowPrivate *priv; 01519 GtkAction* action; 01520 01521 ENTER("window %p, action %s, label %s, visible %d", window, 01522 data->action_name, data->label, data->visible); 01523 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01524 action = gtk_action_group_get_action(priv->action_group, data->action_name); 01525 if (action) 01526 g_object_set(G_OBJECT(action), 01527 "label", data->label, 01528 "visible", data->visible, 01529 (char *)NULL); 01530 #ifdef MAC_INTEGRATION 01531 { 01532 GtkOSXApplication *theApp = 01533 g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); 01534 gtk_osxapplication_sync_menubar(theApp); 01535 } 01536 #endif 01537 LEAVE(" "); 01538 } 01539 01540 01553 static void 01554 gnc_main_window_update_radio_button (GncMainWindow *window) 01555 { 01556 GncMainWindowPrivate *priv; 01557 GtkAction *action, *first_action; 01558 GSList *action_list; 01559 gchar *action_name; 01560 gint index; 01561 01562 ENTER("window %p", window); 01563 01564 /* Show the new entry in all windows. */ 01565 index = g_list_index(active_windows, window); 01566 if (index >= n_radio_entries) 01567 { 01568 LEAVE("window %d, only %d actions", index, n_radio_entries); 01569 return; 01570 } 01571 01572 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01573 action_name = g_strdup_printf("Window%dAction", index); 01574 action = gtk_action_group_get_action(priv->action_group, action_name); 01575 01576 /* Block the signal so as not to affect window ordering (top to 01577 * bottom) on the screen */ 01578 action_list = gtk_radio_action_get_group(GTK_RADIO_ACTION(action)); 01579 if (action_list) 01580 { 01581 first_action = g_slist_last(action_list)->data; 01582 g_signal_handlers_block_by_func(G_OBJECT(first_action), 01583 G_CALLBACK(gnc_main_window_cmd_window_raise), 01584 window); 01585 DEBUG("blocked signal on %p, set %p active, window %p", first_action, 01586 action, window); 01587 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE); 01588 g_signal_handlers_unblock_by_func(G_OBJECT(first_action), 01589 G_CALLBACK(gnc_main_window_cmd_window_raise), 01590 window); 01591 } 01592 g_free(action_name); 01593 LEAVE(" "); 01594 } 01595 01596 01610 static void 01611 gnc_main_window_update_menu_item (GncMainWindow *window) 01612 { 01613 struct menu_update data; 01614 gchar **strings, *title, *expanded; 01615 gint index; 01616 01617 ENTER("window %p", window); 01618 index = g_list_index(active_windows, window); 01619 if (index > n_radio_entries) 01620 { 01621 LEAVE("skip window %d (only %d entries)", index, n_radio_entries); 01622 return; 01623 } 01624 01625 /* Figure out the label name. Add the accelerator if possible. */ 01626 title = gnc_main_window_generate_title(window); 01627 strings = g_strsplit(title, "_", 0); 01628 g_free(title); 01629 expanded = g_strjoinv("__", strings); 01630 if (index < 10) 01631 { 01632 data.label = g_strdup_printf("_%d %s", (index + 1) % 10, expanded); 01633 g_free(expanded); 01634 } 01635 else 01636 { 01637 data.label = expanded; 01638 } 01639 g_strfreev(strings); 01640 01641 data.visible = TRUE; 01642 data.action_name = g_strdup_printf("Window%dAction", index); 01643 g_list_foreach(active_windows, 01644 (GFunc)gnc_main_window_update_one_menu_action, 01645 &data); 01646 g_free(data.action_name); 01647 g_free(data.label); 01648 01649 LEAVE(" "); 01650 } 01651 01659 static void 01660 gnc_main_window_update_all_menu_items (void) 01661 { 01662 struct menu_update data; 01663 gchar *label; 01664 gint i; 01665 01666 ENTER(""); 01667 #ifndef MAC_INTEGRATION 01668 /* First update the entries for all existing windows */ 01669 g_list_foreach(active_windows, 01670 (GFunc)gnc_main_window_update_menu_item, 01671 NULL); 01672 g_list_foreach(active_windows, 01673 (GFunc)gnc_main_window_update_radio_button, 01674 NULL); 01675 01676 /* Now hide any entries that aren't being used. */ 01677 data.visible = FALSE; 01678 for (i = g_list_length(active_windows); i < n_radio_entries; i++) 01679 { 01680 data.action_name = g_strdup_printf("Window%dAction", i); 01681 label = g_strdup_printf("Window _%d", (i - 1) % 10); 01682 data.label = gettext(label); 01683 01684 g_list_foreach(active_windows, 01685 (GFunc)gnc_main_window_update_one_menu_action, 01686 &data); 01687 01688 g_free(data.action_name); 01689 g_free(label); 01690 } 01691 #endif 01692 LEAVE(" "); 01693 } 01694 01695 01707 static void 01708 gnc_main_window_update_tab_close_one_page (GncPluginPage *page, 01709 gpointer user_data) 01710 { 01711 gboolean *new_value = user_data; 01712 GtkWidget * close_button; 01713 01714 ENTER("page %p, visible %d", page, *new_value); 01715 close_button = g_object_get_data(G_OBJECT (page), PLUGIN_PAGE_CLOSE_BUTTON); 01716 if (!close_button) 01717 { 01718 LEAVE("no close button"); 01719 return; 01720 } 01721 01722 if (*new_value) 01723 gtk_widget_show (close_button); 01724 else 01725 gtk_widget_hide (close_button); 01726 LEAVE(" "); 01727 } 01728 01729 01741 static void 01742 gnc_main_window_update_tab_close (GConfEntry *entry, gpointer user_data) 01743 { 01744 gboolean new_value; 01745 01746 ENTER(" "); 01747 new_value = gconf_value_get_bool(entry->value); 01748 gnc_main_window_foreach_page( 01749 gnc_main_window_update_tab_close_one_page, 01750 &new_value); 01751 LEAVE(" "); 01752 } 01753 01754 01767 static void 01768 gnc_main_window_update_tab_width_one_page (GncPluginPage *page, 01769 gpointer user_data) 01770 { 01771 gint *new_value = user_data; 01772 GtkWidget *label; 01773 01774 ENTER("page %p, visible %d", page, *new_value); 01775 label = g_object_get_data(G_OBJECT (page), PLUGIN_PAGE_TAB_LABEL); 01776 if (!label) 01777 { 01778 LEAVE("no label"); 01779 return; 01780 } 01781 01782 if (*new_value != 0) 01783 { 01784 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE); 01785 gtk_label_set_max_width_chars(GTK_LABEL(label), *new_value); 01786 } 01787 else 01788 { 01789 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_NONE); 01790 gtk_label_set_max_width_chars(GTK_LABEL(label), 100); 01791 } 01792 LEAVE(" "); 01793 } 01794 01795 01807 static void 01808 gnc_main_window_update_tab_width (GConfEntry *entry, gpointer user_data) 01809 { 01810 gint new_value; 01811 01812 ENTER(" "); 01813 new_value = gconf_value_get_float(entry->value); 01814 gnc_main_window_foreach_page( 01815 gnc_main_window_update_tab_width_one_page, 01816 &new_value); 01817 LEAVE(" "); 01818 } 01819 01820 01821 /************************************************************ 01822 * Tab Label Implementation * 01823 ************************************************************/ 01824 static gboolean 01825 main_window_find_tab_items (GncMainWindow *window, 01826 GncPluginPage *page, 01827 GtkWidget **label_p, 01828 GtkWidget **entry_p) 01829 { 01830 GncMainWindowPrivate *priv; 01831 GtkWidget *tab_hbox, *widget, *event_box; 01832 GList *children, *tmp; 01833 01834 ENTER("window %p, page %p, label_p %p, entry_p %p", 01835 window, page, label_p, entry_p); 01836 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01837 *label_p = *entry_p = NULL; 01838 01839 if (!page->notebook_page) 01840 { 01841 LEAVE("invalid notebook_page"); 01842 return FALSE; 01843 } 01844 01845 event_box = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook), 01846 page->notebook_page); 01847 01848 tab_hbox = gtk_bin_get_child(GTK_BIN(event_box)); 01849 01850 children = gtk_container_get_children(GTK_CONTAINER(tab_hbox)); 01851 for (tmp = children; tmp; tmp = g_list_next(tmp)) 01852 { 01853 widget = tmp->data; 01854 if (GTK_IS_LABEL(widget)) 01855 { 01856 *label_p = widget; 01857 } 01858 else if (GTK_IS_ENTRY(widget)) 01859 { 01860 *entry_p = widget; 01861 } 01862 } 01863 g_list_free(children); 01864 01865 LEAVE("label %p, entry %p", *label_p, *entry_p); 01866 return (*label_p && *entry_p); 01867 } 01868 01869 static gboolean 01870 main_window_find_tab_event (GncMainWindow *window, 01871 GncPluginPage *page, 01872 GtkWidget **event_p) 01873 { 01874 GncMainWindowPrivate *priv; 01875 GtkWidget *event_box; 01876 01877 ENTER("window %p, page %p, event %p", 01878 window, page, event_p); 01879 *event_p = NULL; 01880 01881 if (!page->notebook_page) 01882 { 01883 LEAVE("invalid notebook_page"); 01884 return FALSE; 01885 } 01886 01887 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01888 event_box = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook), 01889 page->notebook_page); 01890 if (GTK_IS_EVENT_BOX(event_box)) 01891 { 01892 *event_p = event_box; 01893 LEAVE("event %p", *event_p); 01894 return (TRUE); 01895 } 01896 01897 LEAVE("event %p", *event_p); 01898 return (FALSE); 01899 } 01900 01901 void 01902 main_window_update_page_name (GncPluginPage *page, 01903 const gchar *name_in) 01904 { 01905 GncMainWindow *window; 01906 GncMainWindowPrivate *priv; 01907 GtkWidget *label, *entry, *event_box; 01908 gchar *name, *old_page_name, *old_page_long_name; 01909 01910 ENTER(" "); 01911 01912 if ((name_in == NULL) || (*name_in == '\0')) 01913 { 01914 LEAVE("no string"); 01915 return; 01916 } 01917 name = g_strstrip(g_strdup(name_in)); 01918 01919 /* Optimization, if the name hasn't changed, don't update X. */ 01920 if (*name == '\0' || 0 == strcmp(name, gnc_plugin_page_get_page_name(page))) 01921 { 01922 g_free(name); 01923 LEAVE("empty string or name unchanged"); 01924 return; 01925 } 01926 01927 old_page_name = g_strdup( gnc_plugin_page_get_page_name(page)); 01928 old_page_long_name = g_strdup( gnc_plugin_page_get_page_long_name(page)); 01929 01930 /* Update the plugin */ 01931 gnc_plugin_page_set_page_name(page, name); 01932 01933 /* Update the notebook tab */ 01934 window = GNC_MAIN_WINDOW(page->window); 01935 if (!window) 01936 { 01937 g_free(old_page_name); 01938 g_free(old_page_long_name); 01939 g_free(name); 01940 LEAVE("no window widget available"); 01941 return; 01942 } 01943 01944 if (main_window_find_tab_items(window, page, &label, &entry)) 01945 gtk_label_set_text(GTK_LABEL(label), name); 01946 01947 /* Update Tooltip on notebook Tab */ 01948 if (old_page_long_name && old_page_name 01949 && g_strrstr(old_page_long_name, old_page_name) != NULL) 01950 { 01951 gchar *new_page_long_name; 01952 gint string_position; 01953 01954 string_position = strlen(old_page_long_name) - strlen(old_page_name); 01955 new_page_long_name = g_strconcat(g_strndup(old_page_long_name, string_position), name, NULL); 01956 01957 gnc_plugin_page_set_page_long_name(page, new_page_long_name); 01958 01959 if (main_window_find_tab_event(window, page, &event_box)) 01960 gtk_widget_set_tooltip_text(event_box, new_page_long_name); 01961 01962 g_free(new_page_long_name); 01963 } 01964 01965 /* Update the notebook menu */ 01966 if (page->notebook_page) 01967 { 01968 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 01969 label = gtk_notebook_get_menu_label (GTK_NOTEBOOK(priv->notebook), 01970 page->notebook_page); 01971 gtk_label_set_text(GTK_LABEL(label), name); 01972 } 01973 01974 /* Force an update of the window title */ 01975 gnc_main_window_update_title(window); 01976 g_free(old_page_long_name); 01977 g_free(old_page_name); 01978 g_free(name); 01979 LEAVE("done"); 01980 } 01981 01982 01983 void 01984 main_window_update_page_color (GncPluginPage *page, 01985 const gchar *color_in) 01986 { 01987 GncMainWindow *window; 01988 GncMainWindowPrivate *priv; 01989 GtkWidget *event_box; 01990 GdkColor tab_color; 01991 gchar *color_string; 01992 01993 01994 ENTER(" "); 01995 01996 if ((color_in == NULL) || (*color_in == '\0')) 01997 { 01998 LEAVE("no string"); 01999 return; 02000 } 02001 color_string = g_strstrip(g_strdup(color_in)); 02002 02003 /* Optimization, if the color hasn't changed, don't update. */ 02004 if (*color_string == '\0' || 0 == safe_strcmp(color_string, gnc_plugin_page_get_page_color(page))) 02005 { 02006 g_free(color_string); 02007 LEAVE("empty string or color unchanged"); 02008 return; 02009 } 02010 02011 /* Update the plugin */ 02012 window = GNC_MAIN_WINDOW(page->window); 02013 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02014 gnc_plugin_page_set_page_color(page, color_string); 02015 02016 /* Update the notebook tab */ 02017 main_window_find_tab_event(window, page, &event_box); 02018 02019 if (gdk_color_parse(color_string, &tab_color)) 02020 { 02021 gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, &tab_color); 02022 gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, &tab_color); 02023 } 02024 else 02025 { 02026 gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, NULL); 02027 gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, NULL); 02028 } 02029 g_free(color_string); 02030 LEAVE("done"); 02031 } 02032 02033 02034 static void 02035 gnc_main_window_tab_entry_activate (GtkWidget *entry, 02036 GncPluginPage *page) 02037 { 02038 GtkWidget *label, *entry2; 02039 02040 g_return_if_fail(GTK_IS_ENTRY(entry)); 02041 g_return_if_fail(GNC_IS_PLUGIN_PAGE(page)); 02042 02043 ENTER(""); 02044 if (!main_window_find_tab_items(GNC_MAIN_WINDOW(page->window), 02045 page, &label, &entry2)) 02046 { 02047 LEAVE("can't find required widgets"); 02048 return; 02049 } 02050 02051 main_window_update_page_name(page, gtk_entry_get_text(GTK_ENTRY(entry))); 02052 02053 gtk_widget_hide(entry); 02054 gtk_widget_show(label); 02055 LEAVE(""); 02056 } 02057 02058 02059 static gboolean 02060 gnc_main_window_tab_entry_editing_done (GtkWidget *entry, 02061 GncPluginPage *page) 02062 { 02063 ENTER(""); 02064 gnc_main_window_tab_entry_activate(entry, page); 02065 LEAVE(""); 02066 return FALSE; 02067 } 02068 02069 static gboolean 02070 gnc_main_window_tab_entry_focus_out_event (GtkWidget *entry, 02071 GdkEvent *event, 02072 GncPluginPage *page) 02073 { 02074 ENTER(""); 02075 gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry)); 02076 LEAVE(""); 02077 return FALSE; 02078 } 02079 02080 static gboolean 02081 gnc_main_window_tab_entry_key_press_event (GtkWidget *entry, 02082 GdkEventKey *event, 02083 GncPluginPage *page) 02084 { 02085 if (event->keyval == GDK_Escape) 02086 { 02087 GtkWidget *label, *entry2; 02088 02089 g_return_val_if_fail(GTK_IS_ENTRY(entry), FALSE); 02090 g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE); 02091 02092 ENTER(""); 02093 if (!main_window_find_tab_items(GNC_MAIN_WINDOW(page->window), 02094 page, &label, &entry2)) 02095 { 02096 LEAVE("can't find required widgets"); 02097 return FALSE; 02098 } 02099 02100 gtk_entry_set_text(GTK_ENTRY(entry), gtk_label_get_text(GTK_LABEL(label))); 02101 gtk_widget_hide(entry); 02102 gtk_widget_show(label); 02103 LEAVE(""); 02104 } 02105 return FALSE; 02106 } 02107 02108 /************************************************************ 02109 * Widget Implementation * 02110 ************************************************************/ 02111 02112 /* Get the type of a gnc main window. 02113 */ 02114 GType 02115 gnc_main_window_get_type (void) 02116 { 02117 static GType gnc_main_window_type = 0; 02118 02119 if (gnc_main_window_type == 0) 02120 { 02121 static const GTypeInfo our_info = 02122 { 02123 sizeof (GncMainWindowClass), 02124 NULL, 02125 NULL, 02126 (GClassInitFunc) gnc_main_window_class_init, 02127 NULL, 02128 NULL, 02129 sizeof (GncMainWindow), 02130 0, 02131 (GInstanceInitFunc) gnc_main_window_init 02132 }; 02133 02134 static const GInterfaceInfo plugin_info = 02135 { 02136 (GInterfaceInitFunc) gnc_window_main_window_init, 02137 NULL, 02138 NULL 02139 }; 02140 02141 gnc_main_window_type = g_type_register_static (GTK_TYPE_WINDOW, 02142 GNC_MAIN_WINDOW_NAME, 02143 &our_info, 0); 02144 g_type_add_interface_static (gnc_main_window_type, 02145 GNC_TYPE_WINDOW, 02146 &plugin_info); 02147 } 02148 02149 return gnc_main_window_type; 02150 } 02151 02152 02160 static void 02161 gnc_main_window_class_init (GncMainWindowClass *klass) 02162 { 02163 GObjectClass *object_class = G_OBJECT_CLASS (klass); 02164 GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS(klass); 02165 02166 parent_class = g_type_class_peek_parent (klass); 02167 02168 window_type = g_quark_from_static_string ("gnc-main-window"); 02169 02170 object_class->finalize = gnc_main_window_finalize; 02171 02172 /* GtkObject signals */ 02173 gtkobject_class->destroy = gnc_main_window_destroy; 02174 02175 g_type_class_add_private(klass, sizeof(GncMainWindowPrivate)); 02176 02188 main_window_signals[PAGE_ADDED] = 02189 g_signal_new ("page_added", 02190 G_OBJECT_CLASS_TYPE (object_class), 02191 G_SIGNAL_RUN_FIRST, 02192 G_STRUCT_OFFSET (GncMainWindowClass, page_added), 02193 NULL, NULL, 02194 g_cclosure_marshal_VOID__OBJECT, 02195 G_TYPE_NONE, 1, 02196 G_TYPE_OBJECT); 02197 02208 main_window_signals[PAGE_CHANGED] = 02209 g_signal_new ("page_changed", 02210 G_OBJECT_CLASS_TYPE (object_class), 02211 G_SIGNAL_RUN_FIRST, 02212 G_STRUCT_OFFSET (GncMainWindowClass, page_changed), 02213 NULL, NULL, 02214 g_cclosure_marshal_VOID__OBJECT, 02215 G_TYPE_NONE, 1, 02216 G_TYPE_OBJECT); 02217 02218 gnc_gconf_general_register_cb (KEY_SHOW_CLOSE_BUTTON, 02219 gnc_main_window_update_tab_close, 02220 NULL); 02221 gnc_gconf_general_register_cb (KEY_TAB_WIDTH, 02222 gnc_main_window_update_tab_width, 02223 NULL); 02224 gnc_hook_add_dangler(HOOK_BOOK_SAVED, 02225 (GFunc)gnc_main_window_update_all_titles, NULL); 02226 gnc_hook_add_dangler(HOOK_BOOK_OPENED, 02227 (GFunc)gnc_main_window_attach_to_book, NULL); 02228 02229 } 02230 02231 02240 static void 02241 gnc_main_window_init (GncMainWindow *window, 02242 GncMainWindowClass *klass) 02243 { 02244 GncMainWindowPrivate *priv; 02245 02246 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02247 priv->merged_actions_table = 02248 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); 02249 02250 priv->event_handler_id = 02251 qof_event_register_handler(gnc_main_window_event_handler, window); 02252 02253 gnc_main_window_setup_window (window); 02254 gnc_gobject_tracking_remember(G_OBJECT(window), 02255 G_OBJECT_CLASS(klass)); 02256 } 02257 02258 02269 static void 02270 gnc_main_window_finalize (GObject *object) 02271 { 02272 GncMainWindow *window; 02273 GncMainWindowPrivate *priv; 02274 02275 g_return_if_fail (object != NULL); 02276 g_return_if_fail (GNC_IS_MAIN_WINDOW (object)); 02277 02278 window = GNC_MAIN_WINDOW (object); 02279 priv = GNC_MAIN_WINDOW_GET_PRIVATE (window); 02280 02281 if (active_windows == NULL) 02282 { 02283 /* Oops. User killed last window and we didn't catch it. */ 02284 g_idle_add((GSourceFunc)gnc_shutdown, 0); 02285 } 02286 02287 gnc_gobject_tracking_forget(object); 02288 G_OBJECT_CLASS (parent_class)->finalize (object); 02289 } 02290 02291 02292 static void 02293 gnc_main_window_destroy (GtkObject *object) 02294 { 02295 GncMainWindow *window; 02296 GncMainWindowPrivate *priv; 02297 GncPluginManager *manager; 02298 GList *plugins; 02299 02300 g_return_if_fail (object != NULL); 02301 g_return_if_fail (GNC_IS_MAIN_WINDOW (object)); 02302 02303 window = GNC_MAIN_WINDOW (object); 02304 02305 active_windows = g_list_remove (active_windows, window); 02306 02307 /* Do these things once */ 02308 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02309 if (priv->merged_actions_table) 02310 { 02311 02312 /* Close any pages in this window */ 02313 while (priv->current_page) 02314 gnc_main_window_close_page(priv->current_page); 02315 02316 if (gnc_window_get_progressbar_window() == GNC_WINDOW(window)) 02317 gnc_window_set_progressbar_window(NULL); 02318 #ifndef MAC_INTEGRATION 02319 /* Update the "Windows" menu in all other windows */ 02320 gnc_main_window_update_all_menu_items(); 02321 #endif 02322 gnc_gconf_remove_notification(G_OBJECT(window), DESKTOP_GNOME_INTERFACE, 02323 GNC_MAIN_WINDOW_NAME); 02324 gnc_gconf_remove_notification(G_OBJECT(window), GCONF_GENERAL, 02325 GNC_MAIN_WINDOW_NAME); 02326 02327 qof_event_unregister_handler(priv->event_handler_id); 02328 priv->event_handler_id = 0; 02329 02330 g_hash_table_destroy (priv->merged_actions_table); 02331 priv->merged_actions_table = NULL; 02332 02333 /* GncPluginManager stuff */ 02334 manager = gnc_plugin_manager_get (); 02335 plugins = gnc_plugin_manager_get_plugins (manager); 02336 g_list_foreach (plugins, gnc_main_window_remove_plugin, window); 02337 g_list_free (plugins); 02338 } 02339 GTK_OBJECT_CLASS (parent_class)->destroy (object); 02340 } 02341 02342 02343 /* Create a new gnc main window plugin. 02344 */ 02345 GncMainWindow * 02346 gnc_main_window_new (void) 02347 { 02348 GncMainWindow *window; 02349 GtkWidget *old_window; 02350 02351 window = g_object_new (GNC_TYPE_MAIN_WINDOW, NULL); 02352 gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); 02353 02354 old_window = gnc_ui_get_toplevel(); 02355 if (old_window) 02356 { 02357 gint width, height; 02358 gtk_window_get_size (GTK_WINDOW (old_window), &width, &height); 02359 gtk_window_resize (GTK_WINDOW (window), width, height); 02360 if ((gdk_window_get_state((GTK_WIDGET(old_window))->window) 02361 & GDK_WINDOW_STATE_MAXIMIZED) != 0) 02362 { 02363 gtk_window_maximize (GTK_WINDOW (window)); 02364 } 02365 } 02366 active_windows = g_list_append (active_windows, window); 02367 gnc_main_window_update_title(window); 02368 #ifdef MAC_INTEGRATION 02369 gnc_quartz_set_menu(window); 02370 #else 02371 gnc_main_window_update_all_menu_items(); 02372 #endif 02373 gnc_engine_add_commit_error_callback( gnc_main_window_engine_commit_error_callback, window ); 02374 02375 return window; 02376 } 02377 02378 /************************************************************ 02379 * Utility Functions * 02380 ************************************************************/ 02381 02382 static void 02383 gnc_main_window_engine_commit_error_callback( gpointer data, 02384 QofBackendError errcode ) 02385 { 02386 GncMainWindow* window = GNC_MAIN_WINDOW(data); 02387 GtkWidget* dialog; 02388 const gchar *reason = _("Unable to save to database."); 02389 if ( errcode == ERR_BACKEND_READONLY ) 02390 reason = _("Unable to save to database: Book is marked read-only."); 02391 dialog = gtk_message_dialog_new( GTK_WINDOW(window), 02392 GTK_DIALOG_DESTROY_WITH_PARENT, 02393 GTK_MESSAGE_ERROR, 02394 GTK_BUTTONS_CLOSE, 02395 "%s", 02396 reason ); 02397 gtk_dialog_run(GTK_DIALOG (dialog)); 02398 gtk_widget_destroy(dialog); 02399 02400 } 02401 02419 static void 02420 gnc_main_window_connect (GncMainWindow *window, 02421 GncPluginPage *page, 02422 GtkWidget *tab_hbox, 02423 GtkWidget *menu_label) 02424 { 02425 GncMainWindowPrivate *priv; 02426 GtkNotebook *notebook; 02427 02428 page->window = GTK_WIDGET(window); 02429 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02430 notebook = GTK_NOTEBOOK (priv->notebook); 02431 priv->installed_pages = g_list_append (priv->installed_pages, page); 02432 priv->usage_order = g_list_prepend (priv->usage_order, page); 02433 gtk_notebook_append_page_menu (notebook, page->notebook_page, 02434 tab_hbox, menu_label); 02435 gtk_notebook_set_tab_reorderable (notebook, page->notebook_page, TRUE); 02436 gnc_plugin_page_inserted (page); 02437 gtk_notebook_set_current_page (notebook, -1); 02438 if (GNC_PLUGIN_PAGE_GET_CLASS(page)->window_changed) 02439 (GNC_PLUGIN_PAGE_GET_CLASS(page)->window_changed)(page, GTK_WIDGET(window)); 02440 g_signal_emit (window, main_window_signals[PAGE_ADDED], 0, page); 02441 02442 g_signal_connect(G_OBJECT(page->notebook_page), "popup-menu", 02443 G_CALLBACK(gnc_main_window_popup_menu_cb), page); 02444 g_signal_connect_after(G_OBJECT(page->notebook_page), "button-press-event", 02445 G_CALLBACK(gnc_main_window_button_press_cb), page); 02446 } 02447 02448 02462 static void 02463 gnc_main_window_disconnect (GncMainWindow *window, 02464 GncPluginPage *page) 02465 { 02466 GncMainWindowPrivate *priv; 02467 GtkNotebook *notebook; 02468 GncPluginPage *new_page; 02469 gint page_num; 02470 02471 /* Disconnect the callbacks */ 02472 g_signal_handlers_disconnect_by_func(G_OBJECT(page->notebook_page), 02473 G_CALLBACK(gnc_main_window_popup_menu_cb), page); 02474 g_signal_handlers_disconnect_by_func(G_OBJECT(page->notebook_page), 02475 G_CALLBACK(gnc_main_window_button_press_cb), page); 02476 02477 /* Disconnect the page and summarybar from the window */ 02478 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02479 if (priv->current_page == page) 02480 { 02481 gnc_plugin_page_unmerge_actions (page, window->ui_merge); 02482 gnc_plugin_page_unselected (page); 02483 priv->current_page = NULL; 02484 } 02485 02486 /* Remove it from the list of pages in the window */ 02487 priv->installed_pages = g_list_remove (priv->installed_pages, page); 02488 priv->usage_order = g_list_remove (priv->usage_order, page); 02489 02490 /* Switch to the last recently used page */ 02491 notebook = GTK_NOTEBOOK (priv->notebook); 02492 if (gnc_gconf_get_bool(GCONF_GENERAL, KEY_TAB_NEXT_RECENT, NULL)) 02493 { 02494 new_page = g_list_nth_data (priv->usage_order, 0); 02495 if (new_page) 02496 { 02497 page_num = gtk_notebook_page_num(notebook, new_page->notebook_page); 02498 gtk_notebook_set_current_page(notebook, page_num); 02499 } 02500 } 02501 02502 /* Remove the page from the notebook */ 02503 page_num = gtk_notebook_page_num(notebook, page->notebook_page); 02504 gtk_notebook_remove_page (notebook, page_num); 02505 02506 if ( gtk_notebook_get_current_page(notebook) == -1) 02507 { 02508 /* Need to synthesize a page changed signal when the last 02509 * page is removed. The notebook doesn't generate a signal 02510 * for this, therefore the switch_page code in this file 02511 * never gets called to generate this signal. */ 02512 gnc_main_window_switch_page(notebook, NULL, -1, window); 02513 //g_signal_emit (window, main_window_signals[PAGE_CHANGED], 0, NULL); 02514 } 02515 02516 gnc_plugin_page_removed (page); 02517 02518 gtk_ui_manager_ensure_update (window->ui_merge); 02519 gnc_window_set_status (GNC_WINDOW(window), page, NULL); 02520 } 02521 02522 02523 /************************************************************ 02524 * * 02525 ************************************************************/ 02526 02527 02528 void 02529 gnc_main_window_display_page (GncPluginPage *page) 02530 { 02531 GncMainWindow *window; 02532 GncMainWindowPrivate *priv; 02533 GtkNotebook *notebook; 02534 gint page_num; 02535 02536 window = GNC_MAIN_WINDOW (page->window); 02537 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02538 notebook = GTK_NOTEBOOK (priv->notebook); 02539 page_num = gtk_notebook_page_num(notebook, page->notebook_page); 02540 gtk_notebook_set_current_page (notebook, page_num); 02541 gtk_window_present(GTK_WINDOW(window)); 02542 } 02543 02544 02545 /* Display a data plugin page in a window. If the page already 02546 * exists in any window, then that window will be brought to the 02547 * front and the notebook switch to display the specified page. If 02548 * the page is new then it will be added to the specified window. If 02549 * the window is NULL, the new page will be added to the first 02550 * window. 02551 */ 02552 void 02553 gnc_main_window_open_page (GncMainWindow *window, 02554 GncPluginPage *page) 02555 { 02556 GncMainWindowPrivate *priv; 02557 GtkWidget *tab_hbox; 02558 GtkWidget *label, *entry, *event_box; 02559 const gchar *icon, *text, *color_string; 02560 GtkWidget *image; 02561 GList *tmp; 02562 gint width; 02563 GdkColor tab_color; 02564 02565 ENTER("window %p, page %p", window, page); 02566 02567 if (window) 02568 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 02569 g_return_if_fail (GNC_IS_PLUGIN_PAGE (page)); 02570 g_return_if_fail (gnc_plugin_page_has_books(page)); 02571 02572 if (gnc_main_window_page_exists(page)) 02573 { 02574 gnc_main_window_display_page(page); 02575 return; 02576 } 02577 02578 /* Does the page want to be in a new window? */ 02579 if (gnc_plugin_page_get_use_new_window(page)) 02580 { 02581 /* See if there's a blank window. If so, use that. */ 02582 for (tmp = active_windows; tmp; tmp = g_list_next(tmp)) 02583 { 02584 window = GNC_MAIN_WINDOW(tmp->data); 02585 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02586 if (priv->installed_pages == NULL) 02587 { 02588 break; 02589 } 02590 } 02591 if (tmp == NULL) 02592 window = gnc_main_window_new (); 02593 gtk_widget_show(GTK_WIDGET(window)); 02594 } 02595 else if ((window == NULL) && active_windows) 02596 { 02597 window = active_windows->data; 02598 } 02599 02600 page->window = GTK_WIDGET(window); 02601 page->notebook_page = gnc_plugin_page_create_widget (page); 02602 g_object_set_data (G_OBJECT (page->notebook_page), 02603 PLUGIN_PAGE_LABEL, page); 02604 02605 /* 02606 * The page tab. 02607 */ 02608 width = gnc_gconf_get_float(GCONF_GENERAL, KEY_TAB_WIDTH, NULL); 02609 icon = GNC_PLUGIN_PAGE_GET_CLASS(page)->tab_icon; 02610 label = gtk_label_new (gnc_plugin_page_get_page_name(page)); 02611 if (width != 0) 02612 { 02613 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE); 02614 gtk_label_set_max_width_chars(GTK_LABEL(label), width); 02615 } 02616 gtk_widget_show (label); 02617 02618 tab_hbox = gtk_hbox_new (FALSE, 6); 02619 gtk_widget_show (tab_hbox); 02620 02621 if (icon != NULL) 02622 { 02623 image = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); 02624 gtk_widget_show (image); 02625 gtk_box_pack_start (GTK_BOX (tab_hbox), image, FALSE, FALSE, 0); 02626 gtk_box_pack_start (GTK_BOX (tab_hbox), label, TRUE, TRUE, 0); 02627 } 02628 else 02629 gtk_box_pack_start (GTK_BOX (tab_hbox), label, TRUE, TRUE, 0); 02630 02631 event_box = gtk_event_box_new(); 02632 /* Note: this doesn't work properly on Windows with gtk+2.18.x (last 02633 * with 2.18.7). Setting the eventbox visible with that version results 02634 * in the tab's text being invisible. See bug #610675 for more on this. 02635 */ 02636 gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), TRUE); 02637 gtk_widget_show(event_box); 02638 gtk_container_add(GTK_CONTAINER(event_box), tab_hbox); 02639 color_string = gnc_plugin_page_get_page_color(page); 02640 if (color_string == NULL) color_string = ""; 02641 if (gdk_color_parse(color_string, &tab_color)) 02642 { 02643 gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, &tab_color); 02644 gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, &tab_color); 02645 } 02646 else 02647 { 02648 gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, NULL); 02649 gtk_widget_modify_bg(event_box, GTK_STATE_ACTIVE, NULL); 02650 } 02651 02652 text = gnc_plugin_page_get_page_long_name(page); 02653 if (text) 02654 { 02655 gtk_widget_set_tooltip_text(event_box, text); 02656 } 02657 02658 entry = gtk_entry_new(); 02659 gtk_widget_hide (entry); 02660 gtk_box_pack_start (GTK_BOX (tab_hbox), entry, TRUE, TRUE, 0); 02661 g_signal_connect(G_OBJECT(entry), "activate", 02662 G_CALLBACK(gnc_main_window_tab_entry_activate), page); 02663 g_signal_connect(G_OBJECT(entry), "focus-out-event", 02664 G_CALLBACK(gnc_main_window_tab_entry_focus_out_event), 02665 page); 02666 g_signal_connect(G_OBJECT(entry), "key-press-event", 02667 G_CALLBACK(gnc_main_window_tab_entry_key_press_event), 02668 page); 02669 g_signal_connect(G_OBJECT(entry), "editing-done", 02670 G_CALLBACK(gnc_main_window_tab_entry_editing_done), 02671 page); 02672 02673 /* Add close button - Not for immutable pages */ 02674 if (!g_object_get_data (G_OBJECT (page), PLUGIN_PAGE_IMMUTABLE)) 02675 { 02676 GtkWidget *close_image, *close_button; 02677 GtkRequisition requisition; 02678 02679 close_button = gtk_button_new(); 02680 gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE); 02681 close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); 02682 gtk_widget_show(close_image); 02683 gtk_widget_size_request(close_image, &requisition); 02684 gtk_widget_set_size_request(close_button, requisition.width + 4, 02685 requisition.height + 2); 02686 gtk_button_set_alignment(GTK_BUTTON(close_button), 0.5, 0.5); 02687 gtk_container_add(GTK_CONTAINER(close_button), close_image); 02688 if (gnc_gconf_get_bool(GCONF_GENERAL, KEY_SHOW_CLOSE_BUTTON, NULL)) 02689 gtk_widget_show (close_button); 02690 else 02691 gtk_widget_hide (close_button); 02692 02693 g_signal_connect_swapped (G_OBJECT (close_button), "clicked", 02694 G_CALLBACK(gnc_main_window_close_page), page); 02695 02696 gtk_box_pack_start (GTK_BOX (tab_hbox), close_button, FALSE, FALSE, 0); 02697 02698 g_object_set_data (G_OBJECT (page), PLUGIN_PAGE_CLOSE_BUTTON, close_button); 02699 } 02700 02701 /* 02702 * The popup menu 02703 */ 02704 label = gtk_label_new (gnc_plugin_page_get_page_name(page)); 02705 02706 /* 02707 * Now install it all in the window. 02708 */ 02709 gnc_main_window_connect(window, page, event_box, label); 02710 LEAVE(""); 02711 } 02712 02713 02714 /* Remove a data plugin page from a window and display the previous 02715 * page. If the page removed was the last page in the window, and 02716 * there is more than one window open, then the entire window will be 02717 * destroyed. 02718 */ 02719 void 02720 gnc_main_window_close_page (GncPluginPage *page) 02721 { 02722 GncMainWindow *window; 02723 GncMainWindowPrivate *priv; 02724 02725 if (!page || !page->notebook_page) 02726 return; 02727 02728 if (!gnc_plugin_page_finish_pending(page)) 02729 return; 02730 02731 if (!GNC_IS_MAIN_WINDOW (page->window)) 02732 return; 02733 02734 window = GNC_MAIN_WINDOW (page->window); 02735 if (!window) 02736 { 02737 g_warning("Page is not in a window."); 02738 return; 02739 } 02740 02741 gnc_main_window_disconnect(window, page); 02742 gnc_plugin_page_destroy_widget (page); 02743 g_object_unref(page); 02744 02745 /* If this isn't the last window, go ahead and destroy the window. */ 02746 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02747 if (priv->installed_pages == NULL) 02748 { 02749 if (g_list_length(active_windows) > 1) 02750 { 02751 gtk_widget_destroy(GTK_WIDGET(window)); 02752 } 02753 } 02754 } 02755 02756 02757 /* Retrieve a pointer to the page that is currently at the front of 02758 * the specified window. Any plugin that needs to manipulate its 02759 * menus based upon the currently selected menu page should connect 02760 * to the "page_changed" signal on a window. The callback function 02761 * from that signal can then call this function to obtain a pointer 02762 * to the current page. 02763 */ 02764 GncPluginPage * 02765 gnc_main_window_get_current_page (GncMainWindow *window) 02766 { 02767 GncMainWindowPrivate *priv; 02768 02769 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02770 return priv->current_page; 02771 } 02772 02773 02774 /* Manually add a set of actions to the specified window. Plugins 02775 * whose user interface is not hard coded (e.g. the menu-additions 02776 * plugin) must create their actions at run time, then use this 02777 * function to install them into the window. 02778 */ 02779 void 02780 gnc_main_window_manual_merge_actions (GncMainWindow *window, 02781 const gchar *group_name, 02782 GtkActionGroup *group, 02783 guint merge_id) 02784 { 02785 GncMainWindowPrivate *priv; 02786 MergedActionEntry *entry; 02787 02788 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 02789 g_return_if_fail (group_name != NULL); 02790 g_return_if_fail (GTK_IS_ACTION_GROUP(group)); 02791 g_return_if_fail (merge_id > 0); 02792 02793 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02794 entry = g_new0 (MergedActionEntry, 1); 02795 entry->action_group = group; 02796 entry->merge_id = merge_id; 02797 gtk_ui_manager_ensure_update (window->ui_merge); 02798 g_hash_table_insert (priv->merged_actions_table, g_strdup (group_name), entry); 02799 } 02800 02801 02802 /* Add a set of actions to the specified window. This function 02803 * should not need to be called directly by plugin implementors. 02804 * Correctly assigning values to the GncPluginClass fields during 02805 * plugin initialization will cause this routine to be automatically 02806 * called. 02807 */ 02808 void 02809 gnc_main_window_merge_actions (GncMainWindow *window, 02810 const gchar *group_name, 02811 GtkActionEntry *actions, 02812 guint n_actions, 02813 GtkToggleActionEntry *toggle_actions, 02814 guint n_toggle_actions, 02815 const gchar *filename, 02816 gpointer user_data) 02817 { 02818 GncMainWindowPrivate *priv; 02819 GncMainWindowActionData *data; 02820 MergedActionEntry *entry; 02821 GError *error = NULL; 02822 gchar *pathname; 02823 02824 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 02825 g_return_if_fail (group_name != NULL); 02826 g_return_if_fail (actions != NULL); 02827 g_return_if_fail (n_actions > 0); 02828 g_return_if_fail (filename != NULL); 02829 02830 pathname = gnc_gnome_locate_ui_file (filename); 02831 if (pathname == NULL) 02832 return; 02833 02834 data = g_new0 (GncMainWindowActionData, 1); 02835 data->window = window; 02836 data->data = user_data; 02837 02838 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02839 entry = g_new0 (MergedActionEntry, 1); 02840 entry->action_group = gtk_action_group_new (group_name); 02841 gnc_gtk_action_group_set_translation_domain (entry->action_group, GETTEXT_PACKAGE); 02842 gtk_action_group_add_actions (entry->action_group, actions, n_actions, data); 02843 if (toggle_actions != NULL && n_toggle_actions > 0) 02844 { 02845 gtk_action_group_add_toggle_actions (entry->action_group, 02846 toggle_actions, n_toggle_actions, 02847 data); 02848 } 02849 gtk_ui_manager_insert_action_group (window->ui_merge, entry->action_group, 0); 02850 entry->merge_id = gtk_ui_manager_add_ui_from_file (window->ui_merge, pathname, &error); 02851 g_assert(entry->merge_id || error); 02852 if (entry->merge_id) 02853 { 02854 gtk_ui_manager_ensure_update (window->ui_merge); 02855 g_hash_table_insert (priv->merged_actions_table, g_strdup (group_name), entry); 02856 } 02857 else 02858 { 02859 g_critical("Failed to load ui file.\n Filename %s\n Error %s", 02860 filename, error->message); 02861 g_error_free(error); 02862 g_free(entry); 02863 } 02864 g_free(pathname); 02865 } 02866 02867 02868 /* Remove a set of actions from the specified window. This function 02869 * should not need to be called directly by plugin implementors. It 02870 * will automatically be called when a plugin is removed from a 02871 * window. 02872 */ 02873 void 02874 gnc_main_window_unmerge_actions (GncMainWindow *window, 02875 const gchar *group_name) 02876 { 02877 GncMainWindowPrivate *priv; 02878 MergedActionEntry *entry; 02879 02880 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 02881 g_return_if_fail (group_name != NULL); 02882 02883 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02884 if (priv->merged_actions_table == NULL) 02885 return; 02886 entry = g_hash_table_lookup (priv->merged_actions_table, group_name); 02887 02888 if (entry == NULL) 02889 return; 02890 02891 gtk_ui_manager_remove_action_group (window->ui_merge, entry->action_group); 02892 gtk_ui_manager_remove_ui (window->ui_merge, entry->merge_id); 02893 gtk_ui_manager_ensure_update (window->ui_merge); 02894 02895 g_hash_table_remove (priv->merged_actions_table, group_name); 02896 } 02897 02898 02899 /* Force a full update of the user interface for the specified 02900 * window. This can be an expensive function, but is needed because 02901 * the gtk ui manager doesn't always seem to update properly when 02902 * actions are changed. 02903 */ 02904 void 02905 gnc_main_window_actions_updated (GncMainWindow *window) 02906 { 02907 GtkActionGroup *force; 02908 02909 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 02910 02911 /* Unfortunately gtk_ui_manager_ensure_update doesn't work 02912 * here. Force a full update by adding and removing an empty 02913 * action group. 02914 */ 02915 force = gtk_action_group_new("force_update"); 02916 gtk_ui_manager_insert_action_group (window->ui_merge, force, 0); 02917 gtk_ui_manager_ensure_update (window->ui_merge); 02918 gtk_ui_manager_remove_action_group (window->ui_merge, force); 02919 g_object_unref(force); 02920 } 02921 02922 02923 GtkAction * 02924 gnc_main_window_find_action (GncMainWindow *window, const gchar *name) 02925 { 02926 GtkAction *action = NULL; 02927 const GList *groups, *tmp; 02928 02929 groups = gtk_ui_manager_get_action_groups(window->ui_merge); 02930 for (tmp = groups; tmp; tmp = g_list_next(tmp)) 02931 { 02932 action = gtk_action_group_get_action(GTK_ACTION_GROUP(tmp->data), name); 02933 if (action) 02934 break; 02935 } 02936 return action; 02937 } 02938 02939 02940 /* Retrieve a specific set of user interface actions from a window. 02941 * This function can be used to get an group of action to be 02942 * manipulated when the front page of a window has changed. 02943 */ 02944 GtkActionGroup * 02945 gnc_main_window_get_action_group (GncMainWindow *window, 02946 const gchar *group_name) 02947 { 02948 GncMainWindowPrivate *priv; 02949 MergedActionEntry *entry; 02950 02951 g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window), NULL); 02952 g_return_val_if_fail (group_name != NULL, NULL); 02953 02954 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 02955 if (priv->merged_actions_table == NULL) 02956 return NULL; 02957 entry = g_hash_table_lookup (priv->merged_actions_table, group_name); 02958 02959 if (entry == NULL) 02960 return NULL; 02961 02962 return entry->action_group; 02963 } 02964 02965 02966 static void 02967 gnc_main_window_update_toolbar (GncMainWindow *window) 02968 { 02969 GtkToolbarStyle style; 02970 GSList *list; 02971 02972 ENTER("window %p", window); 02973 02974 style = gnc_get_toolbar_style(); 02975 list = gtk_ui_manager_get_toplevels(window->ui_merge, GTK_UI_MANAGER_TOOLBAR); 02976 g_slist_foreach(list, (GFunc)gtk_toolbar_set_style, GINT_TO_POINTER(style)); 02977 g_slist_free(list); 02978 LEAVE(""); 02979 } 02980 02981 static void 02982 gnc_main_window_update_tab_position (GncMainWindow *window) 02983 { 02984 GtkPositionType position = GTK_POS_TOP; 02985 gchar *conf_string; 02986 GncMainWindowPrivate *priv; 02987 02988 ENTER ("window %p", window); 02989 conf_string = gnc_gconf_get_string (GCONF_GENERAL, 02990 KEY_TAB_POSITION, NULL); 02991 if (conf_string) 02992 { 02993 position = gnc_enum_from_nick (GTK_TYPE_POSITION_TYPE, 02994 conf_string, GTK_POS_TOP); 02995 g_free (conf_string); 02996 } 02997 02998 priv = GNC_MAIN_WINDOW_GET_PRIVATE (window); 02999 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (priv->notebook), position); 03000 03001 LEAVE (""); 03002 } 03003 03004 /* 03005 * Based on code from Epiphany (src/ephy-window.c) 03006 */ 03007 static void 03008 gnc_main_window_update_edit_actions_sensitivity (GncMainWindow *window, gboolean hide) 03009 { 03010 GncMainWindowPrivate *priv; 03011 GncPluginPage *page; 03012 GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); 03013 GtkAction *action; 03014 gboolean can_copy = FALSE, can_cut = FALSE, can_paste = FALSE; 03015 03016 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03017 page = priv->current_page; 03018 if (page && GNC_PLUGIN_PAGE_GET_CLASS(page)->update_edit_menu_actions) 03019 { 03020 (GNC_PLUGIN_PAGE_GET_CLASS(page)->update_edit_menu_actions)(page, hide); 03021 return; 03022 } 03023 03024 if (GTK_IS_EDITABLE (widget)) 03025 { 03026 gboolean has_selection; 03027 03028 has_selection = gtk_editable_get_selection_bounds 03029 (GTK_EDITABLE (widget), NULL, NULL); 03030 03031 can_copy = has_selection; 03032 can_cut = has_selection; 03033 can_paste = TRUE; 03034 } 03035 else if (GTK_IS_TEXT_VIEW (widget)) 03036 { 03037 gboolean has_selection; 03038 GtkTextBuffer *text_buffer; 03039 03040 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(widget)); 03041 has_selection = gtk_text_buffer_get_selection_bounds 03042 (text_buffer, NULL, NULL); 03043 03044 can_copy = has_selection; 03045 can_cut = has_selection; 03046 can_paste = TRUE; 03047 } 03048 else 03049 { 03050 #ifdef ORIGINAL_EPIPHANY_CODE 03051 /* For now we assume all actions are possible */ 03052 can_copy = can_cut = can_paste = TRUE; 03053 #else 03054 /* If its not a GtkEditable, we don't know what to do 03055 * with it. */ 03056 can_copy = can_cut = can_paste = FALSE; 03057 #endif 03058 } 03059 03060 action = gnc_main_window_find_action (window, "EditCopyAction"); 03061 gtk_action_set_sensitive (action, can_copy); 03062 gtk_action_set_visible (action, !hide || can_copy); 03063 action = gnc_main_window_find_action (window, "EditCutAction"); 03064 gtk_action_set_sensitive (action, can_cut); 03065 gtk_action_set_visible (action, !hide || can_cut); 03066 action = gnc_main_window_find_action (window, "EditPasteAction"); 03067 gtk_action_set_sensitive (action, can_paste); 03068 gtk_action_set_visible (action, !hide || can_paste); 03069 } 03070 03071 static void 03072 gnc_main_window_enable_edit_actions_sensitivity (GncMainWindow *window) 03073 { 03074 GtkAction *action; 03075 03076 action = gnc_main_window_find_action (window, "EditCopyAction"); 03077 gtk_action_set_sensitive (action, TRUE); 03078 gtk_action_set_visible (action, TRUE); 03079 action = gnc_main_window_find_action (window, "EditCutAction"); 03080 gtk_action_set_sensitive (action, TRUE); 03081 gtk_action_set_visible (action, TRUE); 03082 action = gnc_main_window_find_action (window, "EditPasteAction"); 03083 gtk_action_set_sensitive (action, TRUE); 03084 gtk_action_set_visible (action, TRUE); 03085 } 03086 03087 static void 03088 gnc_main_window_edit_menu_show_cb (GtkWidget *menu, 03089 GncMainWindow *window) 03090 { 03091 gnc_main_window_update_edit_actions_sensitivity (window, FALSE); 03092 } 03093 03094 static void 03095 gnc_main_window_edit_menu_hide_cb (GtkWidget *menu, 03096 GncMainWindow *window) 03097 { 03098 gnc_main_window_enable_edit_actions_sensitivity (window); 03099 } 03100 03101 static void 03102 gnc_main_window_init_menu_updaters (GncMainWindow *window) 03103 { 03104 GtkWidget *edit_menu_item, *edit_menu; 03105 03106 edit_menu_item = gtk_ui_manager_get_widget 03107 (window->ui_merge, "/menubar/Edit"); 03108 edit_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (edit_menu_item)); 03109 03110 g_signal_connect (edit_menu, "show", 03111 G_CALLBACK (gnc_main_window_edit_menu_show_cb), window); 03112 g_signal_connect (edit_menu, "hide", 03113 G_CALLBACK (gnc_main_window_edit_menu_hide_cb), window); 03114 } 03115 03116 static void 03117 gnc_main_window_gconf_changed (GConfClient *client, 03118 guint cnxn_id, 03119 GConfEntry *entry, 03120 gpointer user_data) 03121 { 03122 GncMainWindow *window; 03123 GConfValue *value; 03124 const gchar *key, *key_tail; 03125 03126 window = GNC_MAIN_WINDOW(user_data); 03127 03128 key = gconf_entry_get_key(entry); 03129 value = gconf_entry_get_value(entry); 03130 if (!key || !value) 03131 return; 03132 03133 key_tail = strrchr(key, '/'); 03134 if (key_tail != NULL) 03135 key_tail++; 03136 if (strcmp(key_tail, KEY_TOOLBAR_STYLE) == 0) 03137 { 03138 gnc_main_window_update_toolbar(window); 03139 } 03140 else if (strcmp(key_tail, KEY_TAB_POSITION) == 0) 03141 { 03142 gnc_main_window_update_tab_position(window); 03143 } 03144 } 03145 03146 /* CS: This callback functions will set the statusbar text to the 03147 * "tooltip" property of the currently selected GtkAction. 03148 * 03149 * This code is directly copied from gtk+/test/testmerge.c. 03150 * Thanks to (L)GPL! */ 03151 typedef struct _ActionStatus ActionStatus; 03152 struct _ActionStatus 03153 { 03154 GtkAction *action; 03155 GtkWidget *statusbar; 03156 }; 03157 03158 static void 03159 action_status_destroy (gpointer data) 03160 { 03161 ActionStatus *action_status = data; 03162 03163 g_object_unref (action_status->action); 03164 g_object_unref (action_status->statusbar); 03165 03166 g_free (action_status); 03167 } 03168 03169 static void 03170 set_tip (GtkWidget *widget) 03171 { 03172 ActionStatus *data; 03173 gchar *tooltip; 03174 03175 data = g_object_get_data (G_OBJECT (widget), "action-status"); 03176 03177 if (data) 03178 { 03179 g_object_get (data->action, "tooltip", &tooltip, NULL); 03180 03181 gtk_statusbar_push (GTK_STATUSBAR (data->statusbar), 0, 03182 tooltip ? tooltip : ""); 03183 03184 g_free (tooltip); 03185 } 03186 } 03187 03188 static void 03189 unset_tip (GtkWidget *widget) 03190 { 03191 ActionStatus *data; 03192 03193 data = g_object_get_data (G_OBJECT (widget), "action-status"); 03194 03195 if (data) 03196 gtk_statusbar_pop (GTK_STATUSBAR (data->statusbar), 0); 03197 } 03198 03199 static void 03200 connect_proxy (GtkUIManager *merge, 03201 GtkAction *action, 03202 GtkWidget *proxy, 03203 GtkWidget *statusbar) 03204 { 03205 if (GTK_IS_MENU_ITEM (proxy)) 03206 { 03207 ActionStatus *data; 03208 03209 data = g_object_get_data (G_OBJECT (proxy), "action-status"); 03210 if (data) 03211 { 03212 g_object_unref (data->action); 03213 g_object_unref (data->statusbar); 03214 03215 data->action = g_object_ref (action); 03216 data->statusbar = g_object_ref (statusbar); 03217 } 03218 else 03219 { 03220 data = g_new0 (ActionStatus, 1); 03221 03222 data->action = g_object_ref (action); 03223 data->statusbar = g_object_ref (statusbar); 03224 03225 g_object_set_data_full (G_OBJECT (proxy), "action-status", 03226 data, action_status_destroy); 03227 03228 g_signal_connect (proxy, "select", G_CALLBACK (set_tip), NULL); 03229 g_signal_connect (proxy, "deselect", G_CALLBACK (unset_tip), NULL); 03230 } 03231 } 03232 } 03233 /* CS: end copied code from gtk+/test/testmerge.c */ 03234 03235 static void 03236 gnc_main_window_window_menu (GncMainWindow *window) 03237 { 03238 GncMainWindowPrivate *priv; 03239 guint merge_id; 03240 #ifdef MAC_INTEGRATION 03241 gchar *filename = gnc_gnome_locate_ui_file("gnc-windows-menu-ui-quartz.xml"); 03242 #else 03243 gchar *filename = gnc_gnome_locate_ui_file("gnc-windows-menu-ui.xml"); 03244 #endif 03245 GError *error = NULL; 03246 g_assert(filename); 03247 merge_id = gtk_ui_manager_add_ui_from_file(window->ui_merge, filename, 03248 &error); 03249 g_free(filename); 03250 g_assert(merge_id); 03251 #ifndef MAC_INTEGRATION 03252 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03253 gtk_action_group_add_radio_actions (priv->action_group, 03254 radio_entries, n_radio_entries, 03255 0, 03256 G_CALLBACK(gnc_main_window_cmd_window_raise), 03257 window); 03258 #endif 03259 }; 03260 03261 static void 03262 gnc_main_window_setup_window (GncMainWindow *window) 03263 { 03264 GncMainWindowPrivate *priv; 03265 GtkWidget *main_vbox; 03266 guint merge_id; 03267 GncPluginManager *manager; 03268 GList *plugins; 03269 GError *error = NULL; 03270 gchar *filename; 03271 03272 ENTER(" "); 03273 03274 /* Catch window manager delete signal */ 03275 g_signal_connect (G_OBJECT (window), "delete-event", 03276 G_CALLBACK (gnc_main_window_delete_event), window); 03277 03278 /* Create widgets and add them to the window */ 03279 main_vbox = gtk_vbox_new (FALSE, 0); 03280 gtk_widget_show (main_vbox); 03281 gtk_container_add (GTK_CONTAINER (window), main_vbox); 03282 03283 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03284 priv->menu_dock = gtk_vbox_new (FALSE, 0); 03285 gtk_widget_show (priv->menu_dock); 03286 gtk_box_pack_start (GTK_BOX (main_vbox), priv->menu_dock, 03287 FALSE, TRUE, 0); 03288 03289 priv->notebook = gtk_notebook_new (); 03290 g_object_set(G_OBJECT(priv->notebook), 03291 "scrollable", TRUE, 03292 "enable-popup", TRUE, 03293 (char *)NULL); 03294 gtk_widget_show (priv->notebook); 03295 g_signal_connect (G_OBJECT (priv->notebook), "switch-page", 03296 G_CALLBACK (gnc_main_window_switch_page), window); 03297 g_signal_connect (G_OBJECT (priv->notebook), "page-reordered", 03298 G_CALLBACK (gnc_main_window_page_reordered), window); 03299 gtk_box_pack_start (GTK_BOX (main_vbox), priv->notebook, 03300 TRUE, TRUE, 0); 03301 03302 priv->statusbar = gtk_statusbar_new (); 03303 gtk_widget_show (priv->statusbar); 03304 gtk_box_pack_start (GTK_BOX (main_vbox), priv->statusbar, 03305 FALSE, TRUE, 0); 03306 gtk_statusbar_set_has_resize_grip( GTK_STATUSBAR(priv->statusbar), TRUE ); 03307 03308 priv->progressbar = gtk_progress_bar_new (); 03309 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(priv->progressbar), " "); 03310 gtk_widget_show (priv->progressbar); 03311 gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar, 03312 FALSE, TRUE, 0); 03313 gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(priv->progressbar), 03314 0.01); 03315 03316 window->ui_merge = gtk_ui_manager_new (); 03317 03318 /* Create menu and toolbar information */ 03319 priv->action_group = gtk_action_group_new ("MainWindowActions"); 03320 gnc_gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE); 03321 gtk_action_group_add_actions (priv->action_group, gnc_menu_actions, 03322 gnc_menu_n_actions, window); 03323 gtk_action_group_add_toggle_actions (priv->action_group, 03324 toggle_actions, n_toggle_actions, 03325 window); 03326 gnc_plugin_update_actions(priv->action_group, 03327 initially_insensitive_actions, 03328 "sensitive", FALSE); 03329 gnc_plugin_update_actions(priv->action_group, 03330 always_insensitive_actions, 03331 "sensitive", FALSE); 03332 gnc_plugin_update_actions(priv->action_group, 03333 always_hidden_actions, 03334 "visible", FALSE); 03335 gnc_plugin_set_important_actions (priv->action_group, 03336 gnc_menu_important_actions); 03337 gtk_ui_manager_insert_action_group (window->ui_merge, priv->action_group, 0); 03338 03339 g_signal_connect (G_OBJECT (window->ui_merge), "add_widget", 03340 G_CALLBACK (gnc_main_window_add_widget), window); 03341 /* Use the "connect-proxy" signal for tooltip display in the 03342 status bar */ 03343 g_signal_connect (G_OBJECT (window->ui_merge), "connect-proxy", 03344 G_CALLBACK (connect_proxy), priv->statusbar); 03345 03346 filename = gnc_gnome_locate_ui_file("gnc-main-window-ui.xml"); 03347 03348 /* Can't do much without a ui. */ 03349 g_assert (filename); 03350 03351 merge_id = gtk_ui_manager_add_ui_from_file (window->ui_merge, 03352 filename, &error); 03353 g_assert(merge_id || error); 03354 if (merge_id) 03355 { 03356 gtk_window_add_accel_group (GTK_WINDOW (window), 03357 gtk_ui_manager_get_accel_group(window->ui_merge)); 03358 gtk_ui_manager_ensure_update (window->ui_merge); 03359 } 03360 else 03361 { 03362 g_critical("Failed to load ui file.\n Filename %s\n Error %s", 03363 filename, error->message); 03364 g_error_free(error); 03365 g_assert(merge_id != 0); 03366 } 03367 g_free(filename); 03368 gnc_main_window_window_menu(window); 03369 gnc_gconf_add_notification(G_OBJECT(window), GCONF_GENERAL, 03370 gnc_main_window_gconf_changed, 03371 GNC_MAIN_WINDOW_NAME); 03372 gnc_gconf_add_notification(G_OBJECT(window), DESKTOP_GNOME_INTERFACE, 03373 gnc_main_window_gconf_changed, 03374 GNC_MAIN_WINDOW_NAME); 03375 gnc_main_window_update_toolbar(window); 03376 gnc_main_window_update_tab_position(window); 03377 03378 gnc_main_window_init_menu_updaters(window); 03379 03380 /* Testing */ 03381 /* Now update the "eXtensions" menu */ 03382 if (!gnc_is_extra_enabled()) 03383 { 03384 GtkAction* action; 03385 03386 action = gtk_action_group_get_action(priv->action_group, 03387 "ExtensionsAction"); 03388 gtk_action_set_visible(action, FALSE); 03389 } 03390 03391 /* GncPluginManager stuff */ 03392 manager = gnc_plugin_manager_get (); 03393 plugins = gnc_plugin_manager_get_plugins (manager); 03394 g_list_foreach (plugins, gnc_main_window_add_plugin, window); 03395 g_list_free (plugins); 03396 03397 g_signal_connect (G_OBJECT (manager), "plugin-added", 03398 G_CALLBACK (gnc_main_window_plugin_added), window); 03399 g_signal_connect (G_OBJECT (manager), "plugin-removed", 03400 G_CALLBACK (gnc_main_window_plugin_removed), window); 03401 03402 LEAVE(" "); 03403 } 03404 03405 #ifdef MAC_INTEGRATION 03406 /* Event handlers for the shutdown process. Gnc_quartz_shutdown is 03407 * connected to NSApplicationWillTerminate, the last chance to do 03408 * anything before quitting. The problem is that it's launched from a 03409 * CFRunLoop, not a g_main_loop, and if we call anything that would 03410 * affect the main_loop we get an assert that we're in a subidiary 03411 * loop. 03412 */ 03413 static void 03414 gnc_quartz_shutdown (GtkOSXApplication *theApp, gpointer data) 03415 { 03416 /* Do Nothing. It's too late. */ 03417 } 03418 /* Should quit responds to NSApplicationBlockTermination; returning 03419 * TRUE means "don't terminate", FALSE means "do terminate". If we 03420 * decide that it's OK to terminate, then we queue a gnc_shutdown for 03421 * the next idle time (because we're not running in the main loop) and 03422 * then tell the OS not to terminate. That gives the gnc_shutdown an 03423 * opportunity to shut down. 03424 */ 03425 static gboolean 03426 gnc_quartz_should_quit (GtkOSXApplication *theApp, GncMainWindow *window) 03427 { 03428 QofSession *session; 03429 gboolean needs_save; 03430 03431 if (!gnc_main_window_all_finish_pending() || 03432 gnc_file_save_in_progress()) 03433 { 03434 return TRUE; 03435 } 03436 session = gnc_get_current_session(); 03437 needs_save = qof_book_session_not_saved(qof_session_get_book(session)) && 03438 !gnc_file_save_in_progress(); 03439 if (needs_save && gnc_main_window_prompt_for_save(GTK_WIDGET(window))) 03440 return TRUE; 03441 03442 g_timeout_add(250, gnc_main_window_timed_quit, NULL); 03443 return TRUE; 03444 } 03445 03446 static void 03447 gnc_quartz_set_menu(GncMainWindow* window) 03448 { 03449 GtkOSXApplicationMenuGroup *group; 03450 GtkOSXApplication *theApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); 03451 GtkWidget *menu; 03452 GtkWidget *item; 03453 03454 menu = gtk_ui_manager_get_widget (window->ui_merge, "/menubar"); 03455 if (GTK_IS_MENU_ITEM (menu)) 03456 menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu)); 03457 gtk_widget_hide(menu); 03458 gtk_osxapplication_set_menu_bar (theApp, GTK_MENU_SHELL (menu)); 03459 03460 item = gtk_ui_manager_get_widget (window->ui_merge, 03461 "/menubar/File/FileQuit"); 03462 if (GTK_IS_MENU_ITEM (item)) 03463 gtk_widget_hide (GTK_WIDGET (item)); 03464 03465 item = gtk_ui_manager_get_widget (window->ui_merge, 03466 "/menubar/Edit/EditPreferences"); 03467 if (GTK_IS_MENU_ITEM (item)) 03468 gtk_osxapplication_insert_app_menu_item (theApp, GTK_WIDGET (item), 0); 03469 03470 item = gtk_ui_manager_get_widget (window->ui_merge, 03471 "/menubar/Help/HelpAbout"); 03472 if (GTK_IS_MENU_ITEM (item)) 03473 { 03474 gtk_osxapplication_insert_app_menu_item (theApp, 03475 gtk_separator_menu_item_new (), 03476 0); 03477 gtk_osxapplication_insert_app_menu_item (theApp, GTK_WIDGET (item), 0); 03478 } 03479 03480 item = gtk_ui_manager_get_widget (window->ui_merge, 03481 "/menubar/Help"); 03482 gtk_osxapplication_set_help_menu(theApp, GTK_MENU_ITEM(item)); 03483 item = gtk_ui_manager_get_widget (window->ui_merge, 03484 "/menubar/Windows"); 03485 gtk_osxapplication_set_window_menu(theApp, GTK_MENU_ITEM(item)); 03486 g_signal_connect(theApp, "NSApplicationBlockTermination", 03487 G_CALLBACK(gnc_quartz_should_quit), window); 03488 03489 } 03490 #endif //MAC_INTEGRATION 03491 03492 /* Callbacks */ 03493 static void 03494 gnc_main_window_add_widget (GtkUIManager *merge, 03495 GtkWidget *widget, 03496 GncMainWindow *window) 03497 { 03498 GncMainWindowPrivate *priv; 03499 03500 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03501 if (GTK_IS_TOOLBAR (widget)) 03502 { 03503 priv->toolbar = widget; 03504 } 03505 03506 gtk_box_pack_start (GTK_BOX (priv->menu_dock), widget, FALSE, FALSE, 0); 03507 gtk_widget_show (widget); 03508 } 03509 03522 static gboolean 03523 gnc_main_window_show_summarybar (GncMainWindow *window, GtkAction *action) 03524 { 03525 GncMainWindowPrivate *priv; 03526 03527 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03528 if (action == NULL) 03529 action = gtk_action_group_get_action(priv->action_group, 03530 "ViewSummaryAction"); 03531 if (action == NULL) 03532 return TRUE; 03533 return gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)); 03534 } 03535 03545 static void 03546 gnc_main_window_switch_page (GtkNotebook *notebook, 03547 GtkNotebookPage *notebook_page, 03548 gint pos, 03549 GncMainWindow *window) 03550 { 03551 GncMainWindowPrivate *priv; 03552 GtkWidget *child; 03553 GncPluginPage *page; 03554 gboolean immutable, visible; 03555 03556 ENTER("Notebook %p, page, %p, index %d, window %p", 03557 notebook, notebook_page, pos, window); 03558 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 03559 03560 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03561 if (priv->current_page != NULL) 03562 { 03563 page = priv->current_page; 03564 gnc_plugin_page_unmerge_actions (page, window->ui_merge); 03565 gnc_plugin_page_unselected (page); 03566 } 03567 03568 child = gtk_notebook_get_nth_page (notebook, pos); 03569 if (child) 03570 { 03571 page = g_object_get_data (G_OBJECT (child), PLUGIN_PAGE_LABEL); 03572 } 03573 else 03574 { 03575 page = NULL; 03576 } 03577 03578 priv->current_page = page; 03579 03580 if (page != NULL) 03581 { 03582 /* Update the user interface (e.g. menus and toolbars */ 03583 gnc_plugin_page_merge_actions (page, window->ui_merge); 03584 visible = gnc_main_window_show_summarybar(window, NULL); 03585 gnc_plugin_page_show_summarybar (page, visible); 03586 03587 /* Allow page specific actions */ 03588 gnc_plugin_page_selected (page); 03589 gnc_window_update_status (GNC_WINDOW(window), page); 03590 03591 /* Update the page reference info */ 03592 priv->usage_order = g_list_remove (priv->usage_order, page); 03593 priv->usage_order = g_list_prepend (priv->usage_order, page); 03594 } 03595 03596 /* Update the menus based upon whether this is an "immutable" page. */ 03597 immutable = page && 03598 g_object_get_data (G_OBJECT (page), PLUGIN_PAGE_IMMUTABLE); 03599 gnc_plugin_update_actions(priv->action_group, 03600 immutable_page_actions, 03601 "sensitive", !immutable); 03602 gnc_plugin_update_actions(priv->action_group, 03603 multiple_page_actions, 03604 "sensitive", 03605 g_list_length(priv->installed_pages) > 1); 03606 03607 gnc_main_window_update_title(window); 03608 #ifndef MAC_INTEGRATION 03609 gnc_main_window_update_menu_item(window); 03610 #endif 03611 g_signal_emit (window, main_window_signals[PAGE_CHANGED], 0, page); 03612 LEAVE(" "); 03613 } 03614 03621 static void 03622 gnc_main_window_page_reordered (GtkNotebook *notebook, 03623 GtkWidget *child, 03624 guint pos, 03625 GncMainWindow *window) 03626 { 03627 GncMainWindowPrivate *priv; 03628 GncPluginPage *page; 03629 GList *old_link; 03630 03631 ENTER("Notebook %p, child %p, index %d, window %p", 03632 notebook, child, pos, window); 03633 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 03634 03635 if (!child) return; 03636 03637 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03638 03639 page = g_object_get_data (G_OBJECT (child), PLUGIN_PAGE_LABEL); 03640 if (!page) return; 03641 03642 old_link = g_list_find (priv->installed_pages, page); 03643 if (!old_link) return; 03644 03645 priv->installed_pages = g_list_delete_link (priv->installed_pages, 03646 old_link); 03647 priv->installed_pages = g_list_insert (priv->installed_pages, 03648 page, pos); 03649 03650 LEAVE(" "); 03651 } 03652 03653 static void 03654 gnc_main_window_plugin_added (GncPlugin *manager, 03655 GncPlugin *plugin, 03656 GncMainWindow *window) 03657 { 03658 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 03659 g_return_if_fail (GNC_IS_PLUGIN (plugin)); 03660 03661 gnc_plugin_add_to_window (plugin, window, window_type); 03662 } 03663 03664 static void 03665 gnc_main_window_plugin_removed (GncPlugin *manager, 03666 GncPlugin *plugin, 03667 GncMainWindow *window) 03668 { 03669 g_return_if_fail (GNC_IS_MAIN_WINDOW (window)); 03670 g_return_if_fail (GNC_IS_PLUGIN (plugin)); 03671 03672 gnc_plugin_remove_from_window (plugin, window, window_type); 03673 } 03674 03675 03676 /* Command callbacks */ 03677 static void 03678 gnc_main_window_cmd_page_setup (GtkAction *action, 03679 GncMainWindow *window) 03680 { 03681 GtkWindow *gtk_window; 03682 03683 g_return_if_fail(GNC_IS_MAIN_WINDOW(window)); 03684 03685 gtk_window = gnc_window_get_gtk_window(GNC_WINDOW(window)); 03686 gnc_ui_page_setup(gtk_window); 03687 } 03688 03689 static void 03690 gnc_main_window_cmd_file_properties (GtkAction *action, GncMainWindow *window) 03691 { 03692 SCM func = scm_c_eval_string("gnc:main-window-properties-cb"); 03693 if (!scm_is_procedure (func)) 03694 { 03695 PERR ("not a procedure\n"); 03696 return; 03697 } 03698 scm_call_0(func); 03699 } 03700 03701 static void 03702 gnc_main_window_cmd_file_close (GtkAction *action, GncMainWindow *window) 03703 { 03704 GncMainWindowPrivate *priv; 03705 GncPluginPage *page; 03706 03707 g_return_if_fail(GNC_IS_MAIN_WINDOW(window)); 03708 03709 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03710 page = priv->current_page; 03711 gnc_main_window_close_page(page); 03712 } 03713 03714 static void 03715 gnc_main_window_cmd_file_quit (GtkAction *action, GncMainWindow *window) 03716 { 03717 if (!gnc_main_window_all_finish_pending()) 03718 return; 03719 03720 gnc_main_window_quit(window); 03721 } 03722 03723 static void 03724 gnc_main_window_cmd_edit_cut (GtkAction *action, GncMainWindow *window) 03725 { 03726 GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); 03727 GtkTextBuffer *text_buffer; 03728 GtkClipboard *clipboard; 03729 gboolean editable; 03730 03731 if (GTK_IS_EDITABLE (widget)) 03732 { 03733 gtk_editable_cut_clipboard (GTK_EDITABLE (widget)); 03734 } 03735 else if (GTK_IS_TEXT_VIEW (widget)) 03736 { 03737 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(widget)); 03738 clipboard = gtk_widget_get_clipboard (GTK_WIDGET(text_buffer), 03739 GDK_SELECTION_CLIPBOARD); 03740 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)); 03741 gtk_text_buffer_cut_clipboard (text_buffer, clipboard, editable); 03742 } 03743 } 03744 03745 static void 03746 gnc_main_window_cmd_edit_copy (GtkAction *action, GncMainWindow *window) 03747 { 03748 GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); 03749 GtkTextBuffer *text_buffer; 03750 GtkClipboard *clipboard; 03751 03752 if (GTK_IS_EDITABLE (widget)) 03753 { 03754 gtk_editable_copy_clipboard (GTK_EDITABLE (widget)); 03755 } 03756 else if (GTK_IS_TEXT_VIEW (widget)) 03757 { 03758 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(widget)); 03759 clipboard = gtk_widget_get_clipboard (GTK_WIDGET(text_buffer), 03760 GDK_SELECTION_CLIPBOARD); 03761 gtk_text_buffer_copy_clipboard (text_buffer, clipboard); 03762 } 03763 } 03764 03765 static void 03766 gnc_main_window_cmd_edit_paste (GtkAction *action, GncMainWindow *window) 03767 { 03768 GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); 03769 GtkTextBuffer *text_buffer; 03770 GtkClipboard *clipboard; 03771 gboolean editable; 03772 03773 if (GTK_IS_EDITABLE (widget)) 03774 { 03775 gtk_editable_paste_clipboard (GTK_EDITABLE (widget)); 03776 } 03777 else if (GTK_IS_TEXT_VIEW (widget)) 03778 { 03779 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(widget)); 03780 clipboard = gtk_widget_get_clipboard (GTK_WIDGET(text_buffer), 03781 GDK_SELECTION_CLIPBOARD); 03782 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)); 03783 gtk_text_buffer_paste_clipboard (text_buffer, clipboard, NULL, FALSE); 03784 } 03785 } 03786 03787 static void 03788 gnc_main_window_cmd_edit_preferences (GtkAction *action, GncMainWindow *window) 03789 { 03790 gnc_preferences_dialog (); 03791 } 03792 03793 static void 03794 gnc_main_window_cmd_view_refresh (GtkAction *action, GncMainWindow *window) 03795 { 03796 } 03797 03798 static void 03799 gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window) 03800 { 03801 gnc_reset_warnings_dialog(GTK_WINDOW(window)); 03802 } 03803 03804 static void 03805 gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window) 03806 { 03807 GncMainWindowPrivate *priv; 03808 GncPluginPage *page; 03809 GtkWidget *label, *entry; 03810 03811 ENTER(" "); 03812 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03813 page = priv->current_page; 03814 if (!page) 03815 { 03816 LEAVE("No current page"); 03817 return; 03818 } 03819 03820 if (!main_window_find_tab_items(window, page, &label, &entry)) 03821 { 03822 LEAVE("can't find required widgets"); 03823 return; 03824 } 03825 03826 gtk_entry_set_text(GTK_ENTRY(entry), gtk_label_get_text(GTK_LABEL(label))); 03827 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); 03828 gtk_widget_hide(label); 03829 gtk_widget_show(entry); 03830 gtk_widget_grab_focus(entry); 03831 LEAVE("opened for editing"); 03832 } 03833 03834 static void 03835 gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window) 03836 { 03837 GncMainWindowPrivate *priv; 03838 03839 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03840 if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) 03841 { 03842 gtk_widget_show (priv->toolbar); 03843 } 03844 else 03845 { 03846 gtk_widget_hide (priv->toolbar); 03847 } 03848 } 03849 03850 static void 03851 gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window) 03852 { 03853 GncMainWindowPrivate *priv; 03854 GList *item; 03855 gboolean visible; 03856 03857 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03858 visible = gnc_main_window_show_summarybar(window, action); 03859 for (item = priv->installed_pages; item; item = g_list_next(item)) 03860 { 03861 gnc_plugin_page_show_summarybar(item->data, visible); 03862 } 03863 } 03864 03865 static void 03866 gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window) 03867 { 03868 GncMainWindowPrivate *priv; 03869 03870 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03871 if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) 03872 { 03873 gtk_widget_show (priv->statusbar); 03874 } 03875 else 03876 { 03877 gtk_widget_hide (priv->statusbar); 03878 } 03879 } 03880 03881 static void 03882 gnc_main_window_cmd_window_new (GtkAction *action, GncMainWindow *window) 03883 { 03884 GncMainWindow *new_window; 03885 03886 /* Create the new window */ 03887 ENTER(" "); 03888 new_window = gnc_main_window_new (); 03889 gtk_widget_show(GTK_WIDGET(new_window)); 03890 LEAVE(" "); 03891 } 03892 03893 static void 03894 gnc_main_window_cmd_window_move_page (GtkAction *action, GncMainWindow *window) 03895 { 03896 GncMainWindowPrivate *priv, *new_priv; 03897 GncMainWindow *new_window; 03898 GncPluginPage *page; 03899 GtkNotebook *notebook; 03900 GtkWidget *tab_widget, *menu_widget; 03901 03902 ENTER("action %p,window %p", action, window); 03903 03904 /* Setup */ 03905 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 03906 page = priv->current_page; 03907 if (!page) 03908 { 03909 LEAVE("invalid page"); 03910 return; 03911 } 03912 if (!page->notebook_page) 03913 { 03914 LEAVE("invalid notebook_page"); 03915 return; 03916 } 03917 03918 notebook = GTK_NOTEBOOK (priv->notebook); 03919 tab_widget = gtk_notebook_get_tab_label (notebook, page->notebook_page); 03920 menu_widget = gtk_notebook_get_menu_label (notebook, page->notebook_page); 03921 03922 /* Ref the page components, then remove it from its old window */ 03923 g_object_ref(page); 03924 g_object_ref(tab_widget); 03925 g_object_ref(menu_widget); 03926 g_object_ref(page->notebook_page); 03927 gnc_main_window_disconnect(window, page); 03928 03929 /* Create the new window */ 03930 new_window = gnc_main_window_new (); 03931 gtk_widget_show(GTK_WIDGET(new_window)); 03932 03933 /* Now add the page to the new window */ 03934 gnc_main_window_connect (new_window, page, tab_widget, menu_widget); 03935 03936 /* Unref the page components now that we're done */ 03937 g_object_unref(page->notebook_page); 03938 g_object_unref(menu_widget); 03939 g_object_unref(tab_widget); 03940 g_object_unref(page); 03941 03942 /* just a little debugging. :-) */ 03943 new_priv = GNC_MAIN_WINDOW_GET_PRIVATE(new_window); 03944 DEBUG("Moved page %p from window %p to new window %p", 03945 page, window, new_window); 03946 DEBUG("Old window current is %p, new window current is %p", 03947 priv->current_page, priv->current_page); 03948 03949 LEAVE("page moved"); 03950 } 03951 03952 static void 03953 gnc_main_window_cmd_window_raise (GtkAction *action, 03954 GtkRadioAction *current, 03955 GncMainWindow *old_window) 03956 { 03957 GncMainWindow *new_window; 03958 gint value; 03959 03960 g_return_if_fail(GTK_IS_ACTION(action)); 03961 g_return_if_fail(GTK_IS_RADIO_ACTION(current)); 03962 g_return_if_fail(GNC_IS_MAIN_WINDOW(old_window)); 03963 03964 ENTER("action %p, current %p, window %p", action, current, old_window); 03965 value = gtk_radio_action_get_current_value(current); 03966 new_window = g_list_nth_data(active_windows, value); 03967 gtk_window_present(GTK_WINDOW(new_window)); 03968 #ifndef MAC_INTEGRATION 03969 /* revert the change in the radio group 03970 * impossible while handling "changed" (G_SIGNAL_NO_RECURSE) */ 03971 g_idle_add((GSourceFunc)gnc_main_window_update_radio_button, old_window); 03972 #endif 03973 LEAVE(" "); 03974 } 03975 03976 static void 03977 gnc_main_window_cmd_help_tutorial (GtkAction *action, GncMainWindow *window) 03978 { 03979 gnc_gnome_help (HF_GUIDE, NULL); 03980 } 03981 03982 static void 03983 gnc_main_window_cmd_help_contents (GtkAction *action, GncMainWindow *window) 03984 { 03985 gnc_gnome_help (HF_HELP, NULL); 03986 } 03987 03997 static gchar * 03998 get_file (const gchar *partial) 03999 { 04000 gchar *filename, *text = NULL; 04001 04002 filename = gnc_gnome_locate_data_file(partial); 04003 g_file_get_contents(filename, &text, NULL, NULL); 04004 g_free(filename); 04005 04006 /* Anything there? */ 04007 if (text && *text) 04008 return text; 04009 04010 /* Just a empty string or no string at all. */ 04011 if (text) 04012 g_free(text); 04013 return NULL; 04014 } 04015 04016 04026 static gchar ** 04027 get_file_strsplit (const gchar *partial) 04028 { 04029 gchar *text, **lines; 04030 04031 text = get_file(partial); 04032 if (!text) 04033 return NULL; 04034 04035 lines = g_strsplit_set(text, "\r\n", -1); 04036 g_free(text); 04037 return lines; 04038 } 04039 04040 04047 static void 04048 gnc_main_window_cmd_help_about (GtkAction *action, GncMainWindow *window) 04049 { 04050 const gchar *fixed_message = _("The GnuCash personal finance manager. " 04051 "The GNU way to manage your money!"); 04052 const gchar *copyright = "© 1997-2010 Contributors"; 04053 gchar **authors, **documenters, *license, *message; 04054 GdkPixbuf *logo; 04055 04056 logo = gnc_gnome_get_gdkpixbuf ("gnucash-icon-48x48.png"); 04057 04058 authors = get_file_strsplit("doc/AUTHORS"); 04059 documenters = get_file_strsplit("doc/DOCUMENTERS"); 04060 license = get_file("doc/LICENSE"); 04061 #ifdef GNUCASH_SVN 04062 /* Development version */ 04063 message = g_strdup_printf(_("%s This copy was built from svn r%s on %s."), 04064 fixed_message, GNUCASH_SVN_REV, GNUCASH_BUILD_DATE); 04065 #else 04066 message = g_strdup_printf(_("%s This copy was built from r%s on %s."), 04067 fixed_message, GNUCASH_SVN_REV, GNUCASH_BUILD_DATE); 04068 #endif 04069 gtk_show_about_dialog 04070 (GTK_WINDOW (window), 04071 "authors", authors, 04072 "documenters", documenters, 04073 "comments", message, 04074 "copyright", copyright, 04075 "license", license, 04076 "logo", logo, 04077 "name", "GnuCash", 04078 "translator-credits", _("translator_credits"), 04079 "version", VERSION, 04080 "website", "http://www.gnucash.org", 04081 (gchar *)NULL); 04082 04083 g_free(message); 04084 if (license) g_free(license); 04085 if (documenters) g_strfreev(documenters); 04086 if (authors) g_strfreev(authors); 04087 g_object_unref (logo); 04088 } 04089 04090 04091 /************************************************************ 04092 * * 04093 ************************************************************/ 04094 04095 void 04096 gnc_main_window_show_all_windows(void) 04097 { 04098 GList *window_iter; 04099 #ifdef MAC_INTEGRATION 04100 GtkOSXApplication *theApp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); 04101 #endif 04102 for (window_iter = active_windows; window_iter != NULL; window_iter = window_iter->next) 04103 { 04104 gtk_widget_show(GTK_WIDGET(window_iter->data)); 04105 #ifdef MAC_INTEGRATION 04106 gnc_quartz_set_menu(window_iter->data); 04107 #endif 04108 } 04109 #ifdef MAC_INTEGRATION 04110 g_signal_connect(theApp, "NSApplicationWillTerminate", 04111 G_CALLBACK(gnc_quartz_shutdown), NULL); 04112 gtk_osxapplication_ready(theApp); 04113 #endif 04114 } 04115 04120 GtkWidget * 04121 gnc_ui_get_toplevel (void) 04122 { 04123 GList *window; 04124 04125 for (window = active_windows; window; window = window->next) 04126 if (gtk_window_is_active (GTK_WINDOW (window->data))) 04127 return window->data; 04128 04129 return NULL; 04130 } 04131 04132 04138 static GtkWindow * 04139 gnc_main_window_get_gtk_window (GncWindow *window) 04140 { 04141 g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window), NULL); 04142 return GTK_WINDOW(window); 04143 } 04144 04145 04151 static GtkWidget * 04152 gnc_main_window_get_statusbar (GncWindow *window_in) 04153 { 04154 GncMainWindowPrivate *priv; 04155 GncMainWindow *window; 04156 04157 g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window_in), NULL); 04158 04159 window = GNC_MAIN_WINDOW(window_in); 04160 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 04161 return priv->statusbar; 04162 } 04163 04164 04170 static GtkWidget * 04171 gnc_main_window_get_progressbar (GncWindow *window_in) 04172 { 04173 GncMainWindowPrivate *priv; 04174 GncMainWindow *window; 04175 04176 g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window_in), NULL); 04177 04178 window = GNC_MAIN_WINDOW(window_in); 04179 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 04180 return priv->progressbar; 04181 } 04182 04183 04184 static void 04185 gnc_main_window_all_ui_set_sensitive (GncWindow *unused, gboolean sensitive) 04186 { 04187 GncMainWindow *window; 04188 GncMainWindowPrivate *priv; 04189 GList *groupp, *groups, *winp, *tmp; 04190 GtkWidget *close_button; 04191 04192 for (winp = active_windows; winp; winp = g_list_next(winp)) 04193 { 04194 window = winp->data; 04195 priv = GNC_MAIN_WINDOW_GET_PRIVATE(window); 04196 04197 groups = gtk_ui_manager_get_action_groups(window->ui_merge); 04198 for (groupp = groups; groupp; groupp = g_list_next(groupp)) 04199 { 04200 gtk_action_group_set_sensitive(GTK_ACTION_GROUP(groupp->data), sensitive); 04201 } 04202 04203 for (tmp = priv->installed_pages; tmp; tmp = g_list_next(tmp)) 04204 { 04205 close_button = g_object_get_data(tmp->data, PLUGIN_PAGE_CLOSE_BUTTON); 04206 if (!close_button) 04207 continue; 04208 gtk_widget_set_sensitive (close_button, sensitive); 04209 } 04210 } 04211 } 04212 04213 04218 static void 04219 gnc_window_main_window_init (GncWindowIface *iface) 04220 { 04221 iface->get_gtk_window = gnc_main_window_get_gtk_window; 04222 iface->get_statusbar = gnc_main_window_get_statusbar; 04223 iface->get_progressbar = gnc_main_window_get_progressbar; 04224 iface->ui_set_sensitive = gnc_main_window_all_ui_set_sensitive; 04225 } 04226 04227 04228 /* Set the window where all progressbar updates should occur. This 04229 * is a wrapper around the gnc_window_set_progressbar_window() 04230 * function. 04231 */ 04232 void 04233 gnc_main_window_set_progressbar_window (GncMainWindow *window) 04234 { 04235 GncWindow *gncwin; 04236 gncwin = GNC_WINDOW(window); 04237 gnc_window_set_progressbar_window(gncwin); 04238 } 04239 04240 04253 static void 04254 do_popup_menu(GncPluginPage *page, GdkEventButton *event) 04255 { 04256 GtkUIManager *ui_merge; 04257 GtkWidget *menu; 04258 int button, event_time; 04259 04260 g_return_if_fail(GNC_IS_PLUGIN_PAGE(page)); 04261 04262 ENTER("page %p, event %p", page, event); 04263 ui_merge = gnc_plugin_page_get_ui_merge(page); 04264 if (ui_merge == NULL) 04265 { 04266 LEAVE("no ui merge"); 04267 return; 04268 } 04269 04270 menu = gtk_ui_manager_get_widget(ui_merge, "/MainPopup"); 04271 if (!menu) 04272 { 04273 LEAVE("no menu"); 04274 return; 04275 } 04276 04277 if (event) 04278 { 04279 button = event->button; 04280 event_time = event->time; 04281 } 04282 else 04283 { 04284 button = 0; 04285 event_time = gtk_get_current_event_time (); 04286 } 04287 04288 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time); 04289 LEAVE(" "); 04290 } 04291 04292 04306 static gboolean 04307 gnc_main_window_popup_menu_cb (GtkWidget *widget, 04308 GncPluginPage *page) 04309 { 04310 ENTER("widget %p, page %p", widget, page); 04311 do_popup_menu(page, NULL); 04312 LEAVE(" "); 04313 return TRUE; 04314 } 04315 04316 04317 /* Callback function invoked when the user clicks in the content of 04318 * any Gnucash window. If this was a "right-click" then Gnucash will 04319 * popup the contextual menu. 04320 */ 04321 gboolean 04322 gnc_main_window_button_press_cb (GtkWidget *whatever, 04323 GdkEventButton *event, 04324 GncPluginPage *page) 04325 { 04326 g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE); 04327 04328 ENTER("widget %p, event %p, page %p", whatever, event, page); 04329 /* Ignore double-clicks and triple-clicks */ 04330 if (event->button == 3 && event->type == GDK_BUTTON_PRESS) 04331 { 04332 do_popup_menu(page, event); 04333 LEAVE("menu shown"); 04334 return TRUE; 04335 } 04336 04337 LEAVE("other click"); 04338 return FALSE; 04339 } 04340 04341 04342 /* CS: Code copied from gtk/gtkactiongroup.c */ 04343 static gchar * 04344 dgettext_swapped (const gchar *msgid, 04345 const gchar *domainname) 04346 { 04347 /* CS: Pass this through dgettext if and only if msgid is 04348 nonempty. */ 04349 return (msgid && *msgid) ? dgettext (domainname, msgid) : (gchar*) msgid; 04350 } 04351 04352 /* 04353 * This is copied into GnuCash from Gtk in order to fix problems when 04354 * empty msgids were passed through gettext(). 04355 * 04356 * See http://bugzilla.gnome.org/show_bug.cgi?id=326200 . If that bug 04357 * is fixed in the gtk that we can rely open, then 04358 * gnc_gtk_action_group_set_translation_domain can be replaced by 04359 * gtk_action_group_set_translation_domain again. 04360 */ 04361 void 04362 gnc_gtk_action_group_set_translation_domain (GtkActionGroup *action_group, 04363 const gchar *domain) 04364 { 04365 g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); 04366 04367 gtk_action_group_set_translate_func (action_group, 04368 (GtkTranslateFunc)dgettext_swapped, 04369 g_strdup (domain), 04370 g_free); 04371 } 04372 /* CS: End of code copied from gtk/gtkactiongroup.c */ 04373 04374 void 04375 gnc_main_window_all_action_set_sensitive (const gchar *action_name, 04376 gboolean sensitive) 04377 { 04378 GList *tmp; 04379 GtkAction *action; 04380 04381 for (tmp = active_windows; tmp; tmp = g_list_next(tmp)) 04382 { 04383 action = gnc_main_window_find_action (tmp->data, action_name); 04384 gtk_action_set_sensitive (action, sensitive); 04385 } 04386 } 04387 04388 GtkUIManager *gnc_main_window_get_uimanager (GncMainWindow *window) 04389 { 04390 g_assert(window); 04391 return window->ui_merge; 04392 } 04393
1.7.4