2005-11-02 03:32:36 +00:00
|
|
|
/*
|
|
|
|
|
* gnc-main-window.c -- GtkWindow which represents the
|
|
|
|
|
* GnuCash main window.
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
|
2006-01-23 06:38:20 +00:00
|
|
|
* Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org>
|
2005-11-02 03:32:36 +00:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, contact:
|
|
|
|
|
*
|
|
|
|
|
* Free Software Foundation Voice: +1-617-542-5942
|
2005-11-17 05:35:02 +00:00
|
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
|
|
|
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org
|
2005-11-02 03:32:36 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @addtogroup Windows
|
|
|
|
|
@{ */
|
|
|
|
|
/** @addtogroup GncMainWindow Main Window functions.
|
|
|
|
|
@{ */
|
|
|
|
|
/** @file gnc-main-window.c
|
|
|
|
|
@brief Functions for adding content to a window.
|
|
|
|
|
@author Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
|
2006-01-23 06:38:20 +00:00
|
|
|
@author Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org>
|
2005-11-02 03:32:36 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2005-11-19 23:53:34 +00:00
|
|
|
#include <gnome.h>
|
|
|
|
|
#include <glib/gi18n.h>
|
2005-11-11 14:16:12 +00:00
|
|
|
#ifndef HAVE_GLIB26
|
|
|
|
|
#include "gkeyfile.h"
|
|
|
|
|
#endif
|
2006-01-05 06:35:21 +00:00
|
|
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
|
|
|
#include <valgrind/callgrind.h>
|
|
|
|
|
#endif
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
#include "gnc-plugin.h"
|
|
|
|
|
#include "gnc-plugin-manager.h"
|
|
|
|
|
#include "gnc-main-window.h"
|
|
|
|
|
|
|
|
|
|
#include "dialog-preferences.h"
|
|
|
|
|
#include "dialog-reset-warnings.h"
|
|
|
|
|
#include "dialog-transfer.h"
|
|
|
|
|
#include "dialog-utils.h"
|
2005-11-11 14:16:12 +00:00
|
|
|
#include "file-utils.h"
|
2005-11-02 03:32:36 +00:00
|
|
|
#include "gnc-component-manager.h"
|
|
|
|
|
#include "gnc-engine.h"
|
|
|
|
|
#include "gnc-file.h"
|
2005-11-11 14:16:12 +00:00
|
|
|
#include "gnc-gkeyfile-utils.h"
|
2005-11-02 03:32:36 +00:00
|
|
|
#include "gnc-gnome-utils.h"
|
|
|
|
|
#include "gnc-gobject-utils.h"
|
|
|
|
|
#include "gnc-gui-query.h"
|
2005-11-11 14:16:12 +00:00
|
|
|
#include "gnc-hooks.h"
|
2005-11-02 03:32:36 +00:00
|
|
|
#include "gnc-session.h"
|
|
|
|
|
#include "gnc-ui.h"
|
|
|
|
|
#include "gnc-version.h"
|
|
|
|
|
#include "gnc-window.h"
|
2006-01-25 01:21:28 +00:00
|
|
|
#include "gnc-main.h"
|
2005-11-02 03:32:36 +00:00
|
|
|
#include "gnc-gconf-utils.h"
|
|
|
|
|
// +JSLED
|
|
|
|
|
#include "gnc-html.h"
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** Names of signals generated by the main window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
enum {
|
|
|
|
|
PAGE_ADDED,
|
|
|
|
|
PAGE_CHANGED,
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
|
};
|
|
|
|
|
|
2005-11-06 03:07:21 +00:00
|
|
|
/** This label is used to provide a mapping from a visible page widget
|
|
|
|
|
* back to the corresponding GncPluginPage object. */
|
|
|
|
|
#define PLUGIN_PAGE_LABEL "plugin-page"
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
#define PLUGIN_PAGE_IMMUTABLE "page-immutable"
|
|
|
|
|
#define PLUGIN_PAGE_CLOSE_BUTTON "close-button"
|
|
|
|
|
|
|
|
|
|
#define KEY_SHOW_CLOSE_BUTTON "tab_close_buttons"
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/* Static Globals *******************************************************/
|
|
|
|
|
|
|
|
|
|
/** The debugging module that this .o belongs to. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static QofLogModule log_module = GNC_MOD_GUI;
|
2005-11-14 05:14:21 +00:00
|
|
|
/** A pointer to the parent class of an embedded window. */
|
|
|
|
|
static GObjectClass *parent_class = NULL;
|
|
|
|
|
/** An identifier that indicates a "main" window. */
|
|
|
|
|
static GQuark window_type = 0;
|
|
|
|
|
/** A list of all extant main windows. This is for convenience as the
|
|
|
|
|
* same information can be obtained from the object tracking code. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GList *active_windows = NULL;
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/* Declarations *********************************************************/
|
2005-11-02 03:32:36 +00:00
|
|
|
static void gnc_main_window_class_init (GncMainWindowClass *klass);
|
|
|
|
|
static void gnc_main_window_init (GncMainWindow *window, GncMainWindowClass *klass);
|
|
|
|
|
static void gnc_main_window_finalize (GObject *object);
|
|
|
|
|
static void gnc_main_window_destroy (GtkObject *object);
|
|
|
|
|
|
|
|
|
|
static void gnc_main_window_setup_window (GncMainWindow *window);
|
|
|
|
|
static void gnc_window_main_window_init (GncWindowIface *iface);
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
static void main_window_update_page_name (GncMainWindow *window, GncPluginPage *page, const gchar *name_in);
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/* Callbacks */
|
|
|
|
|
static void gnc_main_window_add_widget (GtkUIManager *merge, GtkWidget *widget, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_switch_page (GtkNotebook *notebook, GtkNotebookPage *notebook_page, gint pos, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_plugin_added (GncPlugin *manager, GncPlugin *plugin, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_plugin_removed (GncPlugin *manager, GncPlugin *plugin, GncMainWindow *window);
|
|
|
|
|
|
|
|
|
|
/* Command callbacks */
|
|
|
|
|
static void gnc_main_window_cmd_file_properties (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_file_close (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_file_quit (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_edit_preferences (GtkAction *action, GncMainWindow *window);
|
2005-11-23 23:28:44 +00:00
|
|
|
static void gnc_main_window_cmd_edit_accelerator_keys (GtkToggleAction *action, GncMainWindow *window);
|
2005-11-02 03:32:36 +00:00
|
|
|
static void gnc_main_window_cmd_view_refresh (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window);
|
2006-01-05 06:35:21 +00:00
|
|
|
static void gnc_main_window_cmd_extensions_callgrind (GtkAction *action, GncMainWindow *window);
|
2005-11-02 03:32:36 +00:00
|
|
|
static void gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window);
|
2005-11-11 14:16:12 +00:00
|
|
|
static void gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window);
|
2005-11-02 03:32:36 +00:00
|
|
|
static void gnc_main_window_cmd_window_new (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_window_move_page (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_window_raise (GtkAction *action, GtkRadioAction *current, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_help_tutorial (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_help_contents (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
static void gnc_main_window_cmd_help_about (GtkAction *action, GncMainWindow *window);
|
|
|
|
|
|
|
|
|
|
static void do_popup_menu(GncPluginPage *page, GdkEventButton *event);
|
|
|
|
|
static gboolean gnc_main_window_popup_menu_cb (GtkWidget *widget, GncPluginPage *page);
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
static GtkAction *gnc_main_window_find_action (GncMainWindow *window, const gchar *name);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The instance private data structure for an embedded window
|
|
|
|
|
* object. */
|
2005-11-06 00:14:40 +00:00
|
|
|
typedef struct GncMainWindowPrivate
|
2005-11-02 03:32:36 +00:00
|
|
|
{
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The dock (vbox) at the top of the window containing the
|
|
|
|
|
* menubar and toolbar. These items are generated bu the UI
|
|
|
|
|
* manager and stored here when the UI manager provides them
|
|
|
|
|
* to the main window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkWidget *menu_dock;
|
2005-11-14 05:14:21 +00:00
|
|
|
/* The toolbar created by the UI manager. This pointer
|
|
|
|
|
* provides easy access for showing/hiding the toolbar. */
|
|
|
|
|
GtkWidget *toolbar;
|
|
|
|
|
/** The notebook containing all the pages in this window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkWidget *notebook;
|
2005-11-14 05:14:21 +00:00
|
|
|
/** A pointer to the status bar at the bottom edge of the
|
|
|
|
|
* window. This pointer provides easy access for
|
|
|
|
|
* updating/showing/hiding the status bar. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkWidget *statusbar;
|
2005-11-14 05:14:21 +00:00
|
|
|
/** A pointer to the progress bar at the bottom right of the
|
|
|
|
|
* window that is contained in the status bar. This pointer
|
|
|
|
|
* provides easy access for updating the progressbar. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkWidget *progressbar;
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The group of all actions provided by the main window
|
|
|
|
|
* itself. This does not include any action provided by menu
|
|
|
|
|
* or content plugins. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkActionGroup *action_group;
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** A list of all pages that are installed in this window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GList *installed_pages;
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The currently selected page. */
|
|
|
|
|
GncPluginPage *current_page;
|
|
|
|
|
/** The identifier for this window's engine event handler. */
|
2005-11-02 03:32:36 +00:00
|
|
|
gint event_handler_id;
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** A hash table of all action groups that have been installed
|
|
|
|
|
* into this window. The keys are the name of an action
|
|
|
|
|
* group, the values are structures of type
|
|
|
|
|
* MergedActionEntry. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GHashTable *merged_actions_table;
|
2005-11-06 00:14:40 +00:00
|
|
|
} GncMainWindowPrivate;
|
|
|
|
|
|
|
|
|
|
#define GNC_MAIN_WINDOW_GET_PRIVATE(o) \
|
|
|
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_MAIN_WINDOW, GncMainWindowPrivate))
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** This data structure maintains information about one action groups
|
|
|
|
|
* that has been installed in this window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
typedef struct {
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The merge identifier for this action group. This number
|
|
|
|
|
* is provided by the UI manager. */
|
2005-11-02 03:32:36 +00:00
|
|
|
guint merge_id;
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The action group itself. This contains all actions added
|
|
|
|
|
* by a single menu or content plugin. */
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkActionGroup *action_group;
|
|
|
|
|
} MergedActionEntry;
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** A holding place for all the signals generated by the main window
|
|
|
|
|
* code. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static guint main_window_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
|
|
|
|
/** An array of all of the actions provided by the main window code.
|
|
|
|
|
* This includes some placeholder actions for the menus that are
|
|
|
|
|
* visible in the menu bar but have no action associated with
|
|
|
|
|
* them. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GtkActionEntry gnc_menu_actions [] =
|
|
|
|
|
{
|
|
|
|
|
/* Toplevel */
|
|
|
|
|
|
|
|
|
|
{ "FileAction", NULL, N_("_File"), NULL, NULL, NULL, },
|
|
|
|
|
{ "EditAction", NULL, N_("_Edit"), NULL, NULL, NULL },
|
|
|
|
|
{ "ViewAction", NULL, N_("_View"), NULL, NULL, NULL },
|
|
|
|
|
{ "ActionsAction", NULL, N_("_Actions"), NULL, NULL, NULL },
|
|
|
|
|
{ "TransactionAction", NULL, N_("_Transaction"), NULL, NULL, NULL },
|
|
|
|
|
{ "ReportsAction", NULL, N_("_Reports"), NULL, NULL, NULL },
|
|
|
|
|
{ "ToolsAction", NULL, N_("_Tools"), NULL, NULL, NULL },
|
|
|
|
|
{ "ExtensionsAction", NULL, N_("E_xtensions"), NULL, NULL, NULL },
|
|
|
|
|
{ "WindowsAction", NULL, N_("_Windows"), NULL, NULL, NULL },
|
|
|
|
|
{ "HelpAction", NULL, N_("_Help"), NULL, NULL, NULL },
|
|
|
|
|
|
|
|
|
|
/* File menu */
|
|
|
|
|
|
|
|
|
|
{ "FileNewMenuAction", GTK_STOCK_NEW, N_("_New"), "", NULL, NULL },
|
|
|
|
|
{ "FileOpenMenuAction", GTK_STOCK_OPEN, N_("_Open"), "", NULL, NULL },
|
|
|
|
|
{ "FileImportAction", NULL, N_("_Import"), NULL, NULL, NULL },
|
|
|
|
|
{ "FileExportAction", NULL, N_("_Export"), NULL, NULL, NULL },
|
2006-01-08 21:37:30 +00:00
|
|
|
{ "FilePrintAction", GTK_STOCK_PRINT, N_("_Print..."), "<control>p",
|
|
|
|
|
N_("Print the currently active page"), NULL },
|
2005-11-25 21:27:26 +00:00
|
|
|
{ "FilePropertiesAction", GTK_STOCK_PROPERTIES, N_("Proper_ties"), "<Alt>Return",
|
2006-01-08 21:37:30 +00:00
|
|
|
N_("Edit the properties of the current file"),
|
2005-11-02 03:32:36 +00:00
|
|
|
G_CALLBACK (gnc_main_window_cmd_file_properties) },
|
|
|
|
|
{ "FileCloseAction", GTK_STOCK_CLOSE, N_("_Close"), NULL,
|
2006-01-08 21:37:30 +00:00
|
|
|
N_("Close the currently active page"),
|
2005-11-02 03:32:36 +00:00
|
|
|
G_CALLBACK (gnc_main_window_cmd_file_close) },
|
|
|
|
|
{ "FileQuitAction", GTK_STOCK_QUIT, N_("_Quit"), NULL,
|
2006-01-08 21:37:30 +00:00
|
|
|
N_("Quit this application"),
|
2005-11-02 03:32:36 +00:00
|
|
|
G_CALLBACK (gnc_main_window_cmd_file_quit) },
|
|
|
|
|
|
|
|
|
|
/* Edit menu */
|
|
|
|
|
|
2006-01-08 21:37:30 +00:00
|
|
|
{ "EditCutAction", GTK_STOCK_CUT, N_("Cu_t"), NULL,
|
|
|
|
|
N_("Cut the current selection and copy it to clipboard"), NULL },
|
|
|
|
|
{ "EditCopyAction", GTK_STOCK_COPY, N_("_Copy"), NULL,
|
|
|
|
|
N_("Copy the current selection to clipboard"), NULL },
|
|
|
|
|
{ "EditPasteAction", GTK_STOCK_PASTE, N_("_Paste"), NULL,
|
|
|
|
|
N_("Paste the clipboard content at the cursor position"), NULL },
|
2005-11-02 03:32:36 +00:00
|
|
|
{ "EditPreferencesAction", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), NULL,
|
2006-01-08 21:37:30 +00:00
|
|
|
N_("Edit the global preferences of GnuCash"),
|
2005-11-02 03:32:36 +00:00
|
|
|
G_CALLBACK (gnc_main_window_cmd_edit_preferences) },
|
|
|
|
|
|
|
|
|
|
/* View menu */
|
|
|
|
|
|
2006-01-08 21:37:30 +00:00
|
|
|
{ "ViewSortByAction", NULL, N_("_Sort By..."), NULL,
|
|
|
|
|
N_("Select sorting criteria for this page view"), NULL },
|
2005-12-31 12:02:22 +00:00
|
|
|
{ "ViewFilterByAction", NULL, N_("_Filter By..."), NULL,
|
|
|
|
|
N_("Select the account types that should be displayed."), NULL },
|
2005-11-02 03:32:36 +00:00
|
|
|
{ "ViewRefreshAction", GTK_STOCK_REFRESH, N_("_Refresh"), "<control>r",
|
|
|
|
|
N_("Refresh this window"),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_view_refresh) },
|
|
|
|
|
|
|
|
|
|
/* Actions menu */
|
|
|
|
|
|
|
|
|
|
{ "ScrubMenuAction", NULL, N_("_Check & Repair"), NULL, NULL, NULL },
|
|
|
|
|
{ "ActionsForgetWarningsAction", NULL, N_("_Reset Warnings..."), NULL,
|
|
|
|
|
N_("Reset the state of all warning message so they will be shown again."),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_actions_reset_warnings) },
|
2005-11-11 14:16:12 +00:00
|
|
|
{ "ActionsRenamePageAction", NULL, N_("Rename Page"), NULL,
|
|
|
|
|
N_("Rename this page."),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_actions_rename_page) },
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
/* Windows menu */
|
|
|
|
|
|
|
|
|
|
{ "WindowNewAction", NULL, N_("_New Window"), NULL,
|
|
|
|
|
N_("Open a new top-level GnuCash window."),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_window_new) },
|
|
|
|
|
{ "WindowMovePageAction", NULL, N_("New Window with _Page"), NULL,
|
|
|
|
|
N_("Move the current page to a new top-level GnuCash window."),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_window_move_page) },
|
|
|
|
|
|
|
|
|
|
/* Help menu */
|
|
|
|
|
|
|
|
|
|
{ "HelpTutorialAction", GNOME_STOCK_BOOK_BLUE, N_("Tutorial and Concepts _Guide"), NULL,
|
|
|
|
|
N_("Open the GnuCash Tutorial"),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_help_tutorial) },
|
2005-11-25 21:27:26 +00:00
|
|
|
{ "HelpContentsAction", GTK_STOCK_HELP, N_("_Contents"), "F1",
|
2005-11-02 03:32:36 +00:00
|
|
|
N_("Open the GnuCash Help"),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_help_contents) },
|
|
|
|
|
{ "HelpAboutAction", GNOME_STOCK_ABOUT, N_("_About"), NULL,
|
2006-01-08 21:37:30 +00:00
|
|
|
N_("About GnuCash"),
|
2005-11-02 03:32:36 +00:00
|
|
|
G_CALLBACK (gnc_main_window_cmd_help_about) },
|
|
|
|
|
};
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The number of actions provided by the main window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static guint gnc_menu_n_actions = G_N_ELEMENTS (gnc_menu_actions);
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** An array of all of the toggle action provided by the main window
|
|
|
|
|
* code. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GtkToggleActionEntry toggle_actions [] =
|
|
|
|
|
{
|
2005-11-23 23:28:44 +00:00
|
|
|
{ "EditAcceleratorKeysAction", NULL, N_("Learn Accelerator Keys"), NULL,
|
|
|
|
|
N_("Learn new accelerator key settings."),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_edit_accelerator_keys), FALSE },
|
2005-11-02 03:32:36 +00:00
|
|
|
{ "ViewToolbarAction", NULL, N_("_Toolbar"), NULL,
|
|
|
|
|
N_("Show/hide the toolbar on this window"),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_view_toolbar), TRUE },
|
|
|
|
|
{ "ViewSummaryAction", NULL, N_("Su_mmary Bar"), NULL,
|
|
|
|
|
N_("Show/hide the summary bar on this window"),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_view_summary), TRUE },
|
|
|
|
|
{ "ViewStatusbarAction", NULL, N_("Stat_us Bar"), NULL,
|
|
|
|
|
N_("Show/hide the status bar on this window"),
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_view_statusbar), TRUE },
|
2006-01-05 06:35:21 +00:00
|
|
|
{ "ExtensionsCallgrindAction", NULL, "Use Callgrind", NULL,
|
|
|
|
|
"Enable/disable the Valgrind/Callgrind profiling tool.",
|
|
|
|
|
G_CALLBACK (gnc_main_window_cmd_extensions_callgrind), FALSE },
|
2005-11-02 03:32:36 +00:00
|
|
|
};
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The number of toggle actions provided by the main window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static guint n_toggle_actions = G_N_ELEMENTS (toggle_actions);
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** An array of all of the radio action provided by the main window
|
|
|
|
|
* code. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GtkRadioActionEntry radio_entries [] =
|
|
|
|
|
{
|
|
|
|
|
{ "Window0Action", NULL, N_("Window _1"), NULL, NULL, 0 },
|
|
|
|
|
{ "Window1Action", NULL, N_("Window _2"), NULL, NULL, 1 },
|
|
|
|
|
{ "Window2Action", NULL, N_("Window _3"), NULL, NULL, 2 },
|
|
|
|
|
{ "Window3Action", NULL, N_("Window _4"), NULL, NULL, 3 },
|
|
|
|
|
{ "Window4Action", NULL, N_("Window _5"), NULL, NULL, 4 },
|
|
|
|
|
{ "Window5Action", NULL, N_("Window _6"), NULL, NULL, 5 },
|
|
|
|
|
{ "Window6Action", NULL, N_("Window _7"), NULL, NULL, 6 },
|
|
|
|
|
{ "Window7Action", NULL, N_("Window _8"), NULL, NULL, 7 },
|
|
|
|
|
{ "Window8Action", NULL, N_("Window _9"), NULL, NULL, 8 },
|
|
|
|
|
{ "Window9Action", NULL, N_("Window _0"), NULL, NULL, 9 },
|
|
|
|
|
};
|
2005-11-14 05:14:21 +00:00
|
|
|
/** The number of radio actions provided by the main window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static guint n_radio_entries = G_N_ELEMENTS (radio_entries);
|
|
|
|
|
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** These are the "important" actions provided by the main window.
|
|
|
|
|
* Their labels will appear when the toolbar is set to "Icons and
|
|
|
|
|
* important text" (e.g. GTK_TOOLBAR_BOTH_HORIZ) mode. */
|
2005-11-03 00:49:05 +00:00
|
|
|
static const gchar *gnc_menu_important_actions[] = {
|
|
|
|
|
"FileCloseAction",
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/** The following are in the main window so they will always be
|
|
|
|
|
* present in the menu structure, but they are never sensitive.
|
|
|
|
|
* These actions should be overridden in child windows where they
|
|
|
|
|
* have meaning. */
|
|
|
|
|
static const gchar *always_insensitive_actions[] = {
|
|
|
|
|
"FilePrintAction",
|
|
|
|
|
"EditCutAction",
|
|
|
|
|
"EditCopyAction",
|
|
|
|
|
"EditPasteAction",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
2005-12-30 05:07:14 +00:00
|
|
|
/** The following are in the main window so they will always be
|
|
|
|
|
* present in the menu structure, but they are always hidden.
|
|
|
|
|
* These actions should be overridden in child windows where they
|
|
|
|
|
* have meaning. */
|
|
|
|
|
static const gchar *always_hidden_actions[] = {
|
|
|
|
|
"ViewSortByAction",
|
|
|
|
|
"ViewFilterByAction",
|
2006-01-05 06:35:21 +00:00
|
|
|
#ifndef HAVE_VALGRIND_CALLGRIND_H
|
|
|
|
|
"ExtensionsCallgrindAction",
|
|
|
|
|
#endif
|
2005-12-30 05:07:14 +00:00
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/** If a page is flagged as immutable, then the following actions
|
2005-11-14 05:14:21 +00:00
|
|
|
* cannot be performed on that page. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static const gchar *immutable_page_actions[] = {
|
|
|
|
|
"FileCloseAction",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/** The following actions can only be performed if there are multiple
|
|
|
|
|
* pages in a window. */
|
|
|
|
|
static const gchar *multiple_page_actions[] = {
|
|
|
|
|
"WindowMovePageAction",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
|
* *
|
|
|
|
|
************************************************************/
|
2005-11-11 14:16:12 +00:00
|
|
|
#define WINDOW_COUNT "Window Count"
|
|
|
|
|
#define WINDOW_STRING "Window %d"
|
|
|
|
|
#define WINDOW_GEOMETRY "Window Geometry"
|
|
|
|
|
#define WINDOW_POSITION "Window Position"
|
2005-12-20 02:06:43 +00:00
|
|
|
#define WINDOW_MAXIMIZED "Window Maximized"
|
2005-11-11 14:16:12 +00:00
|
|
|
#define WINDOW_FIRSTPAGE "First Page"
|
|
|
|
|
#define WINDOW_PAGECOUNT "Page Count"
|
|
|
|
|
#define PAGE_TYPE "Page Type"
|
|
|
|
|
#define PAGE_NAME "Page Name"
|
|
|
|
|
#define PAGE_STRING "Page %d"
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
GKeyFile *key_file;
|
|
|
|
|
const gchar *group_name;
|
|
|
|
|
gint window_num;
|
|
|
|
|
gint page_num;
|
|
|
|
|
gint page_offset;
|
|
|
|
|
} GncMainWindowSaveData;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Restore a single page to a window. This function calls a page
|
|
|
|
|
* specific function to create the actual page. It then handles all
|
|
|
|
|
* the common tasks such as insuring the page is installed into a
|
|
|
|
|
* window, updating the page name, and anything else that might be
|
|
|
|
|
* common to all pages.
|
|
|
|
|
*
|
|
|
|
|
* @param window The GncMainWindow where the new page will be
|
|
|
|
|
* installed.
|
|
|
|
|
*
|
|
|
|
|
* @param data A data structure containing state about the
|
|
|
|
|
* window/page restoration process. */
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_restore_page (GncMainWindow *window, GncMainWindowSaveData *data)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GncPluginPage *page;
|
|
|
|
|
gchar *page_group, *page_type = NULL, *name = NULL;
|
|
|
|
|
const gchar *class_type;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
ENTER("window %p, data %p (key file %p, window %d, page start %d, page num %d)",
|
|
|
|
|
window, data, data->key_file, data->window_num, data->page_offset, data->page_num);
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
page_group = g_strdup_printf(PAGE_STRING, data->page_offset + data->page_num);
|
|
|
|
|
page_type = g_key_file_get_string(data->key_file, page_group,
|
|
|
|
|
PAGE_TYPE, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
page_group, PAGE_TYPE, error->message);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if the page already exists. */
|
|
|
|
|
page = g_list_nth_data(priv->installed_pages, data->page_num);
|
|
|
|
|
if (page) {
|
|
|
|
|
class_type = GNC_PLUGIN_PAGE_GET_CLASS(page)->plugin_name;
|
|
|
|
|
if (strcmp(page_type, class_type) != 0) {
|
|
|
|
|
g_warning("error: page types don't match: state %s, existing page %s",
|
|
|
|
|
page_type, class_type);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* create and install the page */
|
|
|
|
|
page = gnc_plugin_page_recreate_page(GTK_WIDGET(window), page_type,
|
|
|
|
|
data->key_file, page_group);
|
|
|
|
|
if (page) {
|
|
|
|
|
/* Does the page still need to be installed into the window? */
|
|
|
|
|
if (page->window == NULL) {
|
|
|
|
|
gnc_main_window_open_page(window, page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Restore the page name */
|
|
|
|
|
name = g_key_file_get_string(data->key_file, page_group,
|
|
|
|
|
PAGE_NAME, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
page_group, PAGE_NAME, error->message);
|
|
|
|
|
/* Fall through and still show the page. */
|
|
|
|
|
} else {
|
|
|
|
|
DEBUG("updating page name for %p to %s.", page, name);
|
|
|
|
|
main_window_update_page_name(window, page, name);
|
|
|
|
|
g_free(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LEAVE("ok");
|
|
|
|
|
cleanup:
|
|
|
|
|
if (error)
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
if (page_type)
|
|
|
|
|
g_free(page_type);
|
|
|
|
|
g_free(page_group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Restore all the pages in a given window. This function restores
|
|
|
|
|
* all the window specific attributes, then calls a helper function
|
|
|
|
|
* to restore all the pages that are contained in the window.
|
|
|
|
|
*
|
|
|
|
|
* @param window The GncMainWindow whose pages should be restored.
|
|
|
|
|
*
|
|
|
|
|
* @param data A data structure containing state about the
|
|
|
|
|
* window/page restoration process. */
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_restore_window (GncMainWindow *window, GncMainWindowSaveData *data)
|
|
|
|
|
{
|
|
|
|
|
gint *pos, *geom;
|
|
|
|
|
gsize length;
|
2005-12-20 02:06:43 +00:00
|
|
|
gboolean max;
|
2005-11-11 14:16:12 +00:00
|
|
|
gchar *window_group;
|
|
|
|
|
gint page_start, page_count, i;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
/* Setup */
|
|
|
|
|
ENTER("window %p, data %p (key file %p, window %d)",
|
|
|
|
|
window, data, data->key_file, data->window_num);
|
|
|
|
|
window_group = g_strdup_printf(WINDOW_STRING, data->window_num + 1);
|
|
|
|
|
|
2006-01-20 01:02:57 +00:00
|
|
|
/* Get this window's notebook info */
|
|
|
|
|
page_count = g_key_file_get_integer(data->key_file,
|
|
|
|
|
window_group, WINDOW_PAGECOUNT, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
window_group, WINDOW_PAGECOUNT, error->message);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
if (page_count == 0) {
|
|
|
|
|
/* Shound never happen, but has during alpha testing. Having this
|
|
|
|
|
* check doesn't hurt anything. */
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
page_start = g_key_file_get_integer(data->key_file,
|
|
|
|
|
window_group, WINDOW_FIRSTPAGE, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
window_group, WINDOW_FIRSTPAGE, error->message);
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Build a window if we don't already have one */
|
|
|
|
|
if (window == NULL) {
|
|
|
|
|
DEBUG("Window %d doesn't exist. Creating new window.", data->window_num);
|
|
|
|
|
DEBUG("active_windows %p.", active_windows);
|
|
|
|
|
if (active_windows)
|
|
|
|
|
DEBUG("first window %p.", active_windows->data);
|
|
|
|
|
window = gnc_main_window_new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the window coordinates, etc. */
|
2005-11-11 14:16:12 +00:00
|
|
|
pos = g_key_file_get_integer_list(data->key_file, window_group,
|
|
|
|
|
WINDOW_POSITION, &length, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
window_group, WINDOW_POSITION, error->message);
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
error = NULL;
|
|
|
|
|
} else if (length != 2) {
|
|
|
|
|
g_warning("invalid number of values for group %s key %s",
|
|
|
|
|
window_group, WINDOW_POSITION);
|
|
|
|
|
} else {
|
|
|
|
|
gtk_window_move(GTK_WINDOW(window), pos[0], pos[1]);
|
|
|
|
|
DEBUG("window (%p) position %dx%d", window, pos[0], pos[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
geom = g_key_file_get_integer_list(data->key_file, window_group,
|
|
|
|
|
WINDOW_GEOMETRY, &length, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
window_group, WINDOW_GEOMETRY, error->message);
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
error = NULL;
|
|
|
|
|
} else if (length != 2) {
|
|
|
|
|
g_warning("invalid number of values for group %s key %s",
|
|
|
|
|
window_group, WINDOW_GEOMETRY);
|
|
|
|
|
} else {
|
|
|
|
|
gtk_window_resize(GTK_WINDOW(window), geom[0], geom[1]);
|
|
|
|
|
DEBUG("window (%p) size %dx%d", window, geom[0], geom[1]);
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-20 02:06:43 +00:00
|
|
|
max = g_key_file_get_boolean(data->key_file, window_group,
|
|
|
|
|
WINDOW_MAXIMIZED, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
window_group, WINDOW_MAXIMIZED, error->message);
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
error = NULL;
|
|
|
|
|
} else if (max) {
|
|
|
|
|
gtk_window_maximize(GTK_WINDOW(window));
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-20 01:02:57 +00:00
|
|
|
/* Now populate the window with pages. */
|
2005-11-11 14:16:12 +00:00
|
|
|
for (i = 0; i < page_count; i++) {
|
|
|
|
|
data->page_offset = page_start;
|
|
|
|
|
data->page_num = i;
|
|
|
|
|
gnc_main_window_restore_page(window, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LEAVE("window %p", window);
|
|
|
|
|
cleanup:
|
|
|
|
|
if (error)
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
g_free(window_group);
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-26 17:38:26 +00:00
|
|
|
void
|
|
|
|
|
gnc_main_window_restore_all_windows(const GKeyFile *keyfile)
|
2005-11-11 14:16:12 +00:00
|
|
|
{
|
|
|
|
|
gint i, window_count;
|
|
|
|
|
GError *error = NULL;
|
2006-01-26 17:38:26 +00:00
|
|
|
GncMainWindowSaveData data;
|
|
|
|
|
GncMainWindow *window;
|
2005-11-11 14:16:12 +00:00
|
|
|
|
2006-01-26 17:38:26 +00:00
|
|
|
/* We use the same struct for reading and for writing, so we cast
|
|
|
|
|
away the const. */
|
|
|
|
|
data.key_file = (GKeyFile *) keyfile;
|
|
|
|
|
window_count = g_key_file_get_integer(data.key_file, STATE_FILE_TOP,
|
|
|
|
|
WINDOW_COUNT, &error);
|
2005-11-11 14:16:12 +00:00
|
|
|
if (error) {
|
|
|
|
|
g_warning("error reading group %s key %s: %s",
|
|
|
|
|
STATE_FILE_TOP, WINDOW_COUNT, error->message);
|
2006-01-26 17:38:26 +00:00
|
|
|
g_error_free(error);
|
2005-11-11 14:16:12 +00:00
|
|
|
LEAVE("can't read count");
|
2006-01-26 17:38:26 +00:00
|
|
|
return;
|
2005-11-11 14:16:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Restore all state information on the open windows. Window
|
|
|
|
|
numbers in state file are 1-based. GList indices are 0-based. */
|
|
|
|
|
for (i = 0; i < window_count; i++) {
|
|
|
|
|
data.window_num = i;
|
|
|
|
|
window = g_list_nth_data(active_windows, i);
|
|
|
|
|
gnc_main_window_restore_window(window, &data);
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2006-01-26 17:38:26 +00:00
|
|
|
void
|
|
|
|
|
gnc_main_window_restore_default_state(void)
|
|
|
|
|
{
|
|
|
|
|
GtkAction *action;
|
|
|
|
|
GncMainWindow *window;
|
|
|
|
|
|
|
|
|
|
/* The default state should be to have an Account Tree page open
|
|
|
|
|
* in the window. */
|
|
|
|
|
DEBUG("no saved state file");
|
|
|
|
|
window = g_list_nth_data(active_windows, 0);
|
|
|
|
|
action = gnc_main_window_find_action(window, "FileNewAccountTreeAction");
|
|
|
|
|
gtk_action_activate(action);
|
|
|
|
|
}
|
2005-11-11 14:16:12 +00:00
|
|
|
|
|
|
|
|
/** Save the state of a single page to a disk. This function handles
|
|
|
|
|
* all the common tasks such as saving the page type and name, and
|
|
|
|
|
* anything else that might be common to all pages. It then calls a
|
|
|
|
|
* page specific function to save the actual page.
|
|
|
|
|
*
|
|
|
|
|
* @param page The GncPluginPage whose state should be saved.
|
|
|
|
|
*
|
|
|
|
|
* @param data A data structure containing state about the
|
|
|
|
|
* window/page saving process. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
2005-11-11 14:16:12 +00:00
|
|
|
gnc_main_window_save_page (GncPluginPage *page, GncMainWindowSaveData *data)
|
2005-11-02 03:32:36 +00:00
|
|
|
{
|
2005-11-11 14:16:12 +00:00
|
|
|
gchar *page_group;
|
2006-01-27 04:38:47 +00:00
|
|
|
const gchar *plugin_name, *page_name;
|
2005-11-11 14:16:12 +00:00
|
|
|
|
|
|
|
|
ENTER("page %p, data %p (key file %p, window %d, page %d)",
|
|
|
|
|
page, data, data->key_file, data->window_num, data->page_num);
|
2006-01-27 04:38:47 +00:00
|
|
|
plugin_name = gnc_plugin_page_get_plugin_name(page);
|
|
|
|
|
page_name = gnc_plugin_page_get_page_name(page);
|
|
|
|
|
if (!plugin_name || !page_name) {
|
|
|
|
|
LEAVE("not saving invalid page");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2005-11-11 14:16:12 +00:00
|
|
|
page_group = g_strdup_printf(PAGE_STRING, data->page_num++);
|
2006-01-27 04:38:47 +00:00
|
|
|
g_key_file_set_string(data->key_file, page_group, PAGE_TYPE, plugin_name);
|
|
|
|
|
g_key_file_set_string(data->key_file, page_group, PAGE_NAME, page_name);
|
2005-11-11 14:16:12 +00:00
|
|
|
|
|
|
|
|
gnc_plugin_page_save_page(page, data->key_file, page_group);
|
|
|
|
|
g_free(page_group);
|
|
|
|
|
LEAVE(" ");
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
|
|
|
|
|
/** Saves all the pages in a single window to a disk. This function
|
|
|
|
|
* saves all the window specific attributes, then calls a helper
|
|
|
|
|
* function to save all the pages that are contained in the window.
|
|
|
|
|
*
|
|
|
|
|
* @param window The GncMainWindow whose pages should be saved.
|
|
|
|
|
*
|
|
|
|
|
* @param data A data structure containing state about the
|
|
|
|
|
* window/page saving process. */
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_save_window (GncMainWindow *window, GncMainWindowSaveData *data)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
gint num_pages, coords[4];
|
2005-12-20 02:06:43 +00:00
|
|
|
gboolean maximized;
|
2005-11-11 14:16:12 +00:00
|
|
|
gchar *window_group;
|
|
|
|
|
|
|
|
|
|
/* Setup */
|
|
|
|
|
ENTER("window %p, data %p (key file %p, window %d)",
|
|
|
|
|
window, data, data->key_file, data->window_num);
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2006-01-20 01:02:57 +00:00
|
|
|
|
|
|
|
|
/* Check for bogus window structures. */
|
|
|
|
|
num_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook));
|
|
|
|
|
if (0 == num_pages) {
|
|
|
|
|
LEAVE("empty window %p", window);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Save this window's notebook info */
|
2005-11-11 14:16:12 +00:00
|
|
|
window_group = g_strdup_printf(WINDOW_STRING, data->window_num++);
|
2006-01-20 01:02:57 +00:00
|
|
|
g_key_file_set_integer(data->key_file, window_group,
|
|
|
|
|
WINDOW_PAGECOUNT, num_pages);
|
|
|
|
|
g_key_file_set_integer(data->key_file, window_group,
|
|
|
|
|
WINDOW_FIRSTPAGE, data->page_num);
|
2005-11-11 14:16:12 +00:00
|
|
|
|
|
|
|
|
/* Save the window coordinates, etc. */
|
|
|
|
|
gtk_window_get_position(GTK_WINDOW(window), &coords[0], &coords[1]);
|
|
|
|
|
gtk_window_get_size(GTK_WINDOW(window), &coords[2], &coords[3]);
|
2005-12-20 02:06:43 +00:00
|
|
|
maximized = (gdk_window_get_state((GTK_WIDGET(window))->window)
|
|
|
|
|
& GDK_WINDOW_STATE_MAXIMIZED) != 0;
|
2005-11-11 14:16:12 +00:00
|
|
|
g_key_file_set_integer_list(data->key_file, window_group,
|
|
|
|
|
WINDOW_POSITION, &coords[0], 2);
|
|
|
|
|
g_key_file_set_integer_list(data->key_file, window_group,
|
|
|
|
|
WINDOW_GEOMETRY, &coords[2], 2);
|
2005-12-20 02:06:43 +00:00
|
|
|
g_key_file_set_boolean(data->key_file, window_group,
|
|
|
|
|
WINDOW_MAXIMIZED, maximized);
|
|
|
|
|
DEBUG("window (%p) position %dx%d, size %dx%d, %s", window, coords[0], coords[1],
|
|
|
|
|
coords[2], coords[3],
|
|
|
|
|
maximized ? "maximized" : "not maximized");
|
2005-11-11 14:16:12 +00:00
|
|
|
|
|
|
|
|
/* Save individual pages in this window */
|
|
|
|
|
g_list_foreach(priv->installed_pages, (GFunc)gnc_main_window_save_page, data);
|
|
|
|
|
|
|
|
|
|
g_free(window_group);
|
|
|
|
|
LEAVE("window %p", window);
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-26 17:38:26 +00:00
|
|
|
void
|
|
|
|
|
gnc_main_window_save_all_windows(GKeyFile *keyfile)
|
2005-11-02 03:32:36 +00:00
|
|
|
{
|
2006-01-26 17:38:26 +00:00
|
|
|
GncMainWindowSaveData data;
|
|
|
|
|
|
|
|
|
|
/* Set up the iterator data structures */
|
|
|
|
|
data.key_file = keyfile;
|
|
|
|
|
data.window_num = 1;
|
|
|
|
|
data.page_num = 1;
|
|
|
|
|
|
|
|
|
|
g_key_file_set_integer(data.key_file,
|
|
|
|
|
STATE_FILE_TOP, WINDOW_COUNT,
|
|
|
|
|
g_list_length(active_windows));
|
|
|
|
|
/* Dump all state information on the open windows */
|
|
|
|
|
g_list_foreach(active_windows, (GFunc)gnc_main_window_save_window, &data);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** See if the page already exists. For each open window, look
|
|
|
|
|
* through the list of pages installed in that window and see if the
|
|
|
|
|
* specified page is there.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*
|
|
|
|
|
* @param page The page to search for.
|
|
|
|
|
*
|
|
|
|
|
* @return TRUE if the page is present in the window, FALSE otherwise.
|
|
|
|
|
*/
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_page_exists (GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GList *walker;
|
|
|
|
|
|
|
|
|
|
for (walker = active_windows; walker; walker = g_list_next(walker)) {
|
|
|
|
|
window = walker->data;
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (g_list_find(priv->installed_pages, page)) {
|
2005-11-02 03:32:36 +00:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** This function prompts the user to save the file with a dialog that
|
|
|
|
|
* follows the HIG guidelines.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*
|
|
|
|
|
* @returns This function returns TRUE if the user clicked the Cancel
|
|
|
|
|
* button. It returns FALSE if the closing of the window should
|
|
|
|
|
* continue.
|
|
|
|
|
*/
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_prompt_for_save (GtkWidget *window)
|
|
|
|
|
{
|
|
|
|
|
QofSession *session;
|
|
|
|
|
QofBook *book;
|
|
|
|
|
GtkWidget *dialog;
|
|
|
|
|
gint response;
|
|
|
|
|
const gchar *filename, *tmp;
|
2006-01-29 16:06:16 +00:00
|
|
|
const gchar *title = _("Save changes to file %s before closing?");
|
2005-11-02 03:32:36 +00:00
|
|
|
#ifdef HIG_COMPLIANT
|
|
|
|
|
gint oldest_change, minutes;
|
2006-01-29 16:06:16 +00:00
|
|
|
const gchar *message =
|
|
|
|
|
_("If you don't save, changes from the past %d minutes will be discarded.");
|
|
|
|
|
#else
|
|
|
|
|
const gchar *message =
|
|
|
|
|
_("Changes have been made since the last time it was saved. If you "
|
|
|
|
|
"continue without saving these changes will be discarded.");
|
2005-11-02 03:32:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
session = qof_session_get_current_session();
|
|
|
|
|
book = qof_session_get_book(session);
|
|
|
|
|
filename = qof_session_get_file_path(session);
|
|
|
|
|
if (filename == NULL)
|
|
|
|
|
filename = _("<unknown>");
|
|
|
|
|
if ((tmp = rindex(filename, '/')) != NULL)
|
|
|
|
|
filename = tmp + 1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* *** THIS DIALOG IS NOT HIG COMPLIANT. ***
|
|
|
|
|
*
|
|
|
|
|
* According to the HIG, the secondary context should include
|
|
|
|
|
* context about the number of changes that will be lost (either in
|
|
|
|
|
* time or a count). While it is possible to simply provide the
|
2005-11-14 05:14:21 +00:00
|
|
|
* time since the last save, that doesn't appear too useful. If
|
2005-11-02 03:32:36 +00:00
|
|
|
* the user has had Gnucash open for hours in the background, but
|
|
|
|
|
* only made a change in the last few minutes, then telling them
|
|
|
|
|
* they will lose hours work of work is wring. The QOF code needs
|
|
|
|
|
* to be modified to provide better timing information. The best
|
|
|
|
|
* case scenario would be if QOF could provide a timestamp of the
|
|
|
|
|
* oldest unsaved change.
|
|
|
|
|
*/
|
2006-01-29 16:06:16 +00:00
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
|
|
|
|
|
GTK_DIALOG_MODAL,
|
|
|
|
|
GTK_MESSAGE_WARNING,
|
|
|
|
|
GTK_BUTTONS_NONE,
|
|
|
|
|
title,
|
|
|
|
|
filename);
|
2005-11-02 03:32:36 +00:00
|
|
|
#ifdef HIG_COMPLIANT
|
|
|
|
|
oldest_change = qof_book_time_changed(book);
|
|
|
|
|
minutes = (time() - oldest_change) / 60 + 1;
|
2006-01-29 16:06:16 +00:00
|
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
|
|
|
|
message, minutes);
|
2005-11-02 03:32:36 +00:00
|
|
|
#else
|
2006-01-29 16:06:16 +00:00
|
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
|
|
|
|
message);
|
2005-11-02 03:32:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
|
2006-01-29 14:53:19 +00:00
|
|
|
_("Close _Without Saving"), GTK_RESPONSE_CLOSE,
|
2005-11-02 03:32:36 +00:00
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
|
|
|
|
|
NULL);
|
|
|
|
|
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_APPLY);
|
|
|
|
|
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
|
|
|
|
|
|
switch (response) {
|
|
|
|
|
case GTK_RESPONSE_APPLY:
|
|
|
|
|
gnc_file_save();
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
case GTK_RESPONSE_CLOSE:
|
|
|
|
|
qof_book_mark_saved(book);
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_delete_event (GtkWidget *window,
|
|
|
|
|
GdkEvent *event,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
QofSession *session;
|
|
|
|
|
GtkWidget *dialog;
|
|
|
|
|
gint response;
|
2006-01-29 16:06:16 +00:00
|
|
|
const gchar *title = _("Quit Gnucash?");
|
|
|
|
|
const gchar *message =_("You are attempting to close the last "
|
|
|
|
|
"Gnucash window. Doing so will quit the "
|
|
|
|
|
"application. Are you sure that this is "
|
|
|
|
|
"what you want to do?");
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (g_list_length(active_windows) > 1)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
session = qof_session_get_current_session();
|
|
|
|
|
if (qof_book_not_saved(qof_session_get_book(session))) {
|
|
|
|
|
if (!gnc_main_window_prompt_for_save(GTK_WIDGET(window))) {
|
|
|
|
|
/* Tell gnucash to shutdown cleanly */
|
|
|
|
|
g_idle_add((GSourceFunc)gnc_shutdown, 0);
|
|
|
|
|
}
|
|
|
|
|
/* Cancel the window deletion. It'll happen on the just queued shutdown. */
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-29 16:06:16 +00:00
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
|
|
|
|
|
GTK_DIALOG_MODAL,
|
|
|
|
|
GTK_MESSAGE_WARNING,
|
|
|
|
|
GTK_BUTTONS_NONE,
|
|
|
|
|
"%s", title);
|
|
|
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
|
|
|
|
"%s", message);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
|
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
|
GTK_STOCK_QUIT, GTK_RESPONSE_OK,
|
|
|
|
|
NULL);
|
|
|
|
|
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
|
|
|
|
|
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
|
|
|
|
|
|
if (response == GTK_RESPONSE_OK) {
|
|
|
|
|
/* Tell gnucash to shutdown cleanly */
|
|
|
|
|
g_idle_add((GSourceFunc)gnc_shutdown, 0);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** This function handles any event notifications from the engine.
|
|
|
|
|
* The only event it currently cares about is the deletion of a book.
|
|
|
|
|
* When a book is deleted, it runs through all installed pages
|
|
|
|
|
* looking for pages that reference the just (about to be?) deleted
|
|
|
|
|
* book. It closes any page it finds so there are no dangling
|
|
|
|
|
* references to the book.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*
|
|
|
|
|
* @param entity The guid the item being added, deleted, etc.
|
|
|
|
|
*
|
|
|
|
|
* @param type The type of the item being added, deleted, etc. This
|
|
|
|
|
* function only cares about a type of GNC_ID_BOOK.
|
|
|
|
|
*
|
|
|
|
|
* @param event_type The type of the event. This function only cares
|
|
|
|
|
* about an event type of GNC_EVENT_DESTROY.
|
|
|
|
|
*
|
|
|
|
|
* @param user_data A pointer to the window data structure.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_event_handler (GUID *entity, QofIdType type,
|
|
|
|
|
GNCEngineEventType event_type,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GncPluginPage *page;
|
|
|
|
|
GList *item, *next;
|
|
|
|
|
|
|
|
|
|
/* hard failures */
|
|
|
|
|
g_return_if_fail(GNC_IS_MAIN_WINDOW(user_data));
|
|
|
|
|
|
|
|
|
|
/* soft failures */
|
|
|
|
|
if (safe_strcmp(type, GNC_ID_BOOK) != 0)
|
|
|
|
|
return;
|
|
|
|
|
if (event_type != GNC_EVENT_DESTROY)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ENTER("entity %p of type %s, event %d, window %p",
|
|
|
|
|
entity, type, event_type, user_data);
|
|
|
|
|
window = GNC_MAIN_WINDOW(user_data);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
/* This is not a typical list iteration. We're removing while
|
|
|
|
|
* we iterate, so we have to cache the 'next' pointer before
|
|
|
|
|
* executing any code in the loop. */
|
2005-11-06 00:14:40 +00:00
|
|
|
for (item = priv->installed_pages; item; item = next) {
|
2005-11-02 03:32:36 +00:00
|
|
|
next = g_list_next(item);
|
|
|
|
|
page = GNC_PLUGIN_PAGE(item->data);
|
|
|
|
|
if (gnc_plugin_page_has_book (page, entity))
|
|
|
|
|
gnc_main_window_close_page (page);
|
|
|
|
|
}
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Generate a title for this window based upon the Gnome Human
|
|
|
|
|
* Interface Guidelines, v2.0. This title will be used as both the
|
|
|
|
|
* window title and the title of the "Window" menu item associated
|
|
|
|
|
* with the window.
|
|
|
|
|
*
|
|
|
|
|
* @param window The window whose title should be generated.
|
|
|
|
|
*
|
|
|
|
|
* @return The title for the window. It is the callers
|
|
|
|
|
* responsibility to free this string.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static gchar *
|
|
|
|
|
gnc_main_window_generate_title (GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GncPluginPage *page;
|
|
|
|
|
const gchar *filename;
|
|
|
|
|
gchar *title, *ptr;
|
|
|
|
|
|
|
|
|
|
filename = gnc_session_get_url (gnc_get_current_session ());
|
|
|
|
|
|
|
|
|
|
if (!filename)
|
|
|
|
|
filename = _("<no file>");
|
|
|
|
|
else {
|
|
|
|
|
/* The Gnome HIG 2.0 recommends only the file name (no path) be used. (p15) */
|
|
|
|
|
ptr = rindex(filename, '/');
|
|
|
|
|
if (ptr != NULL)
|
|
|
|
|
filename = ptr+1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
page = priv->current_page;
|
2005-11-02 03:32:36 +00:00
|
|
|
if (page) {
|
|
|
|
|
/* The Gnome HIG 2.0 recommends the application name not be used. (p16) */
|
|
|
|
|
title = g_strdup_printf("%s - %s", filename,
|
|
|
|
|
gnc_plugin_page_get_page_name(page));
|
|
|
|
|
} else {
|
|
|
|
|
title = g_strdup_printf("%s", filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return title;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Update the title bar on the specified window. This routine uses
|
|
|
|
|
* the gnc_main_window_generate_title() function to create the title.
|
|
|
|
|
* It is called whenever the user switched pages in a window, as the
|
|
|
|
|
* title includes the name of the current page.
|
|
|
|
|
*
|
|
|
|
|
* @param window The window whose title should be updated.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_title (GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
gchar *title;
|
|
|
|
|
|
|
|
|
|
title = gnc_main_window_generate_title(window);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW(window), title);
|
|
|
|
|
g_free(title);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** This data structure is used to describe the requested state of a
|
|
|
|
|
* GtkRadioAction, and us used to pass data among several
|
|
|
|
|
* functions. */
|
|
|
|
|
struct menu_update {
|
|
|
|
|
/** The name of the GtkRadioAction to be updated. */
|
|
|
|
|
gchar *action_name;
|
|
|
|
|
|
|
|
|
|
/** The new label for this GtkRadioAction. */
|
|
|
|
|
gchar *label;
|
|
|
|
|
|
|
|
|
|
/** Whether or not the GtkRadioAction should be visible. */
|
|
|
|
|
gboolean visible;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Update the label on the specified GtkRadioAction in the specified
|
|
|
|
|
* window. This action is displayed as a menu item in the "Windows"
|
|
|
|
|
* menu. This function will end up being called whenever the front
|
|
|
|
|
* page is changed in any window, or whenever a window is added or
|
|
|
|
|
* deleted.
|
|
|
|
|
*
|
|
|
|
|
* @param window The window whose menu item should be updated.
|
|
|
|
|
*
|
|
|
|
|
* @param data A data structure containing the name of the
|
|
|
|
|
* GtkRadioAction, and describing the new state for this action.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_one_menu_action (GncMainWindow *window,
|
|
|
|
|
struct menu_update *data)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkAction* action;
|
|
|
|
|
|
|
|
|
|
ENTER("window %p, action %s, label %s, visible %d", window,
|
|
|
|
|
data->action_name, data->label, data->visible);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
action = gtk_action_group_get_action(priv->action_group, data->action_name);
|
2005-11-02 03:32:36 +00:00
|
|
|
if (action)
|
|
|
|
|
g_object_set(G_OBJECT(action),
|
|
|
|
|
"label", data->label,
|
|
|
|
|
"visible", data->visible,
|
2005-11-16 21:59:48 +00:00
|
|
|
(char *)NULL);
|
2005-11-02 03:32:36 +00:00
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Update the window selection GtkRadioAction for a specific window.
|
|
|
|
|
* This is fairly simple since the windows are listed in the same
|
|
|
|
|
* order that they appear in the active_windows list, so the index
|
|
|
|
|
* from the window list is used to generate the name of the action.
|
|
|
|
|
* If the code is ever changed to allow more than ten open windows in
|
|
|
|
|
* the menu, then the actions in the menu will need to be dynamically
|
|
|
|
|
* generated/deleted and it gets harder.
|
|
|
|
|
*
|
|
|
|
|
* @param window The window whose menu item should be updated.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_radio_button (GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkAction *action, *first_action;
|
|
|
|
|
GSList *action_list;
|
|
|
|
|
gchar *action_name;
|
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
|
|
ENTER("window %p", window);
|
|
|
|
|
|
|
|
|
|
/* Show the new entry in all windows. */
|
|
|
|
|
index = g_list_index(active_windows, window);
|
2006-01-19 19:34:23 +00:00
|
|
|
if (index >= n_radio_entries) {
|
2005-11-02 03:32:36 +00:00
|
|
|
LEAVE("window %d, only %d actions", index, n_radio_entries);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
action_name = g_strdup_printf("Window%dAction", index);
|
2005-11-06 00:14:40 +00:00
|
|
|
action = gtk_action_group_get_action(priv->action_group, action_name);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
/* Block the signal so as not to affect window ordering (top to
|
|
|
|
|
* bottom) on the screen */
|
|
|
|
|
action_list = gtk_radio_action_get_group(GTK_RADIO_ACTION(action));
|
|
|
|
|
first_action = g_slist_last(action_list)->data;
|
|
|
|
|
g_signal_handlers_block_by_func(first_action,
|
|
|
|
|
gnc_main_window_cmd_window_raise, window);
|
|
|
|
|
DEBUG("blocked signal on %p, set %p active, window %p", first_action, action, window);
|
|
|
|
|
gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
|
|
|
|
|
g_signal_handlers_unblock_by_func(first_action,
|
|
|
|
|
gnc_main_window_cmd_window_raise, window);
|
|
|
|
|
g_free(action_name);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** In every window that the user has open, update the "Window" menu
|
|
|
|
|
* item that points to the specified window. This keeps the "Window"
|
|
|
|
|
* menu items consistent across all open windows. (These items
|
|
|
|
|
* cannot be shared because of the way the GtkUIManager code works.)
|
|
|
|
|
*
|
|
|
|
|
* This function is called whenever the user switches pages in a
|
|
|
|
|
* window, or whenever a window is added or deleted.
|
|
|
|
|
*
|
|
|
|
|
* @param window The window whose menu item should be updated in all
|
|
|
|
|
* open windows.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_menu_item (GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
struct menu_update data;
|
|
|
|
|
gchar **strings, *title, *expanded;
|
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
|
|
ENTER("window %p", window);
|
|
|
|
|
index = g_list_index(active_windows, window);
|
|
|
|
|
if (index > n_radio_entries) {
|
|
|
|
|
LEAVE("skip window %d (only %d entries)", index, n_radio_entries);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Figure out the label name. Add the accelerator if possible. */
|
|
|
|
|
title = gnc_main_window_generate_title(window);
|
|
|
|
|
strings = g_strsplit(title, "_", 0);
|
|
|
|
|
expanded = g_strjoinv("__", strings);
|
|
|
|
|
if (index < 10) {
|
|
|
|
|
data.label = g_strdup_printf("_%d %s", (index + 1) % 10, expanded);
|
|
|
|
|
g_free(expanded);
|
|
|
|
|
} else {
|
|
|
|
|
data.label = expanded;
|
|
|
|
|
}
|
|
|
|
|
g_strfreev(strings);
|
|
|
|
|
|
|
|
|
|
data.visible = TRUE;
|
|
|
|
|
data.action_name = g_strdup_printf("Window%dAction", index);
|
|
|
|
|
g_list_foreach(active_windows,
|
|
|
|
|
(GFunc)gnc_main_window_update_one_menu_action,
|
|
|
|
|
&data);
|
|
|
|
|
g_free(data.action_name);
|
|
|
|
|
g_free(data.label);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Update all menu entries for all window menu items in all windows.
|
|
|
|
|
* This function is called whenever a window is added or deleted.
|
|
|
|
|
* The worst case scenario is where the user has deleted the first
|
|
|
|
|
* window, so every single visible item needs to be updated.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_all_menu_items (void)
|
|
|
|
|
{
|
|
|
|
|
struct menu_update data;
|
|
|
|
|
gchar *label;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
ENTER("");
|
|
|
|
|
|
|
|
|
|
/* First update the entries for all existing windows */
|
|
|
|
|
g_list_foreach(active_windows,
|
|
|
|
|
(GFunc)gnc_main_window_update_menu_item,
|
|
|
|
|
NULL);
|
|
|
|
|
g_list_foreach(active_windows,
|
|
|
|
|
(GFunc)gnc_main_window_update_radio_button,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Now hide any entries that aren't being used. */
|
|
|
|
|
data.visible = FALSE;
|
|
|
|
|
for (i = g_list_length(active_windows); i < n_radio_entries; i++) {
|
|
|
|
|
data.action_name = g_strdup_printf("Window%dAction", i);
|
|
|
|
|
label = g_strdup_printf("Window _%d", (i - 1) % 10);
|
|
|
|
|
data.label = gettext(label);
|
|
|
|
|
|
|
|
|
|
g_list_foreach(active_windows,
|
|
|
|
|
(GFunc)gnc_main_window_update_one_menu_action,
|
|
|
|
|
&data);
|
|
|
|
|
|
|
|
|
|
g_free(data.action_name);
|
|
|
|
|
g_free(label);
|
|
|
|
|
}
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Show/hide the close box on the tab of a notebook page. This
|
|
|
|
|
* function first checks to see if the specified page has a close
|
2005-11-14 05:14:21 +00:00
|
|
|
* box, and if so, sets its visibility to the requested state.
|
2005-11-02 03:32:36 +00:00
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*
|
|
|
|
|
* @param page The GncPluginPage whose notebook tab should be updated.
|
|
|
|
|
*
|
|
|
|
|
* @param new_value A pointer to the boolean that indicates whether
|
|
|
|
|
* or not the close button should be visible.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_tabs_one_page (GncPluginPage *page,
|
|
|
|
|
gboolean *new_value)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget * close_button;
|
|
|
|
|
|
|
|
|
|
ENTER("page %p, visible %d", page, *new_value);
|
|
|
|
|
close_button = g_object_get_data(G_OBJECT (page), PLUGIN_PAGE_CLOSE_BUTTON);
|
|
|
|
|
if (!close_button) {
|
|
|
|
|
LEAVE("no close button");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*new_value)
|
|
|
|
|
gtk_widget_show (close_button);
|
|
|
|
|
else
|
|
|
|
|
gtk_widget_hide (close_button);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Show/hide the close box on all pages in a given window. This
|
|
|
|
|
* function calls the gnc_main_window_update_tabs_one_page() for each
|
|
|
|
|
* page in the window.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*
|
|
|
|
|
* @param window The GncMainWindow whose notebook tabs should be
|
|
|
|
|
* updated.
|
|
|
|
|
*
|
|
|
|
|
* @param new_value A pointer to the boolean that indicates whether
|
|
|
|
|
* or not the close button should be visible.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_tabs_one_window (GncMainWindow *window, gboolean *new_value)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
ENTER("window %p, visible %d", window, *new_value);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
g_list_foreach(priv->installed_pages,
|
2005-11-02 03:32:36 +00:00
|
|
|
(GFunc)gnc_main_window_update_tabs_one_page,
|
|
|
|
|
new_value);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Show/hide the close box on all pages in all windows. This
|
|
|
|
|
* function calls the gnc_main_window_update_tabs_one_window() for
|
|
|
|
|
* each open window in the application.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*
|
|
|
|
|
* @param entry A pointer to the GConfEntry which describes the new
|
|
|
|
|
* state of whether close buttons should be visible on notebook tabs.
|
|
|
|
|
*
|
|
|
|
|
* @param user_data Unused.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_tabs (GConfEntry *entry, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
gboolean new_value;
|
|
|
|
|
|
|
|
|
|
ENTER(" ");
|
|
|
|
|
new_value = gconf_value_get_bool(entry->value);
|
|
|
|
|
g_list_foreach(active_windows,
|
|
|
|
|
(GFunc)gnc_main_window_update_tabs_one_window,
|
|
|
|
|
&new_value);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
/************************************************************
|
|
|
|
|
* Tab Label Implementation *
|
|
|
|
|
************************************************************/
|
|
|
|
|
static gboolean
|
|
|
|
|
main_window_find_tab_items (GncMainWindow *window,
|
|
|
|
|
GncPluginPage *page,
|
|
|
|
|
GtkWidget **label_p,
|
|
|
|
|
GtkWidget **entry_p)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GtkWidget *tab_hbox, *widget;
|
|
|
|
|
GList *children, *tmp;
|
|
|
|
|
|
|
|
|
|
ENTER("window %p, page %p, label_p %p, entry_p %p",
|
|
|
|
|
window, page, label_p, entry_p);
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
*label_p = *entry_p = NULL;
|
|
|
|
|
tab_hbox = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
|
|
|
|
|
page->notebook_page);
|
|
|
|
|
children = gtk_container_get_children(GTK_CONTAINER(tab_hbox));
|
|
|
|
|
for (tmp = children; tmp; tmp = g_list_next(tmp)) {
|
|
|
|
|
widget = tmp->data;
|
|
|
|
|
if (GTK_IS_LABEL(widget)) {
|
|
|
|
|
*label_p = widget;
|
|
|
|
|
} else if (GTK_IS_ENTRY(widget)) {
|
|
|
|
|
*entry_p = widget;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_list_free(children);
|
|
|
|
|
|
|
|
|
|
LEAVE("label %p, entry %p", *label_p, *entry_p);
|
|
|
|
|
return (*label_p && *entry_p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
main_window_update_page_name (GncMainWindow *window,
|
|
|
|
|
GncPluginPage *page,
|
|
|
|
|
const gchar *name_in)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GtkWidget *label, *entry;
|
|
|
|
|
gchar *name;
|
|
|
|
|
|
|
|
|
|
ENTER(" ");
|
|
|
|
|
|
|
|
|
|
if ((name_in == NULL) || (*name_in == '\0')) {
|
|
|
|
|
LEAVE("no string");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
name = g_strstrip(g_strdup(name_in));
|
|
|
|
|
if (*name == '\0') {
|
|
|
|
|
g_free(name);
|
|
|
|
|
LEAVE("empty string");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update the plugin */
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
gnc_plugin_page_set_page_name(page, name);
|
|
|
|
|
|
|
|
|
|
/* Update the notebook tab */
|
|
|
|
|
main_window_find_tab_items(window, page, &label, &entry);
|
|
|
|
|
gtk_label_set_text(GTK_LABEL(label), name);
|
|
|
|
|
|
|
|
|
|
/* Update the notebook menu */
|
|
|
|
|
label = gtk_notebook_get_menu_label (GTK_NOTEBOOK(priv->notebook),
|
|
|
|
|
page->notebook_page);
|
|
|
|
|
gtk_label_set_text(GTK_LABEL(label), name);
|
|
|
|
|
|
|
|
|
|
/* Force an update of the window title */
|
|
|
|
|
gnc_main_window_update_title(window);
|
|
|
|
|
g_free(name);
|
|
|
|
|
LEAVE("done");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_tab_entry_activate (GtkWidget *entry,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *label, *entry2;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(GTK_IS_ENTRY(entry));
|
|
|
|
|
g_return_if_fail(GNC_IS_PLUGIN_PAGE(page));
|
|
|
|
|
|
|
|
|
|
ENTER("");
|
|
|
|
|
if (!main_window_find_tab_items(GNC_MAIN_WINDOW(page->window),
|
|
|
|
|
page, &label, &entry2)) {
|
|
|
|
|
LEAVE("can't find required widgets");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main_window_update_page_name(GNC_MAIN_WINDOW(page->window), page,
|
|
|
|
|
gtk_entry_get_text(GTK_ENTRY(entry)));
|
|
|
|
|
|
|
|
|
|
gtk_widget_hide(entry);
|
|
|
|
|
gtk_widget_show(label);
|
|
|
|
|
LEAVE("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_tab_entry_editing_done (GtkWidget *entry,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
ENTER("");
|
|
|
|
|
gnc_main_window_tab_entry_activate(entry, page);
|
|
|
|
|
LEAVE("");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_tab_entry_focus_out_event (GtkWidget *entry,
|
|
|
|
|
GdkEvent *event,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
ENTER("");
|
|
|
|
|
gnc_main_window_tab_entry_activate(entry, page);
|
|
|
|
|
LEAVE("");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/************************************************************
|
|
|
|
|
* Widget Implementation *
|
|
|
|
|
************************************************************/
|
|
|
|
|
|
|
|
|
|
/* Get the type of a gnc main window.
|
|
|
|
|
*/
|
|
|
|
|
GType
|
|
|
|
|
gnc_main_window_get_type (void)
|
|
|
|
|
{
|
|
|
|
|
static GType gnc_main_window_type = 0;
|
|
|
|
|
|
|
|
|
|
if (gnc_main_window_type == 0) {
|
|
|
|
|
static const GTypeInfo our_info = {
|
|
|
|
|
sizeof (GncMainWindowClass),
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
(GClassInitFunc) gnc_main_window_class_init,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
sizeof (GncMainWindow),
|
|
|
|
|
0,
|
|
|
|
|
(GInstanceInitFunc) gnc_main_window_init
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const GInterfaceInfo plugin_info = {
|
|
|
|
|
(GInterfaceInitFunc) gnc_window_main_window_init,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
gnc_main_window_type = g_type_register_static (GTK_TYPE_WINDOW,
|
|
|
|
|
"GncMainWindow",
|
|
|
|
|
&our_info, 0);
|
|
|
|
|
g_type_add_interface_static (gnc_main_window_type,
|
|
|
|
|
GNC_TYPE_WINDOW,
|
|
|
|
|
&plugin_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return gnc_main_window_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** Initialize the class for a new gnucash main window. This will set
|
|
|
|
|
* up any function pointers that override functions in the parent
|
|
|
|
|
* class, and also initialize the signals that this class of widget
|
|
|
|
|
* can generate.
|
2005-11-02 03:32:36 +00:00
|
|
|
*
|
|
|
|
|
* @param klass The new class structure created by the object system.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_class_init (GncMainWindowClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS(klass);
|
|
|
|
|
|
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
|
|
|
|
|
|
window_type = g_quark_from_static_string ("gnc-main-window");
|
|
|
|
|
|
|
|
|
|
object_class->finalize = gnc_main_window_finalize;
|
|
|
|
|
|
|
|
|
|
/* GtkObject signals */
|
|
|
|
|
gtkobject_class->destroy = gnc_main_window_destroy;
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
g_type_class_add_private(klass, sizeof(GncMainWindowPrivate));
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/**
|
|
|
|
|
* GncMainWindow::page_added:
|
|
|
|
|
* @param window: the #GncMainWindow
|
|
|
|
|
* @param page: the #GncPluginPage
|
|
|
|
|
*
|
|
|
|
|
* The "page_added" signal is emitted when a new page is added
|
|
|
|
|
* to the notebook of a GncMainWindow. This can be used to
|
|
|
|
|
* attach a signal from the page so that menu actions can be
|
|
|
|
|
* adjusted based upon events that occur within the page
|
|
|
|
|
* (e.g. an account is selected.)
|
|
|
|
|
*/
|
|
|
|
|
main_window_signals[PAGE_ADDED] =
|
|
|
|
|
g_signal_new ("page_added",
|
|
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
|
G_STRUCT_OFFSET (GncMainWindowClass, page_added),
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GncMainWindow::page_changed:
|
|
|
|
|
* @param window: the #GncMainWindow
|
|
|
|
|
* @param page: the #GncPluginPage
|
|
|
|
|
*
|
|
|
|
|
* The "page_changed" signal is emitted when a new page is
|
|
|
|
|
* selected in the notebook of a GncMainWindow. This can be
|
|
|
|
|
* used to to adjust menu actions based upon which page is
|
|
|
|
|
* currently displayed in a window.
|
|
|
|
|
*/
|
|
|
|
|
main_window_signals[PAGE_CHANGED] =
|
|
|
|
|
g_signal_new ("page_changed",
|
|
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
|
G_STRUCT_OFFSET (GncMainWindowClass, page_changed),
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
|
|
gnc_gconf_general_register_cb (KEY_SHOW_CLOSE_BUTTON,
|
|
|
|
|
gnc_main_window_update_tabs,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Initialize a new instance of a gnucash main window. This function
|
2005-11-14 05:14:21 +00:00
|
|
|
* initializes the object private storage space. It also adds the
|
|
|
|
|
* new object to a list (for memory tracking purposes).
|
2005-11-02 03:32:36 +00:00
|
|
|
*
|
|
|
|
|
* @param view The new object instance created by the object system.
|
|
|
|
|
*
|
2005-11-14 05:14:21 +00:00
|
|
|
* @param klass A pointer to the class data structure for this
|
|
|
|
|
* object. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_init (GncMainWindow *window,
|
|
|
|
|
GncMainWindowClass *klass)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
priv->merged_actions_table =
|
2005-11-02 03:32:36 +00:00
|
|
|
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv->event_handler_id =
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_engine_register_event_handler(gnc_main_window_event_handler,
|
|
|
|
|
window);
|
|
|
|
|
|
|
|
|
|
gnc_main_window_setup_window (window);
|
|
|
|
|
gnc_gobject_tracking_remember(G_OBJECT(window),
|
|
|
|
|
G_OBJECT_CLASS(klass));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Finalize the GncMainWindow object. This function is called from
|
|
|
|
|
* the G_Object level to complete the destruction of the object. It
|
|
|
|
|
* should release any memory not previously released by the destroy
|
|
|
|
|
* function (i.e. the private data structure), then chain up to the
|
|
|
|
|
* parent's destroy function.
|
|
|
|
|
*
|
|
|
|
|
* @param object The object being destroyed.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_finalize (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (object));
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW (object);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE (window);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (active_windows == NULL) {
|
|
|
|
|
/* Oops. User killed last window and we didn't catch it. */
|
|
|
|
|
g_idle_add((GSourceFunc)gnc_shutdown, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gnc_gobject_tracking_forget(object);
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_destroy (GtkObject *object)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (object));
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW (object);
|
|
|
|
|
|
|
|
|
|
active_windows = g_list_remove (active_windows, window);
|
|
|
|
|
|
|
|
|
|
/* Do these things once */
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (priv->merged_actions_table) {
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
/* Close any pages in this window */
|
2005-11-06 00:14:40 +00:00
|
|
|
while (priv->current_page)
|
|
|
|
|
gnc_main_window_close_page(priv->current_page);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (gnc_window_get_progressbar_window() == GNC_WINDOW(window))
|
|
|
|
|
gnc_window_set_progressbar_window(NULL);
|
|
|
|
|
|
|
|
|
|
/* Update the "Windows" menu in all other windows */
|
|
|
|
|
gnc_main_window_update_all_menu_items();
|
|
|
|
|
|
|
|
|
|
gnc_gconf_remove_notification(G_OBJECT(window), DESKTOP_GNOME_INTERFACE);
|
|
|
|
|
gnc_gconf_remove_notification(G_OBJECT(window), GCONF_GENERAL);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
gnc_engine_unregister_event_handler(priv->event_handler_id);
|
|
|
|
|
priv->event_handler_id = 0;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
g_hash_table_destroy (priv->merged_actions_table);
|
|
|
|
|
priv->merged_actions_table = NULL;
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
GTK_OBJECT_CLASS (parent_class)->destroy (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create a new gnc main window plugin.
|
|
|
|
|
*/
|
|
|
|
|
GncMainWindow *
|
|
|
|
|
gnc_main_window_new (void)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
|
|
|
|
|
|
|
|
|
window = g_object_new (GNC_TYPE_MAIN_WINDOW, NULL);
|
|
|
|
|
active_windows = g_list_append (active_windows, window);
|
|
|
|
|
gnc_main_window_update_all_menu_items();
|
|
|
|
|
return window;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
|
* Utility Functions *
|
|
|
|
|
************************************************************/
|
|
|
|
|
|
|
|
|
|
/** Connect a GncPluginPage to the window. This function will insert
|
|
|
|
|
* the page in to the window's notebook and its list of active pages.
|
|
|
|
|
* It will also emit the "inserted" signal on the page, and the
|
2005-11-14 05:14:21 +00:00
|
|
|
* "add_page" signal on the window.
|
2005-11-02 03:32:36 +00:00
|
|
|
*
|
|
|
|
|
* @param window The window where the new page should be added.
|
|
|
|
|
*
|
|
|
|
|
* @param page The GncPluginPage that should be added to the window.
|
|
|
|
|
* The visible widget for this plugin must have already been created.
|
|
|
|
|
*
|
2005-11-14 05:14:21 +00:00
|
|
|
* @param tab_hbox The widget that should be added into the notebook
|
|
|
|
|
* tab for this page. Generally this is a GtkLabel, but could also
|
|
|
|
|
* be a GtkHBox containing an icon and a label.
|
2005-11-02 03:32:36 +00:00
|
|
|
*
|
2005-11-14 05:14:21 +00:00
|
|
|
* @param menu_label The widget that should be added into the
|
|
|
|
|
* notebook popup menu for this page. This should be a GtkLabel.
|
2005-11-02 03:32:36 +00:00
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_connect (GncMainWindow *window,
|
|
|
|
|
GncPluginPage *page,
|
|
|
|
|
GtkWidget *tab_hbox,
|
|
|
|
|
GtkWidget *menu_label)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkNotebook *notebook;
|
|
|
|
|
|
|
|
|
|
page->window = GTK_WIDGET(window);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
notebook = GTK_NOTEBOOK (priv->notebook);
|
|
|
|
|
priv->installed_pages = g_list_append (priv->installed_pages, page);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_notebook_append_page_menu (notebook, page->notebook_page,
|
|
|
|
|
tab_hbox, menu_label);
|
|
|
|
|
gnc_plugin_page_inserted (page);
|
|
|
|
|
gtk_notebook_set_current_page (notebook, -1);
|
|
|
|
|
if (GNC_PLUGIN_PAGE_GET_CLASS(page)->window_changed)
|
|
|
|
|
(GNC_PLUGIN_PAGE_GET_CLASS(page)->window_changed)(page, GTK_WIDGET(window));
|
|
|
|
|
g_signal_emit (window, main_window_signals[PAGE_ADDED], 0, page);
|
|
|
|
|
|
|
|
|
|
g_signal_connect(G_OBJECT(page->notebook_page), "popup-menu",
|
|
|
|
|
G_CALLBACK(gnc_main_window_popup_menu_cb), page);
|
|
|
|
|
g_signal_connect_after(G_OBJECT(page->notebook_page), "button-press-event",
|
|
|
|
|
G_CALLBACK(gnc_main_window_button_press_cb), page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Disconnect a GncPluginPage page from the window. If this page is
|
|
|
|
|
* currently foremost in the window's notebook, its user interface
|
|
|
|
|
* actions will be disconnected and the page's summarybar widget (if
|
|
|
|
|
* any) will be removed. The page is then removed from the window's
|
|
|
|
|
* notebook and its list of active pages.
|
|
|
|
|
*
|
|
|
|
|
* @param window The window the page should be removed from.
|
|
|
|
|
*
|
|
|
|
|
* @param page The GncPluginPage that should be removed from the
|
|
|
|
|
* window.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_disconnect (GncMainWindow *window,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkNotebook *notebook;
|
|
|
|
|
gint page_num;
|
|
|
|
|
|
|
|
|
|
/* Disconnect the callbacks */
|
|
|
|
|
g_signal_handlers_disconnect_by_func(G_OBJECT(page->notebook_page),
|
|
|
|
|
G_CALLBACK(gnc_main_window_popup_menu_cb), page);
|
|
|
|
|
g_signal_handlers_disconnect_by_func(G_OBJECT(page->notebook_page),
|
|
|
|
|
G_CALLBACK(gnc_main_window_button_press_cb), page);
|
|
|
|
|
|
|
|
|
|
/* Disconnect the page and summarybar from the window */
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (priv->current_page == page) {
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_plugin_page_unmerge_actions (page, window->ui_merge);
|
|
|
|
|
gnc_plugin_page_unselected (page);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv->current_page = NULL;
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove it from the list of pages in the window */
|
2005-11-06 00:14:40 +00:00
|
|
|
priv->installed_pages = g_list_remove (priv->installed_pages, page);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove the page from the notebook */
|
2005-11-06 00:14:40 +00:00
|
|
|
notebook = GTK_NOTEBOOK (priv->notebook);
|
2005-11-02 03:32:36 +00:00
|
|
|
page_num = gtk_notebook_page_num(notebook, page->notebook_page);
|
|
|
|
|
gtk_notebook_remove_page (notebook, page_num);
|
|
|
|
|
|
|
|
|
|
if ( gtk_notebook_get_current_page(notebook) == -1) {
|
|
|
|
|
/* Need to synthesize a page changed signal when the last
|
|
|
|
|
* page is removed. The notebook doesn't generate a signal
|
|
|
|
|
* for this, therefore the switch_page code in this file
|
|
|
|
|
* never gets called to generate this signal. */
|
|
|
|
|
gnc_main_window_switch_page(notebook, NULL, -1, window);
|
|
|
|
|
//g_signal_emit (window, main_window_signals[PAGE_CHANGED], 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gnc_plugin_page_removed (page);
|
|
|
|
|
|
|
|
|
|
gtk_ui_manager_ensure_update (window->ui_merge);
|
|
|
|
|
gnc_window_set_status (GNC_WINDOW(window), page, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
|
* *
|
|
|
|
|
************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_display_page (GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkNotebook *notebook;
|
|
|
|
|
gint page_num;
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW (page->window);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
notebook = GTK_NOTEBOOK (priv->notebook);
|
2005-11-02 03:32:36 +00:00
|
|
|
page_num = gtk_notebook_page_num(notebook, page->notebook_page);
|
|
|
|
|
gtk_notebook_set_current_page (notebook, page_num);
|
|
|
|
|
gtk_window_present(GTK_WINDOW(window));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Display a data plugin page in a window. If the page already
|
|
|
|
|
* exists in any window, then that window will be brought to the
|
|
|
|
|
* front and the notebook switch to display the specified page. If
|
|
|
|
|
* the page is new then it will be added to the specified window. If
|
|
|
|
|
* the window is NULL, the new page will be added to the first
|
|
|
|
|
* window.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_open_page (GncMainWindow *window,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkWidget *tab_hbox;
|
2005-11-11 14:16:12 +00:00
|
|
|
GtkWidget *label, *entry;
|
2005-11-02 03:32:36 +00:00
|
|
|
const gchar *icon;
|
|
|
|
|
GtkWidget *image;
|
|
|
|
|
gboolean immutable = FALSE;
|
|
|
|
|
|
|
|
|
|
if (window)
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (GNC_IS_PLUGIN_PAGE (page));
|
|
|
|
|
g_return_if_fail (gnc_plugin_page_has_books(page));
|
|
|
|
|
|
|
|
|
|
if (gnc_main_window_page_exists(page)) {
|
|
|
|
|
gnc_main_window_display_page(page);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gnc_plugin_page_get_use_new_window(page)) {
|
|
|
|
|
window = gnc_main_window_new ();
|
|
|
|
|
gtk_widget_show(GTK_WIDGET(window));
|
|
|
|
|
} else if ((window == NULL) && active_windows) {
|
|
|
|
|
window = active_windows->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Is this the first page in the first window? */
|
2005-11-06 00:14:40 +00:00
|
|
|
if (window == active_windows->data) {
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (priv->installed_pages == NULL) {
|
|
|
|
|
immutable = TRUE;
|
|
|
|
|
g_object_set_data (G_OBJECT (page), PLUGIN_PAGE_IMMUTABLE,
|
|
|
|
|
GINT_TO_POINTER(1));
|
|
|
|
|
}
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page->window = GTK_WIDGET(window);
|
|
|
|
|
page->notebook_page = gnc_plugin_page_create_widget (page);
|
|
|
|
|
g_object_set_data (G_OBJECT (page->notebook_page),
|
|
|
|
|
PLUGIN_PAGE_LABEL, page);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The page tab.
|
|
|
|
|
*/
|
|
|
|
|
icon = GNC_PLUGIN_PAGE_GET_CLASS(page)->tab_icon;
|
|
|
|
|
label = gtk_label_new (gnc_plugin_page_get_page_name(page));
|
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
|
|
tab_hbox = gtk_hbox_new (FALSE, 6);
|
|
|
|
|
gtk_widget_show (tab_hbox);
|
|
|
|
|
|
|
|
|
|
if (icon != NULL) {
|
|
|
|
|
image = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU);
|
|
|
|
|
gtk_widget_show (image);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (tab_hbox), image, FALSE, FALSE, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (tab_hbox), label, TRUE, TRUE, 0);
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
entry = gtk_entry_new();
|
|
|
|
|
gtk_widget_hide (entry);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (tab_hbox), entry, TRUE, TRUE, 0);
|
|
|
|
|
g_signal_connect(G_OBJECT(entry), "activate",
|
|
|
|
|
G_CALLBACK(gnc_main_window_tab_entry_activate), page);
|
|
|
|
|
g_signal_connect(G_OBJECT(entry), "focus-out-event",
|
|
|
|
|
G_CALLBACK(gnc_main_window_tab_entry_focus_out_event),
|
|
|
|
|
page);
|
|
|
|
|
g_signal_connect(G_OBJECT(entry), "editing-done",
|
|
|
|
|
G_CALLBACK(gnc_main_window_tab_entry_editing_done),
|
|
|
|
|
page);
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/* Add close button - Not for immutable pages */
|
|
|
|
|
if (!immutable) {
|
|
|
|
|
GtkWidget *close_image, *close_button;
|
2005-12-20 02:06:43 +00:00
|
|
|
GtkRequisition requisition;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
close_button = gtk_button_new();
|
|
|
|
|
gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
|
2005-12-20 02:06:43 +00:00
|
|
|
close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_widget_show(close_image);
|
2005-12-20 02:06:43 +00:00
|
|
|
gtk_widget_size_request(close_image, &requisition);
|
|
|
|
|
gtk_widget_set_size_request(close_button, requisition.width + 4,
|
|
|
|
|
requisition.height + 2);
|
|
|
|
|
gtk_button_set_alignment(GTK_BUTTON(close_button), 0.5, 0.5);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(close_button), close_image);
|
|
|
|
|
if (gnc_gconf_get_bool(GCONF_GENERAL, KEY_SHOW_CLOSE_BUTTON, NULL))
|
|
|
|
|
gtk_widget_show (close_button);
|
|
|
|
|
else
|
|
|
|
|
gtk_widget_hide (close_button);
|
|
|
|
|
|
|
|
|
|
g_signal_connect_swapped (G_OBJECT (close_button), "clicked",
|
|
|
|
|
G_CALLBACK(gnc_main_window_close_page), page);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (tab_hbox), close_button, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
g_object_set_data (G_OBJECT (page), PLUGIN_PAGE_CLOSE_BUTTON, close_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The popup menu
|
|
|
|
|
*/
|
|
|
|
|
label = gtk_label_new (gnc_plugin_page_get_page_name(page));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now install it all in the window.
|
|
|
|
|
*/
|
|
|
|
|
gnc_main_window_connect(window, page, tab_hbox, label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove a data plugin page from a window and display the previous
|
|
|
|
|
* page. If the page removed was the last page in the window, and
|
|
|
|
|
* there is more than one window open, then the entire window will be
|
|
|
|
|
* destroyed.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_close_page (GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (!page->notebook_page)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW (page->window);
|
|
|
|
|
if (!window) {
|
|
|
|
|
g_warning("Page is not in a window.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gnc_main_window_disconnect(window, page);
|
|
|
|
|
gnc_plugin_page_destroy_widget (page);
|
|
|
|
|
g_object_unref(page);
|
|
|
|
|
|
|
|
|
|
/* If this isn't the last window, go ahead and destroy the window. */
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (priv->installed_pages == NULL) {
|
2005-11-02 03:32:36 +00:00
|
|
|
if (g_list_length(active_windows) > 1) {
|
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(window));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Retrieve a pointer to the page that is currently at the front of
|
|
|
|
|
* the specified window. Any plugin that needs to manipulate its
|
|
|
|
|
* menus based upon the currently selected menu page should connect
|
|
|
|
|
* to the "page_changed" signal on a window. The callback function
|
|
|
|
|
* from that signal can then call this function to obtain a pointer
|
|
|
|
|
* to the current page.
|
|
|
|
|
*/
|
|
|
|
|
GncPluginPage *
|
|
|
|
|
gnc_main_window_get_current_page (GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
return priv->current_page;
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Manually add a set of actions to the specified window. Plugins
|
2005-11-14 05:14:21 +00:00
|
|
|
* whose user interface is not hard coded (e.g. the menu-additions
|
|
|
|
|
* plugin) must create their actions at run time, then use this
|
2005-11-02 03:32:36 +00:00
|
|
|
* function to install them into the window.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_manual_merge_actions (GncMainWindow *window,
|
|
|
|
|
const gchar *group_name,
|
|
|
|
|
GtkActionGroup *group,
|
|
|
|
|
guint merge_id)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
MergedActionEntry *entry;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (group_name != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_ACTION_GROUP(group));
|
|
|
|
|
g_return_if_fail (merge_id > 0);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
entry = g_new0 (MergedActionEntry, 1);
|
|
|
|
|
entry->action_group = group;
|
|
|
|
|
entry->merge_id = merge_id;
|
|
|
|
|
gtk_ui_manager_ensure_update (window->ui_merge);
|
2005-11-06 00:14:40 +00:00
|
|
|
g_hash_table_insert (priv->merged_actions_table, g_strdup (group_name), entry);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Add a set of actions to the specified window. This function
|
|
|
|
|
* should not need to be called directly by plugin implementors.
|
|
|
|
|
* Correctly assigning values to the GncPluginClass fields during
|
|
|
|
|
* plugin initialization will cause this routine to be automatically
|
|
|
|
|
* called.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_merge_actions (GncMainWindow *window,
|
|
|
|
|
const gchar *group_name,
|
|
|
|
|
GtkActionEntry *actions,
|
|
|
|
|
guint n_actions,
|
|
|
|
|
const gchar *filename,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GncMainWindowActionData *data;
|
|
|
|
|
MergedActionEntry *entry;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
gchar *pathname;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (group_name != NULL);
|
|
|
|
|
g_return_if_fail (actions != NULL);
|
|
|
|
|
g_return_if_fail (n_actions > 0);
|
|
|
|
|
g_return_if_fail (filename != NULL);
|
|
|
|
|
|
|
|
|
|
data = g_new0 (GncMainWindowActionData, 1);
|
|
|
|
|
data->window = window;
|
|
|
|
|
data->data = user_data;
|
|
|
|
|
|
|
|
|
|
pathname = gnc_gnome_locate_ui_file (filename);
|
|
|
|
|
if (pathname == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
entry = g_new0 (MergedActionEntry, 1);
|
|
|
|
|
entry->action_group = gtk_action_group_new (group_name);
|
2006-01-08 14:01:14 +00:00
|
|
|
gnc_gtk_action_group_set_translation_domain (entry->action_group, GETTEXT_PACKAGE);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_action_group_add_actions (entry->action_group, actions, n_actions, data);
|
|
|
|
|
gtk_ui_manager_insert_action_group (window->ui_merge, entry->action_group, 0);
|
|
|
|
|
entry->merge_id = gtk_ui_manager_add_ui_from_file (window->ui_merge, pathname, &error);
|
|
|
|
|
g_assert(entry->merge_id || error);
|
|
|
|
|
if (entry->merge_id) {
|
|
|
|
|
gtk_ui_manager_ensure_update (window->ui_merge);
|
2005-11-06 00:14:40 +00:00
|
|
|
g_hash_table_insert (priv->merged_actions_table, g_strdup (group_name), entry);
|
2005-11-02 03:32:36 +00:00
|
|
|
} else {
|
|
|
|
|
g_critical("Failed to load ui file.\n Filename %s\n Error %s",
|
|
|
|
|
filename, error->message);
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
g_free(entry);
|
|
|
|
|
}
|
|
|
|
|
g_free(pathname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove a set of actions from the specified window. This function
|
|
|
|
|
* should not need to be called directly by plugin implementors. It
|
|
|
|
|
* will automatically be called when a plugin is removed from a
|
|
|
|
|
* window.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_unmerge_actions (GncMainWindow *window,
|
|
|
|
|
const gchar *group_name)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
MergedActionEntry *entry;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (group_name != NULL);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
entry = g_hash_table_lookup (priv->merged_actions_table, group_name);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (entry == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
gtk_ui_manager_remove_action_group (window->ui_merge, entry->action_group);
|
|
|
|
|
gtk_ui_manager_remove_ui (window->ui_merge, entry->merge_id);
|
|
|
|
|
gtk_ui_manager_ensure_update (window->ui_merge);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
g_hash_table_remove (priv->merged_actions_table, group_name);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Force a full update of the user interface for the specified
|
|
|
|
|
* window. This can be an expensive function, but is needed because
|
|
|
|
|
* the gtk ui manager doesn't always seem to update properly when
|
|
|
|
|
* actions are changed.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_actions_updated (GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GtkActionGroup *force;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
|
|
|
|
|
/* Unfortunately gtk_ui_manager_ensure_update doesn't work
|
|
|
|
|
* here. Force a full update by adding and removing an empty
|
|
|
|
|
* action group.
|
|
|
|
|
*/
|
|
|
|
|
force = gtk_action_group_new("force_update");
|
|
|
|
|
gtk_ui_manager_insert_action_group (window->ui_merge, force, 0);
|
|
|
|
|
gtk_ui_manager_ensure_update (window->ui_merge);
|
|
|
|
|
gtk_ui_manager_remove_action_group (window->ui_merge, force);
|
|
|
|
|
g_object_unref(force);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
static GtkAction *
|
|
|
|
|
gnc_main_window_find_action (GncMainWindow *window, const gchar *name)
|
|
|
|
|
{
|
|
|
|
|
GtkAction *action = NULL;
|
|
|
|
|
const GList *groups, *tmp;
|
|
|
|
|
|
|
|
|
|
groups = gtk_ui_manager_get_action_groups(window->ui_merge);
|
|
|
|
|
for (tmp = groups; tmp; tmp = g_list_next(tmp)) {
|
|
|
|
|
action = gtk_action_group_get_action(GTK_ACTION_GROUP(tmp->data), name);
|
|
|
|
|
if (action)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/* Retrieve a specific set of user interface actions from a window.
|
|
|
|
|
* This function can be used to get an group of action to be
|
|
|
|
|
* manipulated when the front page of a window has changed.
|
|
|
|
|
*/
|
|
|
|
|
GtkActionGroup *
|
|
|
|
|
gnc_main_window_get_action_group (GncMainWindow *window,
|
|
|
|
|
const gchar *group_name)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
MergedActionEntry *entry;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window), NULL);
|
|
|
|
|
g_return_val_if_fail (group_name != NULL, NULL);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
entry = g_hash_table_lookup (priv->merged_actions_table, group_name);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (entry == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return entry->action_group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_add_plugin (gpointer plugin,
|
|
|
|
|
gpointer window)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (GNC_IS_PLUGIN (plugin));
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
ENTER(" ");
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_plugin_add_to_window (GNC_PLUGIN (plugin),
|
|
|
|
|
GNC_MAIN_WINDOW (window),
|
|
|
|
|
window_type);
|
2005-11-11 14:16:12 +00:00
|
|
|
LEAVE(" ");
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_update_toolbar (GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GtkToolbarStyle style;
|
|
|
|
|
GSList *list;
|
|
|
|
|
|
|
|
|
|
ENTER("window %p", window);
|
|
|
|
|
|
|
|
|
|
style = gnc_get_toolbar_style();
|
|
|
|
|
list = gtk_ui_manager_get_toplevels(window->ui_merge, GTK_UI_MANAGER_TOOLBAR);
|
|
|
|
|
g_slist_foreach(list, (GFunc)gtk_toolbar_set_style, GINT_TO_POINTER(style));
|
|
|
|
|
g_slist_free(list);
|
|
|
|
|
LEAVE("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_gconf_changed (GConfClient *client,
|
|
|
|
|
guint cnxn_id,
|
|
|
|
|
GConfEntry *entry,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
|
|
|
|
GConfValue *value;
|
|
|
|
|
const gchar *key, *key_tail;
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW(user_data);
|
|
|
|
|
|
|
|
|
|
key = gconf_entry_get_key(entry);
|
|
|
|
|
value = gconf_entry_get_value(entry);
|
|
|
|
|
if (!key || !value)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
key_tail = rindex(key, '/');
|
|
|
|
|
if (key_tail != NULL)
|
|
|
|
|
key_tail++;
|
|
|
|
|
if (strcmp(key_tail, KEY_TOOLBAR_STYLE) == 0) {
|
|
|
|
|
gnc_main_window_update_toolbar(window);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-07 17:12:30 +00:00
|
|
|
/* CS: This callback functions will set the statusbar text to the
|
|
|
|
|
* "tooltip" property of the currently selected GtkAction.
|
|
|
|
|
*
|
|
|
|
|
* This code is directly copied from gtk+/test/testmerge.c.
|
|
|
|
|
* Thanks to (L)GPL! */
|
|
|
|
|
typedef struct _ActionStatus ActionStatus;
|
|
|
|
|
struct _ActionStatus {
|
|
|
|
|
GtkAction *action;
|
|
|
|
|
GtkWidget *statusbar;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
action_status_destroy (gpointer data)
|
|
|
|
|
{
|
|
|
|
|
ActionStatus *action_status = data;
|
|
|
|
|
|
|
|
|
|
g_object_unref (action_status->action);
|
|
|
|
|
g_object_unref (action_status->statusbar);
|
|
|
|
|
|
|
|
|
|
g_free (action_status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_tip (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
ActionStatus *data;
|
|
|
|
|
gchar *tooltip;
|
|
|
|
|
|
|
|
|
|
data = g_object_get_data (G_OBJECT (widget), "action-status");
|
|
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
g_object_get (data->action, "tooltip", &tooltip, NULL);
|
|
|
|
|
|
|
|
|
|
gtk_statusbar_push (GTK_STATUSBAR (data->statusbar), 0,
|
|
|
|
|
tooltip ? tooltip : "");
|
|
|
|
|
|
|
|
|
|
g_free (tooltip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unset_tip (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
ActionStatus *data;
|
|
|
|
|
|
|
|
|
|
data = g_object_get_data (G_OBJECT (widget), "action-status");
|
|
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
|
gtk_statusbar_pop (GTK_STATUSBAR (data->statusbar), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
connect_proxy (GtkUIManager *merge,
|
|
|
|
|
GtkAction *action,
|
|
|
|
|
GtkWidget *proxy,
|
|
|
|
|
GtkWidget *statusbar)
|
|
|
|
|
{
|
|
|
|
|
if (GTK_IS_MENU_ITEM (proxy))
|
|
|
|
|
{
|
|
|
|
|
ActionStatus *data;
|
|
|
|
|
|
|
|
|
|
data = g_object_get_data (G_OBJECT (proxy), "action-status");
|
|
|
|
|
if (data)
|
|
|
|
|
{
|
|
|
|
|
g_object_unref (data->action);
|
|
|
|
|
g_object_unref (data->statusbar);
|
|
|
|
|
|
|
|
|
|
data->action = g_object_ref (action);
|
|
|
|
|
data->statusbar = g_object_ref (statusbar);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
data = g_new0 (ActionStatus, 1);
|
|
|
|
|
|
|
|
|
|
data->action = g_object_ref (action);
|
|
|
|
|
data->statusbar = g_object_ref (statusbar);
|
|
|
|
|
|
|
|
|
|
g_object_set_data_full (G_OBJECT (proxy), "action-status",
|
|
|
|
|
data, action_status_destroy);
|
|
|
|
|
|
|
|
|
|
g_signal_connect (proxy, "select", G_CALLBACK (set_tip), NULL);
|
|
|
|
|
g_signal_connect (proxy, "deselect", G_CALLBACK (unset_tip), NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* CS: end copied code from gtk+/test/testmerge.c */
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_setup_window (GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GtkWidget *main_vbox;
|
|
|
|
|
guint merge_id;
|
|
|
|
|
GncPluginManager *manager;
|
|
|
|
|
GList *plugins;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
gchar *filename;
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
ENTER(" ");
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/* Catch window manager delete signal */
|
|
|
|
|
g_signal_connect (G_OBJECT (window), "delete-event",
|
|
|
|
|
G_CALLBACK (gnc_main_window_delete_event), window);
|
|
|
|
|
|
|
|
|
|
/* Create widgets and add them to the window */
|
|
|
|
|
main_vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_widget_show (main_vbox);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (window), main_vbox);
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
priv->menu_dock = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_widget_show (priv->menu_dock);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), priv->menu_dock,
|
|
|
|
|
FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
priv->notebook = gtk_notebook_new ();
|
|
|
|
|
g_object_set(G_OBJECT(priv->notebook),
|
|
|
|
|
"scrollable", TRUE,
|
|
|
|
|
"enable-popup", TRUE,
|
2005-11-16 21:59:48 +00:00
|
|
|
(char *)NULL);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_widget_show (priv->notebook);
|
|
|
|
|
g_signal_connect (G_OBJECT (priv->notebook), "switch-page",
|
|
|
|
|
G_CALLBACK (gnc_main_window_switch_page), window);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), priv->notebook,
|
|
|
|
|
TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
priv->statusbar = gtk_statusbar_new ();
|
|
|
|
|
gtk_widget_show (priv->statusbar);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), priv->statusbar,
|
|
|
|
|
FALSE, TRUE, 0);
|
|
|
|
|
gtk_statusbar_set_has_resize_grip( GTK_STATUSBAR(priv->statusbar), TRUE );
|
|
|
|
|
|
|
|
|
|
priv->progressbar = gtk_progress_bar_new ();
|
|
|
|
|
gtk_widget_show (priv->progressbar);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar,
|
|
|
|
|
FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
window->ui_merge = gtk_ui_manager_new ();
|
|
|
|
|
|
|
|
|
|
/* Create menu and toolbar information */
|
|
|
|
|
priv->action_group = gtk_action_group_new ("MainWindowActions");
|
2006-01-08 14:01:14 +00:00
|
|
|
gnc_gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_action_group_add_actions (priv->action_group, gnc_menu_actions,
|
|
|
|
|
gnc_menu_n_actions, window);
|
|
|
|
|
gtk_action_group_add_toggle_actions (priv->action_group,
|
|
|
|
|
toggle_actions, n_toggle_actions,
|
|
|
|
|
window);
|
|
|
|
|
gtk_action_group_add_radio_actions (priv->action_group,
|
|
|
|
|
radio_entries, n_radio_entries,
|
|
|
|
|
0,
|
|
|
|
|
G_CALLBACK(gnc_main_window_cmd_window_raise),
|
|
|
|
|
window);
|
2005-11-06 00:14:40 +00:00
|
|
|
gnc_plugin_update_actions(priv->action_group,
|
2005-11-02 03:32:36 +00:00
|
|
|
always_insensitive_actions,
|
|
|
|
|
"sensitive", FALSE);
|
2005-12-30 05:07:14 +00:00
|
|
|
gnc_plugin_update_actions(priv->action_group,
|
|
|
|
|
always_hidden_actions,
|
|
|
|
|
"visible", FALSE);
|
2005-11-06 00:14:40 +00:00
|
|
|
gnc_plugin_set_important_actions (priv->action_group,
|
2005-11-03 00:49:05 +00:00
|
|
|
gnc_menu_important_actions);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_ui_manager_insert_action_group (window->ui_merge, priv->action_group, 0);
|
|
|
|
|
|
|
|
|
|
g_signal_connect (G_OBJECT (window->ui_merge), "add_widget",
|
|
|
|
|
G_CALLBACK (gnc_main_window_add_widget), window);
|
2006-01-07 17:12:30 +00:00
|
|
|
/* Use the "connect-proxy" signal for tooltip display in the
|
|
|
|
|
status bar */
|
|
|
|
|
g_signal_connect (G_OBJECT (window->ui_merge), "connect-proxy",
|
|
|
|
|
G_CALLBACK (connect_proxy), priv->statusbar);
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
filename = gnc_gnome_locate_ui_file("gnc-main-window-ui.xml");
|
|
|
|
|
|
|
|
|
|
/* Can't do much without a ui. */
|
|
|
|
|
g_assert (filename);
|
|
|
|
|
|
|
|
|
|
merge_id = gtk_ui_manager_add_ui_from_file (window->ui_merge,
|
|
|
|
|
filename, &error);
|
|
|
|
|
g_assert(merge_id || error);
|
|
|
|
|
if (merge_id) {
|
|
|
|
|
gtk_window_add_accel_group (GTK_WINDOW (window),
|
|
|
|
|
gtk_ui_manager_get_accel_group(window->ui_merge));
|
|
|
|
|
gtk_ui_manager_ensure_update (window->ui_merge);
|
|
|
|
|
} else {
|
|
|
|
|
g_critical("Failed to load ui file.\n Filename %s\n Error %s",
|
|
|
|
|
filename, error->message);
|
|
|
|
|
g_error_free(error);
|
|
|
|
|
g_assert(merge_id != 0);
|
|
|
|
|
}
|
|
|
|
|
g_free(filename);
|
|
|
|
|
|
|
|
|
|
gnc_gconf_add_notification(G_OBJECT(window), GCONF_GENERAL,
|
|
|
|
|
gnc_main_window_gconf_changed);
|
|
|
|
|
gnc_gconf_add_notification(G_OBJECT(window), DESKTOP_GNOME_INTERFACE,
|
|
|
|
|
gnc_main_window_gconf_changed);
|
|
|
|
|
gnc_main_window_update_toolbar(window);
|
|
|
|
|
|
|
|
|
|
/* Testing */
|
|
|
|
|
/* Now update the "eXtensions" menu */
|
2006-01-25 01:21:28 +00:00
|
|
|
if (!gnc_is_debugging()) {
|
2005-11-02 03:32:36 +00:00
|
|
|
GtkAction* action;
|
|
|
|
|
|
2006-01-25 01:21:28 +00:00
|
|
|
action = gtk_action_group_get_action(priv->action_group,
|
|
|
|
|
"ExtensionsAction");
|
2005-11-16 21:59:48 +00:00
|
|
|
g_object_set(G_OBJECT(action), "visible", FALSE, (char *)NULL);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GncPluginManager stuff */
|
|
|
|
|
manager = gnc_plugin_manager_get ();
|
|
|
|
|
plugins = gnc_plugin_manager_get_plugins (manager);
|
|
|
|
|
g_list_foreach (plugins, gnc_main_window_add_plugin, window);
|
|
|
|
|
g_list_free (plugins);
|
|
|
|
|
|
|
|
|
|
g_signal_connect (G_OBJECT (manager), "plugin-added",
|
|
|
|
|
G_CALLBACK (gnc_main_window_plugin_added), window);
|
|
|
|
|
g_signal_connect (G_OBJECT (manager), "plugin-removed",
|
|
|
|
|
G_CALLBACK (gnc_main_window_plugin_removed), window);
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
LEAVE(" ");
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
/* Callbacks */
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_add_widget (GtkUIManager *merge,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
if (GTK_IS_TOOLBAR (widget)) {
|
2005-11-14 05:14:21 +00:00
|
|
|
priv->toolbar = widget;
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
gtk_box_pack_start (GTK_BOX (priv->menu_dock), widget, FALSE, FALSE, 0);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_widget_show (widget);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-04 05:49:15 +00:00
|
|
|
/** Should a summary bar be visible in this window? In order to
|
|
|
|
|
* prevent synchronization issues, the "ViewSummaryBar"
|
|
|
|
|
* GtkToggleAction is the sole source of information for whether or
|
2005-11-14 05:14:21 +00:00
|
|
|
* not any summary bar should be visible in a window.
|
2005-11-04 05:49:15 +00:00
|
|
|
*
|
|
|
|
|
* @param window A pointer to the window in question.
|
|
|
|
|
*
|
|
|
|
|
* @param action If known, a pointer to the "ViewSummaryBar"
|
|
|
|
|
* GtkToggleAction. If NULL, the function will look up this action.
|
|
|
|
|
*
|
|
|
|
|
* @return TRUE if the summarybar should be visible.
|
|
|
|
|
*/
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_show_summarybar (GncMainWindow *window, GtkAction *action)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-04 05:49:15 +00:00
|
|
|
if (action == NULL)
|
2005-11-06 00:14:40 +00:00
|
|
|
action = gtk_action_group_get_action(priv->action_group,
|
2005-11-04 05:49:15 +00:00
|
|
|
"ViewSummaryAction");
|
|
|
|
|
if (action == NULL)
|
|
|
|
|
return TRUE;
|
|
|
|
|
return gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/** This function is invoked when the GtkNotebook switches pages. It
|
|
|
|
|
* is responsible for updating the rest of the window contents
|
|
|
|
|
* outside of the notebook. I.E. Updating the user interface, the
|
|
|
|
|
* summary bar, etc. This function also emits the "page_changed"
|
|
|
|
|
* signal from the window so that any plugin can also learn about the
|
|
|
|
|
* fact that the page has changed.
|
|
|
|
|
*
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_switch_page (GtkNotebook *notebook,
|
|
|
|
|
GtkNotebookPage *notebook_page,
|
|
|
|
|
gint pos,
|
|
|
|
|
GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-04 05:49:15 +00:00
|
|
|
GtkWidget *child;
|
2005-11-02 03:32:36 +00:00
|
|
|
GncPluginPage *page;
|
2005-11-04 05:49:15 +00:00
|
|
|
gboolean immutable, visible;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
ENTER("Notebook %p, page, %p, index %d, window %p",
|
|
|
|
|
notebook, notebook_page, pos, window);
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (priv->current_page != NULL) {
|
|
|
|
|
page = priv->current_page;
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_plugin_page_unmerge_actions (page, window->ui_merge);
|
|
|
|
|
gnc_plugin_page_unselected (page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child = gtk_notebook_get_nth_page (notebook, pos);
|
|
|
|
|
if (child) {
|
|
|
|
|
page = g_object_get_data (G_OBJECT (child), PLUGIN_PAGE_LABEL);
|
|
|
|
|
} else {
|
|
|
|
|
page = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv->current_page = page;
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
if (page != NULL) {
|
|
|
|
|
/* Update the user interface (e.g. menus and toolbars */
|
|
|
|
|
gnc_plugin_page_merge_actions (page, window->ui_merge);
|
2005-11-04 05:49:15 +00:00
|
|
|
visible = gnc_main_window_show_summarybar(window, NULL);
|
|
|
|
|
gnc_plugin_page_show_summarybar (page, visible);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
/* Allow page specific actions */
|
|
|
|
|
gnc_plugin_page_selected (page);
|
|
|
|
|
gnc_window_update_status (GNC_WINDOW(window), page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update the menus based upon whether this is an "immutable" page. */
|
|
|
|
|
immutable = page &&
|
|
|
|
|
g_object_get_data (G_OBJECT (page), PLUGIN_PAGE_IMMUTABLE);
|
2005-11-06 00:14:40 +00:00
|
|
|
gnc_plugin_update_actions(priv->action_group,
|
2005-11-02 03:32:36 +00:00
|
|
|
immutable_page_actions,
|
|
|
|
|
"sensitive", !immutable);
|
2005-11-06 00:14:40 +00:00
|
|
|
gnc_plugin_update_actions(priv->action_group,
|
2005-11-02 03:32:36 +00:00
|
|
|
multiple_page_actions,
|
|
|
|
|
"sensitive",
|
2005-11-06 00:14:40 +00:00
|
|
|
g_list_length(priv->installed_pages) > 1);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
gnc_main_window_update_title(window);
|
|
|
|
|
gnc_main_window_update_menu_item(window);
|
|
|
|
|
|
|
|
|
|
g_signal_emit (window, main_window_signals[PAGE_CHANGED], 0, page);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_plugin_added (GncPlugin *manager,
|
|
|
|
|
GncPlugin *plugin,
|
|
|
|
|
GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (GNC_IS_PLUGIN (plugin));
|
|
|
|
|
|
|
|
|
|
gnc_plugin_add_to_window (plugin, window, window_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_plugin_removed (GncPlugin *manager,
|
|
|
|
|
GncPlugin *plugin,
|
|
|
|
|
GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
|
|
|
|
|
g_return_if_fail (GNC_IS_PLUGIN (plugin));
|
|
|
|
|
|
|
|
|
|
gnc_plugin_remove_from_window (plugin, window, window_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Command callbacks */
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_file_properties (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
SCM func = scm_c_eval_string("gnc:main-window-properties-cb");
|
|
|
|
|
if (!SCM_PROCEDUREP (func)) {
|
|
|
|
|
PERR ("not a procedure\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
scm_call_0(func);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_file_close (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (priv->current_page != NULL) {
|
|
|
|
|
gnc_main_window_close_page (priv->current_page);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_file_quit (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
QofSession *session;
|
|
|
|
|
session = qof_session_get_current_session();
|
|
|
|
|
if (qof_book_not_saved(qof_session_get_book(session))) {
|
|
|
|
|
if (gnc_main_window_prompt_for_save(GTK_WIDGET(window))) {
|
2005-11-14 05:14:21 +00:00
|
|
|
/* User canceled */
|
2005-11-02 03:32:36 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gnc_shutdown (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_edit_preferences (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
gnc_preferences_dialog ();
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-23 23:28:44 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_edit_accelerator_keys( GtkToggleAction *action, GncMainWindow *window )
|
|
|
|
|
{
|
|
|
|
|
GtkSettings* settings;
|
|
|
|
|
|
|
|
|
|
settings = gtk_settings_get_default();
|
|
|
|
|
g_object_set(G_OBJECT(settings),
|
|
|
|
|
"gtk-can-change-accels", gtk_toggle_action_get_active(action),
|
|
|
|
|
(gchar*)NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_view_refresh (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
gnc_reset_warnings_dialog(GTK_WIDGET(window));
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-11 14:16:12 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GncPluginPage *page;
|
|
|
|
|
GtkWidget *tab_hbox, *widget, *label = NULL, *entry = NULL;
|
|
|
|
|
GList *children, *tmp;
|
|
|
|
|
|
|
|
|
|
ENTER(" ");
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
page = priv->current_page;
|
|
|
|
|
tab_hbox = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
|
|
|
|
|
page->notebook_page);
|
|
|
|
|
children = gtk_container_get_children(GTK_CONTAINER(tab_hbox));
|
|
|
|
|
for (tmp = children; tmp; tmp = g_list_next(tmp)) {
|
|
|
|
|
widget = tmp->data;
|
|
|
|
|
if (GTK_IS_LABEL(widget)) {
|
|
|
|
|
label = widget;
|
|
|
|
|
} else if (GTK_IS_ENTRY(widget)) {
|
|
|
|
|
entry = widget;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_list_free(children);
|
|
|
|
|
|
|
|
|
|
if (!label || !entry) {
|
|
|
|
|
LEAVE("Missing label or entry.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(entry), gtk_label_get_text(GTK_LABEL(label)));
|
|
|
|
|
gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
|
|
|
|
|
gtk_widget_hide(label);
|
|
|
|
|
gtk_widget_show(entry);
|
|
|
|
|
gtk_widget_grab_focus(entry);
|
|
|
|
|
LEAVE("opened for editing");
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
|
2005-11-14 05:14:21 +00:00
|
|
|
gtk_widget_show (priv->toolbar);
|
2005-11-02 03:32:36 +00:00
|
|
|
} else {
|
2005-11-14 05:14:21 +00:00
|
|
|
gtk_widget_hide (priv->toolbar);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
2005-11-04 05:49:15 +00:00
|
|
|
GList *item;
|
|
|
|
|
gboolean visible;
|
|
|
|
|
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-04 05:49:15 +00:00
|
|
|
visible = gnc_main_window_show_summarybar(window, action);
|
2005-11-06 00:14:40 +00:00
|
|
|
for (item = priv->installed_pages; item; item = g_list_next(item)) {
|
2005-11-04 05:49:15 +00:00
|
|
|
gnc_plugin_page_show_summarybar(item->data, visible);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
|
2005-11-06 00:14:40 +00:00
|
|
|
gtk_widget_show (priv->statusbar);
|
2005-11-02 03:32:36 +00:00
|
|
|
} else {
|
2005-11-06 00:14:40 +00:00
|
|
|
gtk_widget_hide (priv->statusbar);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-05 06:35:21 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_extensions_callgrind (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
static struct timeval start, end;
|
|
|
|
|
|
|
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
|
|
|
|
if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
|
|
|
|
|
printf("Start timing.\n");
|
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
|
CALLGRIND_START_INSTRUMENTATION();
|
|
|
|
|
CALLGRIND_TOGGLE_COLLECT();
|
|
|
|
|
} else {
|
|
|
|
|
CALLGRIND_TOGGLE_COLLECT();
|
|
|
|
|
CALLGRIND_STOP_INSTRUMENTATION();
|
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
|
if (start.tv_usec > end.tv_usec) {
|
|
|
|
|
end.tv_usec += 1000000;
|
|
|
|
|
end.tv_sec -= 1;
|
|
|
|
|
}
|
|
|
|
|
printf("Callgrind enabled for %d.%6d seconds.\n",
|
|
|
|
|
(int)(end.tv_sec - start.tv_sec),
|
|
|
|
|
(int)(end.tv_usec - start.tv_usec));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_window_new (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *new_window;
|
|
|
|
|
|
|
|
|
|
/* Create the new window */
|
|
|
|
|
ENTER(" ");
|
|
|
|
|
new_window = gnc_main_window_new ();
|
|
|
|
|
gtk_widget_show(GTK_WIDGET(new_window));
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_window_move_page (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
2005-11-06 00:14:40 +00:00
|
|
|
GncMainWindowPrivate *priv, *new_priv;
|
2005-11-02 03:32:36 +00:00
|
|
|
GncMainWindow *new_window;
|
|
|
|
|
GncPluginPage *page;
|
|
|
|
|
GtkNotebook *notebook;
|
|
|
|
|
GtkWidget *tab_widget, *menu_widget;
|
|
|
|
|
|
|
|
|
|
/* Setup */
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
if (priv->current_page == NULL)
|
|
|
|
|
return;
|
|
|
|
|
notebook = GTK_NOTEBOOK (priv->notebook);
|
|
|
|
|
page = priv->current_page;
|
|
|
|
|
tab_widget = gtk_notebook_get_tab_label (notebook, page->notebook_page);
|
|
|
|
|
menu_widget = gtk_notebook_get_menu_label (notebook, page->notebook_page);
|
|
|
|
|
|
|
|
|
|
/* Ref the page components, then remove it from its old window */
|
|
|
|
|
g_object_ref(page);
|
|
|
|
|
g_object_ref(tab_widget);
|
|
|
|
|
g_object_ref(menu_widget);
|
|
|
|
|
g_object_ref(page->notebook_page);
|
|
|
|
|
gnc_main_window_disconnect(window, page);
|
|
|
|
|
|
|
|
|
|
/* Create the new window */
|
|
|
|
|
new_window = gnc_main_window_new ();
|
|
|
|
|
gtk_widget_show(GTK_WIDGET(new_window));
|
|
|
|
|
|
|
|
|
|
/* Now add the page to the new window */
|
|
|
|
|
gnc_main_window_connect (new_window, page, tab_widget, menu_widget);
|
|
|
|
|
|
|
|
|
|
/* Unref the page components now that we're done */
|
|
|
|
|
g_object_unref(page->notebook_page);
|
|
|
|
|
g_object_unref(menu_widget);
|
|
|
|
|
g_object_unref(tab_widget);
|
|
|
|
|
g_object_unref(page);
|
|
|
|
|
|
|
|
|
|
/* just a little debugging. :-) */
|
2005-11-06 00:14:40 +00:00
|
|
|
new_priv = GNC_MAIN_WINDOW_GET_PRIVATE(new_window);
|
2005-11-04 05:49:15 +00:00
|
|
|
DEBUG("Moved page %p from window %p to new window %p",
|
|
|
|
|
page, window, new_window);
|
2005-11-02 03:32:36 +00:00
|
|
|
DEBUG("Old window current is %p, new window current is %p",
|
2005-11-06 00:14:40 +00:00
|
|
|
priv->current_page, priv->current_page);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_window_raise (GtkAction *action,
|
|
|
|
|
GtkRadioAction *current,
|
|
|
|
|
GncMainWindow *unused)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindow *window;
|
|
|
|
|
gint value;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(GTK_IS_ACTION(action));
|
|
|
|
|
g_return_if_fail(GTK_IS_RADIO_ACTION(current));
|
|
|
|
|
g_return_if_fail(GNC_IS_MAIN_WINDOW(unused));
|
|
|
|
|
|
|
|
|
|
ENTER("action %p, current %p, window %p", action, current, unused);
|
|
|
|
|
value = gtk_radio_action_get_current_value(current);
|
|
|
|
|
window = g_list_nth_data(active_windows, value);
|
|
|
|
|
gtk_window_present(GTK_WINDOW(window));
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_help_tutorial (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
gnc_gnome_help (HF_GUIDE, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_help_contents (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
gnc_gnome_help (HF_HELP, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-21 00:39:22 +00:00
|
|
|
#ifdef HAVE_GLIB26
|
|
|
|
|
/** This is a helper function to find a data file and suck it into
|
|
|
|
|
* memory.
|
|
|
|
|
*
|
|
|
|
|
* @param partial The name of the file relative to the gnucash
|
|
|
|
|
* specific shared data directory.
|
|
|
|
|
*
|
|
|
|
|
* @return The text of the file or NULL. The caller is responsible
|
|
|
|
|
* for freeing this string.
|
|
|
|
|
*/
|
|
|
|
|
static gchar *
|
|
|
|
|
get_file (const gchar *partial)
|
|
|
|
|
{
|
|
|
|
|
gchar *filename, *text = NULL;
|
|
|
|
|
|
|
|
|
|
filename = gnc_gnome_locate_data_file(partial);
|
|
|
|
|
g_file_get_contents(filename, &text, NULL, NULL);
|
|
|
|
|
g_free(filename);
|
|
|
|
|
|
|
|
|
|
/* Anything there? */
|
|
|
|
|
if (text && *text)
|
|
|
|
|
return text;
|
|
|
|
|
|
|
|
|
|
/* Just a empty string or no string at all. */
|
|
|
|
|
if (text)
|
|
|
|
|
g_free(text);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** This is a helper function to find a data file, suck it into
|
|
|
|
|
* memory, and split it into an array of strings.
|
|
|
|
|
*
|
|
|
|
|
* @param partial The name of the file relative to the gnucash
|
|
|
|
|
* specific shared data directory.
|
|
|
|
|
*
|
|
|
|
|
* @return The text of the file as an array of strings, or NULL. The
|
|
|
|
|
* caller is responsible for freeing all the strings and the array.
|
|
|
|
|
*/
|
|
|
|
|
static gchar **
|
|
|
|
|
get_file_strsplit (const gchar *partial)
|
|
|
|
|
{
|
|
|
|
|
gchar *text, **lines;
|
|
|
|
|
|
|
|
|
|
text = get_file(partial);
|
|
|
|
|
if (!text)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
lines = g_strsplit_set(text, "\r\n", -1);
|
|
|
|
|
g_free(text);
|
|
|
|
|
return lines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Create and display the "about" dialog for gnucash.
|
|
|
|
|
*
|
|
|
|
|
* @param action The GtkAction for the "about" menu item.
|
|
|
|
|
*
|
|
|
|
|
* @param window The main window whose menu item was activated.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_help_about (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
const gchar *message = _("The GnuCash personal finance manager.\n"
|
|
|
|
|
"The GNU way to manage your money!\n");
|
|
|
|
|
const gchar *copyright = "© 1998-2005 Linas Vepstas";
|
2005-11-29 03:25:05 +00:00
|
|
|
gchar **authors, **documenters, *license;
|
2005-11-21 00:39:22 +00:00
|
|
|
GdkPixbuf *logo;
|
|
|
|
|
GtkWidget *dialog;
|
|
|
|
|
|
|
|
|
|
logo = gnc_gnome_get_gdkpixbuf ("appicon.png");
|
|
|
|
|
|
|
|
|
|
authors = get_file_strsplit("doc/AUTHORS");
|
|
|
|
|
documenters = get_file_strsplit("doc/DOCUMENTERS");
|
|
|
|
|
license = get_file("doc/LICENSE");
|
|
|
|
|
|
|
|
|
|
dialog = gtk_about_dialog_new();
|
|
|
|
|
g_object_set (G_OBJECT(dialog),
|
|
|
|
|
"authors", authors,
|
|
|
|
|
"documenters", documenters,
|
|
|
|
|
"comments", message,
|
|
|
|
|
"copyright", copyright,
|
|
|
|
|
"license", license,
|
|
|
|
|
"logo", logo,
|
|
|
|
|
"name", "GnuCash",
|
2005-11-29 03:25:05 +00:00
|
|
|
"translator-credits", _("translator_credits"),
|
2005-11-21 00:39:22 +00:00
|
|
|
"version", VERSION,
|
|
|
|
|
"website", "http://www.gnucash.org",
|
|
|
|
|
(gchar *)NULL);
|
|
|
|
|
|
|
|
|
|
if (license) g_free(license);
|
|
|
|
|
if (documenters) g_strfreev(documenters);
|
|
|
|
|
if (authors) g_strfreev(authors);
|
2006-01-11 02:41:26 +00:00
|
|
|
g_object_unref (logo);
|
2005-11-21 00:39:22 +00:00
|
|
|
|
|
|
|
|
gtk_widget_show(dialog);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_main_window_cmd_help_about (GtkAction *action, GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *about;
|
2005-11-28 20:22:43 +00:00
|
|
|
/* Translators: This is the "About" message. */
|
2005-11-02 03:32:36 +00:00
|
|
|
const gchar *message = _("The GnuCash personal finance manager.\n"
|
|
|
|
|
"The GNU way to manage your money!\n"
|
|
|
|
|
"http://www.gnucash.org/");
|
2005-11-21 00:39:22 +00:00
|
|
|
const gchar *copyright = "© 1998-2002 Linas Vepstas";
|
2005-11-02 03:32:36 +00:00
|
|
|
const gchar *authors[] = {
|
|
|
|
|
"Derek Atkins <derek@ihtfp.com>",
|
|
|
|
|
"Rob Browning <rlb@cs.utexas.edu>",
|
|
|
|
|
"Bill Gribble <grib@billgribble.com>",
|
|
|
|
|
"David Hampton <hampton@employees.org>",
|
|
|
|
|
"James LewisMoss <dres@debian.org>",
|
|
|
|
|
"Robert Graham Merkel <rgmerk@mira.net>",
|
|
|
|
|
"Dave Peticolas <dave@krondo.com>",
|
|
|
|
|
"Joshua Sled <jsled@asynchronous.org>",
|
|
|
|
|
"Christian Stimming <stimming@tuhh.de>",
|
|
|
|
|
"Linas Vepstas <linas@linas.org>",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
const gchar *documenters[] = {
|
|
|
|
|
NULL
|
|
|
|
|
};
|
2005-11-28 20:22:43 +00:00
|
|
|
/* Translators: Insert your translator's credits here so that
|
|
|
|
|
they will be shown in the "About" dialog. */
|
2005-11-02 03:32:36 +00:00
|
|
|
const gchar *translator_credits = _("translator_credits");
|
|
|
|
|
GdkPixbuf *logo;
|
|
|
|
|
|
|
|
|
|
logo = gnc_gnome_get_gdkpixbuf ("appicon.png");
|
|
|
|
|
|
|
|
|
|
about = gnome_about_new ("GnuCash", VERSION, copyright, message, authors, documenters,
|
|
|
|
|
strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL,
|
|
|
|
|
logo);
|
|
|
|
|
|
2006-01-11 02:41:26 +00:00
|
|
|
g_object_unref (logo);
|
2005-11-02 03:32:36 +00:00
|
|
|
gtk_dialog_run (GTK_DIALOG (about));
|
|
|
|
|
}
|
2005-11-21 00:39:22 +00:00
|
|
|
#endif
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
|
* *
|
|
|
|
|
************************************************************/
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
/** Get a pointer to a top level window... any top level window. This
|
|
|
|
|
* function just returns a pointer to the first window.
|
|
|
|
|
*
|
|
|
|
|
* @return A pointer to a GtkWindow object. */
|
2005-11-02 03:32:36 +00:00
|
|
|
gncUIWidget
|
|
|
|
|
gnc_ui_get_toplevel (void)
|
|
|
|
|
{
|
|
|
|
|
if (active_windows)
|
|
|
|
|
return active_windows->data;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
|
|
|
|
/** Retrieve the gtk window associated with a main window object.
|
|
|
|
|
* This function is called via a vector off a generic window
|
|
|
|
|
* interface.
|
|
|
|
|
*
|
|
|
|
|
* @param window_in A pointer to a generic window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GtkWindow *
|
|
|
|
|
gnc_main_window_get_gtk_window (GncWindow *window)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window), NULL);
|
|
|
|
|
return GTK_WINDOW(window);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
|
|
|
|
/** Retrieve the status bar associated with a main window object.
|
|
|
|
|
* This function is called via a vector off a generic window
|
|
|
|
|
* interface.
|
|
|
|
|
*
|
|
|
|
|
* @param window_in A pointer to a generic window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GtkWidget *
|
|
|
|
|
gnc_main_window_get_statusbar (GncWindow *window_in)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GncMainWindow *window;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window_in), NULL);
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW(window_in);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
return priv->statusbar;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
|
|
|
|
/** Retrieve the progress bar associated with a main window object.
|
|
|
|
|
* This function is called via a vector off a generic window
|
|
|
|
|
* interface.
|
|
|
|
|
*
|
|
|
|
|
* @param window_in A pointer to a generic window. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static GtkWidget *
|
|
|
|
|
gnc_main_window_get_progressbar (GncWindow *window_in)
|
|
|
|
|
{
|
|
|
|
|
GncMainWindowPrivate *priv;
|
|
|
|
|
GncMainWindow *window;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GNC_IS_MAIN_WINDOW (window_in), NULL);
|
|
|
|
|
|
|
|
|
|
window = GNC_MAIN_WINDOW(window_in);
|
2005-11-06 00:14:40 +00:00
|
|
|
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
|
2005-11-02 03:32:36 +00:00
|
|
|
return priv->progressbar;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-14 05:14:21 +00:00
|
|
|
|
|
|
|
|
/** Initialize the generic window interface for a main window.
|
|
|
|
|
*
|
|
|
|
|
* @param iface A pointer to the interface data structure to
|
|
|
|
|
* populate. */
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_window_main_window_init (GncWindowIface *iface)
|
|
|
|
|
{
|
|
|
|
|
iface->get_gtk_window = gnc_main_window_get_gtk_window;
|
|
|
|
|
iface->get_statusbar = gnc_main_window_get_statusbar;
|
|
|
|
|
iface->get_progressbar = gnc_main_window_get_progressbar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the window where all progressbar updates should occur. This
|
|
|
|
|
* is a wrapper around the gnc_window_set_progressbar_window()
|
|
|
|
|
* function.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_main_window_set_progressbar_window (GncMainWindow *window)
|
|
|
|
|
{
|
|
|
|
|
GncWindow *gncwin;
|
|
|
|
|
gncwin = GNC_WINDOW(window);
|
|
|
|
|
gnc_window_set_progressbar_window(gncwin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Popup a contextual menu. This function ends up being called when
|
|
|
|
|
* the user right-clicks in the context of a window, or uses the
|
|
|
|
|
* keyboard context-menu request key combination (Shift-F10 by
|
|
|
|
|
* default).
|
|
|
|
|
*
|
|
|
|
|
* @param page This is the GncPluginPage corresponding to the visible
|
|
|
|
|
* page.
|
|
|
|
|
*
|
|
|
|
|
* @param event The event parameter passed to the "button-press"
|
|
|
|
|
* callback. May be null if there was no event (aka keyboard
|
|
|
|
|
* request).
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
do_popup_menu(GncPluginPage *page, GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
GtkUIManager *ui_merge;
|
|
|
|
|
GtkWidget *menu;
|
|
|
|
|
int button, event_time;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(GNC_IS_PLUGIN_PAGE(page));
|
|
|
|
|
|
|
|
|
|
ENTER("page %p, event %p", page, event);
|
|
|
|
|
ui_merge = gnc_plugin_page_get_ui_merge(page);
|
|
|
|
|
if (ui_merge == NULL) {
|
|
|
|
|
LEAVE("no ui merge");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
menu = gtk_ui_manager_get_widget(ui_merge, "/MainPopup");
|
|
|
|
|
if (!menu) {
|
|
|
|
|
LEAVE("no menu");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event) {
|
|
|
|
|
button = event->button;
|
|
|
|
|
event_time = event->time;
|
|
|
|
|
} else {
|
|
|
|
|
button = 0;
|
|
|
|
|
event_time = gtk_get_current_event_time ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Callback function invoked when the user requests that Gnucash
|
|
|
|
|
* popup the contextual menu via the keyboard context-menu request
|
|
|
|
|
* key combination (Shift-F10 by default).
|
|
|
|
|
*
|
|
|
|
|
* @param page This is the GncPluginPage corresponding to the visible
|
|
|
|
|
* page.
|
|
|
|
|
*
|
|
|
|
|
* @param widget Whatever widget had focus when the user issued the
|
|
|
|
|
* keyboard context-menu request.
|
|
|
|
|
*
|
|
|
|
|
* @return Always returns TRUE to indicate that the menu request was
|
|
|
|
|
* handled.
|
|
|
|
|
*/
|
|
|
|
|
static gboolean
|
|
|
|
|
gnc_main_window_popup_menu_cb (GtkWidget *widget,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
ENTER("widget %p, page %p", widget, page);
|
|
|
|
|
do_popup_menu(page, NULL);
|
|
|
|
|
LEAVE(" ");
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Callback function invoked when the user clicks in the content of
|
|
|
|
|
* any Gnucash window. If this was a "right-click" then Gnucash will
|
|
|
|
|
* popup the contextual menu.
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
gnc_main_window_button_press_cb (GtkWidget *whatever,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GncPluginPage *page)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE);
|
|
|
|
|
|
|
|
|
|
ENTER("widget %p, event %p, page %p", whatever, event, page);
|
|
|
|
|
/* Ignore double-clicks and triple-clicks */
|
|
|
|
|
if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
|
|
|
|
|
do_popup_menu(page, event);
|
|
|
|
|
LEAVE("menu shown");
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LEAVE("other click");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-01-08 14:01:14 +00:00
|
|
|
/* CS: Code copied from gtk/gtkactiongroup.c */
|
|
|
|
|
static gchar *
|
|
|
|
|
dgettext_swapped (const gchar *msgid,
|
|
|
|
|
const gchar *domainname)
|
|
|
|
|
{
|
|
|
|
|
/* CS: Pass this through dgettext if and only if msgid is
|
|
|
|
|
nonempty. */
|
|
|
|
|
return (msgid && *msgid) ? dgettext (domainname, msgid) : (gchar*) msgid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is copied into GnuCash from Gtk in order to fix problems when
|
|
|
|
|
* empty msgids were passed through gettext().
|
|
|
|
|
*
|
|
|
|
|
* See http://bugzilla.gnome.org/show_bug.cgi?id=326200 . If that bug
|
|
|
|
|
* is fixed in the gtk that we can rely open, then
|
|
|
|
|
* gnc_gtk_action_group_set_translation_domain can be replaced by
|
|
|
|
|
* gtk_action_group_set_translation_domain again.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gnc_gtk_action_group_set_translation_domain (GtkActionGroup *action_group,
|
|
|
|
|
const gchar *domain)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
|
|
|
|
|
|
|
|
|
|
gtk_action_group_set_translate_func (action_group,
|
|
|
|
|
(GtkTranslateFunc)dgettext_swapped,
|
|
|
|
|
g_strdup (domain),
|
|
|
|
|
g_free);
|
|
|
|
|
}
|
|
|
|
|
/* CS: End of code copied from gtk/gtkactiongroup.c */
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/** @} */
|
|
|
|
|
/** @} */
|