Add code to save window state into a Glib Key-Value file. This code

is distributed between the gnc-main-window code and all of the plugin
pages.  It subsumes the existing state file code, and will call that
code upon file open if it cannot find a key-value state file.  This
code is also where the creation of the initial account tree page
occurs when no state file is found.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@11905 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
David Hampton
2005-11-11 14:16:12 +00:00
parent 1d6c73d495
commit 817dd3687f
27 changed files with 1695 additions and 78 deletions

View File

@@ -1,5 +1,29 @@
2005-11-11 David Hampton <hampton@employees.org>
* src/app-utils/file-utils.[ch]:
* src/app-utils/guile-util.[ch]:
* src/business/business-gnome/gnc-plugin-business.c:
* src/business/business-gnome/gnc-plugin-page-invoice.h:
* src/gnome-utils/gnc-main-window.c:
* src/gnome-utils/gnc-plugin-page.[ch]:
* src/gnome-utils/ui/gnc-main-window-ui.xml:
* src/gnome/gnc-plugin-account-tree.[ch]:
* src/gnome/gnc-plugin-budget.c:
* src/gnome/gnc-plugin-page-account-tree.[ch]:
* src/gnome/gnc-plugin-page-budget.h:
* src/gnome/gnc-plugin-page-register.c:
* src/gnome/gnc-plugin-register.c:
* src/gnome/gw-gnc-spec.scm:
* src/report/report-gnome/gnc-plugin-page-report.[ch]:
* src/report/report-gnome/window-report.c:
* src/scm/main-window.scm: Add code to save window state into a
Glib Key-Value file. This code is distributed between the
gnc-main-window code and all of the plugin pages. It subsumes the
existing state file code, and will call that code upon file open
if it cannot find a key-value state file. This code is also where
the creation of the initial account tree page occurs when no state
file is found.
* lib/glib26/gkeyfile.c:
* lib/glib26/gutils26.c: Fix a couple of gcc4 warnings.

View File

@@ -34,6 +34,7 @@
#include "file-utils.h"
#include "messages.h"
#include "gnc-engine.h"
#include "gnc-gkeyfile-utils.h"
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_GUILE;
@@ -166,4 +167,73 @@ gnc_getline (gchar **line, FILE *file)
}
/* Find the state file that corresponds to this URL and guid. The
* URL is used to compute the base name of the file (which will be in
* ~/.gnucash/books) and the guid is used to differentiate when the
* user has multiple data files with the same name. */
GKeyFile *
gnc_find_state_file (const gchar *url,
const gchar *guid,
gchar **filename_p)
{
gchar *basename, *original = NULL, *filename, *tmp, *file_guid;
GKeyFile *key_file = NULL;
GError *error = NULL;
gint i;
ENTER("url %s, guid %s", url, guid);
tmp = index(url, ':');
if (tmp)
url = tmp + 1;
basename = g_path_get_basename(url);
DEBUG("Basename %s", basename);
original = g_build_filename(g_get_home_dir(), ".gnucash",
"books", basename, NULL);
g_free(basename);
DEBUG("Original %s", original);
i = 1;
while (1) {
if (i == 1)
filename = g_strdup(original);
else
filename = g_strdup_printf("%s_%d", original, i);
DEBUG("Trying %s", filename);
key_file = gnc_key_file_load_from_file(filename, FALSE);
DEBUG("Result %p", key_file);
if (!key_file) {
DEBUG("No key file by that name");
break;
}
file_guid = g_key_file_get_string(key_file,
STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
&error);
DEBUG("File GUID is %s", file_guid);
if (strcmp(guid, file_guid) == 0) {
DEBUG("Matched !!!");
g_free(file_guid);
break;
}
DEBUG("Clean up this pass");
g_free(file_guid);
g_key_file_free(key_file);
g_free(filename);
i++;
}
DEBUG("Clean up");
g_free(original);
if (filename_p)
*filename_p = filename;
else
g_free(filename);
LEAVE("key_file %p, filename %s", key_file,
filename_p ? *filename_p : "(none)");
return key_file;
}
/* ----------------------- END OF FILE --------------------- */

View File

@@ -30,6 +30,9 @@
#define GNC_FILE_UTILS_H
#include <stdio.h> /* for FILE* */
#ifndef HAVE_GLIB26
#include "gkeyfile.h"
#endif
char * gncFindFile (const char * filename);
@@ -59,4 +62,24 @@ int gncReadFile (const char * file, char ** data);
gint64 gnc_getline (gchar **line, FILE *file);
/* Definitions shared by file-utils.c and gnc-main-window.c */
#define STATE_FILE_TOP "Top"
#define STATE_FILE_BOOK_GUID "Book Guid"
/** Find the state file that corresponds to this URL and guid. The
* URL is used to compute the base name of the file (which will be in
* ~/.gnucash/books) and the guid is used to differentiate when the
* user has multiple data files with the same name.
*
* @param url The usrl of the data file being used.
*
* @param guid The guid of the book associated with this data file.
*
* @param next_filename Return the next available file name if the
* data file cannot be found.
*
* @return The name of the data file that was located.
*/
GKeyFile *gnc_find_state_file (const gchar *url, const gchar *guid, gchar **filename);
#endif /* GNC_FILE_UTILS_H */

View File

@@ -1152,3 +1152,27 @@ gnc_get_credit_string(GNCAccountType account_type)
return g_strdup(string);
return NULL;
}
/* Clean up a scheme options string for use in a key/value file.
* This function removes all full line comments, removes all blank
* lines, and removes all leading/trailing white space. */
gchar *gnc_guile_strip_comments (const gchar *raw_text)
{
gchar *text, **splits;
gint i, j;
splits = g_strsplit(raw_text, "\n", -1);
for (i = j = 0; splits[i]; i++) {
if ((splits[i][0] == ';') || (splits[i][0] == '\0')) {
g_free(splits[i]);
continue;
}
splits[j++] = g_strstrip(splits[i]);
}
splits[j] = NULL;
text = g_strjoinv(" ", splits);
g_strfreev(splits);
return text;
}

View File

@@ -95,4 +95,13 @@ int gnc_trans_scm_get_num_splits(SCM trans_scm);
char * gnc_get_debit_string(GNCAccountType account_type);
char * gnc_get_credit_string(GNCAccountType account_type);
/** Clean up a scheme options string for use in a key/value file.
* This function removes all full line comments, removes all blank
* lines, and removes all leading/trailing white space.
*
* @note: This function does not correctly handle comments that occur
* at the end of a line. Fortunately there aren't any such
* comments. */
gchar *gnc_guile_strip_comments (const gchar *text);
#endif

View File

@@ -38,6 +38,7 @@
#include "dialog-tax-table.h"
#include "dialog-vendor.h"
#include "gnc-plugin-business.h"
#include "gnc-plugin-page-invoice.h"
#include "gncOwner.h"
#include "messages.h"
#include "gnc-ui-util.h"
@@ -303,6 +304,10 @@ gnc_plugin_business_new (void)
{
GncPluginBusiness *plugin;
/* Reference the invoice page plugin to ensure it exists in
* the gtk type system. */
GNC_TYPE_PLUGIN_PAGE_INVOICE;
plugin = g_object_new (GNC_TYPE_PLUGIN_BUSINESS,
NULL);

View File

@@ -49,7 +49,7 @@ G_BEGIN_DECLS
#define GNC_IS_PLUGIN_PAGE_INVOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_INVOICE))
#define GNC_PLUGIN_PAGE_INVOICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_INVOICE, GncPluginPageInvoiceClass))
#define GNC_PLUGIN_PAGE_INVOICE_NAME "gnc-plugin-page-invoice"
#define GNC_PLUGIN_PAGE_INVOICE_NAME "GncPluginPageInvoice"
/* typedefs & structures */
typedef struct {

View File

@@ -17,6 +17,7 @@ AM_CFLAGS = \
-I${top_srcdir}/src/network-utils \
-I${top_srcdir}/src/app-utils \
-I${top_srcdir}/src \
-I${top_srcdir}/lib/glib26 \
${LIBGUPPI_CFLAGS} \
${GLIB_CFLAGS} \
${GLADE_CFLAGS} \
@@ -40,10 +41,11 @@ AM_CFLAGS = \
-I${top_srcdir}/src/backend/file \
-I${top_srcdir}/src/network-utils \
-I${top_srcdir}/src/app-utils \
-I${top_srcdir}/src \
-I${top_srcdir}/lib/goffice \
-I${top_srcdir}/lib/goffice/split \
-I${top_srcdir}/lib/glib26 \
-I${top_srcdir}/lib \
-I${top_srcdir}/src \
${LIBGUPPI_CFLAGS} \
${GNOME_CFLAGS} \
${GTKHTML_CFLAGS} \
@@ -205,6 +207,7 @@ libgncmod_gnome_utils_la_LIBADD = \
${top_builddir}/src/calculation/libgncmod-calculation.la \
${top_builddir}/src/network-utils/libgncmod-network-utils.la \
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
${top_builddir}/lib/glib26/libgncglib.la \
${LIBGUPPI_LIBS} \
${GNOME_LIBS} \
${GNOME_PRINT_LIBS} \
@@ -228,6 +231,7 @@ libgncmod_gnome_utils_la_LIBADD = \
${top_builddir}/src/network-utils/libgncmod-network-utils.la \
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
${top_builddir}/lib/goffice/libgoffice.la \
${top_builddir}/lib/glib26/libgncglib.la \
${LIBGUPPI_LIBS} \
${GNOME_LIBS} \
${GNOME_PRINT_LIBS} \

View File

@@ -35,8 +35,10 @@
#include "config.h"
#include <gdk/gdkpixbuf.h>
#include <gtk/gtk.h>
#ifndef HAVE_GLIB26
#include "gkeyfile.h"
#endif
#include "gnc-plugin.h"
#include "gnc-plugin-manager.h"
@@ -46,12 +48,15 @@
#include "dialog-reset-warnings.h"
#include "dialog-transfer.h"
#include "dialog-utils.h"
#include "file-utils.h"
#include "gnc-component-manager.h"
#include "gnc-engine.h"
#include "gnc-file.h"
#include "gnc-gkeyfile-utils.h"
#include "gnc-gnome-utils.h"
#include "gnc-gobject-utils.h"
#include "gnc-gui-query.h"
#include "gnc-hooks.h"
#include "gnc-session.h"
#include "gnc-ui.h"
#include "gnc-version.h"
@@ -60,6 +65,7 @@
#include "gnc-gconf-utils.h"
// +JSLED
#include "gnc-html.h"
#include <g-wrap-wct.h>
enum {
PAGE_ADDED,
@@ -89,6 +95,8 @@ 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);
static void main_window_update_page_name (GncMainWindow *window, GncPluginPage *page, const gchar *name_in);
/* 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);
@@ -105,6 +113,7 @@ static void gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *
static void gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window);
static void gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window);
static void gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window);
static void gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window);
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);
@@ -117,6 +126,7 @@ static void gnc_main_window_cmd_test( 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);
static GtkAction *gnc_main_window_find_action (GncMainWindow *window, const gchar *name);
typedef struct GncMainWindowPrivate
{
@@ -200,6 +210,9 @@ static GtkActionEntry gnc_menu_actions [] =
{ "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) },
{ "ActionsRenamePageAction", NULL, N_("Rename Page"), NULL,
N_("Rename this page."),
G_CALLBACK (gnc_main_window_cmd_actions_rename_page) },
/* Windows menu */
@@ -298,18 +311,477 @@ static GQuark window_type = 0;
/************************************************************
* *
************************************************************/
#define WINDOW_COUNT "Window Count"
#define WINDOW_STRING "Window %d"
#define WINDOW_GEOMETRY "Window Geometry"
#define WINDOW_POSITION "Window Position"
#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_save_window (GncMainWindow *window, gpointer session)
gnc_main_window_restore_page (GncMainWindow *window, GncMainWindowSaveData *data)
{
DEBUG("window %p", window);
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_shutdown (gpointer session, gpointer user_data)
gnc_main_window_restore_window (GncMainWindow *window, GncMainWindowSaveData *data)
{
DEBUG("session %p (%s)", session, qof_session_get_url (session));
g_list_foreach (active_windows, (GFunc)gnc_main_window_save_window, session);
GncMainWindowPrivate *priv;
gint *pos, *geom;
gsize length;
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);
priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
window_group = g_strdup_printf(WINDOW_STRING, data->window_num + 1);
/* Save the window coordinates, etc. */
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]);
}
/* Get this window's notebook info */
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;
}
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;
}
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);
}
/** Restore all windows. This function finds the "new" state file
* associated with a specific book guid. It then iterates through
* this state information, calling a helper function to recreate
* each open window.
*
* If the "new" state file cannot be found, this function will open
* an account tree window and then attempt to invoke the old gnucash
* 1.x state routines. This provides a fluid transition for users
* from the old to the new state systems.
*
* @note The name of the state file is based on the name of the data
* file, not the path name of the data file. If there are multiple
* data files with the same name, the state files will be suffixed
* with a number. E.G. test_account, test_account_2, test_account_3,
* etc.
*
* @param session A pointer to the current session.
*
* @param unused An unused pointer. */
static void
gnc_main_window_restore_all_state (gpointer session, gpointer unused)
{
GncMainWindow *window;
GncMainWindowSaveData data;
QofBook *book;
const gchar *url, *guid_string;
gchar *file_guid, *filename = NULL;
const GUID *guid;
gint i, window_count;
GError *error = NULL;
url = qof_session_get_url(session);
ENTER("session %p (%s)", session, url);
if (!url) {
LEAVE("no url, nothing to do");
return;
}
/* Get the book GUID */
book = qof_session_get_book(session);
guid = qof_entity_get_guid(QOF_ENTITY(book));
guid_string = guid_to_string(guid);
data.key_file = gnc_find_state_file(url, guid_string, &filename);
if (filename)
g_free(filename);
if (!data.key_file) {
GtkAction *action;
/* 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);
#if (GNUCASH_MAJOR_VERSION < 2) || ((GNUCASH_MAJOR_VERSION == 2) && (GNUCASH_MINOR_VERSION == 0))
/* See if there's an old style state file to be found */
scm_call_1(scm_c_eval_string("gnc:main-window-book-open-handler"),
(session ?
gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
#endif
LEAVE("old");
return;
}
#ifdef DEBUG
/* Debugging: dump a copy to stdout and the trace log */
{
gchar *file_data;
gint file_length;
file_data = g_key_file_to_data(data.key_file, &file_length, NULL);
DEBUG("=== File Data Read===\n%s\n=== File End ===\n", file_data);
g_free(file_data);
}
#endif
/* validate top level info */
file_guid = g_key_file_get_string(data.key_file,
STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
&error);
if (error) {
g_warning("error reading group %s key %s: %s",
STATE_FILE_TOP, STATE_FILE_BOOK_GUID, error->message);
LEAVE("can't read guid");
goto cleanup;
}
if (!file_guid || strcmp(guid_string, file_guid)) {
g_warning("guid mismatch: book guid %s, state file guid %s",
guid_string, file_guid);
LEAVE("guid values do not match");
goto cleanup;
}
window_count =
g_key_file_get_integer(data.key_file, STATE_FILE_TOP, WINDOW_COUNT, &error);
if (error) {
g_warning("error reading group %s key %s: %s",
STATE_FILE_TOP, WINDOW_COUNT, error->message);
LEAVE("can't read count");
goto cleanup;
}
/* 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);
if (window == NULL) {
DEBUG("Window %d doesn't exist. Creating new window.", i);
DEBUG("active_windows %p.", active_windows);
if (active_windows)
DEBUG("first window %p.", active_windows->data);
window = gnc_main_window_new();
}
gnc_main_window_restore_window(window, &data);
}
/* Clean up */
LEAVE("ok");
cleanup:
if (error)
g_error_free(error);
if (file_guid)
g_free(file_guid);
g_key_file_free(data.key_file);
}
/** 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. */
static void
gnc_main_window_save_page (GncPluginPage *page, GncMainWindowSaveData *data)
{
gchar *page_group;
ENTER("page %p, data %p (key file %p, window %d, page %d)",
page, data, data->key_file, data->window_num, data->page_num);
page_group = g_strdup_printf(PAGE_STRING, data->page_num++);
g_key_file_set_string(data->key_file, page_group, PAGE_TYPE,
GNC_PLUGIN_PAGE_GET_CLASS(page)->plugin_name);
g_key_file_set_string(data->key_file, page_group, PAGE_NAME,
gnc_plugin_page_get_page_name(page));
gnc_plugin_page_save_page(page, data->key_file, page_group);
g_free(page_group);
LEAVE(" ");
}
/** 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];
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);
window_group = g_strdup_printf(WINDOW_STRING, data->window_num++);
/* 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]);
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);
DEBUG("window (%p) position %dx%d, size %dx%d", window, coords[0], coords[1],
coords[2], coords[3]);
/* Save this window's notebook info */
num_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook));
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);
/* 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);
}
/** Save the state of all windows to disk. This function finds the
* name of the "new" state file associated with a specific book guid.
* It saves some top level data, then iterates through the list of
* open windows calling a helper function to save each window.
*
* @note The name of the state file is based on the name of the data
* file, not the path name of the data file. If there are multiple
* data files with the same name, the state files will be suffixed
* with a number. E.G. test_account, test_account_2, test_account_3,
* etc.
*
* @param page The GncPluginPage whose state should be saved.
*
* @param data A data structure containing state about the
* window/page saving process. */
static void
gnc_main_window_save_all_state (gpointer session, gpointer user_data)
{
GncMainWindowSaveData data;
QofBook *book;
const char *url, *guid_string;
gchar *filename;
const GUID *guid;
GError *error = NULL;
url = qof_session_get_url(session);
ENTER("session %p (%s)", session, url);
if (!url) {
LEAVE("no url, nothing to do");
return;
}
/* Get the book GUID */
book = qof_session_get_book(session);
guid = qof_entity_get_guid(QOF_ENTITY(book));
guid_string = guid_to_string(guid);
/* Find the filename to use. This returns the data from the
* file so its possible that we could reuse the data and
* maintain comments that were added to the data file, but
* that's not something we currently do. For now the existing
* data is dumped and completely regenerated.*/
data.key_file = gnc_find_state_file(url, guid_string, &filename);
if (data.key_file)
g_key_file_free(data.key_file);
/* Set up the iterator data structures */
data.key_file = g_key_file_new();
data.window_num = 1;
data.page_num = 1;
/* Store top level info in the data structure */
g_key_file_set_string(data.key_file,
STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
guid_string);
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);
#ifdef DEBUG
/* Debugging: dump a copy to the trace log */
{
gchar *file_data;
gint file_length;
file_data = g_key_file_to_data(data.key_file, &file_length, NULL);
DEBUG("=== File Data Written===\n%s\n=== File End ===\n", file_data);
g_free(file_data);
}
#endif
/* Write it all out to disk */
gnc_key_file_save_to_file(filename, data.key_file, &error);
if (error) {
g_critical(_("Error: Failure saving state file.\n %s"), error->message);
g_error_free(error);
}
g_free(filename);
/* Clean up */
g_key_file_free(data.key_file);
LEAVE("");
}
@@ -873,6 +1345,127 @@ gnc_main_window_update_tabs (GConfEntry *entry, gpointer user_data)
}
/************************************************************
* 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;
}
/************************************************************
* Widget Implementation *
************************************************************/
@@ -982,7 +1575,10 @@ gnc_main_window_class_init (GncMainWindowClass *klass)
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
qof_session_add_close_hook(gnc_main_window_shutdown, NULL);
gnc_hook_add_dangler(HOOK_BOOK_OPENED,
gnc_main_window_restore_all_state, NULL);
gnc_hook_add_dangler(HOOK_BOOK_CLOSED,
gnc_main_window_save_all_state, NULL);
gnc_gconf_general_register_cb (KEY_SHOW_CLOSE_BUTTON,
gnc_main_window_update_tabs,
@@ -1249,7 +1845,7 @@ gnc_main_window_open_page (GncMainWindow *window,
{
GncMainWindowPrivate *priv;
GtkWidget *tab_hbox;
GtkWidget *label;
GtkWidget *label, *entry;
const gchar *icon;
GtkWidget *image;
gboolean immutable = FALSE;
@@ -1304,6 +1900,18 @@ gnc_main_window_open_page (GncMainWindow *window,
gtk_box_pack_start (GTK_BOX (tab_hbox), label, TRUE, TRUE, 0);
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);
/* Add close button - Not for immutable pages */
if (!immutable) {
GtkWidget *close_image, *close_button;
@@ -1525,6 +2133,22 @@ gnc_main_window_actions_updated (GncMainWindow *window)
}
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;
}
/* 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.
@@ -1556,9 +2180,11 @@ gnc_main_window_add_plugin (gpointer plugin,
g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
g_return_if_fail (GNC_IS_PLUGIN (plugin));
ENTER(" ");
gnc_plugin_add_to_window (GNC_PLUGIN (plugin),
GNC_MAIN_WINDOW (window),
window_type);
LEAVE(" ");
}
static void
@@ -1613,6 +2239,8 @@ gnc_main_window_setup_window (GncMainWindow *window)
gchar *filename;
SCM debugging;
ENTER(" ");
/* Catch window manager delete signal */
g_signal_connect (G_OBJECT (window), "delete-event",
G_CALLBACK (gnc_main_window_delete_event), window);
@@ -1721,8 +2349,10 @@ gnc_main_window_setup_window (GncMainWindow *window)
g_signal_connect (G_OBJECT (manager), "plugin-removed",
G_CALLBACK (gnc_main_window_plugin_removed), window);
LEAVE(" ");
}
/* Callbacks */
static void
gnc_main_window_add_widget (GtkUIManager *merge,
GtkWidget *widget,
@@ -1914,6 +2544,43 @@ gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *wi
gnc_reset_warnings_dialog(GTK_WIDGET(window));
}
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");
}
static void
gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window)
{

View File

@@ -35,10 +35,15 @@
#include "config.h"
#include <gtk/gtk.h>
#include "gnc-engine.h"
#include "gnc-trace.h"
#include "gnc-plugin.h"
#include "gnc-plugin-page.h"
#include "gnc-gobject-utils.h"
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_GUI;
static gpointer parent_class = NULL;
static void gnc_plugin_page_class_init (GncPluginPageClass *klass);
@@ -180,6 +185,84 @@ gnc_plugin_page_show_summarybar (GncPluginPage *page,
}
}
/** Call a plugin specific function to save enough information about
* this page that it can be recreated next time the user starts
* gnucash.
*
* @param page The page to save.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be written.
*
* @param group_name The group name to use when saving data. */
void
gnc_plugin_page_save_page (GncPluginPage *page,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPageClass *klass;
g_return_if_fail (GNC_IS_PLUGIN_PAGE (page));
g_return_if_fail (key_file != NULL);
g_return_if_fail (group_name != NULL);
ENTER(" ");
klass = GNC_PLUGIN_PAGE_GET_CLASS (page);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->save_page != NULL);
klass->save_page(page, key_file, group_name);
LEAVE(" ");
}
/** This function looks up a specific plugin type and then calls its
* function to create a new page.
*
* @param window The window where this page should be installed.
*
* @param page_type The name of the page type to create.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be read.
*
* @param group_name The group name to use when restoring data. */
GncPluginPage *
gnc_plugin_page_recreate_page(GtkWidget *window,
const gchar *page_type,
GKeyFile *key_file,
const gchar *page_group)
{
GncPluginPageClass *klass;
GncPluginPage *page = NULL;
GType type;
ENTER("type %s, keyfile %p, group %s", page_type, key_file, page_group);
type = g_type_from_name(page_type);
if (type == 0) {
LEAVE("Cannot find type named %s", page_type);
return NULL;
}
klass = g_type_class_ref(type);
if (klass == NULL) {
LEAVE("Cannot create class %s(%ld)", page_type, type);
return NULL;
}
if (!klass->recreate_page) {
LEAVE("Class %shas no recreate function.", page_type);
g_type_class_unref(klass);
return NULL;
}
page = (klass->recreate_page)(window, key_file, page_group);
g_type_class_unref(klass);
LEAVE(" ");
return page;
}
void
gnc_plugin_page_merge_actions (GncPluginPage *page,
GtkUIManager *ui_merge)
@@ -601,6 +684,7 @@ void
gnc_plugin_page_set_page_name (GncPluginPage *page, const gchar *name)
{
GncPluginPagePrivate *priv;
GncPluginPageClass *klass;
g_return_if_fail (GNC_IS_PLUGIN_PAGE (page));
@@ -608,6 +692,12 @@ gnc_plugin_page_set_page_name (GncPluginPage *page, const gchar *name)
if (priv->page_name)
g_free(priv->page_name);
priv->page_name = g_strdup(name);
/* Perform page specific actions */
klass = GNC_PLUGIN_PAGE_GET_CLASS (page);
if (klass->page_name_changed) {
klass->page_name_changed(page, name);
}
}
const gchar *

View File

@@ -36,6 +36,7 @@
#ifndef __GNC_PLUGIN_PAGE_H
#define __GNC_PLUGIN_PAGE_H
#include <glib.h>
#include "guid.h"
#include "qofbook.h"
@@ -50,6 +51,12 @@ G_BEGIN_DECLS
#define GNC_PLUGIN_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_PLUGIN_PAGE, GncPluginPageClass))
/* typedefs & structures */
#ifndef HAVE_GLIB26
#ifndef __G_KEY_FILE_H__
typedef struct _GKeyFile GKeyFile;
#endif
#endif
typedef struct GncPluginPage {
GObject gobject; /**< The parent object data. */
@@ -84,7 +91,47 @@ typedef struct {
/* Virtual Table */
GtkWidget *(* create_widget) (GncPluginPage *plugin_page);
void (* destroy_widget) (GncPluginPage *plugin_page);
/** Save enough information about this page so that it can be
* recreated next time the user starts gnucash.
*
* @param page The page to save.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be written.
*
* @param group_name The group name to use when writing data.
* The name is specific to this page instance. */
void (* save_page) (GncPluginPage *page, GKeyFile *file, const gchar *group);
/** Create a new page based on the information saved during a
* previous instantiation of gnucash. This function may or
* may not install the new page in the window as it sees fit.
* Generally the function will install the page int the
* window in order to manipulate the menu items that are
* created at install time.
*
* @param window The window where this new page will be
* installed.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be retrieved.
*
* @param group_name The group name to use when retrieving
* data. The name is specific to this page instance.
*
* @return A pointer to the new page. */
GncPluginPage * (* recreate_page) (GtkWidget *window, GKeyFile *file, const gchar *group);
void (* window_changed) (GncPluginPage *plugin_page, GtkWidget *window);
/** This function vector allows page specific actions to occur
* when the page name is changed.
*
* @param page The page to update.
*
* @param name The new name for this page. */
void (* page_name_changed) (GncPluginPage *plugin_page, const gchar *name);
} GncPluginPageClass;
/* function prototypes */
@@ -101,6 +148,14 @@ void gnc_plugin_page_destroy_widget (GncPluginPage *plugin_pag
*/
void gnc_plugin_page_show_summarybar (GncPluginPage *page, gboolean visible);
void gnc_plugin_page_save_page (GncPluginPage *page,
GKeyFile *key_file,
const gchar *group_name);
GncPluginPage * gnc_plugin_page_recreate_page (GtkWidget *window,
const gchar *page_type,
GKeyFile *key_file,
const gchar *group_name);
void gnc_plugin_page_merge_actions (GncPluginPage *plugin_page,
GtkUIManager *merge);
void gnc_plugin_page_unmerge_actions (GncPluginPage *plugin_page,

View File

@@ -82,6 +82,7 @@
<menu name="ScrubMenu" action="ScrubMenuAction"/>
<separator name="ActionSepE"/>
<menuitem name="ActionsForgetWarnings" action="ActionsForgetWarningsAction"/>
<menuitem name="ActionsRenamePage" action="ActionsRenamePageAction"/>
</menu>
<placeholder name="AdditionalMenusPlaceholder"/>
@@ -139,6 +140,7 @@
<popup name="MainPopup" action="FakeToplevel">
<separator name="PopupSep1"/>
<placeholder name="PopupPlaceholder1"/>
<menuitem name="ActionsRenamePage" action="ActionsRenamePageAction"/>
<separator name="PopupSep2"/>
<placeholder name="PopupPlaceholder2"/>
<separator name="PopupSep3"/>

View File

@@ -12,6 +12,7 @@ libgncgnome_la_LIBADD = \
${top_builddir}/src/report/report-gnome/libgncmod-report-gnome.la \
${top_builddir}/src/register/ledger-core/libgncmod-ledger-core.la \
${top_builddir}/src/gnome-search/libgncmod-gnome-search.la \
${top_builddir}/lib/glib26/libgncglib.la \
${GUILE_LIBS} ${GNOME_LIBS} ${GLIB_LIBS} ${QOF_LIBS}
libgw_gnc_la_SOURCES = gw-gnc.c
@@ -142,6 +143,7 @@ AM_CFLAGS = \
-I${top_srcdir}/src/register/register-gnome \
-I${top_srcdir}/src/report/report-system \
-I${top_srcdir}/src/report/report-gnome \
-I${top_srcdir}/lib/glib26 \
${GUILE_INCS} \
${G_WRAP_COMPILE_ARGS} \
${GNOME_CFLAGS} \

View File

@@ -94,6 +94,10 @@ gnc_plugin_account_tree_new (void)
{
GncPluginAccountTree *plugin;
/* Reference the account tree page plugin to ensure it exists
* in the gtk type system. */
GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE;
plugin = g_object_new (GNC_TYPE_PLUGIN_ACCOUNT_TREE,
NULL);
@@ -170,20 +174,11 @@ gnc_plugin_account_tree_create_page (GncPlugin *plugin,
static void
gnc_plugin_account_tree_cmd_new_account_tree (GtkAction *action,
GncMainWindowActionData *data)
{
g_return_if_fail (data != NULL);
gnc_new_account_tree (data->window);
}
/************************************************************
* Other Functions *
************************************************************/
void
gnc_new_account_tree (GncMainWindow *window)
{
GncPluginPage *page;
g_return_if_fail (data != NULL);
page = gnc_plugin_page_account_tree_new ();
gnc_main_window_open_page (window, page);
gnc_main_window_open_page (data->window, page);
}

View File

@@ -55,8 +55,6 @@ GType gnc_plugin_account_tree_get_type (void);
GncPlugin *gnc_plugin_account_tree_new (void);
void gnc_new_account_tree (GncMainWindow *window);
G_END_DECLS
#endif /* __GNC_PLUGIN_ACCOUNT_TREE_H */

View File

@@ -106,6 +106,11 @@ GncPlugin * gnc_plugin_budget_new (void)
{
GncPluginBudget *plugin;
ENTER(" ");
/* Reference the budget page plugin to ensure it exists in the gtk
* type system. */
GNC_TYPE_PLUGIN_PAGE_BUDGET;
plugin = g_object_new (GNC_TYPE_PLUGIN_BUDGET, NULL);
LEAVE(" ");
return GNC_PLUGIN (plugin);

View File

@@ -2,7 +2,7 @@
* gnc-plugin-page-account-tree.c --
*
* Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2003 David Hampton <hampton@employees.org>
* Copyright (C) 2003,2005 David Hampton <hampton@employees.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -22,10 +22,22 @@
* Boston, MA 02111-1307, USA gnu@gnu.org
*/
/** @addtogroup ContentPlugins
@{ */
/** @addtogroup GncPluginPageAccountTree An Account Tree Plugin
@{ */
/** @file gnc-plugin-page-account-tree.c
@brief utility functions for the GnuCash UI
@author Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
Copyright (C) 2003,2005 David Hampton <hampton@employees.org>
*/
#include "config.h"
#include <gtk/gtk.h>
#ifndef HAVE_GLIB26
#include "gkeyfile.h"
#endif
#include "gnc-plugin-page-account-tree.h"
#include "gnc-plugin-page-register.h"
@@ -69,8 +81,6 @@ typedef struct GncPluginPageAccountTreePrivate
GtkWidget *widget;
GtkTreeView *tree_view;
SCM name_change_callback_id;
GNCOptionDB * odb;
SCM options;
int options_id;
@@ -95,6 +105,8 @@ static void gnc_plugin_page_account_tree_finalize (GObject *object);
static GtkWidget *gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page);
static void gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page);
static void gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
static GncPluginPage *gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
/* Callbacks */
static gboolean gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
@@ -232,7 +244,7 @@ gnc_plugin_page_account_tree_get_type (void)
};
gnc_plugin_page_account_tree_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE,
"GncPluginPageAccountTree",
GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME,
&our_info, 0);
}
@@ -266,6 +278,8 @@ gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME;
gnc_plugin_class->create_widget = gnc_plugin_page_account_tree_create_widget;
gnc_plugin_class->destroy_widget = gnc_plugin_page_account_tree_destroy_widget;
gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
g_type_class_add_private(klass, sizeof(GncPluginPageAccountTreePrivate));
@@ -280,11 +294,6 @@ gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
G_TYPE_POINTER);
}
static void
gnc_plugin_page_acct_tree_view_refresh (gpointer data)
{
}
static void
gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
{
@@ -362,14 +371,6 @@ gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
priv->odb = gnc_option_db_new(priv->options);
priv->name_change_callback_id =
gnc_option_db_register_change_callback(priv->odb,
gnc_plugin_page_acct_tree_view_refresh,
priv,
N_("Account Tree"),
N_("Name of account view"));
scm_gc_protect_object(priv->name_change_callback_id);
LEAVE("page %p, priv %p, action group %p",
plugin_page, priv, action_group);
}
@@ -539,6 +540,240 @@ gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page)
LEAVE("widget destroyed");
}
#define ACCT_COUNT "Number of Open Accounts"
#define ACCT_OPEN "Open Account %d"
#define ACCT_SELECTED "Selected Account"
typedef struct foo {
GKeyFile *key_file;
const gchar *group_name;
int count;
} bar_t;
/** Save information about an expanded row. This function is called
* via a gtk_tree_view_map_expanded_rows, which calls it once per
* expanded row. Its job is to write the full account name of the
* row out to the state file.
*
* @param tree_view A pointer to the GtkTreeView embedded in an
* account tree page.
*
* @param path A pointer to a particular entry in the tree.
*
* @param data A pointer to a data structure holding the information
* related to the state file. */
static void
tree_save_expanded_row (GtkTreeView *tree_view,
GtkTreePath *path,
gpointer user_data)
{
Account *account;
bar_t *bar = user_data;
gchar *key;
gchar *account_name;
account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(tree_view), path);
if (account == NULL)
return;
account_name = xaccAccountGetFullName (account, gnc_get_account_separator ());
if (account_name == NULL)
return;
key = g_strdup_printf(ACCT_OPEN, ++bar->count);
g_key_file_set_string(bar->key_file, bar->group_name, key, account_name);
g_free(key);
g_free(account_name);
}
/** Save information about the selected row. Its job is to write the
* full account name of the row out to the state file.
*
* @param tree_view A pointer to the GtkTreeView embedded in an
* account tree page.
*
* @param path A pointer to a particular entry in the tree.
*
* @param data A pointer to a data structure holding the information
* related to the state file. */
static void
tree_save_selected_row (GncTreeViewAccount *view,
gpointer user_data)
{
Account *account;
bar_t *bar = user_data;
gchar *account_name;
account = gnc_tree_view_account_get_selected_account(view);
if (account == NULL)
return;
account_name = xaccAccountGetFullName (account, gnc_get_account_separator ());
if (account_name == NULL)
return;
g_key_file_set_string(bar->key_file, bar->group_name, ACCT_SELECTED, account_name);
g_free(account_name);
}
/** Save enough information about this account tree page that it can
* be recreated next time the user starts gnucash.
*
* @param page The page to save.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be written.
*
* @param group_name The group name to use when saving data. */
static void
gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPageAccountTree *account_page;
GncPluginPageAccountTreePrivate *priv;
bar_t bar;
g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
g_return_if_fail (key_file != NULL);
g_return_if_fail (group_name != NULL);
ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
group_name);
account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
bar.key_file = key_file;
bar.group_name = group_name;
bar.count = 0;
tree_save_selected_row(GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &bar);
gtk_tree_view_map_expanded_rows(priv->tree_view,
tree_save_expanded_row, &bar);
g_key_file_set_integer(key_file, group_name, ACCT_COUNT, bar.count);
LEAVE(" ");
}
/** Expand a row in the tree that was expanded when the user last quit
* gnucash. Its job is to map from account name to tree row and
* expand the row.
*
* @param tree_view A pointer to the GtkTreeView embedded in an
* account tree page.
*
* @param account_name A pointer to the full account name. */
static void
tree_restore_expanded_row (GtkTreeView *tree_view,
const gchar *account_name)
{
Account *account;
QofBook *book;
book = qof_session_get_book(qof_session_get_current_session());
account = xaccGetAccountFromFullName(xaccGetAccountGroup(book),
account_name,
gnc_get_account_separator());
if (account)
gnc_tree_view_account_expand_to_account(GNC_TREE_VIEW_ACCOUNT(tree_view),
account);
}
/** Select the row in the tree that was selected when the user last
* quit gnucash. Its job is to map from account name to tree row and
* select the row.
*
* @param tree_view A pointer to the GtkTreeView embedded in an
* account tree page.
*
* @param account_name A pointer to the full account name. */
static void
tree_restore_selected_row (GtkTreeView *tree_view,
const gchar *account_name)
{
Account *account;
QofBook *book;
book = qof_session_get_book(qof_session_get_current_session());
account = xaccGetAccountFromFullName(xaccGetAccountGroup(book),
account_name,
gnc_get_account_separator());
if (account)
gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(tree_view),
account);
}
/** Create a new account tree page based on the information saved
* during a previous instantiation of gnucash.
*
* @param window The window where this page should be installed.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be read.
*
* @param group_name The group name to use when restoring data. */
static GncPluginPage *
gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPageAccountTree *account_page;
GncPluginPageAccountTreePrivate *priv;
GncPluginPage *page;
GError *error = NULL;
gchar *key, *value;
gint i, count;
g_return_val_if_fail(key_file, NULL);
g_return_val_if_fail(group_name, NULL);
ENTER("key_file %p, group_name %s", key_file, group_name);
/* Create the new page. */
page = gnc_plugin_page_account_tree_new();
account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
/* Install it now so we can them manipulate the created widget */
gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
/* Expanded accounts */
count = g_key_file_get_integer(key_file, group_name, ACCT_COUNT, &error);
if (error) {
g_warning("error reading group %s key %s: %s",
group_name, ACCT_COUNT, error->message);
g_error_free(error);
LEAVE("bad value");
return page;
}
for (i = 1; i <= count; i++) {
key = g_strdup_printf(ACCT_OPEN, i);
value = g_key_file_get_string(key_file, group_name, key, &error);
if (error) {
g_warning("error reading group %s key %s: %s",
group_name, key, error->message);
g_error_free(error);
error = NULL;
} else {
tree_restore_expanded_row(priv->tree_view, value);
g_free(value);
}
}
/* Selected account (if any) */
value = g_key_file_get_string(key_file, group_name, ACCT_SELECTED, NULL);
if (value) {
tree_restore_selected_row(priv->tree_view, value);
g_free(value);
}
LEAVE(" ");
return page;
}
/* Callbacks */
@@ -959,3 +1194,6 @@ gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAcco
xaccGroupScrubOrphans (group);
xaccGroupScrubImbalance (group);
}
/** @} */
/** @} */

