|
GnuCash 2.4.99
|
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 }
1.7.4