GnuCash 2.4.99
gnc-split-reg.c
00001 /********************************************************************\
00002  * gnc-split-reg.c -- A widget for the common register look-n-feel. *
00003  * Copyright (C) 1997 Robin D. Clark                                *
00004  * Copyright (C) 1997-1998 Linas Vepstas <linas@linas.org>          *
00005  * Copyright (C) 1998 Rob Browning <rlb@cs.utexas.edu>              *
00006  * Copyright (C) 1999-2000 Dave Peticolas <dave@krondo.com>         *
00007  * Copyright (C) 2001 Gnumatic, Inc.                                *
00008  * Copyright (C) 2002,2006 Joshua Sled <jsled@asynchronous.org>     *
00009  *                                                                  *
00010  * This program is free software; you can redistribute it and/or    *
00011  * modify it under the terms of the GNU General Public License as   *
00012  * published by the Free Software Foundation; either version 2 of   *
00013  * the License, or (at your option) any later version.              *
00014  *                                                                  *
00015  * This program is distributed in the hope that it will be useful,  *
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00018  * GNU General Public License for more details.                     *
00019  *                                                                  *
00020  * You should have received a copy of the GNU General Public License*
00021  * along with this program; if not, contact:                        *
00022  *                                                                  *
00023  * Free Software Foundation           Voice:  +1-617-542-5942       *
00024  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00025  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00026 \********************************************************************/
00027 
00028 #include "config.h"
00029 
00030 #include <gtk/gtk.h>
00031 #include <glib/gi18n.h>
00032 #include <time.h>
00033 
00034 #include "gnc-split-reg.h"
00035 
00036 #include "Account.h"
00037 #include "qof.h"
00038 #include "SX-book.h"
00039 #include "dialog-account.h"
00040 #include "dialog-sx-editor.h"
00041 #include "dialog-sx-from-trans.h"
00042 #include "gnc-component-manager.h"
00043 #include "gnc-date-edit.h"
00044 #include "gnc-engine.h"
00045 #include "gnc-euro.h"
00046 #include "gnc-gconf-utils.h"
00047 #include "gnc-gui-query.h"
00048 #include "gnc-ledger-display.h"
00049 #include "gnc-pricedb.h"
00050 #include "gnc-ui-util.h"
00051 #include "gnc-ui.h"
00052 #include "gnucash-sheet.h"
00053 #include "table-allgui.h"
00054 
00055 #include <libguile.h>
00056 #include "dialog-utils.h"
00057 
00058 // static QofLogModule log_module = GNC_MOD_SX;
00059 static QofLogModule log_module = GNC_MOD_GUI;
00060 
00061 /***** PROTOTYPES ***************************************************/
00062 void gnc_split_reg_raise( GNCSplitReg *gsr );
00063 
00064 static GtkWidget* add_summary_label( GtkWidget *summarybar,
00065                                      const char *label_str );
00066 
00067 static void gnc_split_reg_determine_read_only( GNCSplitReg *gsr );
00068 
00069 static GNCPlaceholderType gnc_split_reg_get_placeholder( GNCSplitReg *gsr );
00070 static GtkWidget *gnc_split_reg_get_parent( GNCLedgerDisplay *ledger );
00071 
00072 static void gsr_create_table( GNCSplitReg *gsr );
00073 static void gsr_setup_table( GNCSplitReg *gsr );
00074 static void gsr_setup_status_widgets( GNCSplitReg *gsr );
00075 
00076 static void gsr_update_summary_label( GtkWidget *label,
00077                                       xaccGetBalanceFn getter,
00078                                       Account *leader,
00079                                       GNCPrintAmountInfo print_info,
00080                                       gnc_commodity *cmdty,
00081                                       gboolean reverse,
00082                                       gboolean euroFlag );
00083 
00084 static void gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data);
00085 
00086 static void gnc_split_reg_refresh_toolbar( GNCSplitReg *gsr );
00087 
00088 static void gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger );
00089 
00090 static Transaction* create_balancing_transaction(QofBook *book, Account *account,
00091         time_t statement_date, gnc_numeric balancing_amount);
00092 
00093 void gsr_default_enter_handler    ( GNCSplitReg *w, gpointer ud );
00094 void gsr_default_cancel_handler   ( GNCSplitReg *w, gpointer ud );
00095 void gsr_default_delete_handler   ( GNCSplitReg *w, gpointer ud );
00096 void gsr_default_reinit_handler   ( GNCSplitReg *w, gpointer ud );
00097 void gsr_default_dup_handler      ( GNCSplitReg *w, gpointer ud );
00098 void gsr_default_schedule_handler ( GNCSplitReg *w, gpointer ud );
00099 void gsr_default_expand_handler   ( GNCSplitReg *w, gpointer ud );
00100 void gsr_default_blank_handler    ( GNCSplitReg *w, gpointer ud );
00101 void gsr_default_jump_handler     ( GNCSplitReg *w, gpointer ud );
00102 void gsr_default_cut_handler      ( GNCSplitReg *w, gpointer ud );
00103 void gsr_default_cut_txn_handler  ( GNCSplitReg *w, gpointer ud );
00104 void gsr_default_copy_handler     ( GNCSplitReg *w, gpointer ud );
00105 void gsr_default_copy_txn_handler ( GNCSplitReg *w, gpointer ud );
00106 void gsr_default_paste_handler    ( GNCSplitReg *w, gpointer ud );
00107 void gsr_default_paste_txn_handler( GNCSplitReg *w, gpointer ud );
00108 void gsr_default_void_txn_handler ( GNCSplitReg *w, gpointer ud );
00109 void gsr_default_unvoid_txn_handler  ( GNCSplitReg *w, gpointer ud );
00110 void gsr_default_reverse_txn_handler ( GNCSplitReg *w, gpointer ud );
00111 
00112 static void gsr_emit_simple_signal( GNCSplitReg *gsr, const char *sigName );
00113 static void gsr_emit_help_changed( GnucashRegister *reg, gpointer user_data );
00114 static void gsr_emit_include_date_signal( GNCSplitReg *gsr, time_t date );
00115 
00116 void gnc_split_reg_cut_cb(GtkWidget *w, gpointer data);
00117 void gnc_split_reg_copy_cb(GtkWidget *w, gpointer data);
00118 void gnc_split_reg_paste_cb(GtkWidget *w, gpointer data);
00119 
00120 void gnc_split_reg_cut_trans_cb(GtkWidget *w, gpointer data);
00121 void gnc_split_reg_copy_trans_cb(GtkWidget *w, gpointer data);
00122 void gnc_split_reg_paste_trans_cb(GtkWidget *w, gpointer data);
00123 void gnc_split_reg_void_trans_cb(GtkWidget *w, gpointer data);
00124 void gnc_split_reg_unvoid_trans_cb(GtkWidget *w, gpointer data);
00125 void gnc_split_reg_reverse_trans_cb(GtkWidget *w, gpointer data);
00126 
00127 void gnc_split_reg_record_cb (GnucashRegister *reg, gpointer data);
00128 void gnc_split_reg_reinitialize_trans_cb(GtkWidget *w, gpointer data);
00129 void gnc_split_reg_delete_trans_cb(GtkWidget *w, gpointer data);
00130 void gnc_split_reg_duplicate_trans_cb(GtkWidget *w, gpointer data);
00131 void gnc_split_reg_recur_cb(GtkWidget *w, gpointer data);
00132 void gnc_split_reg_record_trans_cb(GtkWidget *w, gpointer data);
00133 void gnc_split_reg_cancel_trans_cb(GtkWidget *w, gpointer data);
00134 
00135 void gnc_split_reg_expand_trans_menu_cb(GtkWidget *widget, gpointer data);
00136 void gnc_split_reg_expand_trans_toolbar_cb(GtkWidget *widget, gpointer data);
00137 void gnc_split_reg_new_trans_cb(GtkWidget *widget, gpointer data);
00138 void gnc_split_reg_jump_cb(GtkWidget *widget, gpointer data);
00139 
00140 void gnc_split_reg_style_ledger_cb (GtkWidget *w, gpointer data);
00141 void gnc_split_reg_style_auto_ledger_cb (GtkWidget *w, gpointer data);
00142 void gnc_split_reg_style_journal_cb (GtkWidget *w, gpointer data);
00143 void gnc_split_reg_double_line_cb (GtkWidget *w, gpointer data);
00144 
00145 void gnc_split_reg_sort_standard_cb (GtkWidget *w, gpointer data);
00146 void gnc_split_reg_sort_date_cb (GtkWidget *w, gpointer data);
00147 void gnc_split_reg_sort_date_entered_cb (GtkWidget *w, gpointer data);
00148 void gnc_split_reg_sort_date_reconciled_cb (GtkWidget *w, gpointer data);
00149 void gnc_split_reg_sort_num_cb (GtkWidget *w, gpointer data);
00150 void gnc_split_reg_sort_amount_cb (GtkWidget *w, gpointer data);
00151 void gnc_split_reg_sort_memo_cb (GtkWidget *w, gpointer data);
00152 void gnc_split_reg_sort_desc_cb (GtkWidget *w, gpointer data);
00153 void gnc_split_reg_sort_action_cb (GtkWidget *w, gpointer data);
00154 void gnc_split_reg_sort_notes_cb (GtkWidget *w, gpointer data);
00155 
00156 void gnc_split_reg_destroy_cb(GtkWidget *widget, gpointer data);
00157 void gnc_split_reg_size_allocate( GtkWidget *widget,
00158                                   GtkAllocation *allocation,
00159                                   gpointer user_data );
00160 
00161 
00162 void gnc_split_reg_handle_exchange_cb (GtkWidget *w, gpointer data);
00163 
00164 static void gnc_split_reg_class_init( GNCSplitRegClass *class );
00165 static void gnc_split_reg_init( GNCSplitReg *gsr );
00166 static void gnc_split_reg_init2( GNCSplitReg *gsr );
00167 
00168 void gnc_split_register_size_allocate (GtkWidget *widget,
00169                                        GtkAllocation *allocation,
00170                                        gpointer user_data);
00171 
00172 FROM_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
00173 AS_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
00174 
00175 GType
00176 gnc_split_reg_get_type( void )
00177 {
00178     static GType gnc_split_reg_type = 0;
00179 
00180     if (!gnc_split_reg_type)
00181     {
00182         GTypeInfo type_info =
00183         {
00184             sizeof(GNCSplitRegClass),      /* class_size */
00185             NULL,                       /* base_init */
00186             NULL,                               /* base_finalize */
00187             (GClassInitFunc)gnc_split_reg_class_init,
00188             NULL,                               /* class_finalize */
00189             NULL,                               /* class_data */
00190             sizeof(GNCSplitReg),                /* */
00191             0,                          /* n_preallocs */
00192             (GInstanceInitFunc)gnc_split_reg_init,
00193         };
00194 
00195         gnc_split_reg_type = g_type_register_static( GTK_TYPE_VBOX,
00196                              "GNCSplitReg",
00197                              &type_info, 0 );
00198     }
00199 
00200     return gnc_split_reg_type;
00201 }
00202 
00203 /* SIGNALS */
00204 enum gnc_split_reg_signal_enum
00205 {
00206     ENTER_ENT_SIGNAL,
00207     CANCEL_ENT_SIGNAL,
00208     DELETE_ENT_SIGNAL,
00209     REINIT_ENT_SIGNAL,
00210     DUP_ENT_SIGNAL,
00211     SCHEDULE_ENT_SIGNAL,
00212     EXPAND_ENT_SIGNAL,
00213     BLANK_SIGNAL,
00214     JUMP_SIGNAL,
00215     CUT_SIGNAL,
00216     CUT_TXN_SIGNAL,
00217     COPY_SIGNAL,
00218     COPY_TXN_SIGNAL,
00219     PASTE_SIGNAL,
00220     PASTE_TXN_SIGNAL,
00221     VOID_TXN_SIGNAL,
00222     UNVOID_TXN_SIGNAL,
00223     REVERSE_TXN_SIGNAL,
00224     HELP_CHANGED_SIGNAL,
00225     INCLUDE_DATE_SIGNAL,
00226     LAST_SIGNAL
00227 };
00228 
00229 static guint gnc_split_reg_signals[LAST_SIGNAL] = { 0 };
00230 
00231 static void
00232 gnc_split_reg_class_init( GNCSplitRegClass *class )
00233 {
00234     int i;
00235     GtkObjectClass *object_class;
00236     static struct similar_signal_info
00237     {
00238         enum gnc_split_reg_signal_enum s;
00239         const char *signal_name;
00240         guint defaultOffset;
00241     } signals[] =
00242     {
00243         { ENTER_ENT_SIGNAL,    "enter_ent",    G_STRUCT_OFFSET( GNCSplitRegClass, enter_ent_cb ) },
00244         { CANCEL_ENT_SIGNAL,   "cancel_ent",   G_STRUCT_OFFSET( GNCSplitRegClass, cancel_ent_cb ) },
00245         { DELETE_ENT_SIGNAL,   "delete_ent",   G_STRUCT_OFFSET( GNCSplitRegClass, delete_ent_cb ) },
00246         { REINIT_ENT_SIGNAL,   "reinit_ent",   G_STRUCT_OFFSET( GNCSplitRegClass, reinit_ent_cb ) },
00247         { DUP_ENT_SIGNAL,      "dup_ent",      G_STRUCT_OFFSET( GNCSplitRegClass, dup_ent_cb ) },
00248         { SCHEDULE_ENT_SIGNAL, "schedule_ent", G_STRUCT_OFFSET( GNCSplitRegClass, schedule_ent_cb ) },
00249         { EXPAND_ENT_SIGNAL,   "expand_ent",   G_STRUCT_OFFSET( GNCSplitRegClass, expand_ent_cb ) },
00250         { BLANK_SIGNAL,        "blank",        G_STRUCT_OFFSET( GNCSplitRegClass, blank_cb ) },
00251         { JUMP_SIGNAL,         "jump",         G_STRUCT_OFFSET( GNCSplitRegClass, jump_cb ) },
00252         { CUT_SIGNAL,          "cut",          G_STRUCT_OFFSET( GNCSplitRegClass, cut_cb ) },
00253         { CUT_TXN_SIGNAL,      "cut_txn",      G_STRUCT_OFFSET( GNCSplitRegClass, cut_txn_cb ) },
00254         { COPY_SIGNAL,         "copy",         G_STRUCT_OFFSET( GNCSplitRegClass, copy_cb ) },
00255         { COPY_TXN_SIGNAL,     "copy_txn",     G_STRUCT_OFFSET( GNCSplitRegClass, copy_txn_cb ) },
00256         { PASTE_SIGNAL,        "paste",        G_STRUCT_OFFSET( GNCSplitRegClass, paste_cb ) },
00257         { PASTE_TXN_SIGNAL,    "paste_txn",    G_STRUCT_OFFSET( GNCSplitRegClass, paste_txn_cb ) },
00258         { VOID_TXN_SIGNAL,     "void_txn",     G_STRUCT_OFFSET( GNCSplitRegClass, void_txn_cb ) },
00259         { UNVOID_TXN_SIGNAL,   "unvoid_txn",   G_STRUCT_OFFSET( GNCSplitRegClass, unvoid_txn_cb ) },
00260         { REVERSE_TXN_SIGNAL,  "reverse_txn",  G_STRUCT_OFFSET( GNCSplitRegClass, reverse_txn_cb ) },
00261         { HELP_CHANGED_SIGNAL, "help-changed", G_STRUCT_OFFSET( GNCSplitRegClass, help_changed_cb ) },
00262         { INCLUDE_DATE_SIGNAL, "include-date", G_STRUCT_OFFSET( GNCSplitRegClass, include_date_cb ) },
00263         { LAST_SIGNAL, NULL, 0 }
00264     };
00265 
00266     object_class = (GtkObjectClass*) class;
00267 
00268     for ( i = 0; signals[i].s != INCLUDE_DATE_SIGNAL; i++ )
00269     {
00270         gnc_split_reg_signals[ signals[i].s ] =
00271             g_signal_new( signals[i].signal_name,
00272                           G_TYPE_FROM_CLASS(object_class),
00273                           G_SIGNAL_RUN_LAST,
00274                           signals[i].defaultOffset,
00275                           NULL, NULL,
00276                           g_cclosure_marshal_VOID__VOID,
00277                           G_TYPE_NONE, 0 );
00278     }
00279     /* Setup the non-default-marshalled signals; 'i' is still valid, here. */
00280     /* "include-date" */
00281     gnc_split_reg_signals[ INCLUDE_DATE_SIGNAL ] =
00282         g_signal_new( "include-date",
00283                       G_TYPE_FROM_CLASS(object_class),
00284                       G_SIGNAL_RUN_LAST,
00285                       signals[i++].defaultOffset,
00286                       NULL, NULL,
00287                       g_cclosure_marshal_VOID__INT, /* time_t == int */
00288                       G_TYPE_NONE, 1, G_TYPE_INT );
00289 
00290     g_assert( i == LAST_SIGNAL );
00291 
00292     /* Setup the default handlers. */
00293     class->enter_ent_cb    = gsr_default_enter_handler;
00294     class->cancel_ent_cb   = gsr_default_cancel_handler;
00295     class->delete_ent_cb   = gsr_default_delete_handler;
00296     class->reinit_ent_cb   = gsr_default_reinit_handler;
00297     class->dup_ent_cb      = gsr_default_dup_handler;
00298     class->schedule_ent_cb = gsr_default_schedule_handler;
00299     class->expand_ent_cb   = gsr_default_expand_handler;
00300     class->blank_cb        = gsr_default_blank_handler;
00301     class->jump_cb         = gsr_default_jump_handler;
00302     class->cut_cb          = gsr_default_cut_handler;
00303     class->cut_txn_cb      = gsr_default_cut_txn_handler;
00304     class->copy_cb         = gsr_default_copy_handler;
00305     class->copy_txn_cb     = gsr_default_copy_txn_handler;
00306     class->paste_cb        = gsr_default_paste_handler;
00307     class->paste_txn_cb    = gsr_default_paste_txn_handler;
00308     class->void_txn_cb     = gsr_default_void_txn_handler;
00309     class->unvoid_txn_cb   = gsr_default_unvoid_txn_handler;
00310     class->reverse_txn_cb  = gsr_default_reverse_txn_handler;
00311 
00312     class->help_changed_cb = NULL;
00313     class->include_date_cb = NULL;
00314 }
00315 
00316 GtkWidget*
00317 gnc_split_reg_new( GNCLedgerDisplay *ld,
00318                    GtkWindow *parent,
00319                    gint numberOfLines,
00320                    gboolean read_only )
00321 {
00322     GNCSplitReg *gsrToRet;
00323 
00324     ENTER("ld=%p, parent=%p, numberOfLines=%d, read_only=%s",
00325           ld, parent, numberOfLines, read_only ? "TRUE" : "FALSE");
00326 
00327     gsrToRet = g_object_new( gnc_split_reg_get_type(), NULL );
00328 
00329     gsrToRet->numRows        = numberOfLines;
00330     gsrToRet->read_only      = read_only;
00331 
00332     gsrToRet->ledger = ld;
00333     gsrToRet->window = GTK_WIDGET(parent);
00334 
00335     gnc_split_reg_init2( gsrToRet );
00336 
00337     LEAVE("%p", gsrToRet);
00338     return GTK_WIDGET( gsrToRet );
00339 }
00340 
00341 static void
00342 gnc_split_reg_init( GNCSplitReg *gsr )
00343 {
00344     gsr->sort_type = BY_STANDARD;
00345     gsr->width = -1;
00346     gsr->height = -1;
00347     gsr->numRows = 10;
00348     gsr->read_only = FALSE;
00349 
00350     g_signal_connect( gsr, "destroy",
00351                       G_CALLBACK (gnc_split_reg_destroy_cb), gsr );
00352 }
00353 
00354 static void
00355 gnc_split_reg_init2( GNCSplitReg *gsr )
00356 {
00357     if ( !gsr ) return;
00358 
00359     gnc_split_reg_determine_read_only( gsr );
00360 
00361     gsr_setup_status_widgets( gsr );
00362     /* ordering is important here... setup_status before create_table */
00363     gsr_create_table( gsr );
00364     gsr_setup_table( gsr );
00365 }
00366 
00367 static
00368 void
00369 gsr_setup_table( GNCSplitReg *gsr )
00370 {
00371     SplitRegister *sr;
00372 
00373     ENTER("gsr=%p", gsr);
00374 
00375     sr = gnc_ledger_display_get_split_register( gsr->ledger );
00376     gnc_split_register_show_present_divider( sr, TRUE );
00377     /* events should be sufficient to redraw this */
00378     /* gnc_ledger_display_refresh( gsr->ledger ); */
00379     gnc_split_reg_refresh_toolbar( gsr );
00380 
00381     LEAVE(" ");
00382 }
00383 
00384 static
00385 void
00386 gsr_create_table( GNCSplitReg *gsr )
00387 {
00388     GtkWidget *register_widget;
00389     SplitRegister *sr;
00390 
00391     ENTER("gsr=%p", gsr);
00392 
00393     gnc_ledger_display_set_user_data( gsr->ledger, (gpointer)gsr );
00394     gnc_ledger_display_set_handlers( gsr->ledger,
00395                                      gnc_split_reg_ld_destroy,
00396                                      gnc_split_reg_get_parent );
00397 
00398     /* FIXME: We'd really rather pass this down... */
00399     sr = gnc_ledger_display_get_split_register( gsr->ledger );
00400     register_widget = gnucash_register_new( sr->table );
00401     gsr->reg = GNUCASH_REGISTER( register_widget );
00402     gnc_table_init_gui( GTK_WIDGET(gsr->reg), sr );
00403 
00404     gtk_box_pack_start (GTK_BOX (gsr), GTK_WIDGET(gsr->reg), TRUE, TRUE, 0);
00405     GNUCASH_SHEET(gsr->reg->sheet)->window = gsr->window;
00406     gtk_widget_show ( GTK_WIDGET(gsr->reg) );
00407     g_signal_connect (gsr->reg, "activate_cursor",
00408                       G_CALLBACK(gnc_split_reg_record_cb), gsr);
00409     g_signal_connect (gsr->reg, "redraw_all",
00410                       G_CALLBACK(gsr_redraw_all_cb), gsr);
00411     g_signal_connect (gsr->reg, "redraw_help",
00412                       G_CALLBACK(gsr_emit_help_changed), gsr);
00413 
00414     LEAVE(" ");
00415 }
00416 
00417 static
00418 void
00419 gsr_setup_status_widgets( GNCSplitReg *gsr )
00420 {
00421     SplitRegister *sr;
00422     gboolean use_double_line;
00423 
00424     sr = gnc_ledger_display_get_split_register( gsr->ledger );
00425     use_double_line = gnc_ledger_display_default_double_line( gsr->ledger );
00426 
00427     /* be sure to initialize the gui elements associated with the cursor */
00428     gnc_split_register_config( sr, sr->type, sr->style, use_double_line );
00429 }
00430 
00431 void
00432 gnc_split_reg_destroy_cb(GtkWidget *widget, gpointer data)
00433 {
00434 }
00435 
00439 void
00440 gnc_split_reg_raise( GNCSplitReg *gsr )
00441 {
00442     if (gsr == NULL)
00443         return;
00444 
00445     if (gsr->window == NULL)
00446         return;
00447 
00448     gtk_window_present( GTK_WINDOW(gsr->window) );
00449 }
00450 
00451 
00456 static
00457 void
00458 gsr_update_summary_label( GtkWidget *label,
00459                           xaccGetBalanceFn getter,
00460                           Account *leader,
00461                           GNCPrintAmountInfo print_info,
00462                           gnc_commodity *cmdty,
00463                           gboolean reverse,
00464                           gboolean euroFlag )
00465 {
00466     gnc_numeric amount;
00467     char string[256];
00468 
00469     if ( label == NULL )
00470         return;
00471 
00472     amount = (*getter)( leader );
00473 
00474     if ( reverse )
00475     {
00476         amount = gnc_numeric_neg( amount );
00477     }
00478 
00479     xaccSPrintAmount( string, amount, print_info );
00480 
00481     if ( euroFlag )
00482     {
00483         strcat( string, " / " );
00484         xaccSPrintAmount( string + strlen( string ),
00485                           gnc_convert_to_euro( cmdty, amount ),
00486                           gnc_commodity_print_info( gnc_get_euro(), TRUE ) );
00487     }
00488 
00489     gnc_set_label_color( label, amount );
00490     gtk_label_set_text( GTK_LABEL(label), string );
00491 }
00492 
00493 static GNCPrice *
00494 account_latest_price (Account *account)
00495 {
00496     QofBook *book;
00497     GNCPriceDB *pdb;
00498     gnc_commodity *commodity;
00499     gnc_commodity *currency;
00500 
00501     if (!account) return NULL;
00502     commodity = xaccAccountGetCommodity (account);
00503     currency = gnc_default_currency ();
00504 
00505     book = gnc_account_get_book (account);
00506     pdb = gnc_pricedb_get_db (book);
00507 
00508     return gnc_pricedb_lookup_latest (pdb, commodity, currency);
00509 }
00510 
00511 static GNCPrice *
00512 account_latest_price_any_currency (Account *account)
00513 {
00514     QofBook *book;
00515     GNCPriceDB *pdb;
00516     gnc_commodity *commodity;
00517     GList *price_list;
00518     GNCPrice *result;
00519 
00520     if (!account) return NULL;
00521     commodity = xaccAccountGetCommodity (account);
00522 
00523     book = gnc_account_get_book (account);
00524     pdb = gnc_pricedb_get_db (book);
00525 
00526     price_list = gnc_pricedb_lookup_latest_any_currency (pdb, commodity);
00527     if (!price_list) return NULL;
00528 
00529     result = gnc_price_clone((GNCPrice *)(price_list->data), book);
00530 
00531     gnc_price_list_destroy(price_list);
00532 
00533     return result;
00534 }
00535 
00536 static
00537 void
00538 gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
00539 {
00540     GNCSplitReg *gsr = data;
00541     gnc_commodity * commodity;
00542     GNCPrintAmountInfo print_info;
00543     gnc_numeric amount;
00544     char string[256];
00545     Account *leader;
00546     gboolean reverse;
00547     gboolean euro;
00548 
00549     if ( gsr->summarybar == NULL )
00550         return;
00551 
00552     leader = gnc_ledger_display_leader( gsr->ledger );
00553 
00554     commodity = xaccAccountGetCommodity( leader );
00555 
00556     /* no EURO converson, if account is already EURO or no EURO currency */
00557     if (commodity != NULL)
00558         euro = (gnc_is_euro_currency( commodity ) &&
00559                 (strncasecmp(gnc_commodity_get_mnemonic(commodity), "EUR", 3)));
00560     else
00561         euro = FALSE;
00562 
00563     print_info = gnc_account_print_info( leader, TRUE );
00564     reverse = gnc_reverse_balance( leader );
00565 
00566     gsr_update_summary_label( gsr->balance_label,
00567                               xaccAccountGetPresentBalance,
00568                               leader, print_info, commodity, reverse, euro );
00569     gsr_update_summary_label( gsr->cleared_label,
00570                               xaccAccountGetClearedBalance,
00571                               leader, print_info, commodity, reverse, euro );
00572     gsr_update_summary_label( gsr->reconciled_label,
00573                               xaccAccountGetReconciledBalance,
00574                               leader, print_info, commodity, reverse, euro );
00575     gsr_update_summary_label( gsr->future_label,
00576                               xaccAccountGetBalance,
00577                               leader, print_info, commodity, reverse, euro );
00578     gsr_update_summary_label( gsr->projectedminimum_label,
00579                               xaccAccountGetProjectedMinimumBalance,
00580                               leader, print_info, commodity, reverse, euro );
00581 
00582     /* Print the summary share amount */
00583     if (gsr->shares_label != NULL)
00584     {
00585         print_info = gnc_account_print_info( leader, TRUE );
00586 
00587         amount = xaccAccountGetBalance( leader );
00588         if (reverse)
00589             amount = gnc_numeric_neg( amount );
00590 
00591         xaccSPrintAmount( string, amount, print_info );
00592 
00593         gnc_set_label_color( gsr->shares_label, amount );
00594         gtk_label_set_text( GTK_LABEL(gsr->shares_label), string );
00595     }
00596 
00597     /* Print the summary share value */
00598     if (gsr->value_label != NULL)
00599     {
00600         GNCPrice *price;
00601 
00602         amount = xaccAccountGetBalance (leader);
00603         if (reverse) amount = gnc_numeric_neg (amount);
00604 
00605         price = account_latest_price (leader);
00606         if (!price)
00607         {
00608             /* If the balance is zero, then print zero. */
00609             if (gnc_numeric_equal(amount, gnc_numeric_zero()))
00610             {
00611                 gnc_commodity *currency = gnc_default_currency ();
00612                 print_info = gnc_commodity_print_info (currency, TRUE);
00613                 amount = gnc_numeric_zero ();
00614 
00615                 xaccSPrintAmount (string, amount, print_info);
00616 
00617                 gnc_set_label_color (gsr->value_label, amount);
00618                 gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
00619             }
00620             else
00621             {
00622                 /* else try to do a double-price-conversion :-( */
00623                 price = account_latest_price_any_currency (leader);
00624                 if (!price)
00625                 {
00626                     gnc_set_label_color (gsr->value_label, gnc_numeric_zero ());
00627                     gtk_label_set_text (GTK_LABEL (gsr->value_label),
00628                                         _("<No information>"));
00629                 }
00630                 else
00631                 {
00632                     gnc_commodity *currency = gnc_price_get_currency (price);
00633                     gnc_commodity *default_currency = gnc_default_currency ();
00634                     gnc_numeric currency_amount;
00635                     gnc_numeric default_currency_amount;
00636 
00637                     print_info = gnc_commodity_print_info (currency, TRUE);
00638 
00639                     currency_amount =
00640                         xaccAccountConvertBalanceToCurrency(leader, amount,
00641                                                             commodity, currency);
00642                     xaccSPrintAmount (string, currency_amount, print_info);
00643 
00644                     default_currency_amount =
00645                         xaccAccountConvertBalanceToCurrency(leader, amount,
00646                                                             commodity,
00647                                                             default_currency);
00648                     if (!gnc_numeric_zero_p(default_currency_amount))
00649                     {
00650                         strcat( string, " / " );
00651                         print_info = gnc_commodity_print_info (default_currency, TRUE);
00652                         xaccSPrintAmount( string + strlen( string ), default_currency_amount,
00653                                           print_info);
00654                     }
00655 
00656                     gnc_set_label_color (gsr->value_label, amount);
00657                     gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
00658 
00659                     gnc_price_unref (price);
00660                 }
00661             }
00662         }
00663         else
00664         {
00665             gnc_commodity *currency = gnc_price_get_currency (price);
00666 
00667             print_info = gnc_commodity_print_info (currency, TRUE);
00668 
00669             amount = gnc_numeric_mul (amount, gnc_price_get_value (price),
00670                                       gnc_commodity_get_fraction (currency),
00671                                       GNC_HOW_RND_ROUND_HALF_UP);
00672 
00673             xaccSPrintAmount (string, amount, print_info);
00674 
00675             gnc_set_label_color (gsr->value_label, amount);
00676             gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
00677 
00678             gnc_price_unref (price);
00679         }
00680     }
00681 }
00682 
00683 static void
00684 gnc_split_reg_refresh_toolbar( GNCSplitReg *gsr )
00685 {
00686     GtkToolbarStyle tbstyle;
00687 
00688     if ((gsr == NULL) || (gsr->toolbar == NULL))
00689         return;
00690 
00691     tbstyle = gnc_get_toolbar_style ();
00692     gtk_toolbar_set_style( GTK_TOOLBAR(gsr->toolbar), tbstyle );
00693 }
00694 
00695 static void
00696 gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger )
00697 {
00698     GNCSplitReg *gsr = gnc_ledger_display_get_user_data( ledger );
00699 
00700     if (gsr)
00701     {
00702         SplitRegister *reg;
00703 
00704         reg = gnc_ledger_display_get_split_register (ledger);
00705 
00706         if (reg && reg->table)
00707             gnc_table_save_state (reg->table);
00708 
00709         /*
00710          * Don't destroy the window here any more.  The register no longer
00711          * owns it.
00712          */
00713     }
00714     gnc_ledger_display_set_user_data (ledger, NULL);
00715 }
00716 
00717 void
00718 gsr_default_cut_handler( GNCSplitReg *gsr, gpointer data )
00719 {
00720     gnucash_register_cut_clipboard( gsr->reg );
00721 }
00722 
00726 void
00727 gnc_split_reg_cut_cb (GtkWidget *w, gpointer data)
00728 {
00729     GNCSplitReg *gsr = data;
00730     gsr_emit_simple_signal( gsr, "cut" );
00731 }
00732 
00733 void
00734 gsr_default_copy_handler( GNCSplitReg *gsr, gpointer data )
00735 {
00736     gnucash_register_copy_clipboard( gsr->reg );
00737 }
00738 
00742 void
00743 gnc_split_reg_copy_cb (GtkWidget *w, gpointer data)
00744 {
00745     GNCSplitReg *gsr = data;
00746     gsr_emit_simple_signal( gsr, "copy" );
00747 }
00748 
00749 void
00750 gsr_default_paste_handler( GNCSplitReg *gsr, gpointer data )
00751 {
00752     gnucash_register_paste_clipboard( gsr->reg );
00753 }
00754 
00758 void
00759 gnc_split_reg_paste_cb (GtkWidget *w, gpointer data)
00760 {
00761     GNCSplitReg *gsr = data;
00762     gsr_emit_simple_signal( gsr, "paste" );
00763 }
00764 
00765 void
00766 gsr_default_cut_txn_handler( GNCSplitReg *gsr, gpointer data )
00767 {
00768     gnc_split_register_cut_current
00769     (gnc_ledger_display_get_split_register( gsr->ledger ));
00770 }
00771 
00775 void
00776 gnc_split_reg_cut_trans_cb (GtkWidget *w, gpointer data)
00777 {
00778     GNCSplitReg *gsr = data;
00779     gsr_emit_simple_signal( gsr, "cut_txn" );
00780 }
00781 
00782 void
00783 gsr_default_copy_txn_handler( GNCSplitReg *gsr, gpointer data )
00784 {
00785     gnc_split_register_copy_current
00786     (gnc_ledger_display_get_split_register( gsr->ledger ));
00787 }
00788 
00792 void
00793 gnc_split_reg_copy_trans_cb(GtkWidget *w, gpointer data)
00794 {
00795     GNCSplitReg *gsr = data;
00796     gsr_emit_simple_signal( gsr, "copy_txn" );
00797 }
00798 
00799 void
00800 gsr_default_paste_txn_handler( GNCSplitReg *gsr, gpointer data )
00801 {
00802     gnc_split_register_paste_current
00803     (gnc_ledger_display_get_split_register( gsr->ledger ));
00804 }
00805 
00809 void
00810 gnc_split_reg_paste_trans_cb (GtkWidget *w, gpointer data)
00811 {
00812     GNCSplitReg *gsr = data;
00813     gsr_emit_simple_signal( gsr, "paste_txn" );
00814 }
00815 
00816 /********************************************************************\
00817  * gnc_split_reg_void_trans_cb                                      *
00818  *                                                                  *
00819  * Args:   widget - the widget that called us                       *
00820  *         data   - the data struct for this register               *
00821  * Return: none                                                     *
00822 \********************************************************************/
00823 void
00824 gsr_default_void_txn_handler (GNCSplitReg *gsr, gpointer data)
00825 {
00826     // Override this function.
00827 }
00828 
00829 void
00830 gnc_split_reg_void_trans_cb (GtkWidget *w, gpointer data)
00831 {
00832     GNCSplitReg *gsr = data;
00833     gsr_emit_simple_signal( gsr, "void_txn" );
00834 }
00835 
00836 /********************************************************************\
00837  * gnc_split_reg_unvoid_trans_cb                                      *
00838  *                                                                  *
00839  * Args:   widget - the widget that called us                       *
00840  *         data   - the data struct for this register               *
00841  * Return: none                                                     *
00842 \********************************************************************/
00843 void
00844 gsr_default_unvoid_txn_handler (GNCSplitReg *gsr, gpointer data)
00845 {
00846     // Override this function.
00847 }
00848 
00849 void
00850 gnc_split_reg_unvoid_trans_cb (GtkWidget *w, gpointer data)
00851 {
00852     GNCSplitReg *gsr = data;
00853     gsr_emit_simple_signal( gsr, "unvoid_txn" );
00854 }
00855 
00856 /********************************************************************\
00857  * gnc_split_reg_reverse_trans_cb                                   *
00858  *                                                                  *
00859  * Args:   widget - the widget that called us                       *
00860  *         data   - the data struct for this register               *
00861  * Return: none                                                     *
00862 \********************************************************************/
00863 void
00864 gsr_default_reverse_txn_handler (GNCSplitReg *gsr, gpointer data)
00865 {
00866     SplitRegister *reg;
00867     Transaction *trans, *new_trans;
00868 
00869     reg = gnc_ledger_display_get_split_register( gsr->ledger );
00870     trans = gnc_split_register_get_current_trans (reg);
00871     if (trans == NULL)
00872         return;
00873 
00874     if (xaccTransGetReversedBy(trans))
00875     {
00876         gnc_error_dialog(gsr->window, "%s",
00877                          _("A reversing entry has already been created for this transaction."));
00878         return;
00879     }
00880 
00881     new_trans = xaccTransReverse(trans);
00882 
00883     /* Clear transaction level info */
00884     xaccTransSetDatePostedSecs(new_trans, time(NULL));
00885     xaccTransSetDateEnteredSecs(new_trans, time(NULL));
00886 
00887     /* Now jump to new trans */
00888     gnc_split_reg_jump_to_split(gsr, xaccTransGetSplit(new_trans, 0));
00889 }
00890 
00891 void
00892 gnc_split_reg_reverse_trans_cb (GtkWidget *w, gpointer data)
00893 {
00894     GNCSplitReg *gsr = data;
00895     gsr_emit_simple_signal( gsr, "reverse_txn" );
00896 }
00897 
00898 
00899 static gboolean
00900 is_trans_readonly_and_warn (const Transaction *trans)
00901 {
00902     GtkWidget *dialog;
00903     const gchar *reason;
00904     const gchar *title = _("Cannot modify or delete this transaction.");
00905     const gchar *message =
00906         _("This transaction is marked read-only with the comment: '%s'");
00907 
00908     if (!trans) return FALSE;
00909 
00910     if (xaccTransIsReadonlyByPostedDate (trans))
00911     {
00912         dialog = gtk_message_dialog_new(NULL,
00913                                         0,
00914                                         GTK_MESSAGE_ERROR,
00915                                         GTK_BUTTONS_OK,
00916                                         "%s", title);
00917         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
00918                 "%s", _("The date of this transaction is older than the \"Read-Only Threshold\" set for this book.  "
00919                         "This setting can be changed in File -> Properties -> Accounts."));
00920         gtk_dialog_run(GTK_DIALOG(dialog));
00921         gtk_widget_destroy(dialog);
00922         return TRUE;
00923     }
00924 
00925     reason = xaccTransGetReadOnly (trans);
00926     if (reason)
00927     {
00928         dialog = gtk_message_dialog_new(NULL,
00929                                         0,
00930                                         GTK_MESSAGE_ERROR,
00931                                         GTK_BUTTONS_OK,
00932                                         "%s", title);
00933         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
00934                 message, reason);
00935         gtk_dialog_run(GTK_DIALOG(dialog));
00936         gtk_widget_destroy(dialog);
00937         return TRUE;
00938     }
00939     return FALSE;
00940 }
00941 
00942 
00943 void
00944 gsr_default_reinit_handler( GNCSplitReg *gsr, gpointer data )
00945 {
00946     VirtualCellLocation vcell_loc;
00947     SplitRegister *reg;
00948     Transaction *trans;
00949     Split *split;
00950     GtkWidget *dialog;
00951     gint response;
00952     const gchar *warning;
00953 
00954     const char *title = _("Remove the splits from this transaction?");
00955     const char *recn_warn = _("This transaction contains reconciled splits. "
00956                               "Modifying it is not a good idea because that will "
00957                               "cause your reconciled balance to be off.");
00958 
00959     reg = gnc_ledger_display_get_split_register( gsr->ledger );
00960 
00961     trans = gnc_split_register_get_current_trans (reg);
00962     if (is_trans_readonly_and_warn(trans))
00963         return;
00964     dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
00965                                     GTK_DIALOG_DESTROY_WITH_PARENT,
00966                                     GTK_MESSAGE_WARNING,
00967                                     GTK_BUTTONS_NONE,
00968                                     "%s", title);
00969     if (xaccTransHasReconciledSplits (trans))
00970     {
00971         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
00972                 "%s", recn_warn);
00973         warning = "register_remove_all_splits2";
00974     }
00975     else
00976     {
00977         warning = "register_remove_all_splits";
00978     }
00979 
00980     gtk_dialog_add_button(GTK_DIALOG(dialog),
00981                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
00982     gnc_gtk_dialog_add_button(dialog, _("_Remove Splits"),
00983                               GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
00984     response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
00985     gtk_widget_destroy (dialog);
00986     if (response != GTK_RESPONSE_ACCEPT)
00987         return;
00988 
00989     /*
00990      * Find the "transaction" split for the current transaction. This is
00991      * the split that appears at the top of the transaction in the
00992      * register.
00993      */
00994     split = gnc_split_register_get_current_split (reg);
00995     if (!gnc_split_register_get_split_virt_loc(reg, split, &vcell_loc))
00996         return;
00997     split = gnc_split_register_get_current_trans_split (reg, &vcell_loc);
00998     gnc_split_register_empty_current_trans_except_split (reg, split);
00999 }
01000 
01004 void
01005 gnc_split_reg_reinitialize_trans_cb(GtkWidget *widget, gpointer data)
01006 {
01007     GNCSplitReg *gsr = data;
01008     gsr_emit_simple_signal( gsr, "reinit_ent" );
01009 }
01010 
01011 void
01012 gsr_default_delete_handler( GNCSplitReg *gsr, gpointer data )
01013 {
01014     SplitRegisterStyle style;
01015     CursorClass cursor_class;
01016     SplitRegister *reg;
01017     Transaction *trans;
01018     Split *split;
01019     GtkWidget *dialog;
01020     gint response;
01021     const gchar *warning;
01022 
01023     reg = gnc_ledger_display_get_split_register( gsr->ledger );
01024 
01025     /* get the current split based on cursor position */
01026     split = gnc_split_register_get_current_split(reg);
01027     if (split == NULL)
01028     {
01029         gnc_split_register_cancel_cursor_split_changes (reg);
01030         return;
01031     }
01032 
01033     trans = xaccSplitGetParent(split);
01034     style = reg->style;
01035     cursor_class = gnc_split_register_get_current_cursor_class (reg);
01036 
01037     /* Deleting the blank split just cancels */
01038     {
01039         Split *blank_split = gnc_split_register_get_blank_split (reg);
01040 
01041         if (split == blank_split)
01042         {
01043             gnc_split_register_cancel_cursor_trans_changes (reg);
01044             return;
01045         }
01046     }
01047 
01048     if (cursor_class == CURSOR_CLASS_NONE)
01049         return;
01050 
01051     if (is_trans_readonly_and_warn(trans))
01052         return;
01053 
01054     /* On a split cursor, just delete the one split. */
01055     if (cursor_class == CURSOR_CLASS_SPLIT)
01056     {
01057         const char *format = _("Delete the split '%s' from the transaction '%s'?");
01058         const char *recn_warn = _("You would be deleting a reconciled split! "
01059                                   "This is not a good idea as it will cause your "
01060                                   "reconciled balance to be off.");
01061         const char *anchor_error = _("You cannot delete this split.");
01062         const char *anchor_split = _("This is the split anchoring this transaction "
01063                                      "to the register. You may not delete it from "
01064                                      "this register window.  You may delete the "
01065                                      "entire transaction from this window, or you "
01066                                      "may navigate to a register that shows "
01067                                      "another side of this same transaction and "
01068                                      "delete the split from that register.");
01069         char *buf = NULL;
01070         const char *memo;
01071         const char *desc;
01072         char recn;
01073 
01074         if (split == gnc_split_register_get_current_trans_split (reg, NULL))
01075         {
01076             dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
01077                                             GTK_DIALOG_MODAL
01078                                             | GTK_DIALOG_DESTROY_WITH_PARENT,
01079                                             GTK_MESSAGE_ERROR,
01080                                             GTK_BUTTONS_OK,
01081                                             "%s", anchor_error);
01082             gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01083                     "%s", anchor_split);
01084             gtk_dialog_run(GTK_DIALOG(dialog));
01085             gtk_widget_destroy (dialog);
01086             return;
01087         }
01088 
01089         memo = xaccSplitGetMemo (split);
01090         memo = (memo && *memo) ? memo : _("(no memo)");
01091 
01092         desc = xaccTransGetDescription (trans);
01093         desc = (desc && *desc) ? desc : _("(no description)");
01094 
01095         /* ask for user confirmation before performing permanent damage */
01096         buf = g_strdup_printf (format, memo, desc);
01097         dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
01098                                         GTK_DIALOG_MODAL
01099                                         | GTK_DIALOG_DESTROY_WITH_PARENT,
01100                                         GTK_MESSAGE_QUESTION,
01101                                         GTK_BUTTONS_NONE,
01102                                         "%s", buf);
01103         g_free(buf);
01104         recn = xaccSplitGetReconcile (split);
01105         if (recn == YREC || recn == FREC)
01106         {
01107             gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01108                     "%s", recn_warn);
01109             warning = "register_delete_split2";
01110         }
01111         else
01112         {
01113             warning = "register_delete_split";
01114         }
01115 
01116         gtk_dialog_add_button(GTK_DIALOG(dialog),
01117                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
01118         gnc_gtk_dialog_add_button(dialog, _("_Delete Split"),
01119                                   GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
01120         response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
01121         gtk_widget_destroy (dialog);
01122         if (response != GTK_RESPONSE_ACCEPT)
01123             return;
01124 
01125         gnc_split_register_delete_current_split (reg);
01126         return;
01127     }
01128 
01129     g_return_if_fail(cursor_class == CURSOR_CLASS_TRANS);
01130 
01131     /* On a transaction cursor with 2 or fewer splits in single or double
01132      * mode, we just delete the whole transaction, kerblooie */
01133     {
01134         const char *title = _("Delete the current transaction?");
01135         const char *recn_warn = _("You would be deleting a transaction "
01136                                   "with reconciled splits! "
01137                                   "This is not a good idea as it will cause your "
01138                                   "reconciled balance to be off.");
01139 
01140         dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
01141                                         GTK_DIALOG_MODAL
01142                                         | GTK_DIALOG_DESTROY_WITH_PARENT,
01143                                         GTK_MESSAGE_WARNING,
01144                                         GTK_BUTTONS_NONE,
01145                                         "%s", title);
01146         if (xaccTransHasReconciledSplits (trans))
01147         {
01148             gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01149                     "%s", recn_warn);
01150             warning = "register_delete_trans2";
01151         }
01152         else
01153         {
01154             warning = "register_delete_trans";
01155         }
01156         gtk_dialog_add_button(GTK_DIALOG(dialog),
01157                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
01158         gnc_gtk_dialog_add_button(dialog, _("_Delete Transaction"),
01159                                   GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
01160         response =  gnc_dialog_run(GTK_DIALOG(dialog), warning);
01161         gtk_widget_destroy (dialog);
01162         if (response != GTK_RESPONSE_ACCEPT)
01163             return;
01164 
01165         gnc_split_register_delete_current_trans (reg);
01166         return;
01167     }
01168 }
01169 
01173 void
01174 gnc_split_reg_delete_trans_cb(GtkWidget *widget, gpointer data)
01175 {
01176     GNCSplitReg *gsr = data;
01177     gsr_emit_simple_signal( gsr, "delete_ent" );
01178 }
01179 
01180 void
01181 gsr_default_dup_handler( GNCSplitReg *gsr, gpointer data )
01182 {
01183     gnc_split_register_duplicate_current
01184     (gnc_ledger_display_get_split_register( gsr->ledger ));
01185 }
01186 
01190 void
01191 gnc_split_reg_duplicate_trans_cb(GtkWidget *w, gpointer data)
01192 {
01193     GNCSplitReg *gsr = data;
01194     gsr_emit_simple_signal( gsr, "dup_ent" );
01195 }
01196 
01202 void
01203 gsr_default_schedule_handler( GNCSplitReg *gsr, gpointer data )
01204 {
01205     SplitRegister *reg = gnc_ledger_display_get_split_register( gsr->ledger );
01206     Transaction *pending_trans = gnc_split_register_get_current_trans (reg);
01207 
01208     /* If the transaction has a sched-xact KVP frame, then go to the editor
01209      * for the existing SX; otherwise, do the sx-from-trans dialog. */
01210     {
01211         kvp_frame *txn_frame;
01212         kvp_value *kvp_val;
01213         /* set a kvp-frame element in the transaction indicating and
01214          * pointing-to the SX this was created from. */
01215         txn_frame = xaccTransGetSlots( pending_trans );
01216         if ( txn_frame != NULL )
01217         {
01218             kvp_val = kvp_frame_get_slot( txn_frame, "from-sched-xaction" );
01219             if ( kvp_val )
01220             {
01221                 GncGUID *fromSXId = kvp_value_get_guid( kvp_val );
01222                 SchedXaction *theSX = NULL;
01223                 GList *sxElts;
01224 
01225                 /* Get the correct SX */
01226                 for ( sxElts = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
01227                         (!theSX) && sxElts;
01228                         sxElts = sxElts->next )
01229                 {
01230                     SchedXaction *sx = (SchedXaction*)sxElts->data;
01231                     theSX =
01232                         ( ( guid_equal( xaccSchedXactionGetGUID( sx ), fromSXId ) )
01233                           ? sx : NULL );
01234                 }
01235 
01236                 if ( theSX )
01237                 {
01238                     gnc_ui_scheduled_xaction_editor_dialog_create(theSX, FALSE);
01239                     return;
01240                 }
01241             }
01242         }
01243     }
01244 
01245     gnc_sx_create_from_trans(pending_trans);
01246 }
01247 
01248 void
01249 gnc_split_reg_recur_cb(GtkWidget *w, gpointer data)
01250 {
01251     GNCSplitReg *gsr = data;
01252     gsr_emit_simple_signal( gsr, "schedule_ent" );
01253 }
01254 
01258 void
01259 gnc_split_reg_record_trans_cb (GtkWidget *w, gpointer data)
01260 {
01261     GNCSplitReg *gsr = data;
01262     gsr_emit_simple_signal( gsr, "enter_ent" );
01263 }
01264 
01265 void
01266 gsr_default_cancel_handler( GNCSplitReg *gsr, gpointer data )
01267 {
01268     gnc_split_register_cancel_cursor_trans_changes
01269     (gnc_ledger_display_get_split_register( gsr->ledger ));
01270 }
01271 
01275 void
01276 gnc_split_reg_cancel_trans_cb(GtkWidget *w, gpointer data)
01277 {
01278     GNCSplitReg *gsr = data;
01279     gsr_emit_simple_signal( gsr, "cancel_ent" );
01280 }
01281 
01282 void
01283 gsr_default_expand_handler( GNCSplitReg *gsr, gpointer data )
01284 {
01285     gint activeCount;
01286     gboolean expand;
01287     SplitRegister *reg;
01288 
01289     if (!gsr)
01290         return;
01291 
01292     reg = gnc_ledger_display_get_split_register (gsr->ledger);
01293 
01294     /* These should all be in agreement. */
01295     activeCount =
01296         ( ( GTK_CHECK_MENU_ITEM(gsr->split_menu_check)->active ? 1 : -1 )
01297           + ( GTK_CHECK_MENU_ITEM(gsr->split_popup_check)->active ? 1 : -1 )
01298           + ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(gsr->split_button) )
01299               ? 1 : -1 ) );
01300 
01301     /* If activeCount > 0, then there's more active than inactive; otherwise,
01302      * more inactive than active.  Both determine which state the user is
01303      * attempting to get to. */
01304     expand = ( activeCount < 0 );
01305 
01306     /* The ledger's invocation of 'redraw_all' will force the agreement in the
01307      * other split state widgets, so we neglect doing it here.  */
01308     gnc_split_register_expand_current_trans (reg, expand);
01309 }
01310 
01311 void
01312 gnc_split_reg_expand_trans_menu_cb (GtkWidget *widget, gpointer data)
01313 {
01314     GNCSplitReg *gsr = data;
01315     gsr_emit_simple_signal( gsr, "expand_ent" );
01316 }
01317 
01318 void
01319 gnc_split_reg_expand_trans_toolbar_cb (GtkWidget *widget, gpointer data)
01320 {
01321     GNCSplitReg *gsr = data;
01322     gsr_emit_simple_signal( gsr, "expand_ent" );
01323 }
01324 
01328 void
01329 gnc_split_reg_jump_to_split(GNCSplitReg *gsr, Split *split)
01330 {
01331     Transaction *trans;
01332     VirtualCellLocation vcell_loc;
01333     SplitRegister *reg;
01334 
01335     if (!gsr) return;
01336 
01337     trans = xaccSplitGetParent(split);
01338 
01339     gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
01340 
01341     reg = gnc_ledger_display_get_split_register( gsr->ledger );
01342 
01343     if (gnc_split_register_get_split_virt_loc(reg, split, &vcell_loc))
01344         gnucash_register_goto_virt_cell( gsr->reg, vcell_loc );
01345 
01346     gnc_ledger_display_refresh( gsr->ledger );
01347 }
01348 
01349 
01353 void
01354 gnc_split_reg_jump_to_split_amount(GNCSplitReg *gsr, Split *split)
01355 {
01356     VirtualLocation virt_loc;
01357     SplitRegister *reg;
01358     Transaction *trans;
01359 
01360     if (!gsr) return;
01361 
01362     trans = xaccSplitGetParent(split);
01363     gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
01364 
01365     reg = gnc_ledger_display_get_split_register (gsr->ledger);
01366 
01367     if (gnc_split_register_get_split_amount_virt_loc (reg, split, &virt_loc))
01368         gnucash_register_goto_virt_loc (gsr->reg, virt_loc);
01369 
01370     gnc_ledger_display_refresh (gsr->ledger);
01371 }
01372 
01373 void
01374 gnc_split_reg_jump_to_blank (GNCSplitReg *gsr)
01375 {
01376     SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
01377     VirtualCellLocation vcell_loc;
01378     Split *blank;
01379 
01380     ENTER("gsr=%p", gsr);
01381 
01382     blank = gnc_split_register_get_blank_split (reg);
01383     if (blank == NULL)
01384     {
01385         LEAVE("no blank split");
01386         return;
01387     }
01388 
01389     if (gnc_split_register_get_split_virt_loc (reg, blank, &vcell_loc))
01390         gnucash_register_goto_virt_cell (gsr->reg, vcell_loc);
01391 
01392     gnc_ledger_display_refresh (gsr->ledger);
01393     LEAVE(" ");
01394 }
01395 
01396 void
01397 gnc_split_reg_balancing_entry(GNCSplitReg *gsr, Account *account,
01398                               time_t statement_date, gnc_numeric balancing_amount)
01399 {
01400 
01401     Transaction *transaction;
01402     Split *split;
01403 
01404     // create transaction
01405     transaction = create_balancing_transaction(gnc_get_current_book(),
01406                   account, statement_date, balancing_amount);
01407 
01408     // jump to transaction
01409     split = xaccTransFindSplitByAccount(transaction, account);
01410     if (split == NULL)
01411     {
01412         // default behaviour: jump to blank split
01413         g_warning("create_balancing_transaction failed");
01414         gnc_split_reg_jump_to_blank(gsr);
01415     }
01416     else
01417     {
01418         // goto balancing transaction
01419         gnc_split_reg_jump_to_split(gsr, split );
01420     }
01421 }
01422 
01423 static Transaction*
01424 create_balancing_transaction(QofBook *book, Account *account,
01425                              time_t statement_date, gnc_numeric balancing_amount)
01426 {
01427 
01428     Transaction *trans;
01429     Split *split;
01430 
01431     if (!account)
01432         return NULL;
01433     if (gnc_numeric_zero_p(balancing_amount))
01434         return NULL;
01435 
01436     xaccAccountBeginEdit(account);
01437 
01438     trans = xaccMallocTransaction(book);
01439 
01440     xaccTransBeginEdit(trans);
01441 
01442     // fill Transaction
01443     xaccTransSetCurrency(trans, xaccAccountGetCommodity(account));
01444     xaccTransSetDatePostedSecs(trans, statement_date);
01445     xaccTransSetDescription(trans, _("Balancing entry from reconcilation"));
01446 
01447     // 1. Split
01448     split = xaccMallocSplit(book);
01449     xaccTransAppendSplit(trans, split);
01450     xaccAccountInsertSplit(account, split);
01451     xaccSplitSetAmount(split, balancing_amount);
01452     xaccSplitSetValue(split, balancing_amount);
01453 
01454     // 2. Split (no account is defined: split goes to orphan account)
01455     split = xaccMallocSplit(book);
01456     xaccTransAppendSplit(trans, split);
01457 
01458     balancing_amount = gnc_numeric_neg(balancing_amount);
01459     xaccSplitSetAmount(split, balancing_amount);
01460     xaccSplitSetValue(split, balancing_amount);
01461 
01462     xaccTransCommitEdit(trans);
01463     xaccAccountCommitEdit(account);
01464     return trans;
01465 }
01466 
01467 void
01468 gsr_default_blank_handler( GNCSplitReg *gsr, gpointer data )
01469 {
01470     SplitRegister *reg;
01471 
01472     ENTER("gsr=%p, gpointer=%p", gsr, data);
01473 
01474     reg = gnc_ledger_display_get_split_register (gsr->ledger);
01475 
01476     if (gnc_split_register_save (reg, TRUE))
01477         gnc_split_register_redraw (reg);
01478 
01479     gnc_split_reg_jump_to_blank (gsr);
01480     LEAVE(" ");
01481 }
01482 
01483 void
01484 gnc_split_reg_new_trans_cb (GtkWidget *widget, gpointer data)
01485 {
01486     GNCSplitReg *gsr = data;
01487     gsr_emit_simple_signal( gsr, "blank" );
01488 }
01489 
01490 void
01491 gsr_default_jump_handler( GNCSplitReg *gsr, gpointer data )
01492 {
01493     g_assert_not_reached();
01494 }
01495 
01496 void
01497 gnc_split_reg_jump_cb( GtkWidget *widget, gpointer data )
01498 {
01499     GNCSplitReg *gsr = data;
01500     gsr_emit_simple_signal( gsr, "jump" );
01501 }
01502 
01503 void
01504 gnc_split_reg_change_style (GNCSplitReg *gsr, SplitRegisterStyle style)
01505 {
01506     SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
01507 
01508     if (style == reg->style)
01509         return;
01510 
01511     gnc_split_register_config (reg, reg->type, style, reg->use_double_line);
01512     gnc_ledger_display_refresh (gsr->ledger);
01513 }
01514 
01515 void
01516 gnc_split_reg_style_ledger_cb (GtkWidget *w, gpointer data)
01517 {
01518     GNCSplitReg *gsr = data;
01519 
01520     if (!GTK_CHECK_MENU_ITEM(w)->active)
01521         return;
01522 
01523     gnc_split_reg_change_style (gsr, REG_STYLE_LEDGER);
01524 }
01525 
01526 void
01527 gnc_split_reg_style_auto_ledger_cb (GtkWidget *w, gpointer data)
01528 {
01529     GNCSplitReg *gsr = data;
01530 
01531     if (!GTK_CHECK_MENU_ITEM(w)->active)
01532         return;
01533 
01534     gnc_split_reg_change_style (gsr, REG_STYLE_AUTO_LEDGER);
01535 }
01536 
01537 void
01538 gnc_split_reg_style_journal_cb (GtkWidget *w, gpointer data)
01539 {
01540     GNCSplitReg *gsr = data;
01541 
01542     if (!GTK_CHECK_MENU_ITEM(w)->active)
01543         return;
01544 
01545     gnc_split_reg_change_style (gsr, REG_STYLE_JOURNAL);
01546 }
01547 
01548 void
01549 gnc_split_reg_double_line_cb (GtkWidget *w, gpointer data)
01550 {
01551     GNCSplitReg *gsr = data;
01552     SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
01553     gboolean use_double_line;
01554 
01555     use_double_line = GTK_CHECK_MENU_ITEM(w)->active;
01556     if ( use_double_line == reg->use_double_line )
01557         return;
01558 
01559     gnc_split_register_config( reg, reg->type, reg->style, use_double_line );
01560     gnc_ledger_display_refresh( gsr->ledger );
01561 }
01562 
01563 static void
01564 gnc_split_reg_sort( GNCSplitReg *gsr, SortType sort_code )
01565 {
01566     Query *query = gnc_ledger_display_get_query( gsr->ledger );
01567     gboolean show_present_divider = FALSE;
01568     GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
01569     SplitRegister *reg;
01570 
01571     if (gsr->sort_type == sort_code)
01572         return;
01573 
01574     standard = g_slist_prepend( NULL, QUERY_DEFAULT_SORT );
01575 
01576     switch (sort_code)
01577     {
01578     case BY_STANDARD:
01579         p1 = standard;
01580         show_present_divider = TRUE;
01581         break;
01582     case BY_DATE:
01583         p1 = g_slist_prepend (p1, TRANS_DATE_POSTED);
01584         p1 = g_slist_prepend (p1, SPLIT_TRANS);
01585         p2 = standard;
01586         show_present_divider = TRUE;
01587         break;
01588     case BY_DATE_ENTERED:
01589         p1 = g_slist_prepend (p1, TRANS_DATE_ENTERED);
01590         p1 = g_slist_prepend (p1, SPLIT_TRANS);
01591         p2 = standard;
01592         break;
01593     case BY_DATE_RECONCILED:
01594         p1 = g_slist_prepend (p1, SPLIT_RECONCILE);
01595         p2 = g_slist_prepend (p2, SPLIT_DATE_RECONCILED);
01596         p3 = standard;
01597         break;
01598     case BY_NUM:
01599         p1 = g_slist_prepend (p1, TRANS_NUM);
01600         p1 = g_slist_prepend (p1, SPLIT_TRANS);
01601         p2 = standard;
01602         break;
01603     case BY_AMOUNT:
01604         p1 = g_slist_prepend (p1, SPLIT_VALUE);
01605         p2 = standard;
01606         break;
01607     case BY_MEMO:
01608         p1 = g_slist_prepend (p1, SPLIT_MEMO);
01609         p2 = standard;
01610         break;
01611     case BY_DESC:
01612         p1 = g_slist_prepend (p1, TRANS_DESCRIPTION);
01613         p1 = g_slist_prepend (p1, SPLIT_TRANS);
01614         p2 = standard;
01615         break;
01616     case BY_ACTION:
01617         p1 = g_slist_prepend (p1, SPLIT_ACTION);
01618         p2 = standard;
01619         break;
01620     case BY_NOTES:
01621         p1 = g_slist_prepend (p1, TRANS_NOTES);
01622         p1 = g_slist_prepend (p1, SPLIT_TRANS);
01623         p2 = standard;
01624         break;
01625     default:
01626         g_slist_free (standard);
01627         g_return_if_fail (FALSE);
01628     }
01629 
01630     qof_query_set_sort_order( query, p1, p2, p3 );
01631     reg = gnc_ledger_display_get_split_register( gsr->ledger );
01632     gnc_split_register_show_present_divider( reg, show_present_divider );
01633     gsr->sort_type = sort_code;
01634     gnc_ledger_display_refresh( gsr->ledger );
01635 }
01636 
01637 void
01638 gnc_split_reg_sort_standard_cb(GtkWidget *w, gpointer data)
01639 {
01640     GNCSplitReg *gsr = data;
01641     gnc_split_reg_sort(gsr, BY_STANDARD);
01642 }
01643 
01644 void
01645 gnc_split_reg_sort_date_cb(GtkWidget *w, gpointer data)
01646 {
01647     GNCSplitReg *gsr = data;
01648     gnc_split_reg_sort(gsr, BY_DATE);
01649 }
01650 
01651 void
01652 gnc_split_reg_sort_date_entered_cb(GtkWidget *w, gpointer data)
01653 {
01654     GNCSplitReg *gsr = data;
01655     gnc_split_reg_sort(gsr, BY_DATE_ENTERED);
01656 }
01657 
01658 void
01659 gnc_split_reg_sort_date_reconciled_cb(GtkWidget *w, gpointer data)
01660 {
01661     GNCSplitReg *gsr = data;
01662     gnc_split_reg_sort(gsr, BY_DATE_RECONCILED);
01663 }
01664 
01665 void
01666 gnc_split_reg_sort_num_cb(GtkWidget *w, gpointer data)
01667 {
01668     GNCSplitReg *gsr = data;
01669     gnc_split_reg_sort(gsr, BY_NUM);
01670 }
01671 
01672 void
01673 gnc_split_reg_sort_amount_cb(GtkWidget *w, gpointer data)
01674 {
01675     GNCSplitReg *gsr = data;
01676     gnc_split_reg_sort(gsr, BY_AMOUNT);
01677 }
01678 
01679 void
01680 gnc_split_reg_sort_memo_cb(GtkWidget *w, gpointer data)
01681 {
01682     GNCSplitReg *gsr = data;
01683     gnc_split_reg_sort(gsr, BY_MEMO);
01684 }
01685 
01686 void
01687 gnc_split_reg_sort_desc_cb(GtkWidget *w, gpointer data)
01688 {
01689     GNCSplitReg *gsr = data;
01690     gnc_split_reg_sort(gsr, BY_DESC);
01691 }
01692 
01693 void
01694 gnc_split_reg_sort_action_cb(GtkWidget *w, gpointer data)
01695 {
01696     GNCSplitReg *gsr = data;
01697     gnc_split_reg_sort(gsr, BY_ACTION);
01698 }
01699 
01700 void
01701 gnc_split_reg_sort_notes_cb(GtkWidget *w, gpointer data)
01702 {
01703     GNCSplitReg *gsr = data;
01704     gnc_split_reg_sort(gsr, BY_NOTES);
01705 }
01706 
01707 void
01708 gnc_split_reg_handle_exchange_cb (GtkWidget *w, gpointer data)
01709 {
01710     GNCSplitReg *gsr = data;
01711     SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
01712 
01713     /* XXX Ignore the return value -- we don't care if this succeeds */
01714     (void)gnc_split_register_handle_exchange (reg, TRUE);
01715 }
01716 
01717 static void
01718 gnc_split_reg_record (GNCSplitReg *gsr)
01719 {
01720     SplitRegister *reg;
01721     Transaction *trans;
01722 
01723     ENTER("gsr=%p", gsr);
01724 
01725     reg = gnc_ledger_display_get_split_register (gsr->ledger);
01726     trans = gnc_split_register_get_current_trans (reg);
01727 
01728     if (!gnc_split_register_save (reg, TRUE))
01729     {
01730         LEAVE("no save");
01731         return;
01732     }
01733 
01734     gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
01735 
01736     /* Explicit redraw shouldn't be needed,
01737      * since gui_refresh events should handle this. */
01738     /* gnc_split_register_redraw (reg); */
01739     LEAVE(" ");
01740 }
01741 
01742 static gboolean
01743 gnc_split_reg_match_trans_row( VirtualLocation virt_loc,
01744                                gpointer user_data )
01745 {
01746     GNCSplitReg *gsr = user_data;
01747     CursorClass cursor_class;
01748     SplitRegister *sr;
01749 
01750     sr = gnc_ledger_display_get_split_register (gsr->ledger);
01751     cursor_class = gnc_split_register_get_cursor_class (sr, virt_loc.vcell_loc);
01752 
01753     return (cursor_class == CURSOR_CLASS_TRANS);
01754 }
01755 
01756 static void
01757 gnc_split_reg_goto_next_trans_row (GNCSplitReg *gsr)
01758 {
01759     ENTER("gsr=%p", gsr);
01760     gnucash_register_goto_next_matching_row( gsr->reg,
01761             gnc_split_reg_match_trans_row,
01762             gsr );
01763     LEAVE(" ");
01764 }
01765 
01766 void
01767 gnc_split_reg_enter( GNCSplitReg *gsr, gboolean next_transaction )
01768 {
01769     SplitRegister *sr = gnc_ledger_display_get_split_register( gsr->ledger );
01770     gboolean goto_blank;
01771 
01772     ENTER("gsr=%p, next_transaction=%s", gsr, next_transaction ? "TRUE" : "FALSE");
01773 
01774     goto_blank = gnc_gconf_get_bool(GCONF_GENERAL_REGISTER,
01775                                     "enter_moves_to_end", NULL);
01776 
01777     /* If we are in single or double line mode and we hit enter
01778      * on the blank split, go to the blank split instead of the
01779      * next row. This prevents the cursor from jumping around
01780      * when you are entering transactions. */
01781     if ( !goto_blank && !next_transaction )
01782     {
01783         SplitRegisterStyle style = sr->style;
01784 
01785         if (style == REG_STYLE_LEDGER)
01786         {
01787             Split *blank_split;
01788 
01789             blank_split = gnc_split_register_get_blank_split(sr);
01790             if (blank_split != NULL)
01791             {
01792                 Split *current_split;
01793 
01794                 current_split = gnc_split_register_get_current_split(sr);
01795 
01796                 if (blank_split == current_split)
01797                     goto_blank = TRUE;
01798             }
01799         }
01800     }
01801 
01802     /* First record the transaction. This will perform a refresh. */
01803     gnc_split_reg_record( gsr );
01804 
01805     if (!goto_blank && next_transaction)
01806         gnc_split_register_expand_current_trans (sr, FALSE);
01807 
01808     /* Now move. */
01809     if (goto_blank)
01810         gnc_split_reg_jump_to_blank( gsr );
01811     else if (next_transaction)
01812         gnc_split_reg_goto_next_trans_row( gsr );
01813     else
01814         gnucash_register_goto_next_virt_row( gsr->reg );
01815     LEAVE(" ");
01816 }
01817 
01818 void
01819 gsr_default_enter_handler( GNCSplitReg *gsr, gpointer data )
01820 {
01821     gnc_split_reg_enter( gsr, FALSE );
01822 }
01823 
01824 void
01825 gnc_split_reg_record_cb (GnucashRegister *reg, gpointer data)
01826 {
01827     gsr_emit_simple_signal( (GNCSplitReg*)data, "enter_ent" );
01828 }
01829 
01830 void
01831 gnc_split_reg_size_allocate (GtkWidget *widget,
01832                              GtkAllocation *allocation,
01833                              gpointer user_data)
01834 {
01835     GNCSplitReg *gsr = user_data;
01836     gsr->width = allocation->width;
01837     gtk_window_set_default_size( GTK_WINDOW(gsr->window), gsr->width, 0 );
01838 }
01839 
01840 static
01841 GtkWidget*
01842 add_summary_label (GtkWidget *summarybar, const char *label_str)
01843 {
01844     GtkWidget *hbox;
01845     GtkWidget *label;
01846 
01847     hbox = gtk_hbox_new(FALSE, 2);
01848     gtk_box_pack_start( GTK_BOX(summarybar), hbox, FALSE, FALSE, 5 );
01849 
01850     label = gtk_label_new( label_str );
01851     gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
01852     gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, FALSE, 0 );
01853 
01854     label = gtk_label_new( "" );
01855     gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
01856     gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, FALSE, 0 );
01857 
01858     return label;
01859 }
01860 
01861 GtkWidget *
01862 gsr_create_summary_bar( GNCSplitReg *gsr )
01863 {
01864     GtkWidget *summarybar;
01865 
01866     gsr->cleared_label    = NULL;
01867     gsr->balance_label    = NULL;
01868     gsr->reconciled_label = NULL;
01869     gsr->future_label     = NULL;
01870     gsr->projectedminimum_label  = NULL;
01871     gsr->shares_label     = NULL;
01872     gsr->value_label      = NULL;
01873 
01874     if ( gnc_ledger_display_type(gsr->ledger) >= LD_SUBACCOUNT )
01875     {
01876         gsr->summarybar = NULL;
01877         return NULL;
01878     }
01879 
01880     summarybar = gtk_hbox_new (FALSE, 4);
01881 
01882     if (!xaccAccountIsPriced(gnc_ledger_display_leader(gsr->ledger)))
01883     {
01884         gsr->balance_label    = add_summary_label (summarybar, _("Present:"));
01885         gsr->future_label     = add_summary_label (summarybar, _("Future:"));
01886         gsr->cleared_label    = add_summary_label (summarybar, _("Cleared:"));
01887         gsr->reconciled_label = add_summary_label (summarybar, _("Reconciled:"));
01888         gsr->projectedminimum_label  = add_summary_label (summarybar, _("Projected Minimum:"));
01889     }
01890     else
01891     {
01892         gsr->shares_label     = add_summary_label (summarybar, _("Shares:"));
01893         gsr->value_label      = add_summary_label (summarybar, _("Current Value:"));
01894     }
01895 
01896     gsr->summarybar = summarybar;
01897 
01898     /* Force the first update */
01899     gsr_redraw_all_cb(NULL, gsr);
01900     return gsr->summarybar;
01901 }
01902 
01909 static
01910 GNCPlaceholderType
01911 gnc_split_reg_get_placeholder( GNCSplitReg *gsr )
01912 {
01913     Account *leader;
01914     SplitRegister *reg;
01915     gboolean single_account;
01916 
01917     if (gsr == NULL)
01918         return PLACEHOLDER_NONE;
01919 
01920     reg = gnc_ledger_display_get_split_register( gsr->ledger );
01921 
01922     switch (reg->type)
01923     {
01924     case GENERAL_LEDGER:
01925     case INCOME_LEDGER:
01926     case PORTFOLIO_LEDGER:
01927     case SEARCH_LEDGER:
01928         single_account = FALSE;
01929         break;
01930     default:
01931         single_account = TRUE;
01932         break;
01933     }
01934 
01935     leader = gnc_ledger_display_leader( gsr->ledger );
01936 
01937     if (leader == NULL)
01938         return PLACEHOLDER_NONE;
01939     if (single_account)
01940     {
01941         if (xaccAccountGetPlaceholder( leader ))
01942             return PLACEHOLDER_THIS;
01943         return PLACEHOLDER_NONE;
01944     }
01945     return xaccAccountGetDescendantPlaceholder( leader );
01946 }
01947 
01951 typedef struct dialog_args
01952 {
01953     GNCSplitReg *gsr;
01954     gchar *string;
01955 } dialog_args;
01956 
01962 static
01963 gboolean
01964 gtk_callback_bug_workaround (gpointer argp)
01965 {
01966     dialog_args *args = argp;
01967     const gchar *read_only = _("This account register is read-only.");
01968     GtkWidget *dialog;
01969 
01970     dialog = gtk_message_dialog_new(GTK_WINDOW(args->gsr->window),
01971                                     GTK_DIALOG_DESTROY_WITH_PARENT,
01972                                     GTK_MESSAGE_WARNING,
01973                                     GTK_BUTTONS_CLOSE,
01974                                     "%s", read_only);
01975     gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
01976             "%s", args->string);
01977     gnc_dialog_run(GTK_DIALOG(dialog), "register_read_only");
01978     gtk_widget_destroy(dialog);
01979     g_free(args);
01980     return FALSE;
01981 }
01982 
01986 static
01987 void
01988 gnc_split_reg_determine_read_only( GNCSplitReg *gsr )
01989 {
01990     dialog_args *args = g_malloc(sizeof(dialog_args));
01991     SplitRegister *reg;
01992 
01993     if (qof_book_is_readonly(gnc_get_current_book()))
01994     {
01995         /* Is the book read-only? Then for sure also make this register
01996         read-only. */
01997         gsr->read_only = TRUE;
01998     }
01999 
02000     if ( !gsr->read_only )
02001     {
02002 
02003         switch (gnc_split_reg_get_placeholder(gsr))
02004         {
02005         case PLACEHOLDER_NONE:
02006             /* stay as false. */
02007             return;
02008 
02009         case PLACEHOLDER_THIS:
02010             args->string = _("This account may not be edited.  If you want "
02011                              "to edit transactions in this register, please "
02012                              "open the account options and turn off the "
02013                              "placeholder checkbox.");
02014             break;
02015 
02016         default:
02017             args->string = _("One of the sub-accounts selected may not be "
02018                              "edited.  If you want to edit transactions in "
02019                              "this register, please open the sub-account "
02020                              "options and turn off the placeholder checkbox. "
02021                              "You may also open an individual account instead "
02022                              "of a set of accounts.");
02023             break;
02024         }
02025         gsr->read_only = TRUE;
02026         /* Put up a warning dialog */
02027         args->gsr = gsr;
02028         g_timeout_add (250, gtk_callback_bug_workaround, args); /* 0.25 seconds */
02029     }
02030 
02031     /* Make the contents immutable */
02032     reg = gnc_ledger_display_get_split_register( gsr->ledger );
02033     gnc_split_register_set_read_only( reg, TRUE );
02034 
02035 }
02036 
02037 static
02038 GtkWidget *
02039 gnc_split_reg_get_parent( GNCLedgerDisplay *ledger )
02040 {
02041     GNCSplitReg *gsr =
02042         GNC_SPLIT_REG(gnc_ledger_display_get_user_data( ledger ));
02043 
02044     if (gsr == NULL)
02045         return NULL;
02046 
02047     return gsr->window;
02048 }
02049 
02050 static
02051 void
02052 gsr_emit_help_changed( GnucashRegister *reg, gpointer user_data )
02053 {
02054     gsr_emit_simple_signal( (GNCSplitReg*)user_data, "help-changed" );
02055 }
02056 
02057 static
02058 void
02059 gsr_emit_include_date_signal( GNCSplitReg *gsr, time_t date )
02060 {
02061     g_signal_emit_by_name( gsr, "include-date", date, NULL );
02062 }
02063 
02064 static
02065 void
02066 gsr_emit_simple_signal( GNCSplitReg *gsr, const char *sigName )
02067 {
02068     g_signal_emit_by_name( gsr, sigName, NULL );
02069 }
02070 
02071 GnucashRegister*
02072 gnc_split_reg_get_register( GNCSplitReg *gsr )
02073 {
02074     if ( !gsr )
02075         return NULL;
02076 
02077     return gsr->reg;
02078 }
02079 
02080 SortType
02081 gnc_split_reg_get_sort_type( GNCSplitReg *gsr )
02082 {
02083     g_assert( gsr );
02084     return gsr->sort_type;
02085 }
02086 
02087 void
02088 gnc_split_reg_set_sort_type( GNCSplitReg *gsr, SortType t )
02089 {
02090     gnc_split_reg_sort( gsr, t );
02091 }
02092 
02093 GtkWidget*
02094 gnc_split_reg_get_summarybar( GNCSplitReg *gsr )
02095 {
02096     if ( !gsr ) return NULL;
02097     return gsr->summarybar;
02098 }
02099 
02100 gboolean
02101 gnc_split_reg_get_read_only( GNCSplitReg *gsr )
02102 {
02103     g_assert( gsr );
02104     return gsr->read_only;
02105 }
02106 
02107 void
02108 gnc_split_reg_set_moved_cb( GNCSplitReg *gsr, GFunc cb, gpointer cb_data )
02109 {
02110     gnucash_register_set_moved_cb (gsr->reg, cb, cb_data);
02111 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines