GnuCash 2.4.99
split-register.c
00001 /********************************************************************\
00002  * This program is free software; you can redistribute it and/or    *
00003  * modify it under the terms of the GNU General Public License as   *
00004  * published by the Free Software Foundation; either version 2 of   *
00005  * the License, or (at your option) any later version.              *
00006  *                                                                  *
00007  * This program is distributed in the hope that it will be useful,  *
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00010  * GNU General Public License for more details.                     *
00011  *                                                                  *
00012  * You should have received a copy of the GNU General Public License*
00013  * along with this program; if not, contact:                        *
00014  *                                                                  *
00015  * Free Software Foundation           Voice:  +1-617-542-5942       *
00016  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00017  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00018  *                                                                  *
00019 \********************************************************************/
00020 /*
00021  * split-register.c
00022  * author Copyright (c) 1998-2000 Linas Vepstas <linas@linas.org>
00023  * author Copyright (c) 2000-2001 Dave Peticolas <dave@krondo.com>
00024  */
00025 #include "config.h"
00026 
00027 #include <glib.h>
00028 #include <glib/gi18n.h>
00029 #include <libguile.h>
00030 
00031 #include "combocell.h"
00032 #include "datecell.h"
00033 #include "dialog-utils.h"
00034 #include "gnc-component-manager.h"
00035 #include "gnc-gconf-utils.h"
00036 #include "split-register-p.h"
00037 #include "gnc-ledger-display.h"
00038 #include "gnc-ui.h"
00039 #include "guile-util.h"
00040 #include "numcell.h"
00041 #include "pricecell.h"
00042 #include "quickfillcell.h"
00043 #include "recncell.h"
00044 #include "split-register.h"
00045 #include "split-register-control.h"
00046 #include "split-register-layout.h"
00047 #include "split-register-model.h"
00048 #include "split-register-model-save.h"
00049 #include "table-allgui.h"
00050 #include "dialog-account.h"
00051 #include "dialog-dup-trans.h"
00052 
00053 
00056 /* This static indicates the debugging module that this .o belongs to. */
00057 static QofLogModule log_module = GNC_MOD_LEDGER;
00058 
00059 /* The copied split or transaction, if any */
00060 static CursorClass copied_class = CURSOR_CLASS_NONE;
00061 static SCM copied_item = SCM_UNDEFINED;
00062 static GncGUID copied_leader_guid;
00063 
00064 
00067 static gboolean gnc_split_register_save_to_scm (SplitRegister *reg,
00068         SCM trans_scm, SCM split_scm,
00069         gboolean use_cut_semantics);
00070 static gboolean gnc_split_register_auto_calc (SplitRegister *reg,
00071         Split *split);
00072 
00073 
00076 /* Uses the scheme split copying routines */
00077 static void
00078 gnc_copy_split_onto_split(Split *from, Split *to, gboolean use_cut_semantics)
00079 {
00080     SCM split_scm;
00081 
00082     if ((from == NULL) || (to == NULL))
00083         return;
00084 
00085     split_scm = gnc_copy_split(from, use_cut_semantics);
00086     if (split_scm == SCM_UNDEFINED)
00087         return;
00088 
00089     gnc_copy_split_scm_onto_split(split_scm, to, gnc_get_current_book ());
00090 }
00091 
00092 /* Uses the scheme transaction copying routines */
00093 void
00094 gnc_copy_trans_onto_trans(Transaction *from, Transaction *to,
00095                           gboolean use_cut_semantics,
00096                           gboolean do_commit)
00097 {
00098     SCM trans_scm;
00099 
00100     if ((from == NULL) || (to == NULL))
00101         return;
00102 
00103     trans_scm = gnc_copy_trans(from, use_cut_semantics);
00104     if (trans_scm == SCM_UNDEFINED)
00105         return;
00106 
00107     gnc_copy_trans_scm_onto_trans(trans_scm, to, do_commit,
00108                                   gnc_get_current_book ());
00109 }
00110 
00111 static int
00112 gnc_split_get_value_denom (Split *split)
00113 {
00114     gnc_commodity *currency;
00115     int denom;
00116 
00117     currency = xaccTransGetCurrency (xaccSplitGetParent (split));
00118     denom = gnc_commodity_get_fraction (currency);
00119     if (denom == 0)
00120     {
00121         gnc_commodity *commodity = gnc_default_currency ();
00122         denom = gnc_commodity_get_fraction (commodity);
00123         if (denom == 0)
00124             denom = 100;
00125     }
00126 
00127     return denom;
00128 }
00129 
00130 static int
00131 gnc_split_get_amount_denom (Split *split)
00132 {
00133     int denom;
00134 
00135     denom = xaccAccountGetCommoditySCU (xaccSplitGetAccount (split));
00136     if (denom == 0)
00137     {
00138         gnc_commodity *commodity = gnc_default_currency ();
00139         denom = gnc_commodity_get_fraction (commodity);
00140         if (denom == 0)
00141             denom = 100;
00142     }
00143 
00144     return denom;
00145 }
00146 
00147 /* returns TRUE if begin_edit was aborted */
00148 gboolean
00149 gnc_split_register_begin_edit_or_warn(SRInfo *info, Transaction *trans)
00150 {
00151     ENTER("info=%p, trans=%p", info, trans);
00152 
00153     if (!xaccTransIsOpen(trans))
00154     {
00155         xaccTransBeginEdit(trans);
00156         /* This is now the pending transaction */
00157         info->pending_trans_guid = *xaccTransGetGUID(trans);
00158         LEAVE("opened and marked pending");
00159         return FALSE;
00160     }
00161     else
00162     {
00163         Split       *blank_split = xaccSplitLookup (&info->blank_split_guid,
00164                                    gnc_get_current_book ());
00165         Transaction *blank_trans = xaccSplitGetParent (blank_split);
00166 
00167         if (trans == blank_trans)
00168         {
00169             /* This is a brand-new transaction. It is already
00170              * open, so just mark it as pending. */
00171             info->pending_trans_guid = *xaccTransGetGUID(trans);
00172             LEAVE("already open, now pending.");
00173             return FALSE;
00174         }
00175         else
00176         {
00177             GtkWidget *parent = NULL;
00178             if (info->get_parent)
00179                 parent = info->get_parent(info->user_data);
00180             gnc_error_dialog(parent, "%s", _("This transaction is already being edited in another register. Please finish editing it there first."));
00181             LEAVE("already editing");
00182             return TRUE;
00183         }
00184     }
00185     LEAVE(" ");
00186 }
00187 
00188 void
00189 gnc_split_register_expand_current_trans (SplitRegister *reg, gboolean expand)
00190 {
00191     SRInfo *info = gnc_split_register_get_info (reg);
00192     VirtualLocation virt_loc;
00193 
00194     if (!reg)
00195         return;
00196 
00197     if (reg->style == REG_STYLE_AUTO_LEDGER ||
00198             reg->style == REG_STYLE_JOURNAL)
00199         return;
00200 
00201     /* ok, so I just wanted an excuse to use exclusive-or */
00202     if (!(expand ^ info->trans_expanded))
00203         return;
00204 
00205     if (!expand)
00206     {
00207         virt_loc = reg->table->current_cursor_loc;
00208         gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
00209                                             &virt_loc.vcell_loc);
00210 
00211         if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
00212             gnc_table_move_cursor_gui (reg->table, virt_loc);
00213         else
00214         {
00215             PERR ("Can't find place to go!");
00216             return;
00217         }
00218     }
00219 
00220     info->trans_expanded = expand;
00221 
00222     gnc_table_set_virt_cell_cursor (reg->table,
00223                                     reg->table->current_cursor_loc.vcell_loc,
00224                                     gnc_split_register_get_active_cursor (reg));
00225 
00226     gnc_split_register_set_trans_visible(
00227         reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
00228 
00229     virt_loc = reg->table->current_cursor_loc;
00230     if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
00231     {
00232         if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
00233             gnc_table_move_cursor_gui (reg->table, virt_loc);
00234         else
00235         {
00236             PERR ("Can't find place to go!");
00237             return;
00238         }
00239     }
00240 
00241     gnc_table_refresh_gui (reg->table, TRUE);
00242 
00243     if (expand)
00244         gnc_split_register_show_trans (reg,
00245                                        reg->table->current_cursor_loc.vcell_loc);
00246 }
00247 
00248 gboolean
00249 gnc_split_register_current_trans_expanded (SplitRegister *reg)
00250 {
00251     SRInfo *info = gnc_split_register_get_info (reg);
00252 
00253     if (!reg)
00254         return FALSE;
00255 
00256     if (reg->style == REG_STYLE_AUTO_LEDGER ||
00257             reg->style == REG_STYLE_JOURNAL)
00258         return TRUE;
00259 
00260     return info->trans_expanded;
00261 }
00262 
00263 Transaction *
00264 gnc_split_register_get_current_trans (SplitRegister *reg)
00265 {
00266     Split *split;
00267     VirtualCellLocation vcell_loc;
00268 
00269     if (reg == NULL)
00270         return NULL;
00271 
00272     split = gnc_split_register_get_current_split (reg);
00273     if (split != NULL)
00274         return xaccSplitGetParent(split);
00275 
00276     /* Split is blank. Assume it is the blank split of a multi-line
00277      * transaction. Go back one row to find a split in the transaction. */
00278     vcell_loc = reg->table->current_cursor_loc.vcell_loc;
00279 
00280     vcell_loc.virt_row--;
00281 
00282     split = gnc_split_register_get_split (reg, vcell_loc);
00283 
00284     return xaccSplitGetParent (split);
00285 }
00286 
00287 Split *
00288 gnc_split_register_get_current_split (SplitRegister *reg)
00289 {
00290     if (reg == NULL)
00291         return NULL;
00292 
00293     return gnc_split_register_get_split(
00294                reg, reg->table->current_cursor_loc.vcell_loc);
00295 }
00296 
00297 Split *
00298 gnc_split_register_get_blank_split (SplitRegister *reg)
00299 {
00300     SRInfo *info = gnc_split_register_get_info (reg);
00301 
00302     if (!reg) return NULL;
00303 
00304     return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
00305 }
00306 
00307 gboolean
00308 gnc_split_register_get_split_virt_loc (SplitRegister *reg, Split *split,
00309                                        VirtualCellLocation *vcell_loc)
00310 {
00311     Table *table;
00312     int v_row;
00313     int v_col;
00314 
00315     if (!reg || !split) return FALSE;
00316 
00317     table = reg->table;
00318 
00319     /* go backwards because typically you search for splits at the end
00320      * and because we find split rows before transaction rows. */
00321 
00322     for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
00323         for (v_col = 0; v_col < table->num_virt_cols; v_col++)
00324         {
00325             VirtualCellLocation vc_loc = { v_row, v_col };
00326             VirtualCell *vcell;
00327             Split *s;
00328 
00329             vcell = gnc_table_get_virtual_cell (table, vc_loc);
00330             if (!vcell || !vcell->visible)
00331                 continue;
00332 
00333             s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
00334 
00335             if (s == split)
00336             {
00337                 if (vcell_loc)
00338                     *vcell_loc = vc_loc;
00339 
00340                 return TRUE;
00341             }
00342         }
00343 
00344     return FALSE;
00345 }
00346 
00347 gboolean
00348 gnc_split_register_get_split_amount_virt_loc (SplitRegister *reg, Split *split,
00349         VirtualLocation *virt_loc)
00350 {
00351     VirtualLocation v_loc;
00352     CursorClass cursor_class;
00353     const char *cell_name;
00354     gnc_numeric value;
00355 
00356     if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
00357         return FALSE;
00358 
00359     cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
00360 
00361     value = xaccSplitGetValue (split);
00362 
00363     switch (cursor_class)
00364     {
00365     case CURSOR_CLASS_SPLIT:
00366     case CURSOR_CLASS_TRANS:
00367         cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
00368         break;
00369     default:
00370         return FALSE;
00371     }
00372 
00373     if (!gnc_table_get_cell_location (reg->table, cell_name,
00374                                       v_loc.vcell_loc, &v_loc))
00375         return FALSE;
00376 
00377     if (virt_loc == NULL)
00378         return TRUE;
00379 
00380     *virt_loc = v_loc;
00381 
00382     return TRUE;
00383 }
00384 
00385 Split *
00386 gnc_split_register_duplicate_current (SplitRegister *reg)
00387 {
00388     SRInfo *info = gnc_split_register_get_info(reg);
00389     CursorClass cursor_class;
00390     Transaction *trans;
00391     Split *return_split;
00392     Split *trans_split;
00393     Split *blank_split;
00394     gboolean changed;
00395     Split *split;
00396 
00397     ENTER("reg=%p", reg);
00398 
00399     blank_split = xaccSplitLookup(&info->blank_split_guid,
00400                                   gnc_get_current_book ());
00401     split = gnc_split_register_get_current_split (reg);
00402     trans = gnc_split_register_get_current_trans (reg);
00403     trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
00404 
00405     /* This shouldn't happen, but be paranoid. */
00406     if (trans == NULL)
00407     {
00408         LEAVE("no transaction");
00409         return NULL;
00410     }
00411 
00412     cursor_class = gnc_split_register_get_current_cursor_class (reg);
00413 
00414     /* Can't do anything with this. */
00415     if (cursor_class == CURSOR_CLASS_NONE)
00416     {
00417         LEAVE("no cursor class");
00418         return NULL;
00419     }
00420 
00421     /* This shouldn't happen, but be paranoid. */
00422     if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
00423     {
00424         LEAVE("no split with transaction class");
00425         return NULL;
00426     }
00427 
00428     changed = gnc_table_current_cursor_changed (reg->table, FALSE);
00429 
00430     /* See if we were asked to duplicate an unchanged blank split.
00431      * There's no point in doing that! */
00432     if (!changed && ((split == NULL) || (split == blank_split)))
00433     {
00434         LEAVE("skip unchanged blank split");
00435         return NULL;
00436     }
00437 
00438     gnc_suspend_gui_refresh ();
00439 
00440     /* If the cursor has been edited, we are going to have to commit
00441      * it before we can duplicate. Make sure the user wants to do that. */
00442     if (changed)
00443     {
00444         GtkWidget *dialog, *window;
00445         gint response;
00446         const char *title = _("Save transaction before duplicating?");
00447         const char *message =
00448             _("The current transaction has been changed. Would you like to "
00449               "record the changes before duplicating the transaction, or "
00450               "cancel the duplication?");
00451 
00452         window = gnc_split_register_get_parent(reg);
00453         dialog = gtk_message_dialog_new(GTK_WINDOW(window),
00454                                         GTK_DIALOG_DESTROY_WITH_PARENT,
00455                                         GTK_MESSAGE_QUESTION,
00456                                         GTK_BUTTONS_CANCEL,
00457                                         "%s", title);
00458         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
00459                 "%s", message);
00460         gtk_dialog_add_button(GTK_DIALOG(dialog),
00461                               _("_Record"), GTK_RESPONSE_ACCEPT);
00462         response = gnc_dialog_run(GTK_DIALOG(dialog), "transaction_duplicated");
00463         gtk_widget_destroy(dialog);
00464 
00465         if (response != GTK_RESPONSE_ACCEPT)
00466         {
00467             gnc_resume_gui_refresh ();
00468             LEAVE("save cancelled");
00469             return NULL;
00470         }
00471 
00472         gnc_split_register_save (reg, TRUE);
00473 
00474         /* If the split is NULL, then we were on a blank split row
00475          * in an expanded transaction. The new split (created by
00476          * gnc_split_register_save above) will be the last split in the
00477          * current transaction, as it was just added. */
00478         if (split == NULL)
00479             split = xaccTransGetSplit (trans, xaccTransCountSplits (trans) - 1);
00480     }
00481 
00482     /* Ok, we are now ready to make the copy. */
00483 
00484     if (cursor_class == CURSOR_CLASS_SPLIT)
00485     {
00486         Split *new_split;
00487 
00488         /* We are on a split in an expanded transaction.
00489          * Just copy the split and add it to the transaction. */
00490 
00491         new_split = xaccMallocSplit (gnc_get_current_book ());
00492 
00493         xaccTransBeginEdit (trans);
00494         xaccSplitSetParent (new_split, trans);
00495         gnc_copy_split_onto_split (split, new_split, FALSE);
00496         xaccTransCommitEdit (trans);
00497 
00498         return_split = new_split;
00499 
00500         info->cursor_hint_split = new_split;
00501         info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
00502     }
00503     else
00504     {
00505         NumCell *num_cell;
00506         Transaction *new_trans;
00507         int trans_split_index;
00508         int split_index;
00509         const char *in_num = NULL;
00510         char *out_num;
00511         time_t date;
00512         gboolean use_autoreadonly = qof_book_uses_autoreadonly(gnc_get_current_book());
00513 
00514         /* We are on a transaction row. Copy the whole transaction. */
00515 
00516         date = info->last_date_entered;
00517         if (gnc_strisnum (xaccTransGetNum (trans)))
00518         {
00519             Account *account = gnc_split_register_get_default_account (reg);
00520 
00521             if (account)
00522                 in_num = xaccAccountGetLastNum (account);
00523             else
00524                 in_num = xaccTransGetNum (trans);
00525         }
00526 
00527         if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg),
00528                                    &date, in_num, &out_num))
00529         {
00530             gnc_resume_gui_refresh ();
00531             LEAVE("dup cancelled");
00532             return NULL;
00533         }
00534 
00535         if (use_autoreadonly)
00536         {
00537             GDate d;
00538             GDate *readonly_threshold = qof_book_get_autoreadonly_gdate(gnc_get_current_book());
00539             g_date_set_time_t (&d, date);
00540             if (g_date_compare(&d, readonly_threshold) < 0)
00541             {
00542                 GtkWidget *dialog = gtk_message_dialog_new(NULL,
00543                                     0,
00544                                     GTK_MESSAGE_ERROR,
00545                                     GTK_BUTTONS_OK,
00546                                     "%s", _("Cannot store a transaction at this date"));
00547                 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
00548                         "%s", _("The entered date of the duplicated transaction is older than the \"Read-Only Threshold\" set for this book.  "
00549                                 "This setting can be changed in File -> Properties -> Accounts."));
00550                 gtk_dialog_run(GTK_DIALOG(dialog));
00551                 gtk_widget_destroy(dialog);
00552 
00553                 g_date_free(readonly_threshold);
00554                 return NULL;
00555             }
00556             g_date_free(readonly_threshold);
00557         }
00558 
00559         split_index = xaccTransGetSplitIndex(trans, split);
00560         trans_split_index = xaccTransGetSplitIndex(trans, trans_split);
00561 
00562         /* we should *always* find the split, but be paranoid */
00563         if (split_index < 0)
00564         {
00565             gnc_resume_gui_refresh ();
00566             LEAVE("no split");
00567             return NULL;
00568         }
00569 
00570         new_trans = xaccMallocTransaction (gnc_get_current_book ());
00571 
00572         xaccTransBeginEdit (new_trans);
00573         gnc_copy_trans_onto_trans (trans, new_trans, FALSE, FALSE);
00574         xaccTransSetDatePostedSecs (new_trans, date);
00575         xaccTransSetNum (new_trans, out_num);
00576         xaccTransCommitEdit (new_trans);
00577 
00578         num_cell = (NumCell *) gnc_table_layout_get_cell (reg->table->layout,
00579                    NUM_CELL);
00580         if (gnc_num_cell_set_last_num (num_cell, out_num))
00581             gnc_split_register_set_last_num (reg, out_num);
00582 
00583         g_free (out_num);
00584 
00585         /* This shouldn't happen, but be paranoid. */
00586         if (split_index >= xaccTransCountSplits (new_trans))
00587             split_index = 0;
00588 
00589         return_split = xaccTransGetSplit (new_trans, split_index);
00590         trans_split = xaccTransGetSplit (new_trans, trans_split_index);
00591 
00592         info->cursor_hint_trans = new_trans;
00593         info->cursor_hint_split = return_split;
00594         info->cursor_hint_trans_split = trans_split;
00595         info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
00596 
00597         info->trans_expanded = FALSE;
00598     }
00599 
00600     /* Refresh the GUI. */
00601     gnc_resume_gui_refresh ();
00602 
00603     LEAVE(" ");
00604     return return_split;
00605 }
00606 
00607 static void
00608 gnc_split_register_copy_current_internal (SplitRegister *reg,
00609         gboolean use_cut_semantics)
00610 {
00611     SRInfo *info = gnc_split_register_get_info(reg);
00612     CursorClass cursor_class;
00613     Transaction *trans;
00614     Split *blank_split;
00615     gboolean changed;
00616     Split *split;
00617     SCM new_item;
00618 
00619     g_return_if_fail(reg);
00620     ENTER("reg=%p, use_cut_semantics=%s", reg,
00621           use_cut_semantics ? "TRUE" : "FALSE");
00622 
00623     blank_split = xaccSplitLookup(&info->blank_split_guid,
00624                                   gnc_get_current_book ());
00625     split = gnc_split_register_get_current_split (reg);
00626     trans = gnc_split_register_get_current_trans (reg);
00627 
00628     /* This shouldn't happen, but be paranoid. */
00629     if (trans == NULL)
00630     {
00631         LEAVE("no trans");
00632         return;
00633     }
00634 
00635     cursor_class = gnc_split_register_get_current_cursor_class (reg);
00636 
00637     /* Can't do anything with this. */
00638     if (cursor_class == CURSOR_CLASS_NONE)
00639     {
00640         LEAVE("no cursor class");
00641         return;
00642     }
00643 
00644     /* This shouldn't happen, but be paranoid. */
00645     if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
00646     {
00647         g_warning("BUG DETECTED: transaction cursor with no anchoring split!");
00648         LEAVE("transaction cursor with no anchoring split");
00649         return;
00650     }
00651 
00652     changed = gnc_table_current_cursor_changed (reg->table, FALSE);
00653 
00654     /* See if we were asked to copy an unchanged blank split. Don't. */
00655     if (!changed && ((split == NULL) || (split == blank_split)))
00656     {
00657         /* We're either on an unedited, brand-new split or an unedited, brand-new
00658          * transaction (the transaction anchored by the blank split.) */
00659         /* FIXME: This doesn't work exactly right. When entering a new transaction,
00660          *        you can edit the description, move to a split row, then move
00661          *        back to the description, then ask for a copy, and this code will
00662          *        be reached. It forgets that you changed the row the first time
00663          *        you were there.  -Charles */
00664         LEAVE("nothing to copy/cut");
00665         return;
00666     }
00667 
00668     /* Ok, we are now ready to make the copy. */
00669 
00670     if (cursor_class == CURSOR_CLASS_SPLIT)
00671     {
00672         /* We are on a split in an expanded transaction. Just copy the split. */
00673         new_item = gnc_copy_split(split, use_cut_semantics);
00674 
00675         if (new_item != SCM_UNDEFINED)
00676         {
00677             if (changed)
00678                 gnc_split_register_save_to_scm (reg, SCM_UNDEFINED, new_item,
00679                                                 use_cut_semantics);
00680 
00681             copied_leader_guid = *guid_null();
00682         }
00683     }
00684     else
00685     {
00686         /* We are on a transaction row. Copy the whole transaction. */
00687         new_item = gnc_copy_trans(trans, use_cut_semantics);
00688 
00689         if (new_item != SCM_UNDEFINED)
00690         {
00691             if (changed)
00692             {
00693                 int split_index;
00694                 SCM split_scm;
00695 
00696                 split_index = xaccTransGetSplitIndex(trans, split);
00697                 if (split_index >= 0)
00698                     split_scm = gnc_trans_scm_get_split_scm(new_item, split_index);
00699                 else
00700                     split_scm = SCM_UNDEFINED;
00701 
00702                 gnc_split_register_save_to_scm (reg, new_item, split_scm,
00703                                                 use_cut_semantics);
00704             }
00705 
00706             copied_leader_guid = info->default_account;
00707         }
00708     }
00709 
00710     if (new_item == SCM_UNDEFINED)
00711     {
00712         g_warning("BUG DETECTED: copy failed");
00713         LEAVE("copy failed");
00714         return;
00715     }
00716 
00717     /* unprotect the old object, if any */
00718     if (copied_item != SCM_UNDEFINED)
00719         scm_gc_unprotect_object(copied_item);
00720 
00721     copied_item = new_item;
00722     scm_gc_protect_object(copied_item);
00723 
00724     copied_class = cursor_class;
00725     LEAVE("%s %s", use_cut_semantics ? "cut" : "copied",
00726           cursor_class == CURSOR_CLASS_SPLIT ? "split" : "transaction");
00727 }
00728 
00729 void
00730 gnc_split_register_copy_current (SplitRegister *reg)
00731 {
00732     gnc_split_register_copy_current_internal (reg, FALSE);
00733 }
00734 
00735 void
00736 gnc_split_register_cut_current (SplitRegister *reg)
00737 {
00738     SRInfo *info = gnc_split_register_get_info (reg);
00739     CursorClass cursor_class;
00740     Transaction *trans;
00741     Split *blank_split;
00742     gboolean changed;
00743     Split *split;
00744 
00745     blank_split = xaccSplitLookup (&info->blank_split_guid,
00746                                    gnc_get_current_book ());
00747     split = gnc_split_register_get_current_split (reg);
00748     trans = gnc_split_register_get_current_trans (reg);
00749 
00750     /* This shouldn't happen, but be paranoid. */
00751     if (trans == NULL)
00752         return;
00753 
00754     cursor_class = gnc_split_register_get_current_cursor_class (reg);
00755 
00756     /* Can't do anything with this. */
00757     if (cursor_class == CURSOR_CLASS_NONE)
00758         return;
00759 
00760     /* This shouldn't happen, but be paranoid. */
00761     if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
00762         return;
00763 
00764     changed = gnc_table_current_cursor_changed (reg->table, FALSE);
00765 
00766     /* See if we were asked to cut an unchanged blank split. Don't. */
00767     if (!changed && ((split == NULL) || (split == blank_split)))
00768         return;
00769 
00770     gnc_split_register_copy_current_internal (reg, TRUE);
00771 
00772     if (cursor_class == CURSOR_CLASS_SPLIT)
00773         gnc_split_register_delete_current_split (reg);
00774     else
00775         gnc_split_register_delete_current_trans (reg);
00776 }
00777 
00778 void
00779 gnc_split_register_paste_current (SplitRegister *reg)
00780 {
00781     SRInfo *info = gnc_split_register_get_info(reg);
00782     CursorClass cursor_class;
00783     Transaction *trans;
00784     Transaction *blank_trans;
00785     Split *blank_split;
00786     Split *trans_split;
00787     Split *split;
00788 
00789     ENTER("reg=%p", reg);
00790 
00791     if (copied_class == CURSOR_CLASS_NONE)
00792     {
00793         LEAVE("no copied cursor class");
00794         return;
00795     }
00796 
00797     blank_split = xaccSplitLookup (&info->blank_split_guid,
00798                                    gnc_get_current_book ());
00799     blank_trans = xaccSplitGetParent (blank_split);
00800     split = gnc_split_register_get_current_split (reg);
00801     trans = gnc_split_register_get_current_trans (reg);
00802 
00803     trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
00804 
00805     /* This shouldn't happen, but be paranoid. */
00806     if (trans == NULL)
00807     {
00808         LEAVE("no transaction");
00809         return;
00810     }
00811 
00812     cursor_class = gnc_split_register_get_current_cursor_class (reg);
00813 
00814     /* Can't do anything with this. */
00815     if (cursor_class == CURSOR_CLASS_NONE)
00816     {
00817         LEAVE("no current cursor class");
00818         return;
00819     }
00820 
00821     /* This shouldn't happen, but be paranoid. */
00822     if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
00823     {
00824         g_warning("BUG DETECTED: transaction cursor with no anchoring split!");
00825         LEAVE("transaction cursor with no anchoring split");
00826         return;
00827     }
00828 
00829     if (cursor_class == CURSOR_CLASS_SPLIT)
00830     {
00831         const char *message = _("You are about to overwrite an existing split. "
00832                                 "Are you sure you want to do that?");
00833 
00834         if (copied_class == CURSOR_CLASS_TRANS)
00835         {
00836             /* An entire transaction was copied, but we're just on a split. */
00837             LEAVE("can't copy trans to split");
00838             return;
00839         }
00840 
00841         /* Ask before overwriting an existing split. */
00842         if (split != NULL &&
00843                 !gnc_verify_dialog (gnc_split_register_get_parent (reg),
00844                                     FALSE, "%s", message))
00845         {
00846             LEAVE("user cancelled");
00847             return;
00848         }
00849 
00850         gnc_suspend_gui_refresh ();
00851 
00852         if (split == NULL)
00853         {
00854             /* We are on a null split in an expanded transaction. */
00855             split = xaccMallocSplit(gnc_get_current_book ());
00856             xaccSplitSetParent(split, trans);
00857         }
00858 
00859         gnc_copy_split_scm_onto_split(copied_item, split,
00860                                       gnc_get_current_book ());
00861     }
00862     else
00863     {
00864         const char *message = _("You are about to overwrite an existing "
00865                                 "transaction. "
00866                                 "Are you sure you want to do that?");
00867         Account * copied_leader;
00868         const GncGUID *new_guid;
00869         int trans_split_index;
00870         int split_index;
00871         int num_splits;
00872 
00873         if (copied_class == CURSOR_CLASS_SPLIT)
00874         {
00875             LEAVE("can't copy split to transaction");
00876             return;
00877         }
00878 
00879         /* Ask before overwriting an existing transaction. */
00880         if (split != blank_split &&
00881                 !gnc_verify_dialog(gnc_split_register_get_parent(reg),
00882                                    FALSE, "%s", message))
00883         {
00884             LEAVE("user cancelled");
00885             return;
00886         }
00887 
00888         /* Open the transaction for editing. */
00889         if (gnc_split_register_begin_edit_or_warn(info, trans))
00890         {
00891             LEAVE("can't begin editing");
00892             return;
00893         }
00894 
00895         gnc_suspend_gui_refresh ();
00896 
00897         DEBUG("Pasting txn, trans=%p, split=%p, blank_trans=%p, blank_split=%p",
00898               trans, split, blank_trans, blank_split);
00899 
00900         split_index = xaccTransGetSplitIndex(trans, split);
00901         trans_split_index = xaccTransGetSplitIndex(trans, trans_split);
00902 
00903         copied_leader = xaccAccountLookup(&copied_leader_guid,
00904                                           gnc_get_current_book());
00905         if (copied_leader && (gnc_split_register_get_default_account(reg) != NULL))
00906         {
00907             new_guid = &info->default_account;
00908             gnc_copy_trans_scm_onto_trans_swap_accounts(copied_item, trans,
00909                     &copied_leader_guid,
00910                     new_guid, FALSE,
00911                     gnc_get_current_book ());
00912         }
00913         else
00914             gnc_copy_trans_scm_onto_trans(copied_item, trans, FALSE,
00915                                           gnc_get_current_book ());
00916 
00917         num_splits = xaccTransCountSplits(trans);
00918         if (split_index >= num_splits)
00919             split_index = 0;
00920 
00921         if (trans == blank_trans)
00922         {
00923             /* In pasting, the blank split is deleted. Pick a new one. */
00924             blank_split = xaccTransGetSplit(trans, 0);
00925             info->blank_split_guid = *xaccSplitGetGUID (blank_split);
00926             info->blank_split_edited = TRUE;
00927             DEBUG("replacement blank_split=%p", blank_split);
00928 
00929             /* NOTE: At this point, the blank transaction virtual cell is still
00930              *       anchored by the old, deleted blank split. The register will
00931              *       have to be reloaded (redrawn) to correct this. */
00932         }
00933 
00934         info->cursor_hint_trans = trans;
00935         info->cursor_hint_split = xaccTransGetSplit(trans, split_index);
00936         info->cursor_hint_trans_split = xaccTransGetSplit(trans,
00937                                         trans_split_index);
00938         info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
00939     }
00940 
00941     /* Refresh the GUI. */
00942     gnc_resume_gui_refresh ();
00943     LEAVE(" ");
00944 }
00945 
00946 void
00947 gnc_split_register_delete_current_split (SplitRegister *reg)
00948 {
00949     SRInfo *info = gnc_split_register_get_info (reg);
00950     Transaction *pending_trans;
00951     Transaction *trans;
00952     Split *blank_split;
00953     Split *split;
00954 
00955     if (!reg) return;
00956 
00957     blank_split = xaccSplitLookup (&info->blank_split_guid,
00958                                    gnc_get_current_book ());
00959 
00960     pending_trans = xaccTransLookup (&info->pending_trans_guid,
00961                                      gnc_get_current_book ());
00962 
00963     /* get the current split based on cursor position */
00964     split = gnc_split_register_get_current_split (reg);
00965     if (split == NULL)
00966         return;
00967 
00968     /* If we are deleting the blank split, just cancel. The user is
00969      * allowed to delete the blank split as a method for discarding
00970      * any edits they may have made to it. */
00971     if (split == blank_split)
00972     {
00973         gnc_split_register_cancel_cursor_split_changes (reg);
00974         return;
00975     }
00976 
00977     gnc_suspend_gui_refresh ();
00978 
00979     trans = xaccSplitGetParent(split);
00980 
00981     /* Check pending transaction */
00982     if (trans == pending_trans)
00983     {
00984         g_assert(xaccTransIsOpen(trans));
00985     }
00986     else
00987     {
00988         g_assert(!pending_trans);
00989         if (gnc_split_register_begin_edit_or_warn(info, trans))
00990         {
00991             gnc_resume_gui_refresh ();
00992             return;
00993         }
00994     }
00995     xaccSplitDestroy (split);
00996 
00997     gnc_resume_gui_refresh ();
00998     gnc_split_register_redraw(reg);
00999 }
01000 
01001 void
01002 gnc_split_register_delete_current_trans (SplitRegister *reg)
01003 {
01004     SRInfo *info = gnc_split_register_get_info (reg);
01005     Transaction *pending_trans;
01006     Transaction *trans;
01007     Split *blank_split;
01008     Split *split;
01009     gboolean was_open;
01010 
01011     ENTER("reg=%p", reg);
01012     if (!reg)
01013     {
01014         LEAVE("no register");
01015         return;
01016     }
01017 
01018     blank_split = xaccSplitLookup (&info->blank_split_guid,
01019                                    gnc_get_current_book ());
01020     pending_trans = xaccTransLookup (&info->pending_trans_guid,
01021                                      gnc_get_current_book ());
01022 
01023     /* get the current split based on cursor position */
01024     split = gnc_split_register_get_current_split (reg);
01025     if (split == NULL)
01026     {
01027         LEAVE("no split");
01028         return;
01029     }
01030 
01031     gnc_suspend_gui_refresh ();
01032     trans = xaccSplitGetParent(split);
01033 
01034     /* If we just deleted the blank split, clean up. The user is
01035      * allowed to delete the blank split as a method for discarding
01036      * any edits they may have made to it. */
01037     if (split == blank_split)
01038     {
01039         DEBUG("deleting blank split");
01040         info->blank_split_guid = *guid_null();
01041     }
01042     else
01043     {
01044         info->trans_expanded = FALSE;
01045     }
01046 
01047     /* Check pending transaction */
01048     if (trans == pending_trans)
01049     {
01050         DEBUG("clearing pending trans");
01051         info->pending_trans_guid = *guid_null();
01052         pending_trans = NULL;
01053     }
01054 
01055     was_open = xaccTransIsOpen(trans);
01056     xaccTransDestroy(trans);
01057     if (was_open)
01058     {
01059         DEBUG("committing");
01060         xaccTransCommitEdit(trans);
01061     }
01062     gnc_resume_gui_refresh ();
01063     LEAVE(" ");
01064 }
01065 
01066 void
01067 gnc_split_register_void_current_trans (SplitRegister *reg, const char *reason)
01068 {
01069     SRInfo *info = gnc_split_register_get_info (reg);
01070     Transaction *pending_trans;
01071     Transaction *trans;
01072     Split *blank_split;
01073     Split *split;
01074 
01075     if (!reg) return;
01076 
01077     blank_split = xaccSplitLookup (&info->blank_split_guid,
01078                                    gnc_get_current_book ());
01079     pending_trans = xaccTransLookup (&info->pending_trans_guid,
01080                                      gnc_get_current_book ());
01081 
01082     /* get the current split based on cursor position */
01083     split = gnc_split_register_get_current_split (reg);
01084     if (split == NULL)
01085         return;
01086 
01087     /* Bail if trying to void the blank split. */
01088     if (split == blank_split)
01089         return;
01090 
01091     /* already voided. */
01092     if (xaccSplitGetReconcile (split) == VREC)
01093         return;
01094 
01095     info->trans_expanded = FALSE;
01096 
01097     gnc_suspend_gui_refresh ();
01098 
01099     trans = xaccSplitGetParent(split);
01100     xaccTransVoid(trans, reason);
01101 
01102     /* Check pending transaction */
01103     if (trans == pending_trans)
01104     {
01105         info->pending_trans_guid = *guid_null();
01106         pending_trans = NULL;
01107     }
01108     if (xaccTransIsOpen(trans))
01109     {
01110         PERR("We should not be voiding an open transaction.");
01111         xaccTransCommitEdit(trans);
01112     }
01113     gnc_resume_gui_refresh ();
01114 }
01115 
01116 void
01117 gnc_split_register_unvoid_current_trans (SplitRegister *reg)
01118 {
01119     SRInfo *info = gnc_split_register_get_info (reg);
01120     Transaction *pending_trans;
01121     Transaction *trans;
01122     Split *blank_split;
01123     Split *split;
01124 
01125     if (!reg) return;
01126 
01127     blank_split = xaccSplitLookup (&info->blank_split_guid,
01128                                    gnc_get_current_book ());
01129     pending_trans = xaccTransLookup (&info->pending_trans_guid,
01130                                      gnc_get_current_book ());
01131 
01132     /* get the current split based on cursor position */
01133     split = gnc_split_register_get_current_split (reg);
01134     if (split == NULL)
01135         return;
01136 
01137     /* Bail if trying to unvoid the blank split. */
01138     if (split == blank_split)
01139         return;
01140 
01141     /* not voided. */
01142     if (xaccSplitGetReconcile (split) != VREC)
01143         return;
01144 
01145     info->trans_expanded = FALSE;
01146 
01147     gnc_suspend_gui_refresh ();
01148 
01149     trans = xaccSplitGetParent(split);
01150 
01151     xaccTransUnvoid(trans);
01152 
01153     /* Check pending transaction */
01154     if (trans == pending_trans)
01155     {
01156         info->pending_trans_guid = *guid_null();
01157         pending_trans = NULL;
01158     }
01159 
01160     gnc_resume_gui_refresh ();
01161 }
01162 
01163 void
01164 gnc_split_register_empty_current_trans_except_split (SplitRegister *reg,
01165         Split *split)
01166 {
01167     SRInfo *info;
01168     Transaction *trans;
01169     Transaction *pending;
01170     int i = 0;
01171     Split *s;
01172 
01173     if ((reg == NULL)  || (split == NULL))
01174         return;
01175 
01176     gnc_suspend_gui_refresh ();
01177     info = gnc_split_register_get_info(reg);
01178     pending = xaccTransLookup(&info->pending_trans_guid, gnc_get_current_book());
01179 
01180     trans = xaccSplitGetParent(split);
01181     if (!pending)
01182     {
01183         if (gnc_split_register_begin_edit_or_warn(info, trans))
01184         {
01185             gnc_resume_gui_refresh ();
01186             return;
01187         }
01188     }
01189     else if (pending == trans)
01190     {
01191         g_assert(xaccTransIsOpen(trans));
01192     }
01193     else g_assert_not_reached();
01194 
01195     while ((s = xaccTransGetSplit(trans, i)) != NULL)
01196     {
01197         if (s != split)
01198             xaccSplitDestroy(s);
01199         else i++;
01200     }
01201 
01202     gnc_resume_gui_refresh ();
01203     gnc_split_register_redraw(reg);
01204 }
01205 
01206 void
01207 gnc_split_register_empty_current_trans (SplitRegister *reg)
01208 {
01209     Split *split;
01210 
01211     /* get the current split based on cursor position */
01212     split = gnc_split_register_get_current_split (reg);
01213     gnc_split_register_empty_current_trans_except_split (reg, split);
01214 }
01215 
01216 void
01217 gnc_split_register_cancel_cursor_split_changes (SplitRegister *reg)
01218 {
01219     VirtualLocation virt_loc;
01220 
01221     if (reg == NULL)
01222         return;
01223 
01224     virt_loc = reg->table->current_cursor_loc;
01225 
01226     if (!gnc_table_current_cursor_changed (reg->table, FALSE))
01227         return;
01228 
01229     /* We're just cancelling the current split here, not the transaction.
01230      * When cancelling edits, reload the cursor from the transaction. */
01231     gnc_table_clear_current_cursor_changes (reg->table);
01232 
01233     if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
01234         gnc_table_move_cursor_gui (reg->table, virt_loc);
01235 
01236     gnc_table_refresh_gui (reg->table, TRUE);
01237 }
01238 
01239 void
01240 gnc_split_register_cancel_cursor_trans_changes (SplitRegister *reg)
01241 {
01242     SRInfo *info = gnc_split_register_get_info (reg);
01243     Transaction *pending_trans;
01244 
01245     pending_trans = xaccTransLookup (&info->pending_trans_guid,
01246                                      gnc_get_current_book ());
01247 
01248     /* Get the currently open transaction, rollback the edits on it, and
01249      * then repaint everything. To repaint everything, make a note of
01250      * all of the accounts that will be affected by this rollback. */
01251     if (!xaccTransIsOpen (pending_trans))
01252     {
01253         gnc_split_register_cancel_cursor_split_changes (reg);
01254         return;
01255     }
01256 
01257     if (!pending_trans)
01258         return;
01259 
01260     gnc_suspend_gui_refresh ();
01261 
01262     xaccTransRollbackEdit (pending_trans);
01263 
01264     info->pending_trans_guid = *guid_null ();
01265 
01266     gnc_resume_gui_refresh ();
01267     gnc_split_register_redraw(reg);
01268 }
01269 
01270 void
01271 gnc_split_register_redraw (SplitRegister *reg)
01272 {
01273     gnc_ledger_display_refresh_by_split_register (reg);
01274 }
01275 
01276 /* Copy from the register object to scheme. This needs to be
01277  * in sync with gnc_split_register_save and xaccSRSaveChangedCells. */
01278 static gboolean
01279 gnc_split_register_save_to_scm (SplitRegister *reg,
01280                                 SCM trans_scm, SCM split_scm,
01281                                 gboolean use_cut_semantics)
01282 {
01283     SCM other_split_scm = SCM_UNDEFINED;
01284     Transaction *trans;
01285 
01286     /* use the changed flag to avoid heavy-weight updates
01287      * of the split & transaction fields. This will help
01288      * cut down on uneccessary register redraws. */
01289     if (!gnc_table_current_cursor_changed (reg->table, FALSE))
01290         return FALSE;
01291 
01292     /* get the handle to the current split and transaction */
01293     trans = gnc_split_register_get_current_trans (reg);
01294     if (trans == NULL)
01295         return FALSE;
01296 
01297     /* copy the contents from the cursor to the split */
01298     if (gnc_table_layout_get_cell_changed (reg->table->layout, DATE_CELL, TRUE))
01299     {
01300         BasicCell *cell;
01301         Timespec ts;
01302 
01303         cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
01304         gnc_date_cell_get_date ((DateCell *) cell, &ts);
01305 
01306         gnc_trans_scm_set_date(trans_scm, &ts);
01307     }
01308 
01309     if (gnc_table_layout_get_cell_changed (reg->table->layout, NUM_CELL, TRUE))
01310     {
01311         const char *value;
01312 
01313         value = gnc_table_layout_get_cell_value (reg->table->layout, NUM_CELL);
01314         gnc_trans_scm_set_num (trans_scm, value);
01315     }
01316 
01317     if (gnc_table_layout_get_cell_changed (reg->table->layout, DESC_CELL, TRUE))
01318     {
01319         const char *value;
01320 
01321         value = gnc_table_layout_get_cell_value (reg->table->layout, DESC_CELL);
01322         gnc_trans_scm_set_description (trans_scm, value);
01323     }
01324 
01325     if (gnc_table_layout_get_cell_changed (reg->table->layout, NOTES_CELL, TRUE))
01326     {
01327         const char *value;
01328 
01329         value = gnc_table_layout_get_cell_value (reg->table->layout, NOTES_CELL);
01330         gnc_trans_scm_set_notes (trans_scm, value);
01331     }
01332 
01333     if (gnc_table_layout_get_cell_changed (reg->table->layout, RECN_CELL, TRUE))
01334     {
01335         BasicCell *cell;
01336         char flag;
01337 
01338         cell = gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);
01339         flag = gnc_recn_cell_get_flag ((RecnCell *) cell);
01340 
01341         gnc_split_scm_set_reconcile_state(split_scm, flag);
01342     }
01343 
01344     if (gnc_table_layout_get_cell_changed (reg->table->layout, ACTN_CELL, TRUE))
01345     {
01346         const char *value;
01347 
01348         value = gnc_table_layout_get_cell_value (reg->table->layout, ACTN_CELL);
01349         gnc_split_scm_set_action (split_scm, value);
01350     }
01351 
01352     if (gnc_table_layout_get_cell_changed (reg->table->layout, MEMO_CELL, TRUE))
01353     {
01354         const char *value;
01355 
01356         value = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
01357         gnc_split_scm_set_memo (split_scm, value);
01358     }
01359 
01360     if (gnc_table_layout_get_cell_changed (reg->table->layout, XFRM_CELL, TRUE))
01361     {
01362         Account *new_account;
01363 
01364         new_account = gnc_split_register_get_account (reg, XFRM_CELL);
01365 
01366         if (new_account != NULL)
01367             gnc_split_scm_set_account (split_scm, new_account);
01368     }
01369 
01370     if (reg->style == REG_STYLE_LEDGER)
01371         other_split_scm = gnc_trans_scm_get_other_split_scm (trans_scm, split_scm);
01372 
01373     if (gnc_table_layout_get_cell_changed (reg->table->layout, MXFRM_CELL, TRUE))
01374     {
01375         other_split_scm = gnc_trans_scm_get_other_split_scm (trans_scm, split_scm);
01376 
01377         if (other_split_scm == SCM_UNDEFINED)
01378         {
01379             if (gnc_trans_scm_get_num_splits(trans_scm) == 1)
01380             {
01381                 Split *temp_split;
01382 
01383                 temp_split = xaccMallocSplit (gnc_get_current_book ());
01384                 other_split_scm = gnc_copy_split (temp_split, use_cut_semantics);
01385                 xaccSplitDestroy (temp_split);
01386 
01387                 gnc_trans_scm_append_split_scm (trans_scm, other_split_scm);
01388             }
01389         }
01390 
01391         if (other_split_scm != SCM_UNDEFINED)
01392         {
01393             Account *new_account;
01394 
01395             new_account = gnc_split_register_get_account (reg, MXFRM_CELL);
01396 
01397             if (new_account != NULL)
01398                 gnc_split_scm_set_account (other_split_scm, new_account);
01399         }
01400     }
01401 
01402     if (gnc_table_layout_get_cell_changed (reg->table->layout,
01403                                            DEBT_CELL, TRUE) ||
01404             gnc_table_layout_get_cell_changed (reg->table->layout,
01405                     CRED_CELL, TRUE))
01406     {
01407         BasicCell *cell;
01408         gnc_numeric new_value;
01409         gnc_numeric credit;
01410         gnc_numeric debit;
01411 
01412         cell = gnc_table_layout_get_cell (reg->table->layout, CRED_CELL);
01413         credit = gnc_price_cell_get_value ((PriceCell *) cell);
01414 
01415         cell = gnc_table_layout_get_cell (reg->table->layout, DEBT_CELL);
01416         debit = gnc_price_cell_get_value ((PriceCell *) cell);
01417 
01418         new_value = gnc_numeric_sub_fixed (debit, credit);
01419 
01420         gnc_split_scm_set_value (split_scm, new_value);
01421     }
01422 
01423     if (gnc_table_layout_get_cell_changed (reg->table->layout, PRIC_CELL, TRUE))
01424     {
01425         /* do nothing for now */
01426     }
01427 
01428     if (gnc_table_layout_get_cell_changed (reg->table->layout, SHRS_CELL, TRUE))
01429     {
01430         BasicCell *cell;
01431         gnc_numeric shares;
01432 
01433         cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
01434 
01435         shares = gnc_price_cell_get_value ((PriceCell *) cell);
01436 
01437         gnc_split_scm_set_amount (split_scm, shares);
01438     }
01439 
01440     if (gnc_table_layout_get_cell_changed (reg->table->layout,
01441                                            DEBT_CELL, TRUE) ||
01442             gnc_table_layout_get_cell_changed (reg->table->layout,
01443                     CRED_CELL, TRUE) ||
01444             gnc_table_layout_get_cell_changed (reg->table->layout,
01445                     PRIC_CELL, TRUE) ||
01446             gnc_table_layout_get_cell_changed (reg->table->layout,
01447                     SHRS_CELL, TRUE))
01448     {
01449         if (other_split_scm != SCM_UNDEFINED)
01450         {
01451             gnc_numeric num;
01452 
01453             num = gnc_split_scm_get_amount (split_scm);
01454             gnc_split_scm_set_amount (other_split_scm, gnc_numeric_neg (num));
01455 
01456             num = gnc_split_scm_get_value (split_scm);
01457             gnc_split_scm_set_value (other_split_scm, gnc_numeric_neg (num));
01458         }
01459     }
01460 
01461     return TRUE;
01462 }
01463 
01464 gboolean
01465 gnc_split_register_save (SplitRegister *reg, gboolean do_commit)
01466 {
01467     SRInfo *info = gnc_split_register_get_info (reg);
01468     Transaction *pending_trans;
01469     Transaction *blank_trans;
01470     Transaction *trans;
01471     Account *account;
01472     Split *blank_split;
01473     const char *memo;
01474     const char *desc;
01475     Split *split;
01476 
01477     ENTER("reg=%p, do_commit=%s", reg, do_commit ? "TRUE" : "FALSE");
01478 
01479     if (!reg)
01480     {
01481         LEAVE("no register");
01482         return FALSE;
01483     }
01484 
01485     blank_split = xaccSplitLookup (&info->blank_split_guid,
01486                                    gnc_get_current_book ());
01487 
01488     pending_trans = xaccTransLookup (&info->pending_trans_guid,
01489                                      gnc_get_current_book ());
01490 
01491     blank_trans = xaccSplitGetParent (blank_split);
01492 
01493     /* get the handle to the current split and transaction */
01494     split = gnc_split_register_get_current_split (reg);
01495     trans = gnc_split_register_get_current_trans (reg);
01496     if (trans == NULL)
01497     {
01498         LEAVE("no transaction");
01499         return FALSE;
01500     }
01501 
01502     /* use the changed flag to avoid heavy-weight updates
01503      * of the split & transaction fields. This will help
01504      * cut down on unnecessary register redraws. */
01505     if (!gnc_table_current_cursor_changed (reg->table, FALSE))
01506     {
01507         if (!do_commit)
01508         {
01509             LEAVE("commit unnecessary");
01510             return FALSE;
01511         }
01512 
01513         if (!xaccTransIsOpen(trans))
01514         {
01515             LEAVE("transaction not open");
01516             return FALSE;
01517         }
01518 
01519         if (trans == pending_trans ||
01520                 (trans == blank_trans && info->blank_split_edited))
01521         {
01522             /* We are going to commit. */
01523 
01524             gnc_suspend_gui_refresh ();
01525 
01526             if (trans == blank_trans)
01527             {
01528                 /* We have to clear the blank split before the
01529                  * refresh or a new one won't be created. */
01530                 info->last_date_entered = xaccTransGetDate (trans);
01531                 info->blank_split_guid = *guid_null ();
01532                 info->blank_split_edited = FALSE;
01533             }
01534 
01535             /* We have to clear the pending guid *before* committing the
01536              * trans, because the event handler will find it otherwise. */
01537             if (trans == pending_trans)
01538                 info->pending_trans_guid = *guid_null ();
01539 
01540             PINFO("committing trans (%p)", trans);
01541             xaccTransCommitEdit(trans);
01542 
01543             gnc_resume_gui_refresh ();
01544         }
01545         else
01546             DEBUG("leaving trans (%p) open", trans);
01547 
01548         LEAVE("unchanged cursor");
01549         return TRUE;
01550     }
01551 
01552     DEBUG("save split=%p", split);
01553     DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p, trans=%p",
01554           blank_split, blank_trans, pending_trans, trans);
01555 
01556     /* Act on any changes to the current cell before the save. */
01557     (void) gnc_split_register_check_cell (reg,
01558                                           gnc_table_get_current_cell_name (reg->table));
01559 
01560     if (!gnc_split_register_auto_calc (reg, split))
01561     {
01562         LEAVE("auto calc failed");
01563         return FALSE;
01564     }
01565 
01566     /* Validate the transfer account names */
01567     (void)gnc_split_register_get_account (reg, MXFRM_CELL);
01568     (void)gnc_split_register_get_account (reg, XFRM_CELL);
01569 
01570     /* Maybe deal with exchange-rate transfers */
01571     if (gnc_split_register_handle_exchange (reg, FALSE))
01572     {
01573         LEAVE("no exchange rate");
01574         return TRUE;
01575     }
01576 
01577     gnc_suspend_gui_refresh ();
01578 
01579     /* determine whether we should commit the pending transaction */
01580     if (pending_trans != trans)
01581     {
01582         // FIXME: How could the pending transaction not be open?
01583         // FIXME: For that matter, how could an open pending
01584         // transaction ever not be the current trans?
01585         if (xaccTransIsOpen (pending_trans))
01586         {
01587             g_warning("Impossible? commiting pending %p", pending_trans);
01588             xaccTransCommitEdit (pending_trans);
01589         }
01590         else if (pending_trans)
01591         {
01592             g_critical("BUG DETECTED! pending transaction (%p) not open",
01593                        pending_trans);
01594             g_assert_not_reached();
01595         }
01596 
01597         if (trans == blank_trans)
01598         {
01599             /* Don't begin editing the blank trans, because it's
01600                already open, but mark it pending now. */
01601             g_assert(xaccTransIsOpen(blank_trans));
01602             /* This is now the pending transaction */
01603             info->pending_trans_guid = *xaccTransGetGUID(blank_trans);
01604         }
01605         else
01606         {
01607             PINFO("beginning edit of trans %p", trans);
01608             if (gnc_split_register_begin_edit_or_warn(info, trans))
01609             {
01610                 gnc_resume_gui_refresh ();
01611                 LEAVE("transaction opened elsewhere");
01612                 return FALSE;
01613             }
01614         }
01615         pending_trans = trans;
01616     }
01617     g_assert(xaccTransIsOpen(trans));
01618 
01619     /* If we are saving a brand new transaction and the blank split hasn't
01620      * been edited, then we need to give it a default account. */
01621     /* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
01622      *    even better? What if there were some way that we could be on
01623      *    a row other than the transaction row or blank split row, but
01624      *    the blank split still hasn't been edited? It seems to be assumed
01625      *    that it isn't possible, but... -Charles, Jan 2009 */
01626     if (split == blank_split && !info->blank_split_edited)
01627     {
01628         /* If we've reached this point, it means that the blank split is
01629          * anchoring the transaction - see gnc_split_register_add_transaction()
01630          * for an explanation - and the transaction has been edited (as evidenced
01631          * by the earlier check for a changed cursor.) Since the blank split
01632          * itself has not been edited, we'll have to assign a default account. */
01633         account = gnc_split_register_get_default_account(reg);
01634         if (account)
01635             xaccSplitSetAccount(blank_split, account);
01636         xaccTransSetDateEnteredSecs(trans, time(NULL));
01637     }
01638 
01639     if (split == NULL)
01640     {
01641         /* If we were asked to save data for a row for which there is no
01642          * associated split, then assume that this was an "empty" row - see
01643          * gnc_split_register_add_transaction() for an explanation. This row
01644          * is used to add splits to an existing transaction, or to add the
01645          * 2nd through nth split rows to a brand new transaction.
01646          * xaccSRGetCurrent will handle this case, too. We will create
01647          * a new split, copy the row contents to that split, and append
01648          * the split to the pre-existing transaction. */
01649         Split *trans_split;
01650 
01651         split = xaccMallocSplit (gnc_get_current_book ());
01652         xaccTransAppendSplit (trans, split);
01653 
01654         gnc_table_set_virt_cell_data (reg->table,
01655                                       reg->table->current_cursor_loc.vcell_loc,
01656                                       xaccSplitGetGUID (split));
01657         DEBUG("assigned cell to new split=%p", split);
01658 
01659         trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
01660         if ((info->cursor_hint_trans == trans) &&
01661                 (info->cursor_hint_trans_split == trans_split) &&
01662                 (info->cursor_hint_split == NULL))
01663         {
01664             info->cursor_hint_split = split;
01665             info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
01666         }
01667     }
01668 
01669     DEBUG("updating trans=%p", trans);
01670 
01671     {
01672         SRSaveData *sd;
01673 
01674         sd = gnc_split_register_save_data_new (
01675                  trans, split, (info->trans_expanded ||
01676                                 reg->style == REG_STYLE_AUTO_LEDGER ||
01677                                 reg->style == REG_STYLE_JOURNAL));
01678         gnc_table_save_cells (reg->table, sd);
01679         gnc_split_register_save_data_destroy (sd);
01680     }
01681 
01682     memo = xaccSplitGetMemo (split);
01683     memo = memo ? memo : "(null)";
01684     desc = xaccTransGetDescription (trans);
01685     desc = desc ? desc : "(null)";
01686     PINFO ("finished saving split \"%s\" of trans \"%s\"", memo, desc);
01687 
01688     /* If the modified split is the "blank split", then it is now an
01689      * official part of the account. Set the blank split to NULL, so we
01690      * can be sure of getting a new blank split. Also, save the date
01691      * for the new blank split. */
01692     if (trans == blank_trans)
01693     {
01694         if (do_commit)
01695         {
01696             info->blank_split_guid = *guid_null ();
01697             blank_split = NULL;
01698             info->last_date_entered = xaccTransGetDate (trans);
01699         }
01700         else
01701             info->blank_split_edited = TRUE;
01702     }
01703 
01704     /* If requested, commit the current transaction and set the pending
01705      * transaction to NULL. */
01706     if (do_commit)
01707     {
01708         g_assert(trans == blank_trans || trans == pending_trans);
01709         if (pending_trans == trans)
01710         {
01711             pending_trans = NULL;
01712             info->pending_trans_guid = *guid_null ();
01713         }
01714         xaccTransCommitEdit (trans);
01715     }
01716 
01717     gnc_table_clear_current_cursor_changes (reg->table);
01718 
01719     gnc_resume_gui_refresh ();
01720 
01721     LEAVE(" ");
01722     return TRUE;
01723 }
01724 
01725 
01726 Account *
01727 gnc_split_register_get_account_by_name (SplitRegister *reg, BasicCell * bcell,
01728                                         const char *name)
01729 {
01730     const char *placeholder = _("The account %s does not allow transactions.");
01731     const char *missing = _("The account %s does not exist. "
01732                             "Would you like to create it?");
01733     char *account_name;
01734     ComboCell *cell = (ComboCell *) bcell;
01735     Account *account;
01736 
01737     if (!name || (strlen(name) == 0))
01738         return NULL;
01739 
01740     /* Find the account */
01741     account = gnc_account_lookup_for_register (gnc_get_current_root_account (), name);
01742     if (!account)
01743         account = gnc_account_lookup_by_code(gnc_get_current_root_account(), name);
01744 
01745     if (!account)
01746     {
01747         /* Ask if they want to create a new one. */
01748         if (!gnc_verify_dialog (gnc_split_register_get_parent (reg),
01749                                 TRUE, missing, name))
01750             return NULL;
01751 
01752         /* User said yes, they want to create a new account. */
01753         account = gnc_ui_new_accounts_from_name_window (name);
01754         if (!account)
01755             return NULL;
01756     }
01757 
01758     /* Now have the account. */
01759     account_name = gnc_get_account_name_for_register (account);
01760     if (safe_strcmp(account_name, gnc_basic_cell_get_value(bcell)))
01761     {
01762         /* The name has changed. Update the cell. */
01763         gnc_combo_cell_set_value (cell, account_name);
01764         gnc_basic_cell_set_changed (&cell->cell, TRUE);
01765     }
01766     g_free (account_name);
01767 
01768     /* See if the account (either old or new) is a placeholder. */
01769     if (xaccAccountGetPlaceholder (account))
01770     {
01771         gnc_error_dialog (gnc_split_register_get_parent (reg),
01772                           placeholder, name);
01773     }
01774 
01775     /* Be seeing you. */
01776     return account;
01777 }
01778 
01779 Account *
01780 gnc_split_register_get_account (SplitRegister *reg, const char * cell_name)
01781 {
01782     BasicCell *cell;
01783     const char *name;
01784 
01785     if (!gnc_table_layout_get_cell_changed (reg->table->layout, cell_name, TRUE))
01786         return NULL;
01787 
01788     cell = gnc_table_layout_get_cell (reg->table->layout, cell_name);
01789     if (!cell)
01790         return NULL;
01791     name = gnc_basic_cell_get_value (cell);
01792     return gnc_split_register_get_account_by_name (reg, cell, name);
01793 }
01794 
01795 static gboolean
01796 gnc_split_register_auto_calc (SplitRegister *reg, Split *split)
01797 {
01798     PriceCell *cell;
01799     gboolean recalc_shares = FALSE;
01800     gboolean recalc_price = FALSE;
01801     gboolean recalc_value = FALSE;
01802     gboolean price_changed;
01803     gboolean amount_changed;  /* please s/amount_changed/value_changed/ */
01804     gboolean shares_changed;
01805     gnc_numeric calc_value;
01806     gnc_numeric value;
01807     gnc_numeric price;
01808     gnc_numeric amount;
01809     Account *account;
01810     int denom;
01811 
01812     if (STOCK_REGISTER    != reg->type &&
01813             CURRENCY_REGISTER != reg->type &&
01814             PORTFOLIO_LEDGER  != reg->type)
01815         return TRUE;
01816 
01817     account = gnc_split_register_get_account (reg, XFRM_CELL);
01818 
01819     if (!account)
01820         account = xaccSplitGetAccount (split);
01821 
01822     if (!account)
01823         account = gnc_split_register_get_default_account (reg);
01824 
01825     if (!xaccAccountIsPriced(account))
01826         return TRUE;
01827 
01828     price_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
01829                     PRIC_CELL, TRUE);
01830     amount_changed = (gnc_table_layout_get_cell_changed (reg->table->layout,
01831                       DEBT_CELL, TRUE) ||
01832                       gnc_table_layout_get_cell_changed (reg->table->layout,
01833                               CRED_CELL, TRUE));
01834     shares_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
01835                      SHRS_CELL, TRUE);
01836 
01837     if (!price_changed && !amount_changed && !shares_changed)
01838         return TRUE;
01839 
01840     /* If we are using commodity trading accounts then the value may
01841        not really be the value.  Punt if so. */
01842     if (xaccTransUseTradingAccounts (xaccSplitGetParent (split)))
01843     {
01844         gnc_commodity *acc_commodity;
01845         acc_commodity = xaccAccountGetCommodity (account);
01846         if (! (xaccAccountIsPriced (account) ||
01847                 !gnc_commodity_is_iso (acc_commodity)))
01848             return TRUE;
01849     }
01850 
01851     if (shares_changed)
01852     {
01853         cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
01854                 SHRS_CELL);
01855         amount = gnc_price_cell_get_value (cell);
01856     }
01857     else
01858         amount = xaccSplitGetAmount (split);
01859 
01860     if (price_changed)
01861     {
01862         cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
01863                 PRIC_CELL);
01864         price = gnc_price_cell_get_value (cell);
01865     }
01866     else
01867         price = xaccSplitGetSharePrice (split);
01868 
01869     if (amount_changed)
01870     {
01871         gnc_numeric credit;
01872         gnc_numeric debit;
01873 
01874         cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
01875                 CRED_CELL);
01876         credit = gnc_price_cell_get_value (cell);
01877 
01878         cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
01879                 DEBT_CELL);
01880         debit = gnc_price_cell_get_value (cell);
01881 
01882         value = gnc_numeric_sub_fixed (debit, credit);
01883     }
01884     else
01885         value = xaccSplitGetValue (split);
01886 
01887 
01888     /* Check if shares and price are BOTH zero (and value is non-zero).
01889      * If so, we can assume that this is an income-correcting split
01890      */
01891     if (gnc_numeric_zero_p(amount) && gnc_numeric_zero_p(price) &&
01892             !gnc_numeric_zero_p(value))
01893     {
01894         /* XXX: should we ask the user? */
01895         return TRUE;
01896     }
01897 
01898     /* Check if precisely one value is zero. If so, we can assume that the
01899      * zero value needs to be recalculated.   */
01900 
01901     if (!gnc_numeric_zero_p (amount))
01902     {
01903         if (gnc_numeric_zero_p (price))
01904         {
01905             if (!gnc_numeric_zero_p (value))
01906                 recalc_price = TRUE;
01907         }
01908         else if (gnc_numeric_zero_p (value))
01909             recalc_value = TRUE;
01910     }
01911     else if (!gnc_numeric_zero_p (price))
01912         if (!gnc_numeric_zero_p (value))
01913             recalc_shares = TRUE;
01914 
01915     /* If we have not already flagged a recalc, check if this is a split
01916      * which has 2 of the 3 values changed. */
01917 
01918     if ((!recalc_shares) &&
01919             (!recalc_price)  &&
01920             (!recalc_value))
01921     {
01922         if (price_changed && amount_changed)
01923         {
01924             if (!shares_changed)
01925                 recalc_shares = TRUE;
01926         }
01927         else if (amount_changed && shares_changed)
01928             recalc_price = TRUE;
01929         else if (price_changed && shares_changed)
01930             recalc_value = TRUE;
01931     }
01932 
01933     calc_value = gnc_numeric_mul (price, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
01934 
01935     denom = gnc_split_get_value_denom (split);
01936 
01937     /*  Now, if we have not flagged one of the recalcs, and value and
01938      *  calc_value are not the same number, then we need to ask for
01939      *  help from the user. */
01940 
01941     if (!recalc_shares &&
01942             !recalc_price &&
01943             !recalc_value &&
01944             !gnc_numeric_same (value, calc_value, denom, GNC_HOW_RND_ROUND_HALF_UP))
01945     {
01946         int choice;
01947         int default_value;
01948         GList *node;
01949         GList *radio_list = NULL;
01950         const char *title = _("Recalculate Transaction");
01951         const char *message = _("The values entered for this transaction "
01952                                 "are inconsistent. Which value would you "
01953                                 "like to have recalculated?");
01954 
01955         if (shares_changed)
01956             radio_list = g_list_append (radio_list,
01957                                         g_strdup_printf ("%s (%s)",
01958                                                 _("_Shares"), _("Changed")));
01959         else
01960             radio_list = g_list_append (radio_list, g_strdup (_("_Shares")));
01961 
01962         if (price_changed)
01963             radio_list = g_list_append (radio_list,
01964                                         g_strdup_printf ("%s (%s)",
01965                                                 _("_Price"), _("Changed")));
01966         else
01967             radio_list = g_list_append (radio_list, g_strdup (_("_Price")));
01968 
01969         if (amount_changed)
01970             radio_list = g_list_append (radio_list,
01971                                         g_strdup_printf ("%s (%s)",
01972                                                 _("_Value"), _("Changed")));
01973         else
01974             radio_list = g_list_append (radio_list, g_strdup (_("_Value")));
01975 
01976         if (price_changed) default_value = 2;  /* change the value */
01977         else  default_value = 1;  /* change the value */
01978 
01979         choice = gnc_choose_radio_option_dialog
01980                  (gnc_split_register_get_parent (reg),
01981                   title,
01982                   message,
01983                   _("_Recalculate"),
01984                   default_value,
01985                   radio_list);
01986 
01987         for (node = radio_list; node; node = node->next)
01988             g_free (node->data);
01989 
01990         g_list_free (radio_list);
01991 
01992         switch (choice)
01993         {
01994         case 0: /* Modify number of shares */
01995             recalc_shares = TRUE;
01996             break;
01997         case 1: /* Modify the share price */
01998             recalc_price = TRUE;
01999             break;
02000         case 2: /* Modify total value */
02001             recalc_value = TRUE;
02002             break;
02003         default: /* Cancel */
02004             return FALSE;
02005         }
02006     }
02007 
02008     if (recalc_shares)
02009         if (!gnc_numeric_zero_p (price))
02010         {
02011             BasicCell *cell;
02012 
02013             denom = gnc_split_get_amount_denom (split);
02014 
02015             amount = gnc_numeric_div (value, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
02016 
02017             cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
02018             gnc_price_cell_set_value ((PriceCell *) cell, amount);
02019             gnc_basic_cell_set_changed (cell, TRUE);
02020 
02021             if (amount_changed)
02022             {
02023                 cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
02024                 gnc_basic_cell_set_changed (cell, FALSE);
02025             }
02026         }
02027 
02028     if (recalc_price)
02029         if (!gnc_numeric_zero_p (amount))
02030         {
02031             BasicCell *price_cell;
02032 
02033             price = gnc_numeric_div (value, amount,
02034                                      GNC_DENOM_AUTO,
02035                                      GNC_HOW_DENOM_EXACT);
02036 
02037             if (gnc_numeric_negative_p (price))
02038             {
02039                 BasicCell *debit_cell;
02040                 BasicCell *credit_cell;
02041 
02042                 debit_cell = gnc_table_layout_get_cell (reg->table->layout,
02043                                                         DEBT_CELL);
02044 
02045                 credit_cell = gnc_table_layout_get_cell (reg->table->layout,
02046                               CRED_CELL);
02047 
02048                 price = gnc_numeric_neg (price);
02049 
02050                 gnc_price_cell_set_debt_credit_value ((PriceCell *) debit_cell,
02051                                                       (PriceCell *) credit_cell,
02052                                                       gnc_numeric_neg (value));
02053 
02054                 gnc_basic_cell_set_changed (debit_cell, TRUE);
02055                 gnc_basic_cell_set_changed (credit_cell, TRUE);
02056             }
02057 
02058             price_cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
02059             gnc_price_cell_set_value ((PriceCell *) price_cell, price);
02060             gnc_basic_cell_set_changed (price_cell, TRUE);
02061         }
02062 
02063     if (recalc_value)
02064     {
02065         BasicCell *debit_cell;
02066         BasicCell *credit_cell;
02067 
02068         debit_cell = gnc_table_layout_get_cell (reg->table->layout, DEBT_CELL);
02069         credit_cell = gnc_table_layout_get_cell (reg->table->layout, CRED_CELL);
02070 
02071         denom = gnc_split_get_value_denom (split);
02072 
02073         value = gnc_numeric_mul (price, amount, denom, GNC_HOW_RND_ROUND_HALF_UP);
02074 
02075         gnc_price_cell_set_debt_credit_value ((PriceCell *) debit_cell,
02076                                               (PriceCell *) credit_cell, value);
02077 
02078         gnc_basic_cell_set_changed (debit_cell, TRUE);
02079         gnc_basic_cell_set_changed (credit_cell, TRUE);
02080 
02081         if (shares_changed)
02082         {
02083             BasicCell *cell;
02084 
02085             cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
02086             gnc_basic_cell_set_changed (cell, FALSE);
02087         }
02088     }
02089 
02090     return TRUE;
02091 }
02092 
02093 static GNCAccountType
02094 gnc_split_register_type_to_account_type (SplitRegisterType sr_type)
02095 {
02096     switch (sr_type)
02097     {
02098     case BANK_REGISTER:
02099         return ACCT_TYPE_BANK;
02100     case CASH_REGISTER:
02101         return ACCT_TYPE_CASH;
02102     case ASSET_REGISTER:
02103         return ACCT_TYPE_ASSET;
02104     case CREDIT_REGISTER:
02105         return ACCT_TYPE_CREDIT;
02106     case LIABILITY_REGISTER:
02107         return ACCT_TYPE_LIABILITY;
02108     case PAYABLE_REGISTER:
02109         return ACCT_TYPE_PAYABLE;
02110     case RECEIVABLE_REGISTER:
02111         return ACCT_TYPE_RECEIVABLE;
02112     case INCOME_LEDGER:
02113     case INCOME_REGISTER:
02114         return ACCT_TYPE_INCOME;
02115     case EXPENSE_REGISTER:
02116         return ACCT_TYPE_EXPENSE;
02117     case STOCK_REGISTER:
02118     case PORTFOLIO_LEDGER:
02119         return ACCT_TYPE_STOCK;
02120     case CURRENCY_REGISTER:
02121         return ACCT_TYPE_CURRENCY;
02122     case TRADING_REGISTER:
02123         return ACCT_TYPE_TRADING;
02124     case GENERAL_LEDGER:
02125         return ACCT_TYPE_NONE;
02126     case EQUITY_REGISTER:
02127         return ACCT_TYPE_EQUITY;
02128     case SEARCH_LEDGER:
02129         return ACCT_TYPE_NONE;
02130     default:
02131         return ACCT_TYPE_NONE;
02132     }
02133 }
02134 
02135 const char *
02136 gnc_split_register_get_debit_string (SplitRegister *reg)
02137 {
02138     SRInfo *info = gnc_split_register_get_info (reg);
02139 
02140     if (!reg)
02141         return NULL;
02142 
02143     if (info->debit_str)
02144         return info->debit_str;
02145 
02146     info->debit_str =
02147         gnc_get_debit_string
02148         (gnc_split_register_type_to_account_type (reg->type));
02149 
02150     if (info->debit_str)
02151         return info->debit_str;
02152 
02153     info->debit_str = g_strdup (_("Debit"));
02154 
02155     return info->debit_str;
02156 }
02157 
02158 const char *
02159 gnc_split_register_get_credit_string (SplitRegister *reg)
02160 {
02161     SRInfo *info = gnc_split_register_get_info (reg);
02162 
02163     if (!reg)
02164         return NULL;
02165 
02166     if (info->credit_str)
02167         return info->credit_str;
02168 
02169     info->credit_str =
02170         gnc_get_credit_string
02171         (gnc_split_register_type_to_account_type (reg->type));
02172 
02173     if (info->credit_str)
02174         return info->credit_str;
02175 
02176     info->credit_str = g_strdup (_("Credit"));
02177 
02178     return info->credit_str;
02179 }
02180 
02181 gboolean
02182 gnc_split_register_changed (SplitRegister *reg)
02183 {
02184     SRInfo *info = gnc_split_register_get_info (reg);
02185     Transaction *pending_trans;
02186 
02187     ENTER("reg=%p", reg);
02188 
02189     if (reg == NULL)
02190     {
02191         LEAVE("no register");
02192         return FALSE;
02193     }
02194 
02195     if (gnc_table_current_cursor_changed (reg->table, FALSE))
02196     {
02197         LEAVE("cursor changed");
02198         return TRUE;
02199     }
02200 
02201     pending_trans = xaccTransLookup (&info->pending_trans_guid,
02202                                      gnc_get_current_book ());
02203     if (xaccTransIsOpen (pending_trans))
02204     {
02205         LEAVE("open and pending txn");
02206         return TRUE;
02207     }
02208 
02209     LEAVE("register unchanged");
02210     return FALSE;
02211 }
02212 
02213 void
02214 gnc_split_register_show_present_divider (SplitRegister *reg,
02215         gboolean show_present)
02216 {
02217     SRInfo *info = gnc_split_register_get_info (reg);
02218 
02219     if (reg == NULL)
02220         return;
02221 
02222     info->show_present_divider = show_present;
02223 }
02224 
02225 gboolean
02226 gnc_split_register_full_refresh_ok (SplitRegister *reg)
02227 {
02228     SRInfo *info = gnc_split_register_get_info (reg);
02229 
02230     if (!info)
02231         return FALSE;
02232 
02233     return info->full_refresh;
02234 }
02235 
02236 /* configAction strings into the action cell */
02237 /* hack alert -- this stuff really, really should be in a config file ... */
02238 static void
02239 gnc_split_register_config_action (SplitRegister *reg)
02240 {
02241     ComboCell *cell;
02242 
02243     cell = (ComboCell *) gnc_table_layout_get_cell (reg->table->layout,
02244             ACTN_CELL);
02245 
02246     /* setup strings in the action pull-down */
02247     switch (reg->type)
02248     {
02249     case BANK_REGISTER:
02250         /* broken ! FIXME bg */
02251     case SEARCH_LEDGER:
02252         /* Translators: This string has a context prefix; the translation
02253                 must only contain the part after the | character. */
02254         gnc_combo_cell_add_menu_item (cell, Q_("Action Column|Deposit"));
02255         gnc_combo_cell_add_menu_item (cell, _("Withdraw"));
02256         gnc_combo_cell_add_menu_item (cell, _("Check"));
02257         gnc_combo_cell_add_menu_item (cell, _("Interest"));
02258         gnc_combo_cell_add_menu_item (cell, _("ATM Deposit"));
02259         gnc_combo_cell_add_menu_item (cell, _("ATM Draw"));
02260         gnc_combo_cell_add_menu_item (cell, _("Teller"));
02261         gnc_combo_cell_add_menu_item (cell, _("Charge"));
02262         gnc_combo_cell_add_menu_item (cell, _("Payment"));
02263         gnc_combo_cell_add_menu_item (cell, _("Receipt"));
02264         gnc_combo_cell_add_menu_item (cell, _("Increase"));
02265         gnc_combo_cell_add_menu_item (cell, _("Decrease"));
02266         /* Action: Point Of Sale */
02267         gnc_combo_cell_add_menu_item (cell, _("POS"));
02268         gnc_combo_cell_add_menu_item (cell, _("Phone"));
02269         gnc_combo_cell_add_menu_item (cell, _("Online"));
02270         /* Action: Automatic Deposit ?!? */
02271         gnc_combo_cell_add_menu_item (cell, _("AutoDep"));
02272         gnc_combo_cell_add_menu_item (cell, _("Wire"));
02273         gnc_combo_cell_add_menu_item (cell, _("Credit"));
02274         gnc_combo_cell_add_menu_item (cell, _("Direct Debit"));
02275         gnc_combo_cell_add_menu_item (cell, _("Transfer"));
02276         break;
02277     case CASH_REGISTER:
02278         gnc_combo_cell_add_menu_item (cell, _("Increase"));
02279         gnc_combo_cell_add_menu_item (cell, _("Decrease"));
02280         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02281         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02282         break;
02283     case ASSET_REGISTER:
02284         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02285         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02286         gnc_combo_cell_add_menu_item (cell, _("Fee"));
02287         break;
02288     case CREDIT_REGISTER:
02289         gnc_combo_cell_add_menu_item (cell, _("ATM Deposit"));
02290         gnc_combo_cell_add_menu_item (cell, _("ATM Draw"));
02291         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02292         gnc_combo_cell_add_menu_item (cell, _("Credit"));
02293         gnc_combo_cell_add_menu_item (cell, _("Fee"));
02294         gnc_combo_cell_add_menu_item (cell, _("Interest"));
02295         gnc_combo_cell_add_menu_item (cell, _("Online"));
02296         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02297         break;
02298     case LIABILITY_REGISTER:
02299         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02300         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02301         gnc_combo_cell_add_menu_item (cell, _("Loan"));
02302         gnc_combo_cell_add_menu_item (cell, _("Interest"));
02303         gnc_combo_cell_add_menu_item (cell, _("Payment"));
02304         break;
02305     case RECEIVABLE_REGISTER:
02306     case PAYABLE_REGISTER:
02307         gnc_combo_cell_add_menu_item (cell, _("Invoice"));
02308         gnc_combo_cell_add_menu_item (cell, _("Payment"));
02309         gnc_combo_cell_add_menu_item (cell, _("Interest"));
02310         gnc_combo_cell_add_menu_item (cell, _("Credit"));
02311         break;
02312     case INCOME_LEDGER:
02313     case INCOME_REGISTER:
02314         gnc_combo_cell_add_menu_item (cell, _("Increase"));
02315         gnc_combo_cell_add_menu_item (cell, _("Decrease"));
02316         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02317         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02318         gnc_combo_cell_add_menu_item (cell, _("Interest"));
02319         gnc_combo_cell_add_menu_item (cell, _("Payment"));
02320         gnc_combo_cell_add_menu_item (cell, _("Rebate"));
02321         gnc_combo_cell_add_menu_item (cell, _("Paycheck"));
02322         break;
02323     case EXPENSE_REGISTER:
02324     case TRADING_REGISTER:
02325         gnc_combo_cell_add_menu_item (cell, _("Increase"));
02326         gnc_combo_cell_add_menu_item (cell, _("Decrease"));
02327         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02328         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02329         break;
02330     case GENERAL_LEDGER:
02331     case EQUITY_REGISTER:
02332         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02333         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02334         gnc_combo_cell_add_menu_item (cell, _("Equity"));
02335         break;
02336     case STOCK_REGISTER:
02337     case PORTFOLIO_LEDGER:
02338     case CURRENCY_REGISTER:
02339         gnc_combo_cell_add_menu_item (cell, ACTION_BUY_STR);
02340         gnc_combo_cell_add_menu_item (cell, ACTION_SELL_STR);
02341         gnc_combo_cell_add_menu_item (cell, _("Price"));
02342         gnc_combo_cell_add_menu_item (cell, _("Fee"));
02343         /* Action: Dividend */
02344         gnc_combo_cell_add_menu_item (cell, _("Dividend"));
02345         gnc_combo_cell_add_menu_item (cell, _("Interest"));
02346         /* Action: Long Term Capital Gains */
02347         gnc_combo_cell_add_menu_item (cell, _("LTCG"));
02348         /* Action: Short Term Capital Gains */
02349         gnc_combo_cell_add_menu_item (cell, _("STCG"));
02350         gnc_combo_cell_add_menu_item (cell, _("Income"));
02351         /* Action: Distribution */
02352         gnc_combo_cell_add_menu_item (cell, _("Dist"));
02353         /* Translators: This string has a disambiguation prefix */
02354         gnc_combo_cell_add_menu_item (cell, Q_("Action Column|Split"));
02355         break;
02356 
02357     default:
02358         gnc_combo_cell_add_menu_item (cell, _("Increase"));
02359         gnc_combo_cell_add_menu_item (cell, _("Decrease"));
02360         gnc_combo_cell_add_menu_item (cell, _("Buy"));
02361         gnc_combo_cell_add_menu_item (cell, _("Sell"));
02362         break;
02363     }
02364 }
02365 
02366 static void
02367 gnc_split_register_config_cells (SplitRegister *reg)
02368 {
02369     gnc_combo_cell_add_ignore_string
02370     ((ComboCell *)
02371      gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
02372      SPLIT_TRANS_STR);
02373 
02374     gnc_combo_cell_add_ignore_string
02375     ((ComboCell *)
02376      gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
02377      STOCK_SPLIT_STR);
02378 
02379     /* the action cell */
02380     gnc_combo_cell_set_autosize
02381     ((ComboCell *)
02382      gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), TRUE);
02383 
02384     /* Use 6 decimal places for prices and "exchange rates"  */
02385     gnc_price_cell_set_fraction
02386     ((PriceCell *)
02387      gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL), 1000000);
02388 
02389     /* Initialize shares and share balance cells */
02390     gnc_price_cell_set_print_info
02391     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL),
02392      gnc_default_share_print_info ());
02393 
02394     gnc_price_cell_set_print_info
02395     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, TSHRS_CELL),
02396      gnc_default_share_print_info ());
02397 
02398     /* Initialize the rate cell
02399      * use a share_print_info to make sure we don't have rounding errors
02400      */
02401     gnc_price_cell_set_print_info
02402     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL),
02403      gnc_default_share_print_info());
02404 
02405     /* The action cell should accept strings not in the list */
02406     gnc_combo_cell_set_strict
02407     ((ComboCell *)
02408      gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), FALSE);
02409 
02410     /* number format for share quantities in stock ledgers */
02411     switch (reg->type)
02412     {
02413     case CURRENCY_REGISTER:
02414     case STOCK_REGISTER:
02415     case PORTFOLIO_LEDGER:
02416         gnc_price_cell_set_print_info
02417         ((PriceCell *)
02418          gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
02419          gnc_default_price_print_info ());
02420         break;
02421 
02422     default:
02423         break;
02424     }
02425 
02426     /* add menu items for the action cell */
02427     gnc_split_register_config_action (reg);
02428 }
02429 
02430 static void
02431 split_register_gconf_changed (GConfEntry *entry, gpointer user_data)
02432 {
02433     SplitRegister * reg = user_data;
02434     SRInfo *info;
02435 
02436     g_return_if_fail(entry && entry->key);
02437     if (reg == NULL)
02438         return;
02439 
02440     info = reg->sr_info;
02441     if (!info)
02442         return;
02443 
02444     if (g_str_has_suffix(entry->key, KEY_ACCOUNTING_LABELS))
02445     {
02446         /* Release current strings. Will be reloaded at next reference. */
02447         g_free (info->debit_str);
02448         g_free (info->tdebit_str);
02449         g_free (info->credit_str);
02450         g_free (info->tcredit_str);
02451 
02452         info->debit_str = NULL;
02453         info->tdebit_str = NULL;
02454         info->credit_str = NULL;
02455         info->tcredit_str = NULL;
02456 
02457     }
02458     else if (g_str_has_suffix(entry->key, KEY_ACCOUNT_SEPARATOR))
02459     {
02460         info->separator_changed = TRUE;
02461     }
02462     else
02463     {
02464         g_warning("split_register_gconf_changed: Unknown gconf key %s", entry->key);
02465     }
02466 }
02467 
02468 static void
02469 gnc_split_register_init (SplitRegister *reg,
02470                          SplitRegisterType type,
02471                          SplitRegisterStyle style,
02472                          gboolean use_double_line,
02473                          gboolean do_auto_complete,
02474                          gboolean is_template)
02475 {
02476     TableLayout *layout;
02477     TableModel *model;
02478     TableControl *control;
02479 
02480     /* Register 'destroy' callback */
02481     gnc_gconf_general_register_cb(KEY_ACCOUNTING_LABELS,
02482                                   split_register_gconf_changed,
02483                                   reg);
02484     gnc_gconf_general_register_cb(KEY_ACCOUNT_SEPARATOR,
02485                                   split_register_gconf_changed,
02486                                   reg);
02487 
02488     reg->sr_info = NULL;
02489 
02490     reg->type = type;
02491     reg->style = style;
02492     reg->use_double_line = use_double_line;
02493     reg->do_auto_complete = do_auto_complete;
02494     reg->is_template = is_template;
02495 
02496     layout = gnc_split_register_layout_new (reg);
02497 
02498     if (is_template)
02499         model = gnc_template_register_model_new ();
02500     else
02501         model = gnc_split_register_model_new ();
02502     model->handler_user_data = reg;
02503 
02504     control = gnc_split_register_control_new ();
02505     control->user_data = reg;
02506 
02507     reg->table = gnc_table_new (layout, model, control);
02508 
02509     gnc_split_register_config_cells (reg);
02510 
02511     /* Set up header */
02512     {
02513         VirtualCellLocation vcell_loc = { 0, 0 };
02514         CellBlock *header;
02515 
02516         header = gnc_table_layout_get_cursor (reg->table->layout, CURSOR_HEADER);
02517 
02518         gnc_table_set_vcell (reg->table, header, NULL, TRUE, TRUE, vcell_loc);
02519     }
02520 
02521     /* Set up first and only initial row */
02522     {
02523         VirtualLocation vloc;
02524         CellBlock *cursor;
02525 
02526         vloc.vcell_loc.virt_row = 1;
02527         vloc.vcell_loc.virt_col = 0;
02528         vloc.phys_row_offset = 0;
02529         vloc.phys_col_offset = 0;
02530 
02531         cursor = gnc_table_layout_get_cursor (reg->table->layout,
02532                                               CURSOR_SINGLE_LEDGER);
02533 
02534         gnc_table_set_vcell (reg->table, cursor, NULL, TRUE, TRUE, vloc.vcell_loc);
02535 
02536         if (gnc_table_find_close_valid_cell (reg->table, &vloc, FALSE))
02537             gnc_table_move_cursor (reg->table, vloc);
02538         else
02539         {
02540             PERR ("Can't find valid initial location");
02541         }
02542     }
02543 }
02544 
02545 SplitRegister *
02546 gnc_split_register_new (SplitRegisterType type,
02547                         SplitRegisterStyle style,
02548                         gboolean use_double_line,
02549                         gboolean is_template)
02550 {
02551     SplitRegister * reg;
02552     gboolean default_do_auto_complete = TRUE;
02553 
02554     reg = g_new0 (SplitRegister, 1);
02555 
02556     if (type >= NUM_SINGLE_REGISTER_TYPES)
02557         style = REG_STYLE_JOURNAL;
02558 
02559     gnc_split_register_init (reg,
02560                              type,
02561                              style,
02562                              use_double_line,
02563                              default_do_auto_complete,
02564                              is_template);
02565 
02566     return reg;
02567 }
02568 
02569 void
02570 gnc_split_register_config (SplitRegister *reg,
02571                            SplitRegisterType newtype,
02572                            SplitRegisterStyle newstyle,
02573                            gboolean use_double_line)
02574 {
02575     if (!reg) return;
02576 
02577     /* If shrinking the transaction split, put the cursor on the first row of the trans */
02578     if (reg->use_double_line && !use_double_line)
02579     {
02580         VirtualLocation virt_loc = reg->table->current_cursor_loc;
02581         if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
02582         {
02583             if (virt_loc.phys_row_offset)
02584             {
02585                 gnc_table_move_vertical_position (reg->table, &virt_loc, -virt_loc.phys_row_offset);
02586                 gnc_table_move_cursor_gui (reg->table, virt_loc);
02587             }
02588         }
02589         else
02590         {
02591             /* WTF?  Go to a known safe location. */
02592             virt_loc.vcell_loc.virt_row = 1;
02593             virt_loc.vcell_loc.virt_col = 0;
02594             virt_loc.phys_row_offset = 0;
02595             virt_loc.phys_col_offset = 0;
02596             gnc_table_move_cursor_gui (reg->table, virt_loc);
02597         }
02598     }
02599 
02600     reg->type = newtype;
02601 
02602     if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
02603         newstyle = REG_STYLE_JOURNAL;
02604 
02605     reg->style = newstyle;
02606     reg->use_double_line = use_double_line;
02607 
02608     gnc_table_realize_gui (reg->table);
02609 }
02610 
02611 void
02612 gnc_split_register_set_auto_complete(SplitRegister *reg,
02613                                      gboolean do_auto_complete)
02614 {
02615     g_return_if_fail(reg);
02616     reg->do_auto_complete = do_auto_complete;
02617 }
02618 
02619 static void
02620 gnc_split_register_destroy_info (SplitRegister *reg)
02621 {
02622     SRInfo *info;
02623 
02624     if (reg == NULL)
02625         return;
02626 
02627     info = reg->sr_info;
02628     if (!info)
02629         return;
02630 
02631     g_free (info->debit_str);
02632     g_free (info->tdebit_str);
02633     g_free (info->credit_str);
02634     g_free (info->tcredit_str);
02635 
02636     info->debit_str = NULL;
02637     info->tdebit_str = NULL;
02638     info->credit_str = NULL;
02639     info->tcredit_str = NULL;
02640 
02641     g_free (reg->sr_info);
02642 
02643     reg->sr_info = NULL;
02644 }
02645 
02646 void
02647 gnc_split_register_set_data (SplitRegister *reg, void *user_data,
02648                              SRGetParentCallback get_parent)
02649 {
02650     SRInfo *info = gnc_split_register_get_info (reg);
02651 
02652     g_return_if_fail (reg != NULL);
02653 
02654     info->user_data = user_data;
02655     info->get_parent = get_parent;
02656 }
02657 
02658 static void
02659 gnc_split_register_cleanup (SplitRegister *reg)
02660 {
02661     SRInfo *info = gnc_split_register_get_info (reg);
02662     Transaction *pending_trans;
02663     Transaction *blank_trans = NULL;
02664     Split *blank_split;
02665 
02666     ENTER("reg=%p", reg);
02667 
02668     blank_split = xaccSplitLookup (&info->blank_split_guid,
02669                                    gnc_get_current_book ());
02670 
02671     pending_trans = xaccTransLookup (&info->pending_trans_guid,
02672                                      gnc_get_current_book ());
02673 
02674     gnc_suspend_gui_refresh ();
02675 
02676     /* Destroy the transaction containing the "blank split", which was only
02677      * created to support the area for entering a new transaction. Since the
02678      * register is closing, this transaction is no longer needed. */
02679     if (blank_split != NULL)
02680     {
02681         gboolean was_open;
02682 
02683         blank_trans = xaccSplitGetParent (blank_split);
02684 
02685         DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p",
02686               blank_split, blank_trans, pending_trans);
02687 
02688         /* Destroying the transaction will automatically remove its splits. */
02689         was_open = xaccTransIsOpen (blank_trans);
02690         xaccTransDestroy (blank_trans);
02691         if (was_open)
02692             xaccTransCommitEdit (blank_trans);
02693 
02694         /* Update the register info. */
02695         if (blank_trans == pending_trans)
02696         {
02697             info->pending_trans_guid = *guid_null ();
02698             pending_trans = NULL;
02699         }
02700         info->blank_split_guid = *guid_null ();
02701         blank_split = NULL;
02702     }
02703 
02704     /* be sure to take care of any open transactions */
02705     if (pending_trans != NULL)
02706     {
02707         g_critical("BUG DETECTED: pending_trans=%p, blank_split=%p, blank_trans=%p",
02708                    pending_trans, blank_split, blank_trans);
02709         g_assert_not_reached();
02710         info->pending_trans_guid = *guid_null ();
02711         /* CAS: It's not clear to me that we'd really want to commit
02712            here, rather than rollback. But, maybe this is just dead
02713            code. */
02714         if (xaccTransIsOpen (pending_trans))
02715             xaccTransCommitEdit (pending_trans);
02716         else g_assert_not_reached();
02717 
02718         pending_trans = NULL;
02719     }
02720 
02721     gnc_split_register_destroy_info (reg);
02722 
02723     gnc_resume_gui_refresh ();
02724 
02725     LEAVE(" ");
02726 }
02727 
02728 void
02729 gnc_split_register_destroy (SplitRegister *reg)
02730 {
02731     g_return_if_fail(reg);
02732 
02733     ENTER("reg=%p", reg);
02734 
02735     gnc_gconf_general_remove_cb(KEY_ACCOUNTING_LABELS,
02736                                 split_register_gconf_changed,
02737                                 reg);
02738     gnc_gconf_general_remove_cb(KEY_ACCOUNT_SEPARATOR,
02739                                 split_register_gconf_changed,
02740                                 reg);
02741     gnc_split_register_cleanup (reg);
02742 
02743     gnc_table_destroy (reg->table);
02744     reg->table = NULL;
02745 
02746     /* free the memory itself */
02747     g_free (reg);
02748     LEAVE(" ");
02749 }
02750 
02751 void
02752 gnc_split_register_set_read_only (SplitRegister *reg, gboolean read_only)
02753 {
02754     gnc_table_model_set_read_only (reg->table->model, read_only);
02755 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines