GnuCash c935c2f+
Loading...
Searching...
No Matches
split-register-util.c
1/********************************************************************\
2 * split-register-util.c -- split register utilities *
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
23#include <config.h>
24
25#include <glib.h>
26
27#include "gnc-date.h"
28#include "pricecell.h"
29#include "split-register-p.h"
30
31
32static QofLogModule log_module = GNC_MOD_LEDGER;
33
34
35/* The routines below create, access, and destroy the SRInfo structure
36 * used by SplitLedger routines to store data for a particular register.
37 * This is the only code that should access the user_data member of a
38 * SplitRegister directly. If additional user data is needed, just add
39 * it to the SRInfo structure above. */
40static void
41gnc_split_register_init_info (SplitRegister *reg)
42{
43 SRInfo *info;
44
45 if (reg == NULL)
46 return;
47
48 info = g_new0 (SRInfo, 1);
49
50 info->blank_split_guid = *guid_null ();
51 info->pending_trans_guid = *guid_null ();
52 info->default_account = *guid_null ();
53 info->template_account = *guid_null ();
54
55 info->last_date_entered = gnc_time64_get_today_start ();
56
57 info->first_pass = TRUE;
58 info->quickfill_setup = FALSE;
59 info->full_refresh = TRUE;
60 info->separator_changed = TRUE;
61
62 reg->sr_info = info;
63}
64
65SRInfo *
66gnc_split_register_get_info (SplitRegister *reg)
67{
68 if (!reg)
69 return NULL;
70
71 if (reg->sr_info == NULL)
72 gnc_split_register_init_info (reg);
73
74 return reg->sr_info;
75}
76
77GtkWidget *
78gnc_split_register_get_parent (SplitRegister *reg)
79{
80 SRInfo *info = gnc_split_register_get_info (reg);
81
82 if (reg == NULL)
83 return NULL;
84
85 if (info->get_parent == NULL)
86 return NULL;
87
88 return info->get_parent (info->user_data);
89}
90
91Split *
92gnc_split_register_get_split (SplitRegister *reg,
93 VirtualCellLocation vcell_loc)
94{
95 GncGUID *guid;
96
97 if (reg == NULL)
98 return NULL;
99
100 guid = gnc_table_get_vcell_data (reg->table, vcell_loc);
101 if (guid == NULL)
102 return NULL;
103
104 return xaccSplitLookup (guid, gnc_get_current_book ());
105}
106
107Account *
108gnc_split_register_get_default_account (SplitRegister *reg)
109{
110 SRInfo *info = gnc_split_register_get_info (reg);
111
112 return xaccAccountLookup (&info->default_account,
113 gnc_get_current_book ());
114}
115
116void
118 Account *template_account)
119{
120 SRInfo *info = gnc_split_register_get_info (reg);
121
122 g_return_if_fail (reg != NULL);
123
124 info->template_account = *xaccAccountGetGUID (template_account);
125}
126
127Transaction *
128gnc_split_register_get_trans (SplitRegister *reg,
129 VirtualCellLocation vcell_loc)
130{
131 Split *split;
132
133 if (!reg || !reg->table)
134 return NULL;
135
136 split = gnc_split_register_get_split (reg, vcell_loc);
137
138 if (split != NULL)
139 return xaccSplitGetParent(split);
140
141 /* Split is blank. Assume it is the blank split of a multi-line
142 * transaction. Go back one row to find a split in the transaction. */
143 vcell_loc.virt_row--;
144
145 split = gnc_split_register_get_split (reg, vcell_loc);
146
147 /* This split could be NULL during register initialization. */
148 if (split == NULL)
149 return NULL;
150
151 return xaccSplitGetParent(split);
152}
153
154Split *
155gnc_split_register_get_trans_split (SplitRegister *reg,
156 VirtualCellLocation vcell_loc,
157 VirtualCellLocation *trans_split_loc)
158{
159 CursorClass cursor_class;
160
161 if (reg == NULL)
162 return NULL;
163
164 while (TRUE)
165 {
166 if ((0 > vcell_loc.virt_row) || (0 > vcell_loc.virt_col))
167 {
168 PERR ("bad row\n");
169 return NULL;
170 }
171
172 cursor_class = gnc_split_register_get_cursor_class (reg, vcell_loc);
173
174 if (cursor_class == CURSOR_CLASS_TRANS)
175 {
176 if (trans_split_loc)
177 *trans_split_loc = vcell_loc;
178
179 return gnc_split_register_get_split (reg, vcell_loc);
180 }
181
182 vcell_loc.virt_row--;
183 }
184}
185
186Split *
188 SplitRegister *reg, VirtualCellLocation *trans_split_loc)
189{
190 VirtualCellLocation vcell_loc;
191
192 if (reg == NULL)
193 return NULL;
194
195 vcell_loc = reg->table->current_cursor_loc.vcell_loc;
196
197 return gnc_split_register_get_trans_split (reg, vcell_loc, trans_split_loc);
198}
199
200gboolean
201gnc_split_register_find_split (SplitRegister *reg,
202 Transaction *trans, Split *trans_split,
203 Split *split, CursorClass find_class,
204 VirtualCellLocation *vcell_loc)
205{
206 Table *table = reg->table;
207 gboolean found_trans = FALSE;
208 gboolean found_trans_split = FALSE;
209 gboolean found_something = FALSE;
210 CursorClass cursor_class;
211 int v_row, v_col;
212 Transaction *t;
213 Split *s;
214
215 for (v_row = 1; v_row < table->num_virt_rows; v_row++)
216 for (v_col = 0; v_col < table->num_virt_cols; v_col++)
217 {
218 VirtualCellLocation vc_loc = { v_row, v_col };
219
220 s = gnc_split_register_get_split (reg, vc_loc);
221 t = xaccSplitGetParent(s);
222
223 cursor_class = gnc_split_register_get_cursor_class (reg, vc_loc);
224
225 if (t == trans)
226 {
227 /* A register entry for the correct transaction. */
228 found_trans = TRUE;
229
230 if (cursor_class == CURSOR_CLASS_TRANS)
231 {
232 /* This row is the transaction split for this transaction. */
233 if (s == trans_split)
234 /* It's the copy of the transaction that we want. */
235 found_trans_split = TRUE;
236 else
237 found_trans_split = FALSE;
238
239 if (find_class == CURSOR_CLASS_TRANS &&
240 (s == split || reg->style == REG_STYLE_JOURNAL))
241 {
242 /* We're looking for a transaction split and this is the split we're looking for
243 or there is only one entry for this transaction in this register (since it's
244 a journal style register) so we must return the only transaction split there is. */
245 if (vcell_loc != NULL)
246 *vcell_loc = vc_loc;
247 return TRUE;
248 }
249 }
250 }
251 else
252 {
253 /* Not the correct transaction. We shouldn't get here if these are true, but just
254 to be safe reset them. */
255 found_trans = FALSE;
256 found_trans_split = FALSE;
257 }
258
259 if (found_trans && (s == split) && s)
260 {
261 /* We're on the right transaction, but perhaps not the copy of it we want, and
262 this is the correct split, return it if we don't find anything better. */
263 if (vcell_loc != NULL)
264 *vcell_loc = vc_loc;
265
266 found_something = TRUE;
267 }
268
269 if (found_trans_split && (s == split))
270 {
271 /* We're on the right copy of the right transaction, and this is the split we
272 want, return it (it should be the right class since if we wanted a transaction
273 split we would have returned it above. */
274 if (vcell_loc != NULL)
275 *vcell_loc = vc_loc;
276
277 if (cursor_class == find_class)
278 return TRUE;
279 }
280 }
281
282 return found_something;
283}
284
285void
286gnc_split_register_show_trans (SplitRegister *reg,
287 VirtualCellLocation start_loc)
288{
289 VirtualCellLocation end_loc;
290 int v_row;
291
292 end_loc = start_loc;
293
294 for (v_row = end_loc.virt_row + 1;
295 v_row < reg->table->num_virt_rows; v_row++)
296 {
297 VirtualCellLocation vc_loc = { v_row, 0 };
298 CursorClass cursor_class;
299
300 cursor_class = gnc_split_register_get_cursor_class (reg, vc_loc);
301 if (cursor_class == CURSOR_CLASS_TRANS)
302 break;
303
304 if (cursor_class != CURSOR_CLASS_SPLIT)
305 {
306 v_row--;
307 break;
308 }
309 }
310
311 end_loc.virt_row = MIN (v_row, reg->table->num_virt_rows - 1);
312
313 gnc_table_show_range (reg->table, start_loc, end_loc);
314}
315
316void
318 VirtualCellLocation vcell_loc,
319 gboolean visible,
320 gboolean only_blank_split)
321{
322 CursorClass cursor_class;
323
324 while (TRUE)
325 {
326 vcell_loc.virt_row++;
327
328 cursor_class = gnc_split_register_get_cursor_class (reg, vcell_loc);
329 if (cursor_class != CURSOR_CLASS_SPLIT)
330 return;
331
332 if (only_blank_split && gnc_split_register_get_split (reg, vcell_loc))
333 continue;
334
335 gnc_table_set_virt_cell_visible (reg->table, vcell_loc, visible);
336 }
337}
338
339void
340gnc_split_register_set_cell_fractions (SplitRegister *reg, Split *split)
341{
342 Account *split_account;
343 Account *reg_account;
344 Transaction *trans;
345 gnc_commodity *trans_currency; /* or default currency if no transaction */
346 PriceCell *cell;
347 int fraction;
348 gboolean trading_accts;
349 gnc_commodity *commodity;
350
351 /* This function must use the same algorithm as gnc_split_register_get_shares_entry
352 and gnc_split_register_get_debcred_entry. Changes here may require changes in
353 one of them or vice versa. */
354
355 /* If the split has a new account use that, otherwise use the one it
356 had before we started editing it. */
357 split_account = gnc_split_register_get_account (reg, XFRM_CELL);
358 if (!split_account)
359 split_account = xaccSplitGetAccount (split);
360
361 reg_account = gnc_split_register_get_default_account (reg);
362
363 trans = xaccSplitGetParent (split);
364 if (trans)
365 {
366 trading_accts = xaccTransUseTradingAccounts (trans);
367 trans_currency = xaccTransGetCurrency (trans);
368 }
369 else
370 {
371 /* It should be ok to use the current book since that's what
372 gnc_split_register_get_account uses to find the account. */
373 trading_accts = qof_book_use_trading_accounts (gnc_get_current_book());
374 trans_currency = gnc_default_currency();
375 }
376
377 /* What follows is similar to the tests in gnc_split_register_get_debcred_entry */
378 if (trading_accts)
379 {
380 if (reg->type == STOCK_REGISTER ||
381 reg->type == CURRENCY_REGISTER ||
382 reg->type == PORTFOLIO_LEDGER)
383 {
384 /* These tests are similar to gnc_split_register_use_security_cells */
385 if (!split_account)
386 commodity = trans_currency;
387 else if (trading_accts &&
389 commodity = trans_currency;
390 else if (xaccAccountIsPriced (split_account))
391 commodity = trans_currency;
392 else
393 commodity = xaccAccountGetCommodity (split_account);
394 }
395 else
396 {
397 commodity = xaccAccountGetCommodity (split_account);
398 }
399 }
400 else
401 {
402 /* Not trading accounts */
403 if (reg->type == STOCK_REGISTER ||
404 reg->type == CURRENCY_REGISTER ||
405 reg->type == PORTFOLIO_LEDGER)
406 commodity = trans_currency;
407 else
408 commodity = xaccAccountGetCommodity (reg_account);
409 }
410 if (!commodity)
411 commodity = gnc_default_currency ();
412
413 fraction = gnc_commodity_get_fraction (commodity);
414
415 cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
416 DEBT_CELL);
417 gnc_price_cell_set_fraction (cell, fraction);
418
419 cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
420 CRED_CELL);
421 gnc_price_cell_set_fraction (cell, fraction);
422
423 cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
424 SHRS_CELL);
425
426 /* gnc_split_register_get_shares_entry always uses the split's commodity */
427 if (split_account)
429 else
431}
432
433CellBlock *
434gnc_split_register_get_passive_cursor (SplitRegister *reg)
435{
436 const char *cursor_name = NULL;
437
438 switch (reg->style)
439 {
440 case REG_STYLE_LEDGER:
441 case REG_STYLE_AUTO_LEDGER:
442 cursor_name = reg->use_double_line ?
443 (reg->use_tran_num_for_num_field ? CURSOR_DOUBLE_LEDGER
444 : CURSOR_DOUBLE_LEDGER_NUM_ACTN)
445 : CURSOR_SINGLE_LEDGER;
446 break;
447
448 case REG_STYLE_JOURNAL:
449 cursor_name = reg->use_double_line ?
450 (reg->use_tran_num_for_num_field ? CURSOR_DOUBLE_JOURNAL
451 : CURSOR_DOUBLE_JOURNAL_NUM_ACTN)
452 : CURSOR_SINGLE_JOURNAL;
453 break;
454 }
455
456 if (!cursor_name)
457 {
458 PWARN ("bad register style");
459 return NULL;
460 }
461
462 return gnc_table_layout_get_cursor (reg->table->layout, cursor_name);
463}
464
465CellBlock *
466gnc_split_register_get_active_cursor (SplitRegister *reg)
467{
468 SRInfo *info = gnc_split_register_get_info (reg);
469 const char *cursor_name = NULL;
470
471 switch (reg->style)
472 {
473 case REG_STYLE_LEDGER:
474 if (!info->trans_expanded)
475 {
476 cursor_name = reg->use_double_line ?
477 (reg->use_tran_num_for_num_field ? CURSOR_DOUBLE_LEDGER
478 : CURSOR_DOUBLE_LEDGER_NUM_ACTN)
479 : CURSOR_SINGLE_LEDGER;
480 break;
481 }
482
483 /* fall through */
484 case REG_STYLE_AUTO_LEDGER:
485 case REG_STYLE_JOURNAL:
486 cursor_name = reg->use_double_line ?
487 (reg->use_tran_num_for_num_field ? CURSOR_DOUBLE_JOURNAL
488 : CURSOR_DOUBLE_JOURNAL_NUM_ACTN)
489 : CURSOR_SINGLE_JOURNAL;
490 break;
491 }
492
493 if (!cursor_name)
494 {
495 PWARN ("bad register style");
496 return NULL;
497 }
498
499 return gnc_table_layout_get_cursor (reg->table->layout, cursor_name);
500}
501
502void
503gnc_split_register_set_last_num (SplitRegister *reg, const char *num)
504{
505 Account *account;
506
507 account = gnc_split_register_get_default_account (reg);
508 if (!account)
509 return;
510
511 xaccAccountSetLastNum (account, num);
512}
513
514static CursorClass
515gnc_split_register_cursor_class (SplitRegister *reg,
516 CellBlock *cursor)
517{
518 if (cursor == NULL)
519 return CURSOR_CLASS_NONE;
520
521 return gnc_split_register_cursor_name_to_class (cursor->cursor_name);
522}
523
526 VirtualCellLocation vcell_loc)
527{
528 VirtualCell *vcell;
529 Table *table;
530
531 if (reg == NULL)
532 return CURSOR_CLASS_NONE;
533
534 table = reg->table;
535 if (table == NULL)
536 return CURSOR_CLASS_NONE;
537
538 vcell = gnc_table_get_virtual_cell (table, vcell_loc);
539 if (vcell == NULL)
540 return CURSOR_CLASS_NONE;
541
542 return gnc_split_register_cursor_class (reg, vcell->cellblock);
543}
544
547{
548 Table *table;
549
550 if (reg == NULL)
551 return CURSOR_CLASS_NONE;
552
553 table = reg->table;
554 if (table == NULL)
555 return CURSOR_CLASS_NONE;
556
557 return gnc_split_register_cursor_class (reg, table->current_cursor);
558}
559
561gnc_split_register_cursor_name_to_class (const char *cursor_name)
562{
563 if (cursor_name == NULL)
564 return CURSOR_CLASS_NONE;
565
566 if (strcmp (cursor_name, CURSOR_SINGLE_LEDGER) == 0 ||
567 strcmp (cursor_name, CURSOR_DOUBLE_LEDGER) == 0 ||
568 strcmp (cursor_name, CURSOR_DOUBLE_LEDGER_NUM_ACTN) == 0 ||
569 strcmp (cursor_name, CURSOR_SINGLE_JOURNAL) == 0 ||
570 strcmp (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0 ||
571 strcmp (cursor_name, CURSOR_DOUBLE_JOURNAL_NUM_ACTN) == 0)
572 return CURSOR_CLASS_TRANS;
573
574 if (strcmp (cursor_name, CURSOR_SPLIT) == 0)
575 return CURSOR_CLASS_SPLIT;
576
577 return CURSOR_CLASS_NONE;
578}
Date and Time handling routines.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition Account.cpp:2745
#define xaccAccountGetGUID(X)
Definition Account.h:252
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false.
Definition Account.cpp:4551
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition Account.cpp:4692
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
gboolean qof_book_use_trading_accounts(const QofBook *book)
Returns flag indicating whether this book uses trading accounts.
Definition qofbook.cpp:921
void gnc_price_cell_set_fraction(PriceCell *cell, int fraction)
Sets the fraction used for rounding.
Definition pricecell.c:242
#define GNC_COMMODITY_MAX_FRACTION
Max fraction is 10^9 because 10^10 would require changing it to an int64_t.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency.
time64 gnc_time64_get_today_start(void)
The gnc_time64_get_today_start() routine returns a time64 value corresponding to the first second of ...
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition guid.cpp:165
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
void gnc_split_register_set_template_account(SplitRegister *reg, Account *template_account)
Set the template account for use in a template register.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
void gnc_split_register_set_trans_visible(SplitRegister *reg, VirtualCellLocation vcell_loc, gboolean visible, gboolean only_blank_split)
Set the visibility of the split rows belonging to a transaction located at vcell_loc.
CursorClass
Types of cursors.
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
void gnc_table_set_virt_cell_visible(Table *table, VirtualCellLocation vcell_loc, gboolean visible)
Set the visibility flag for a particular location.
gpointer gnc_table_get_vcell_data(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell data associated with a cursor located at the given virtual coords,...
void gnc_table_show_range(Table *table, VirtualCellLocation start_loc, VirtualCellLocation end_loc)
Try to show the whole range in the register.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id,...
Definition Split.cpp:1091
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
private declarations for SplitRegister
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
The PriceCell object implements a cell handler that stores a single double-precision value,...
Definition pricecell.h:55
holds information about each virtual cell.