View File

@@ -50,7 +50,7 @@ G_BEGIN_DECLS
#define GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE))
#define GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE, GncPluginPageAccountTreeClass))
#define GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME "gnc-plugin-page-account-tree"
#define GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME "GncPluginPageAccountTree"
/* typedefs & structures */
typedef struct {

View File

@@ -45,7 +45,7 @@ G_BEGIN_DECLS
#define GNC_IS_PLUGIN_PAGE_BUDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_BUDGET))
#define GNC_PLUGIN_PAGE_BUDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_BUDGET, GncPluginPageBudgetClass))
#define GNC_PLUGIN_PAGE_BUDGET_NAME "gnc-plugin-page-budget"
#define GNC_PLUGIN_PAGE_BUDGET_NAME "GncPluginPageBudget"
/* typedefs & structures */
typedef struct {

View File

@@ -2,7 +2,7 @@
* gnc-plugin-page-register.c --
*
* Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2003 David Hampton <hampton@employees.org>
* Copyright (C) 2003,2005 David Hampton <hampton@employees.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -22,9 +22,22 @@
* Boston, MA 02111-1307, USA gnu@gnu.org
*/
/** @addtogroup ContentPlugins
@{ */
/** @addtogroup RegisterPlugin Register Page
@{ */
/** @file gnc-plugin-page-register.c
@brief Functions for creating a register page for the GnuCash UI
@author Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
@author Copyright (C) 2003,2005 David Hampton <hampton@employees.org>
*/
#include "config.h"
#include <gtk/gtk.h>
#ifndef HAVE_GLIB26
#include "gkeyfile.h"
#endif
#include <g-wrap-wct.h>
#include "gnc-plugin-page-register.h"
@@ -75,6 +88,8 @@ static void gnc_plugin_page_register_finalize (GObject *object);
static GtkWidget *gnc_plugin_page_register_create_widget (GncPluginPage *plugin_page);
static void gnc_plugin_page_register_destroy_widget (GncPluginPage *plugin_page);
static void gnc_plugin_page_register_window_changed (GncPluginPage *plugin_page, GtkWidget *window);
static void gnc_plugin_page_register_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
static GncPluginPage *gnc_plugin_page_register_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
static gchar *gnc_plugin_page_register_get_tab_name (GncPluginPage *plugin_page);
@@ -276,10 +291,11 @@ static action_short_labels short_labels[] = {
};
struct {
struct status_action {
const char *action_name;
int value;
} status_actions[] = {
};
static struct status_action status_actions[] = {
{ "filter_status_reconciled", CLEARED_RECONCILED },
{ "filter_status_cleared", CLEARED_CLEARED },
{ "filter_status_voided", CLEARED_VOIDED },
@@ -445,6 +461,8 @@ gnc_plugin_page_register_class_init (GncPluginPageRegisterClass *klass)
gnc_plugin_class->create_widget = gnc_plugin_page_register_create_widget;
gnc_plugin_class->destroy_widget = gnc_plugin_page_register_destroy_widget;
gnc_plugin_class->window_changed = gnc_plugin_page_register_window_changed;
gnc_plugin_class->save_page = gnc_plugin_page_register_save_page;
gnc_plugin_class->recreate_page = gnc_plugin_page_register_recreate_page;
g_type_class_add_private(klass, sizeof(GncPluginPageRegisterPrivate));
}
@@ -533,9 +551,9 @@ gnc_plugin_page_register_update_menus (GncPluginPageRegister *page)
{
GncPluginPageRegisterPrivate *priv ;
GtkActionGroup *action_group;
GtkAction *action;
Account *account;
SplitRegister *sr;
GtkAction *action;
int i;
priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
@@ -683,6 +701,214 @@ gnc_plugin_page_register_window_changed (GncPluginPage *plugin_page,
priv->gsr->window =
GTK_WIDGET(gnc_window_get_gtk_window(GNC_WINDOW(window)));
}
static const gchar *style_names[] = {
"Ledger",
"Auto Ledger",
"Journal",
NULL
};
#define KEY_REGISTER_TYPE "Register Type"
#define KEY_ACCOUNT_NAME "Account Name"
#define KEY_REGISTER_STYLE "Register Style"
#define KEY_DOUBLE_LINE "Double Line Mode"
#define LABEL_ACCOUNT "Account"
#define LABEL_SUBACCOUNT "SubAccount"
#define LABEL_GL "GL"
#define LABEL_SEARCH "Search"
/** Save enough information about this register page that it can be
* recreated next time the user starts gnucash.
*
* @param page The page to save.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be written.
*
* @param group_name The group name to use when saving data. */
static void
gnc_plugin_page_register_save_page (GncPluginPage *plugin_page,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPageRegister *page;
GncPluginPageRegisterPrivate *priv;
GNCLedgerDisplayType ledger_type;
SplitRegister *reg;
Account *leader;
g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
g_return_if_fail (key_file != NULL);
g_return_if_fail (group_name != NULL);
ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
group_name);
page = GNC_PLUGIN_PAGE_REGISTER(plugin_page);
priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
reg = gnc_ledger_display_get_split_register(priv->ledger);
ledger_type = gnc_ledger_display_type(priv->ledger);
if (ledger_type > LD_GL) {
LEAVE("Unsupported ledger type");
return;
}
if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT)) {
const gchar *label;
label = (ledger_type == LD_SINGLE) ? LABEL_ACCOUNT : LABEL_SUBACCOUNT;
leader = gnc_ledger_display_leader(priv->ledger);
g_key_file_set_string(key_file, group_name, KEY_REGISTER_TYPE, label);
g_key_file_set_string(key_file, group_name, KEY_ACCOUNT_NAME,
xaccAccountGetFullName(leader,
gnc_get_account_separator()));
} else if (reg->type == GENERAL_LEDGER) {
g_key_file_set_string(key_file, group_name, KEY_REGISTER_TYPE,
LABEL_GL);
} else if (reg->type == SEARCH_LEDGER) {
g_key_file_set_string(key_file, group_name, KEY_REGISTER_TYPE,
LABEL_SEARCH);
} else {
LEAVE("Unsupported register type");
return;
}
g_key_file_set_string(key_file, group_name, KEY_REGISTER_STYLE,
style_names[reg->style]);
g_key_file_set_boolean(key_file, group_name, KEY_DOUBLE_LINE,
reg->use_double_line);
LEAVE(" ");
}
/** Read and restore the edit menu settings on the specified register
* page. This function will restore the register style (ledger, auto
* ledger, journal) and whether or not the register is in double line
* mode. It should eventually restore the "filter by" and "sort by
* settings.
*
* @param page The register being restored.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be read.
*
* @param group_name The group name to use when restoring data. */
static void
gnc_plugin_page_register_restore_edit_menu (GncPluginPage *page,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPageRegisterPrivate *priv;
GtkActionGroup *action_group;
GtkAction *action;
GError *error = NULL;
gchar *style_name;
gint i;
gboolean use_double_line;
ENTER(" ");
priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
action_group = gnc_plugin_page_get_action_group(page);
/* Convert the style name to an index */
style_name = g_key_file_get_string(key_file, group_name,
KEY_REGISTER_STYLE, &error);
for (i = 0 ; style_names[i]; i++) {
if (g_ascii_strcasecmp(style_name, style_names[i]) == 0) {
DEBUG("Found match for style name: %s", style_name);
break;
}
}
g_free(style_name);
/* Update the style menu action for this page */
if (i <= REG_STYLE_JOURNAL) {
DEBUG("Setting style: %d", i);
action_group =
gnc_plugin_page_get_action_group(page);
action= gtk_action_group_get_action(action_group, radio_entries_2[i].name);
gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
}
/* Update the double line action on this page */
use_double_line =
g_key_file_get_boolean(key_file, group_name, KEY_DOUBLE_LINE, &error);
DEBUG("Setting double_line_mode: %d", use_double_line);
action = gtk_action_group_get_action(action_group,
"ViewStyleDoubleLineAction");
gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_double_line);
LEAVE(" ");
}
/** Create a new register page based on the information saved during a
* previous instantiation of gnucash.
*
* @param window The window where this page should be installed.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be read.
*
* @param group_name The group name to use when restoring data. */
static GncPluginPage *
gnc_plugin_page_register_recreate_page (GtkWidget *window,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPage *page;
GError *error = NULL;
gchar *reg_type, *acct_name;
Account *account;
QofBook *book;
gboolean include_subs;
g_return_val_if_fail(key_file, NULL);
g_return_val_if_fail(group_name, NULL);
ENTER("key_file %p, group_name %s", key_file, group_name);
/* Create the new page. */
reg_type = g_key_file_get_string(key_file, group_name,
KEY_REGISTER_TYPE, &error);
DEBUG("Page type: %s", reg_type);
if ((g_ascii_strcasecmp(reg_type, LABEL_ACCOUNT) == 0) ||
(g_ascii_strcasecmp(reg_type, LABEL_SUBACCOUNT) == 0)) {
include_subs = (g_ascii_strcasecmp(reg_type, LABEL_SUBACCOUNT) == 0);
DEBUG("Include subs: %d", include_subs);
acct_name = g_key_file_get_string(key_file, group_name,
KEY_ACCOUNT_NAME, &error);
book = qof_session_get_book(qof_session_get_current_session());
account = xaccGetAccountFromFullName(xaccGetAccountGroup(book),
acct_name,
gnc_get_account_separator());
g_free(acct_name);
if (account == NULL) {
LEAVE("Bad account name");
g_free(reg_type);
return NULL;
}
page = gnc_plugin_page_register_new (account, include_subs);
} else if (g_ascii_strcasecmp(reg_type, LABEL_GL) == 0) {
page = gnc_plugin_page_register_new_gl();
} else {
LEAVE("Bad ledger type");
g_free(reg_type);
return NULL;
}
g_free(reg_type);
/* Install it now so we can them manipulate the created widget */
gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
/* Now update the page to the last state it was in */
gnc_plugin_page_register_restore_edit_menu(page, key_file, group_name);
LEAVE(" ");
return page;
}
static gchar *
gnc_plugin_page_register_get_tab_name (GncPluginPage *plugin_page)
@@ -2370,3 +2596,6 @@ gnc_plugin_page_register_refresh_cb (GHashTable *changes, gpointer user_data)
gnucash_register_refresh_from_gconf(priv->gsr->reg);
gtk_widget_queue_draw(priv->widget);
}
/** @} */
/** @} */

View File

@@ -128,6 +128,10 @@ gnc_plugin_register_new (void)
{
GncPluginRegister *plugin;
/* Reference the register page plugin to ensure it exists in
* the gtk type system. */
GNC_TYPE_PLUGIN_PAGE_REGISTER;
plugin = g_object_new (GNC_TYPE_PLUGIN_REGISTER,
NULL);

View File

@@ -130,14 +130,6 @@
'()
"Destroy the UI.")
(gw:wrap-function
ws
'gnc:new-account-tree
'<gw:void>
"gnc_new_account_tree"
'((<gnc:MainWindow*> window))
"Create a new account tree window.")
(gw:wrap-as-wct ws
'<gnc:ProgressDialog*>
"GNCProgressDialog *" "const GNCProgressDialog *")

View File

@@ -14,6 +14,7 @@ AM_CFLAGS = \
-I${top_srcdir}/src/gnome-utils \
-I${top_srcdir}/src/gnome \
-I${top_srcdir}/src/report/report-system \
-I${top_srcdir}/lib/glib26 \
${GLADE_CFLAGS} \
${GUILE_INCS} \
${GTKHTML_CFLAGS} \
@@ -42,6 +43,7 @@ libgncmod_report_gnome_la_LIBADD = \
${top_builddir}/src/gnc-module/libgncmodule.la \
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
${top_builddir}/src/report/report-system/libgncmod-report-system.la \
${top_builddir}/lib/glib26/libgncglib.la \
${GLADE_LIBS} \
${GUILE_LIBS} \
${GNOME_PRINT_LIBS} \

View File

@@ -1,5 +1,6 @@
/* gnc-plugin-page-report.c
* Copyright (C) 2004 Joshua Sled <jsled@asynchronous.org>
* Copyright (C) 2005 David Hampton <hampton@employees.org>
*
* Originally from window-report.c:
* Copyright (C) 1997 Robin D. Clark
@@ -26,10 +27,23 @@
* Boston, MA 02111-1307, USA gnu@gnu.org
*/
/** @addtogroup GUI
@{ */
/** @addtogroup GuiReport Reports
@{ */
/** @file gnc-plugin-page-report.c
@brief Report page.
@author Copyright (C) 2004 Joshua Sled <jsled@asynchronous.org>
@author Copyright (C) 2005 David Hampton <hampton@employees.org>
*/
#include "config.h"
#include <errno.h>
#include <gtk/gtk.h>
#ifndef HAVE_GLIB26
#include "gkeyfile.h"
#endif
#include <g-wrap-wct.h>
#include <libguile.h>
#include <sys/stat.h>
@@ -47,6 +61,7 @@
#include "gnc-ui-util.h"
#include "gnc-ui.h"
#include "gnc-window.h"
#include "guile-util.h"
#include "messages.h"
#include "option-util.h"
@@ -111,6 +126,9 @@ static void gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page,
static GtkWidget* gnc_plugin_page_report_create_widget( GncPluginPage *plugin_page );
static void gnc_plugin_page_report_destroy_widget( GncPluginPage *plugin_page );
static void gnc_plugin_page_report_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
static GncPluginPage *gnc_plugin_page_report_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
static void gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name);
static int gnc_plugin_page_report_check_urltype(URLType t);
static void gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
@@ -233,6 +251,9 @@ gnc_plugin_page_report_class_init (GncPluginPageReportClass *klass)
gnc_plugin_page_class->create_widget = gnc_plugin_page_report_create_widget;
gnc_plugin_page_class->destroy_widget = gnc_plugin_page_report_destroy_widget;
gnc_plugin_page_class->save_page = gnc_plugin_page_report_save_page;
gnc_plugin_page_class->recreate_page = gnc_plugin_page_report_recreate_page;
gnc_plugin_page_class->page_name_changed = gnc_plugin_page_report_name_changed;
g_type_class_add_private(klass, sizeof(GncPluginPageReportPrivate));
@@ -474,7 +495,7 @@ gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
priv->option_change_cb_id =
gnc_option_db_register_change_callback(priv->cur_odb,
gnc_plugin_page_report_option_change_cb,
priv, NULL, NULL);
report, NULL, NULL);
if (gnc_html_history_forward_p(gnc_html_get_history(priv->html))) {
gnc_plugin_page_report_set_fwd_button(report, TRUE);
@@ -491,17 +512,45 @@ gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
LEAVE( "done" );
}
/** This function is called when one of the options for a register
* page has changed. It is responsible for marking the report as
* dirty, and causing the report to reload using the new options.
*
* @note This function currently also calls the main window code to
* update it if the name of the report has changed. This code should
* eventually go away, and the only way to change the name should be
* via the main window. gnucash.
*
* @param data A pointer to the GncPluginPageReport data structure
* that describes a report. */
static void
gnc_plugin_page_report_option_change_cb(gpointer data)
{
GncPluginPageReportPrivate *priv = data;
GncPluginPageReport *report;
GncPluginPageReportPrivate *priv;
SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
const gchar *old_name;
gchar *new_name;
g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(data));
report = GNC_PLUGIN_PAGE_REPORT(data);
priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
DEBUG( "option_change" );
if (priv->cur_report == SCM_BOOL_F)
return;
DEBUG( "set-dirty, queue-draw" );
/* Update the page (i.e. the notebook tab and window title) */
old_name = gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(report));
new_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
"Report name", NULL);
if (strcmp(old_name, new_name) != 0) {
gnc_plugin_page_set_page_name(GNC_PLUGIN_PAGE(report), new_name);
}
g_free(new_name);
/* it's probably already dirty, but make sure */
scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
@@ -590,6 +639,144 @@ gnc_plugin_page_report_destroy_widget(GncPluginPage *plugin_page)
scm_call_1(remover, scm_int2num(report_id));
}
/** The key name used it the state file for storing the report
* options. */
#define SCHEME_OPTIONS "Scheme Options"
/** Save enough information about this report page that it can be
* recreated next time the user starts gnucash.
*
* @param page The page to save.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be written.
*
* @param group_name The group name to use when saving data. */
static void
gnc_plugin_page_report_save_page (GncPluginPage *plugin_page,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPageReport *report;
GncPluginPageReportPrivate *priv;
SCM gen_save_text, scm_text;
gchar *text;
g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT(plugin_page));
g_return_if_fail (key_file != NULL);
g_return_if_fail (group_name != NULL);
ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
group_name);
report = GNC_PLUGIN_PAGE_REPORT(plugin_page);
priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
gen_save_text = scm_c_eval_string("gnc:report-generate-restore-forms");
scm_text = scm_call_1(gen_save_text, priv->cur_report);
if (!SCM_STRINGP (scm_text)) {
LEAVE("nothing to save");
return;
}
text = gnc_guile_strip_comments(SCM_STRING_CHARS(scm_text));
g_key_file_set_string(key_file, group_name, SCHEME_OPTIONS, text);
g_free(text);
LEAVE(" ");
}
/** Create a new report page based on the information saved during a
* previous instantiation of gnucash.
*
* @param window The window where this page should be installed.
*
* @param key_file A pointer to the GKeyFile data structure where the
* page information should be read.
*
* @param group_name The group name to use when restoring data. */
static GncPluginPage *
gnc_plugin_page_report_recreate_page (GtkWidget *window,
GKeyFile *key_file,
const gchar *group_name)
{
GncPluginPage *page;
GError *error = NULL;
gchar *option_string;
gint report_id;
SCM scm_id;
g_return_val_if_fail(key_file, NULL);
g_return_val_if_fail(group_name, NULL);
ENTER("key_file %p, group_name %s", key_file, group_name);
option_string = g_key_file_get_string(key_file, group_name,
SCHEME_OPTIONS, &error);
if (error) {
g_warning("error reading group %s key %s: %s",
group_name, SCHEME_OPTIONS, error->message);
LEAVE("bad value");
return NULL;
}
scm_id = scm_c_eval_string(option_string);
if (!scm_integer_p(scm_id)) {
g_free(option_string);
LEAVE("report id not an integer");
return NULL;
}
report_id = scm_num2int(scm_id, SCM_ARG1, __FUNCTION__);
page = gnc_plugin_page_report_new( report_id );
g_free(option_string);
LEAVE(" ");
return page;
}
/** Update a report page to reflect a name change made by external
* code. This is called from the main window code when a page's name
* is changes. The report code will update its copy of the name and
* regenerate the report.
*
* @internal
*
* @param page The page whose name has changed.
*
* @param name The new name for the page. */
static void
gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name)
{
GncPluginPageReportPrivate *priv;
static gint count = 1, max_count = 10;
const gchar *old_name;
g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(page));
g_return_if_fail(name != NULL);
g_return_if_fail(count++ <= max_count);
ENTER("page %p, name %s", page, name);
priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
/* Is this a redundant call? */
old_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
"Report name", NULL);
DEBUG("Comparing old name '%s' to new name '%s'", old_name, name);
if (old_name && (strcmp(old_name, name) == 0)) {
LEAVE("no change");
return;
}
gnc_option_db_set_string_option(priv->cur_odb, "General",
"Report name", name);
gnc_plugin_page_report_option_change_cb(page);
LEAVE(" ");
}
/********************************************************************
* gnc_report_window_destroy
* free and destroy a window
@@ -696,8 +883,8 @@ gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint report
GncPluginPageReportPrivate *priv;
GtkActionGroup *action_group;
GncPluginPage *parent;
GString *tmpStr;
gboolean use_new;
gchar *name;
DEBUG( "property reportId=%d", reportId );
priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
@@ -708,15 +895,14 @@ gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint report
/* Init parent declared variables */
parent = GNC_PLUGIN_PAGE(plugin_page);
use_new = gnc_gconf_get_bool(GCONF_GENERAL_REPORT, KEY_USE_NEW, NULL);
tmpStr = g_string_sized_new( 32 );
g_string_sprintf( tmpStr, "%s: %s", _("Report"),
gnc_report_name( priv->initial_report ) );
name = gnc_report_name( priv->initial_report );
g_object_set(G_OBJECT(plugin_page),
"page-name", tmpStr->str,
"page-name", name,
"page-uri", "default:",
"ui-description", "gnc-plugin-page-report-ui.xml",
"use-new-window", use_new,
NULL);
g_free(name);
/* change me when the system supports multiple books */
gnc_plugin_page_add_book(parent, gnc_get_current_book());
@@ -1125,3 +1311,6 @@ gnc_main_window_open_report_url(const char * url, GncMainWindow *window)
reportPage = gnc_plugin_page_report_new( 42 /* url? */ );
gnc_main_window_open_page( window, reportPage );
}
/** @} */
/** @} */

