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