1 /********************************************************************\ 2 * split-register.h -- split register API * 3 * * 4 * This program is free software; you can redistribute it and/or * 5 * modify it under the terms of the GNU General Public License as * 6 * published by the Free Software Foundation; either version 2 of * 7 * the License, or (at your option) any later version. * 8 * * 9 * This program is distributed in the hope that it will be useful, * 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 * GNU General Public License for more details. * 13 * * 14 * You should have received a copy of the GNU General Public License* 15 * along with this program; if not, contact: * 16 * * 17 * Free Software Foundation Voice: +1-617-542-5942 * 18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 19 * Boston, MA 02110-1301, USA gnu@gnu.org * 20 * * 21 \********************************************************************/ 22 #ifndef SPLIT_REGISTER_H 23 #define SPLIT_REGISTER_H 24 25 #include <glib.h> 26 27 #include "Transaction.h" 28 #include "table-allgui.h" 29 30 /** @addtogroup GUI 31 * @{ 32 */ 33 /** @addtogroup Register 34 * @{ 35 */ 36 /** @addtogroup SplitRegister Split Register 37 * @brief GnuCash-specific ledger and journal displays based on 38 * RegisterCore. 39 * 40 * @details The split register is a spreadsheet-like area that looks like 41 * a checkbook register. It displays transactions and allows the user to 42 * edit them in-place. The register does @b not contain any of the other 43 * window decorations that one might want to have for a free standing window 44 * (e.g. menubars, * toolbars, etc.) 45 * 46 * The layout of the register is configurable. There's a broad 47 * variety of cell types to choose from: date cells that know 48 * how to parse dates, price cells that know how to parse prices, 49 * etc. These cells can be laid out in any column; even a multi-row 50 * layout is supported. The name "split register" is derived from 51 * the fact that this register can display multiple rows of 52 * transaction splits underneath a transaction title/summary row. 53 * 54 * An area for entering new transactions is provided at the bottom of 55 * the register. 56 * 57 * All user input to the register is handled by the 'cursor', which 58 * is mapped onto one of the displayed rows. 59 * 60 * @par Design Notes. 61 * Some notes about the "blank split":@n 62 * Q: What is the "blank split"?@n 63 * A: A new, empty split appended to the bottom of the ledger 64 * window. The blank split provides an area where the user 65 * can type in new split/transaction info. 66 * The "blank split" is treated in a special way for a number 67 * of reasons: 68 * - it must always appear as the bottom-most split 69 * in the Ledger window, 70 * - it must be committed if the user edits it, and 71 * a new blank split must be created. 72 * - it must be deleted when the ledger window is closed. 73 * @par 74 * To implement the above, the register "user_data" is used 75 * to store an SRInfo structure containing the blank split. 76 * 77 * @par Some notes on Commit/Rollback: 78 * There's an engine component and a gui component to the commit/rollback 79 * scheme. On the engine side, one must always call BeginEdit() 80 * before starting to edit a transaction. When you think you're done, 81 * you can call CommitEdit() to commit the changes, or RollbackEdit() to 82 * go back to how things were before you started the edit. Think of it as 83 * a one-shot mega-undo for that transaction. 84 * @par 85 * Note that the query engine uses the original values, not the currently 86 * edited values, when performing a sort. This allows your to e.g. edit 87 * the date without having the transaction hop around in the gui while you 88 * do it. 89 * @par 90 * On the gui side, commits are now performed on a per-transaction basis, 91 * rather than a per-split (per-journal-entry) basis. This means that 92 * if you have a transaction with a lot of splits in it, you can edit them 93 * all you want without having to commit one before moving to the next. 94 * @par 95 * Similarly, the "cancel" button will now undo the changes to all of the 96 * lines in the transaction display, not just to one line (one split) at a 97 * time. 98 * 99 * @par Some notes on Reloads & Redraws: 100 * Reloads and redraws tend to be heavyweight. We try to use change flags 101 * as much as possible in this code, but imagine the following scenario: 102 * @par 103 * Create two bank accounts. Transfer money from one to the other. 104 * Open two registers, showing each account. Change the amount in one window. 105 * Note that the other window also redraws, to show the new correct amount. 106 * @par 107 * Since you changed an amount value, potentially *all* displayed 108 * balances change in *both* register windows (as well as the ledger 109 * balance in the main window). Three or more windows may be involved 110 * if you have e.g. windows open for bank, employer, taxes and your 111 * entering a paycheck (or correcting a typo in an old paycheck). 112 * Changing a date might even cause all entries in all three windows 113 * to be re-ordered. 114 * @par 115 * The only thing I can think of is a bit stored with every table 116 * entry, stating 'this entry has changed since lst time, redraw it'. 117 * But that still doesn't avoid the overhead of reloading the table 118 * from the engine. 119 * 120 * The Register itself is independent of GnuCash, and is designed 121 * so that it can be used with other applications. 122 * The Ledger is an adaptation of the Register for use by GnuCash. 123 * The Ledger sets up an explicit visual layout, putting certain 124 * types of cells in specific locations (e.g. date on left, summary 125 * in middle, value at right), and hooks up these cells to 126 * the various GnuCash financial objects. 127 * 128 * This code is also theoretically independent of the actual GUI 129 * toolkit/widget-set (it once worked with both Motif and Gnome). 130 * The actual GUI-toolkit specific code is supposed to be in a 131 * GUI portability layer. Over the years, some gnome-isms may 132 * have snuck in; these should also be cleaned up. 133 * 134 * @{ 135 */ 136 /** @file split-register.h 137 * @brief API for checkbook register display area 138 * @author Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org> 139 */ 140 141 /** @brief Register types 142 * 143 * "registers" are single-account display windows. 144 * "ledgers" are multiple-account display windows */ 145 typedef enum 146 { 147 BANK_REGISTER, 148 CASH_REGISTER, 149 ASSET_REGISTER, 150 CREDIT_REGISTER, 151 LIABILITY_REGISTER, 152 INCOME_REGISTER, 153 EXPENSE_REGISTER, 154 EQUITY_REGISTER, 155 STOCK_REGISTER, 156 CURRENCY_REGISTER, 157 RECEIVABLE_REGISTER, 158 PAYABLE_REGISTER, 159 TRADING_REGISTER, 160 NUM_SINGLE_REGISTER_TYPES, 161 162 GENERAL_JOURNAL = NUM_SINGLE_REGISTER_TYPES, 163 INCOME_LEDGER, 164 PORTFOLIO_LEDGER, 165 SEARCH_LEDGER, 166 167 NUM_REGISTER_TYPES 168 } SplitRegisterType; 169 170 /** @brief Register group types 171 * 172 * used for grouping registers that have the same layout */ 173 typedef enum 174 { 175 REG_TYPE_GROUP_UNKNOWN, 176 REG_TYPE_GROUP_CURRENCY, 177 REG_TYPE_GROUP_APAR, 178 REG_TYPE_GROUP_STOCK, 179 REG_TYPE_GROUP_JOURNAL, 180 REG_TYPE_GROUP_PORTFOLIO, 181 } SplitRegisterTypeGroup; 182 183 /** Register styles */ 184 typedef enum 185 { 186 REG_STYLE_LEDGER, 187 REG_STYLE_AUTO_LEDGER, 188 REG_STYLE_JOURNAL 189 } SplitRegisterStyle; 190 191 /** @name Cell Names 192 * T* cells are transaction summary cells 193 * @{ 194 */ 195 #define ACTN_CELL "action" 196 #define DOCLINK_CELL "doclink" 197 #define BALN_CELL "balance" 198 #define CRED_CELL "credit" 199 #define DATE_CELL "date" 200 #define DDUE_CELL "date-due" 201 #define DEBT_CELL "debit" 202 #define DESC_CELL "description" 203 #define FCRED_CELL "credit-formula" 204 #define FDEBT_CELL "debit-formula" 205 #define MEMO_CELL "memo" 206 #define MXFRM_CELL "transfer" 207 #define NOTES_CELL "notes" 208 #define NUM_CELL "num" 209 #define TNUM_CELL "trans-num" 210 #define PRIC_CELL "price" 211 #define RATE_CELL "exchrate" 212 #define RECN_CELL "reconcile" 213 #define SHRS_CELL "shares" 214 #define TBALN_CELL "trans-balance" 215 #define TCRED_CELL "trans-credit" 216 #define TDEBT_CELL "trans-debit" 217 #define TSHRS_CELL "trans-shares" 218 #define TYPE_CELL "split-type" 219 #define XFRM_CELL "account" 220 #define VNOTES_CELL "void-notes" 221 #define RBALN_CELL "reg-run-balance" 222 /** @} */ 223 224 /** @name Cursor Names 225 * Cursors ending in 'NUM_ACTN' use the split action field for the NUM_CELL 226 * rather than the transaction number field which is shown in the TNUM_CELL 227 * @{ 228 */ 229 #define CURSOR_SINGLE_LEDGER "cursor-single-ledger" 230 #define CURSOR_DOUBLE_LEDGER "cursor-double-ledger" 231 #define CURSOR_DOUBLE_LEDGER_NUM_ACTN "cursor-double-ledger-num-actn" 232 #define CURSOR_SINGLE_JOURNAL "cursor-single-journal" 233 #define CURSOR_DOUBLE_JOURNAL "cursor-double-journal" 234 #define CURSOR_DOUBLE_JOURNAL_NUM_ACTN "cursor-double-journal-num-actn" 235 #define CURSOR_SPLIT "cursor-split" 236 /** @} */ 237 238 239 /** Types of cursors */ 240 typedef enum 241 { 242 CURSOR_CLASS_NONE = -1, 243 CURSOR_CLASS_SPLIT, 244 CURSOR_CLASS_TRANS, 245 NUM_CURSOR_CLASSES 246 } CursorClass; 247 248 249 /** @brief A split register created with ::gnc_split_register_new */ 250 typedef struct split_register SplitRegister; 251 typedef struct sr_info SRInfo; 252 253 /** @brief The type, style and table for the register. */ 254 struct split_register 255 { 256 Table* table; /**< The table itself that implements the underlying GUI. */ 257 258 SplitRegisterType type; 259 SplitRegisterStyle style; 260 261 gboolean use_double_line; /**< whether to use two lines per transaction */ 262 gboolean use_tran_num_for_num_field; /**< whether to use transaction number 263 or split action for number 264 field in register */ 265 gboolean show_leaf_accounts; /**< whether to show full account names */ 266 gboolean double_alt_color; /**< whether transaction use alternate colors */ 267 268 gboolean is_template; 269 gboolean do_auto_complete; /**< whether to use auto-completion */ 270 gboolean mismatched_commodities; /**< indicates the register includes transactions in 271 mismatched commodities */ 272 273 SplitList* 274 unrecn_splits; /**< list of splits to unreconcile after transaction edit */ 275 276 SRInfo* sr_info; /**< private data; outsiders should not access this */ 277 }; 278 279 /** Callback function type */ 280 typedef GtkWidget* (*SRGetParentCallback) (gpointer user_data); 281 282 283 /* Prototypes ******************************************************/ 284 285 /** Creates a new split register. 286 * 287 * @param type a ::SplitRegisterType to use for the new register 288 * 289 * @param style a ::SplitRegisterStyle to use for the new register 290 * 291 * @param use_double_line @c TRUE to show two lines for transactions, 292 * @c FALSE for one 293 * 294 * @param is_template @c TRUE for a new template, @c FALSE otherwise 295 * 296 * @return a newly created ::SplitRegister 297 */ 298 SplitRegister* gnc_split_register_new (SplitRegisterType type, 299 SplitRegisterStyle style, 300 gboolean use_double_line, 301 gboolean is_template, 302 gboolean mismatched_commodities); 303 304 /** Destroys a split register. 305 * 306 * @param reg a ::SplitRegister 307 */ 308 void gnc_split_register_destroy (SplitRegister* reg); 309 310 /** Sets a split register's type, style or line use. 311 * 312 * @param reg a ::SplitRegister 313 * 314 * @param type a ::SplitRegisterType to use for the register 315 * 316 * @param style a ::SplitRegisterStyle to use for the register 317 * 318 * @param use_double_line @c TRUE to show two lines for transactions, 319 * @c FALSE for one 320 */ 321 void gnc_split_register_config (SplitRegister* reg, 322 SplitRegisterType type, 323 SplitRegisterStyle style, 324 gboolean use_double_line); 325 326 /** Sets whether a register uses auto-completion. 327 * 328 * @param reg a ::SplitRegister 329 * 330 * @param do_auto_complete @c TRUE to use auto-completion, @c FALSE otherwise 331 */ 332 void gnc_split_register_set_auto_complete (SplitRegister* reg, 333 gboolean do_auto_complete); 334 335 /** Sets whether a register window is "read only". 336 * 337 * @param reg a ::SplitRegister 338 * 339 * @param read_only @c TRUE to use "read only" mode, @c FALSE otherwise 340 */ 341 void gnc_split_register_set_read_only (SplitRegister* reg, gboolean read_only); 342 343 /** Group registers for common layouts. 344 * @param reg a ::SplitRegister 345 * 346 * @return the ::SplitRegisterTypeGroup that groups registers together 347 */ 348 SplitRegisterTypeGroup gnc_split_register_get_register_group (SplitRegister *reg); 349 350 /** Set the template account for use in a template register. 351 * 352 * @param reg a ::SplitRegister 353 * 354 * @param template_account the account to use for the template 355 */ 356 void gnc_split_register_set_template_account (SplitRegister* reg, 357 Account* template_account); 358 359 /** Sets the user data and callback hooks for the register. */ 360 void gnc_split_register_set_data (SplitRegister* reg, gpointer user_data, 361 SRGetParentCallback get_parent); 362 363 /** Returns the class of a register's current cursor. 364 * 365 * @param reg a ::SplitRegister 366 * 367 * @return the ::CursorClass of the current cursor 368 */ 369 CursorClass gnc_split_register_get_current_cursor_class (SplitRegister* reg); 370 371 /** Returns the class of the cursor at the given virtual cell location. 372 * 373 * @param reg a ::SplitRegister 374 * 375 * @param vcell_loc the location of a virtual cell 376 * 377 * @return the ::CursorClass of the cursor at @a vcell_loc 378 */ 379 CursorClass gnc_split_register_get_cursor_class 380 (SplitRegister* reg, 381 VirtualCellLocation vcell_loc); 382 383 /** Gets the transaction at the current cursor location, which may be on 384 * the transaction itself or on any of its splits. 385 * 386 * @param reg a ::SplitRegister 387 * 388 * @return the ::Transaction at the cursor location, or @c NULL 389 */ 390 Transaction* gnc_split_register_get_current_trans (SplitRegister* reg); 391 392 /** Gets the anchoring split of the transaction at the current cursor location, 393 * which may be on the transaction itself or on any of its splits. 394 * 395 * @param reg a ::SplitRegister 396 * 397 * @param vcell_loc a pointer to be filled with the location of the 398 * transaction's virtual cell 399 * 400 * @return the anchoring ::Split of the transaction 401 */ 402 Split* 403 gnc_split_register_get_current_trans_split (SplitRegister* reg, 404 VirtualCellLocation* vcell_loc); 405 406 /** Returns the split at which the cursor is currently located. 407 * 408 * @param reg a ::SplitRegister 409 * 410 * @return the ::Split at the cursor location, or the anchoring split 411 * if the cursor is currently on a transaction 412 */ 413 Split* gnc_split_register_get_current_split (SplitRegister* reg); 414 415 /** Gets the blank split for a register. 416 * 417 * @param reg a ::SplitRegister 418 * 419 * @return the ::Split used as the blank split, or @c NULL if 420 * there currently isn't one 421 */ 422 Split* gnc_split_register_get_blank_split (SplitRegister* reg); 423 424 /** Searches the split register for a given split. 425 * The search begins from the bottom row and works backwards. The location 426 * of the first virtual cell that matches will be returned in @a vcell_loc. 427 * 428 * @param reg a ::SplitRegister 429 * 430 * @param split the ::Split to find 431 * 432 * @param vcell_loc a pointer to be filled with the location of the matching 433 * virtual cell 434 * 435 * @return @c TRUE if the split was found and the location has been stored 436 * at @a vcell_loc, @c FALSE otherwise 437 */ 438 gboolean 439 gnc_split_register_get_split_virt_loc (SplitRegister* reg, Split* split, 440 VirtualCellLocation* vcell_loc); 441 442 /** Searches the split register for the given split and determines the 443 * location of either its credit (if non-zero) or debit cell. 444 * 445 * @param reg a ::SplitRegister 446 * 447 * @param split the ::Split to find 448 * 449 * @param virt_loc a pointer to be filled with the amount cell's location 450 * 451 * @return @c TRUE if the split was found and the location has been stored 452 * at @a virt_loc, @c FALSE otherwise 453 */ 454 gboolean 455 gnc_split_register_get_split_amount_virt_loc (SplitRegister* reg, Split* split, 456 VirtualLocation* virt_loc); 457 458 /** Duplicates either the current transaction or the current split 459 * depending on the register mode and cursor position. Returns the 460 * split just created, or the 'main' split of the transaction just 461 * created, or NULL if nothing happened. */ 462 Split* gnc_split_register_duplicate_current (SplitRegister* reg); 463 464 /** Makes a copy of the current entity, either a split or a 465 * transaction, so that it can be pasted later. */ 466 void gnc_split_register_copy_current (SplitRegister* reg); 467 468 /** Equivalent to copying the current entity and the deleting it with 469 * the appropriate delete method. */ 470 void gnc_split_register_cut_current (SplitRegister* reg); 471 472 /** Pastes a previous copied entity onto the current entity, but only 473 * if the copied and current entity have the same type. */ 474 void gnc_split_register_paste_current (SplitRegister* reg); 475 476 /** Deletes the split associated with the current cursor, if both are 477 * non-NULL. Deleting the blank split just clears cursor values. */ 478 void gnc_split_register_delete_current_split (SplitRegister* reg); 479 480 /** Deletes the transaction associated with the current cursor, if both 481 * are non-NULL. */ 482 void gnc_split_register_delete_current_trans (SplitRegister* reg); 483 484 /** Voids the transaction associated with the current cursor, if 485 * non-NULL. */ 486 void gnc_split_register_void_current_trans (SplitRegister* reg, 487 const char* reason); 488 489 /** Unvoids the transaction associated with the current cursor, if 490 * non-NULL. */ 491 void gnc_split_register_unvoid_current_trans (SplitRegister* reg); 492 493 /** Deletes the non-transaction splits associated with the current 494 * cursor, if both are non-NULL. */ 495 void gnc_split_register_empty_current_trans_except_split (SplitRegister* reg, 496 Split* split); 497 void gnc_split_register_empty_current_trans (SplitRegister* reg); 498 499 /** Cancels any changes made to the current cursor, reloads the cursor 500 * from the engine, reloads the table from the cursor, and updates 501 * the GUI. The change flags are cleared. */ 502 void gnc_split_register_cancel_cursor_split_changes (SplitRegister* reg); 503 504 /** Cancels any changes made to the current pending transaction, 505 * reloads the table from the engine, and updates the GUI. The 506 * change flags are cleared. */ 507 void gnc_split_register_cancel_cursor_trans_changes (SplitRegister* reg); 508 509 /** Populates the rows of a register. 510 * 511 * The rows are filled, based on the register style, with data associated 512 * with the given list of splits @a slist. In addition, an area for the 513 * user to begin entering new transactions is placed at the tail end of the 514 * register. This area is anchored by the "blank split". 515 * 516 * The account @a default_account, if provided, is used to determine 517 * various default values for the blank split (such as currency, last check 518 * number, and transfer account) for the blank split. 519 * 520 * @param reg a ::SplitRegister 521 * 522 * @param slist a list of splits 523 * 524 * @param default_account an account to provide defaults for the blank split 525 */ 526 void gnc_split_register_load (SplitRegister* reg, GList* slist, 527 Account* default_account); 528 529 /** Copy the contents of the current cursor to a split. The split and 530 * transaction that are updated are the ones associated with the 531 * current cursor (register entry) position. If the do_commit flag 532 * is set, the transaction will also be committed. If it is the 533 * blank transaction, and the do_commit flag is set, a refresh will 534 * result in a new blank transaction. The method returns TRUE if 535 * something was changed. */ 536 gboolean gnc_split_register_save (SplitRegister* reg, gboolean do_commit); 537 538 /** Causes a redraw of the register window associated with reg. */ 539 void gnc_split_register_redraw (SplitRegister* reg); 540 541 /** Returns TRUE if the register has changed cells. */ 542 gboolean gnc_split_register_changed (SplitRegister* reg); 543 544 /** If TRUE, visually indicate the demarcation between splits with post 545 * dates prior to the present, and after. This will only make sense if 546 * the splits are ordered primarily by post date. */ 547 void gnc_split_register_show_present_divider (SplitRegister* reg, 548 gboolean show_present); 549 550 /** Expand the current transaction if it is collapsed. */ 551 void gnc_split_register_expand_current_trans (SplitRegister* reg, 552 gboolean expand); 553 554 /** Mark the current transaction as collapsed, and do callbacks. */ 555 void gnc_split_register_collapse_current_trans (SplitRegister* reg); 556 557 /** Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER. */ 558 gboolean gnc_split_register_current_trans_expanded (SplitRegister* reg); 559 560 /** Return the debit string used in the register. */ 561 const char* gnc_split_register_get_debit_string (SplitRegister* reg); 562 563 /** Return the credit string used in the register. */ 564 const char* gnc_split_register_get_credit_string (SplitRegister* reg); 565 566 /** Return TRUE if split is the blank_split. */ 567 gboolean gnc_split_register_is_blank_split (SplitRegister* reg, Split* split); 568 569 /** Change the blank_split reference from pointing to split to another 570 * split of the transaction. This is used when deleting a split after an 571 * autocomplete as the blank_split reference will be pointing to one of 572 * the splits so it does not cancel the whole transaction */ 573 void gnc_split_register_change_blank_split_ref (SplitRegister* reg, 574 Split* split); 575 576 /** Pop up the exchange-rate dialog, maybe, for the current split. 577 * If force_dialog is TRUE, the forces the dialog to be called. 578 * If the dialog does not complete successfully, then return TRUE. 579 * Return FALSE in all other cases (meaning "move on") 580 */ 581 gboolean 582 gnc_split_register_handle_exchange (SplitRegister* reg, gboolean force_dialog); 583 584 /* returns TRUE if begin_edit was aborted */ 585 gboolean 586 gnc_split_register_begin_edit_or_warn (SRInfo* info, Transaction* trans); 587 588 /** @} */ 589 /** @} */ 590 /** @} */ 591 /* -------------------------------------------------------------- */ 592 593 /** Private function -- outsiders must not use this */ 594 gboolean gnc_split_register_full_refresh_ok (SplitRegister* reg); 595 596 /** Private function -- outsiders must not use this */ 597 void gnc_copy_trans_onto_trans (Transaction* from, Transaction* to, 598 gboolean use_cut_semantics, 599 gboolean do_commit); 600 601 #endif 602