View File

@@ -47,7 +47,7 @@ G_BEGIN_DECLS
#define GNC_IS_PLUGIN_PAGE_REPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_REPORT))
#define GNC_PLUGIN_PAGE_REPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportClass))
#define GNC_PLUGIN_PAGE_REPORT_NAME "gnc-plugin-page-report"
#define GNC_PLUGIN_PAGE_REPORT_NAME "GncPluginPageReport"
/* typedefs & structures */
typedef struct {

View File

@@ -293,6 +293,10 @@ gnc_html_help_url_cb (const char *location, const char *label,
void
gnc_report_init (void)
{
/* Reference the report page plugin to ensure it exists in the gtk
* type system. */
GNC_TYPE_PLUGIN_PAGE_REPORT;
gnc_html_register_stream_handler (URL_TYPE_HELP, gnc_html_file_stream_cb);
gnc_html_register_stream_handler (URL_TYPE_FILE, gnc_html_file_stream_cb);
gnc_html_register_stream_handler (URL_TYPE_REPORT, gnc_html_report_stream_cb);

View File

@@ -39,12 +39,6 @@
(lambda (opt)
(gnc:register-option options opt))))
(add-option
(gnc:make-string-option
(N_ "Account Tree") (N_ "Name of account view")
"a" (N_ "If you keep multiple account views open, it may be helpful \
to give each one a descriptive name") (_ "Accounts")))
(add-option
(gnc:make-simple-boolean-option
(N_ "Account Tree") (N_ "Double click expands parent accounts")
@@ -138,8 +132,6 @@ the account instead of opening a register.") #f))
))))
(define (gnc:main-window-book-close-handler session)
(gnc:main-window-save-state session)
(let ((dead-reports '()))
;; get a list of the reports we'll be needing to nuke
(hash-fold
@@ -169,7 +161,6 @@ the account instead of opening a register.") #f))
(dead-reports '()))
(if conf-file-name
(try-load conf-file-name))
(gnc:new-account-tree #f)
;; the reports have only been created at this point; create their ui component.
(hash-fold (lambda (key val prior-result)
@@ -190,11 +181,6 @@ the account instead of opening a register.") #f))
slots (_ "Book Options")
changed_cb)))
(gnc:hook-remove-dangler gnc:*book-opened-hook*
gnc:main-window-book-open-handler)
(gnc:hook-add-dangler gnc:*book-opened-hook*
gnc:main-window-book-open-handler)
(gnc:hook-remove-dangler gnc:*book-closed-hook*
gnc:main-window-book-close-handler)
(gnc:hook-add-dangler gnc:*book-closed-hook*