GnuCash  5.6-150-g038405b370+
dialog-lot-viewer.c
1 /*******************************************************************\
2  * dialog-lot-viewer.c -- a basic lot viewer for GnuCash *
3  * Copyright (C) 2003 Linas Vepstas <linas@linas.org> *
4  * Copyright (C) 2011 Geert Janssens <geert@kobaltwit.be> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \********************************************************************/
24 
25 /* XXX todo: The button "view lot in register" is not implemented.
26  * it needs to open register window showing only the splits in the
27  * given lot ...
28  */
29 
30 #include <config.h>
31 
32 #include <gtk/gtk.h>
33 #include <glib/gi18n.h>
34 
35 #include "Account.h"
36 #include "cap-gains.h"
37 #include "gnc-commodity.h"
38 #include "qof.h"
39 #include "gnc-lot.h"
40 #include "Scrub3.h"
41 #include "ScrubBusiness.h"
42 #include "Transaction.h"
43 #include "engine-helpers.h"
44 #include "gncInvoice.h"
45 
46 #include "dialog-utils.h"
47 #include "dialog-lot-viewer.h"
48 #include "gnc-component-manager.h"
49 #include "gnc-event.h"
50 #include "gnc-prefs.h"
51 #include "gnc-ui-util.h"
52 #include "gnc-session.h"
53 #include "gnc-window.h"
54 #include "misc-gnome-utils.h"
55 #include "tree-view-utils.h"
56 
57 #define LOT_VIEWER_CM_CLASS "dialog-lot-viewer"
58 
59 enum lot_cols
60 {
61  LOT_COL_TYPE = 0,
62  LOT_COL_OPEN,
63  LOT_COL_CLOSE,
64  LOT_COL_TITLE,
65  LOT_COL_BALN,
66  LOT_COL_BALN_DOUBLE, // used only for sorting
67  LOT_COL_GAINS,
68  LOT_COL_GAINS_DOUBLE, // used only for sorting
69  LOT_COL_PNTR,
70  NUM_LOT_COLS
71 };
72 
73 enum split_cols
74 {
75  SPLIT_COL_DATE = 0,
76  SPLIT_COL_NUM,
77  SPLIT_COL_DESCRIPTION,
78  SPLIT_COL_AMOUNT,
79  SPLIT_COL_AMOUNT_DOUBLE, // used only for sorting
80  SPLIT_COL_VALUE,
81  SPLIT_COL_VALUE_DOUBLE, // used only for sorting
82  SPLIT_COL_GAIN_LOSS,
83  SPLIT_COL_GAIN_LOSS_DOUBLE, // used only for sorting
84  SPLIT_COL_BALANCE,
85  SPLIT_COL_BALANCE_DOUBLE, // used only for sorting
86  SPLIT_COL_PNTR,
87  NUM_SPLIT_COLS
88 };
89 
90 #define RESPONSE_VIEW 1
91 #define RESPONSE_DELETE 2
92 #define RESPONSE_SCRUB_LOT 3
93 #define RESPONSE_SCRUB_ACCOUNT 4
94 #define RESPONSE_NEW_LOT 5
95 
96 #define GNC_PREFS_GROUP "dialogs.lot-viewer"
97 #define GNC_PREF_HPOS "hpane-position"
98 #define GNC_PREF_VPOS "vpane-position"
99 
101 {
102  GtkWidget * window;
103 #ifdef LOTS_READY_FOR_SHOWTIME
104  GtkButton * regview_button;
105 #endif
106  GtkButton * delete_button;
107  GtkButton * scrub_lot_button;
108  GtkButton * new_lot_button;
109  GtkTreeView * lot_view;
110  GtkListStore * lot_store;
111  GtkTextView * lot_notes;
112  GtkEntry * title_entry;
113  GtkTreeView * split_in_lot_view;
114  GtkListStore * split_in_lot_store;
115  GtkTreeView * split_free_view;
116  GtkListStore * split_free_store;
117  GtkWidget * split_hpaned;
118  GtkButton * add_split_to_lot_button;
119  GtkButton * remove_split_from_lot_button;
120  GtkToggleButton * only_show_open_lots_checkbutton;
121  GtkToggleButton * show_adjusted_amounts_checkbutton;
122 
123  Account * account;
124  GNCLot * selected_lot;
125  gint component_id;
126  GncGUID account_id;
127 };
128 
129 static void gnc_lot_viewer_fill (GNCLotViewer *lv);
130 static void gnc_split_viewer_fill (GNCLotViewer *lv, GtkListStore *store, SplitList *split_list);
131 
132 /* ======================================================================== */
133 /* Callback prototypes */
134 
135 void lv_title_entry_changed_cb (GtkEntry *ent, gpointer user_data);
136 void lv_response_cb (GtkDialog *dialog, gint response, gpointer data);
137 void lv_window_destroy_cb (GtkWidget *object, gpointer user_data);
138 
139 /* ======================================================================== */
140 /* Get the realized gains for this lot. This routine or a variant of it
141  * should probably be moved to gnc-lot.c.
142  * The conceptual difficulty here is that this works only if all of the
143  * realized gains in the lot are of the
144  */
145 
146 static gnc_commodity *
147 find_first_currency (GNCLot *lot)
148 {
149  SplitList *split_list, *node;
150 
151  split_list = gnc_lot_get_split_list (lot);
152  for (node = split_list; node; node = node->next)
153  {
154  Split *s = node->data;
155  Transaction *trans;
156  if (FALSE == gnc_numeric_zero_p (xaccSplitGetAmount (s))) continue;
157  trans = xaccSplitGetParent (s);
158  return xaccTransGetCurrency (trans);
159  }
160  return NULL;
161 }
162 
163 static gnc_numeric
164 get_realized_gains (GNCLot *lot, gnc_commodity *currency)
165 {
166  gnc_numeric zero = gnc_numeric_zero ();
167  gnc_numeric gains = zero;
168  SplitList *split_list, *node;
169 
170  if (!currency) return zero;
171 
172  split_list = gnc_lot_get_split_list (lot);
173  for (node = split_list; node; node = node->next)
174  {
175  Split *s = node->data;
176  Transaction *trans;
177 
178  if (FALSE == gnc_numeric_zero_p (xaccSplitGetAmount (s))) continue;
179  trans = xaccSplitGetParent (s);
180  if (FALSE == gnc_commodity_equal (xaccTransGetCurrency (trans), currency)) continue;
181 
183  }
184  return gains;
185 }
186 
187 
188 /* ======================================================================== */
189 /* Populate the lot split list view based on the currently selected lot */
190 
191 static void
192 lv_show_splits_in_lot (GNCLotViewer *lv)
193 {
194  GNCLot *lot = lv->selected_lot;
195  SplitList *split_list;
196 
197  if (NULL == lot) return;
198 
199  split_list = gnc_lot_get_split_list (lot);
200  gnc_split_viewer_fill (lv, lv->split_in_lot_store, split_list);
201 }
202 
203 /* ======================================================================== */
204 /* Populate the free split list view */
205 
206 static void
207 lv_show_splits_free (GNCLotViewer *lv)
208 {
209  SplitList *split_list, *node;
210  SplitList *filtered_list = NULL;
211 
212  /* get splits */
213  split_list = xaccAccountGetSplitList (lv->account);
214 
215  /* filter splits */
216  for (node = split_list; node; node = node->next)
217  {
218  Split *split = node->data;
219  if (NULL == xaccSplitGetLot (split))
220  {
221  filtered_list = g_list_prepend (filtered_list, split);
222  }
223  }
224  filtered_list = g_list_reverse (filtered_list);
225 
226  /* display list */
227  gnc_split_viewer_fill (lv, lv->split_free_store, filtered_list);
228  g_list_free (filtered_list);
229  g_list_free (split_list);
230 }
231 
232 /* ======================================================================== */
233 /* Save potential changes to the currently selected lot */
234 
235 static void
236 lv_save_current_lot (GNCLotViewer *lv)
237 {
238  GNCLot *lot = lv->selected_lot;
239  const char * str;
240  char * notes;
241 
242  if (lot)
243  {
244  gnc_lot_begin_edit (lot);
245 
246  /* Get the title, save_the_title */
247  str = gtk_entry_get_text (lv->title_entry);
248  gnc_lot_set_title (lot, str);
249 
250  /* Get the notes, save the notes */
251  notes = xxxgtk_textview_get_text (lv->lot_notes);
252  gnc_lot_set_notes (lot, notes);
253  g_free (notes);
254 
255  gnc_lot_commit_edit (lot);
256  }
257 }
258 
259 /* ======================================================================== */
260 /* Clear all information related to the currently selected lot */
261 
262 static void
263 lv_unset_lot (GNCLotViewer *lv)
264 {
265  /* Set immediately, to avoid recursion in gtkentry "changed" cb. */
266  lv->selected_lot = NULL;
267 
268  /* Blank the title widget */
269  gtk_entry_set_text (lv->title_entry, "");
270  gtk_editable_set_editable (GTK_EDITABLE(lv->title_entry), FALSE);
271 
272  /* Blank the notes area */
273  xxxgtk_textview_set_text (lv->lot_notes, "");
274  gtk_text_view_set_editable (lv->lot_notes, FALSE);
275 
276  /* Erase the mini-view area */
277  gtk_list_store_clear (lv->split_in_lot_store);
278 
279 #ifdef LOTS_READY_FOR_SHOWTIME
280  gtk_widget_set_sensitive (GTK_WIDGET(lv->regview_button), FALSE);
281 #endif
282  gtk_widget_set_sensitive (GTK_WIDGET(lv->delete_button), FALSE);
283  gtk_widget_set_sensitive (GTK_WIDGET(lv->scrub_lot_button), FALSE);
284 }
285 
286 /* ======================================================================== */
287 /* Select a row in the lot list */
288 
289 static void
290 lv_select_row (GNCLotViewer *lv,
291  GNCLot *lot)
292 {
293  const char * str;
294 
295  lv_save_current_lot (lv);
296 
297  str = gnc_lot_get_title (lot);
298  if (!str) str = "";
299  gtk_entry_set_text (lv->title_entry, str);
300  gtk_editable_set_editable (GTK_EDITABLE(lv->title_entry), TRUE);
301 
302  /* Set the notes field */
303  str = gnc_lot_get_notes (lot);
304  if (!str) str = "";
305  xxxgtk_textview_set_text (lv->lot_notes, str);
306  gtk_text_view_set_editable (lv->lot_notes, TRUE);
307 
308  /* Don't set until end, to avoid recursion in gtkentry "changed" cb. */
309  lv->selected_lot = lot;
310  lv_show_splits_in_lot (lv);
311 
312 #ifdef LOTS_READY_FOR_SHOWTIME
313  gtk_widget_set_sensitive (GTK_WIDGET(lv->regview_button), TRUE);
314 #endif
315  gtk_widget_set_sensitive (GTK_WIDGET(lv->delete_button), TRUE);
316  gtk_widget_set_sensitive (GTK_WIDGET(lv->scrub_lot_button), TRUE);
317 }
318 
319 /* ======================================================================== */
320 /* Un-select a row of the lot list */
321 
322 static void
323 lv_unselect_row (GNCLotViewer *lv)
324 {
325  lv_save_current_lot (lv);
326  lv_unset_lot (lv);
327 }
328 
329 /* ======================================================================== */
330 /* Populate the lot list view */
331 
332 static void
333 gnc_lot_viewer_fill (GNCLotViewer *lv)
334 {
335  LotList *lot_list = xaccAccountGetLotList (lv->account);
336  GNCLot *this_lot, *selected_lot = NULL;
337  GtkListStore *store;
338  GtkTreeModel *model;
339  GtkTreeIter iter;
340  GtkTreeSelection *selection = gtk_tree_view_get_selection (lv->lot_view);
341  gboolean found = FALSE;
342  gboolean is_business_lot = xaccAccountIsAPARType (xaccAccountGetType (lv->account));
343  gboolean show_only_open_lots = gtk_toggle_button_get_active (lv->only_show_open_lots_checkbutton);
344 
345  if (gtk_tree_selection_get_selected (selection, &model, &iter))
346  gtk_tree_model_get (model, &iter, LOT_COL_PNTR, &selected_lot, -1);
347 
348  /* Crazy. Should update in place if possible. */
349  gtk_list_store_clear (lv->lot_store);
350 
351  for (LotList *node = lot_list; node; node = node->next)
352  {
353  char type_buff[200];
354  char baln_buff[200];
355  char gain_buff[200];
356  GNCLot *lot = node->data;
357  Split *esplit = gnc_lot_get_earliest_split (lot);
358  gnc_numeric amt_baln = gnc_lot_get_balance (lot);
359  gnc_commodity *currency = find_first_currency (lot);
360  gnc_numeric gains_baln = get_realized_gains (lot, currency);
361 
362  /* Skip closed lots when only open should be shown */
363  if (show_only_open_lots && gnc_lot_is_closed (lot))
364  {
365  continue;
366  }
367 
368  store = lv->lot_store;
369  gtk_list_store_append (store, &iter);
370 
371  /* Part of invoice */
372  type_buff[0] = '\0';
373  if ( NULL != gncInvoiceGetInvoiceFromLot (lot) )
374  {
375  snprintf (type_buff, 200, "I");
376  }
377  gtk_list_store_set (store, &iter, LOT_COL_TYPE, type_buff, -1);
378 
379  /* Opening date */
380  if (esplit)
381  {
382  Transaction *etrans = xaccSplitGetParent (esplit);
383  time64 open_date = xaccTransGetDate (etrans);
384  gtk_list_store_set (store, &iter, LOT_COL_OPEN, open_date, -1);
385  }
386  else
387  gtk_list_store_set (store, &iter, LOT_COL_OPEN, G_MININT64, -1);
388 
389  /* Closing date */
390  if (gnc_lot_is_closed (lot))
391  {
392  Split *fsplit = gnc_lot_get_latest_split (lot);
393  Transaction *ftrans = xaccSplitGetParent (fsplit);
394  time64 close_date = xaccTransGetDate (ftrans);
395 
396  gtk_list_store_set (store, &iter, LOT_COL_CLOSE, close_date, -1);
397  }
398  else
399  {
400  gtk_list_store_set (store, &iter, LOT_COL_CLOSE, G_MAXINT64, -1);
401  }
402 
403  /* Title */
404  gtk_list_store_set (store, &iter, LOT_COL_TITLE, gnc_lot_get_title (lot), -1);
405 
406  /* Amount */
407  xaccSPrintAmount (baln_buff, amt_baln,
408  gnc_account_print_info (lv->account, is_business_lot));
409  gtk_list_store_set (store, &iter, LOT_COL_BALN, baln_buff, -1);
410  gtk_list_store_set (store, &iter, LOT_COL_BALN_DOUBLE, gnc_numeric_to_double (amt_baln), -1);
411 
412  /* Capital Gains/Losses Appreciation/Depreciation */
413  xaccSPrintAmount (gain_buff, gains_baln,
414  gnc_commodity_print_info (currency, TRUE));
415  gtk_list_store_set (store, &iter, LOT_COL_GAINS, gain_buff, -1);
416  gtk_list_store_set (store, &iter, LOT_COL_GAINS_DOUBLE, gnc_numeric_to_double (gains_baln), -1);
417 
418  /* Self-reference */
419  gtk_list_store_set (store, &iter, LOT_COL_PNTR, lot, -1);
420  }
421  g_list_free (lot_list);
422 
423  /* re-select the row that the user had previously selected,
424  * if possible. */
425  if (selected_lot)
426  {
427  model = GTK_TREE_MODEL (lv->lot_store);
428  if (gtk_tree_model_get_iter_first (model, &iter))
429  {
430  do
431  {
432  gtk_tree_model_get (model, &iter, LOT_COL_PNTR, &this_lot, -1);
433  if (this_lot == selected_lot)
434  {
435  gtk_tree_selection_select_iter (selection, &iter);
436  found = TRUE;
437  break;
438  }
439  }
440  while (gtk_tree_model_iter_next (model, &iter));
441  }
442  }
443 
444  if (!found)
445  gtk_tree_selection_unselect_all (selection);
446 }
447 
448 /* ======================================================================== */
449 /* Get selected split in a split list view */
450 
451 static Split *
452 lv_get_selected_split (GNCLotViewer *lv, GtkTreeView *view)
453 {
454  Split *split = NULL;
455  GtkTreeModel *model;
456  GtkTreeSelection *selection;
457  GtkTreeIter iter;
458 
459  selection = gtk_tree_view_get_selection (view);
460  if (gtk_tree_selection_get_selected (selection, &model, &iter))
461  {
462  gtk_tree_model_get (model, &iter, SPLIT_COL_PNTR, &split, -1);
463  }
464 
465  return split;
466 }
467 
468 /* ======================================================================== */
469 /* Check if split is main invoice split in lot */
470 
471 static gboolean
472 lv_can_remove_split_from_lot (Split * split, GNCLot * lot)
473 {
474  GncInvoice *lot_invoice, *txn_invoice;
475  Transaction *txn;
476 
477  lot_invoice = gncInvoiceGetInvoiceFromLot (lot);
478  txn = xaccSplitGetParent (split);
479  txn_invoice = gncInvoiceGetInvoiceFromTxn (txn);
480  if ( lot_invoice != NULL && lot_invoice == txn_invoice )
481  return FALSE;
482 
483  return TRUE;
484 }
485 
486 /* ======================================================================== */
487 /* Populate a split list view */
488 
489 static void
490 gnc_split_viewer_fill (GNCLotViewer *lv, GtkListStore *store, SplitList *split_list)
491 {
492  gboolean is_business_lot = xaccAccountIsAPARType (xaccAccountGetType (lv->account));
493  gboolean show_adjusted_amounts = gtk_toggle_button_get_active (lv->show_adjusted_amounts_checkbutton);
494  gnc_numeric baln = gnc_numeric_zero ();
495 
496  gtk_list_store_clear (store);
497 
498  for (SplitList *node = split_list; node; node = node->next)
499  {
500  Split *split = node->data;
501  char amtbuff[200];
502  char valbuff[200];
503  char gainbuff[200];
504  char balnbuff[200];
505  gnc_commodity *currency;
506  Transaction *trans = xaccSplitGetParent (split);
507  time64 date = xaccTransGetDate (trans);
508  gnc_numeric amnt = xaccSplitGetAdjustedAmount (split);
509  gnc_numeric value, gain;
510  GtkTreeIter iter;
511 
512  /* Do not show gains splits, however do show empty business splits */
513  if (!is_business_lot && gnc_numeric_zero_p (amnt)) continue;
514 
515  if (xaccSplitIsStockSplit (split)) continue;
516 
517  gtk_list_store_append (store, &iter);
518 
519  /* Date */
520  gtk_list_store_set (store, &iter, SPLIT_COL_DATE, date, -1);
521 
522  /* Num - retrieve number based on book option */
523  gtk_list_store_set (store, &iter, SPLIT_COL_NUM,
524  gnc_get_num_action (trans, split), -1);
525 
526  /* Description */
527  gtk_list_store_set (store, &iter, SPLIT_COL_DESCRIPTION, xaccTransGetDescription (trans), -1);
528 
529  /* Amount */
530  xaccSPrintAmount (amtbuff, show_adjusted_amounts ? amnt : xaccSplitGetAmount (split),
531  gnc_account_print_info (lv->account, is_business_lot));
532  gtk_list_store_set (store, &iter, SPLIT_COL_AMOUNT, amtbuff, -1);
533  gtk_list_store_set (store, &iter, SPLIT_COL_AMOUNT_DOUBLE, gnc_numeric_to_double (amnt), -1);
534 
535  /* Value.
536  * For non-business accounts which are part of a lot,
537  * invert the sign on the first. */
538  currency = xaccTransGetCurrency (trans);
539  value = xaccSplitGetValue (split);
540  if (lv->selected_lot && !is_business_lot && (node != split_list))
541  value = gnc_numeric_neg (value);
542  xaccSPrintAmount (valbuff, value,
543  gnc_commodity_print_info (currency, TRUE));
544  gtk_list_store_set (store, &iter, SPLIT_COL_VALUE, valbuff, -1);
545  gtk_list_store_set (store, &iter, SPLIT_COL_VALUE_DOUBLE, gnc_numeric_to_double (value), -1);
546 
547  /* Gains. Blank if none. */
548  gain = (store == lv->split_in_lot_store) ?
549  xaccSplitGetCapGains (split) : xaccLotFreeSplitCapGain (split, lv->selected_lot);
550  if (gnc_numeric_zero_p (gain))
551  {
552  gainbuff[0] = 0;
553  }
554  else
555  {
556  xaccSPrintAmount (gainbuff, gain,
557  gnc_commodity_print_info (currency, TRUE));
558  }
559  gtk_list_store_set (store, &iter, SPLIT_COL_GAIN_LOSS, gainbuff, -1);
560  gtk_list_store_set (store, &iter, SPLIT_COL_GAIN_LOSS_DOUBLE, gnc_numeric_to_double (gain), -1);
561 
562  /* Balance of Amounts */
563  baln = gnc_numeric_add_fixed (baln, amnt);
564  if (gnc_numeric_zero_p (baln))
565  {
566  balnbuff[0] = 0;
567  }
568  else
569  {
570  xaccSPrintAmount (balnbuff, baln,
571  gnc_account_print_info (lv->account, is_business_lot));
572  }
573  gtk_list_store_set (store, &iter, SPLIT_COL_BALANCE, balnbuff, -1);
574  gtk_list_store_set (store, &iter, SPLIT_COL_BALANCE_DOUBLE, gnc_numeric_to_double (baln), -1);
575 
576  /* Self-reference */
577  gtk_list_store_set (store, &iter, SPLIT_COL_PNTR, split, -1);
578  }
579 }
580 
581 /* ======================================================================== */
582 
583 static void
584 lv_update_split_buttons (GNCLotViewer *lv)
585 {
586  Split *split;
587  gtk_widget_set_sensitive (GTK_WIDGET(lv->add_split_to_lot_button), FALSE);
588  gtk_widget_set_sensitive (GTK_WIDGET(lv->remove_split_from_lot_button), FALSE);
589  if (NULL != lv->selected_lot)
590  {
591  if (NULL != lv_get_selected_split (lv, lv->split_free_view) )
592  {
593  gtk_widget_set_sensitive (GTK_WIDGET(lv->add_split_to_lot_button), TRUE);
594  }
595  split = lv_get_selected_split (lv, lv->split_in_lot_view);
596  if (NULL != split && TRUE == lv_can_remove_split_from_lot (split, lv->selected_lot))
597  {
598  gtk_widget_set_sensitive (GTK_WIDGET(lv->remove_split_from_lot_button), TRUE);
599  }
600  }
601 }
602 
603 static void set_window_title (GNCLotViewer *lv)
604 {
605  gchar *win_title = g_strdup_printf (_("Lots in Account %s"), xaccAccountGetName (lv->account));
606  gtk_window_set_title (GTK_WINDOW (lv->window), win_title);
607  g_free (win_title);
608 }
609 
610 static void set_adjusted_ammounts_checkbutton_visibility (GNCLotViewer *lv)
611 {
612  GtkWidget *widget = GTK_WIDGET(lv->show_adjusted_amounts_checkbutton);
613  gboolean has_stock_split = xaccAccountHasStockSplit (lv->account);
614 
615  gtk_widget_set_visible (widget, has_stock_split);
616  gtk_widget_set_no_show_all (widget, !has_stock_split);
617 }
618 
619 static void lv_refresh (GNCLotViewer *lv)
620 {
621  gnc_lot_viewer_fill (lv);
622  lv_show_splits_free (lv);
623  lv_show_splits_in_lot (lv);
624  set_window_title (lv);
625  set_adjusted_ammounts_checkbutton_visibility (lv);
626 }
627 
628 /* ======================================================================== */
629 
630 static void
631 lv_refresh_handler (GHashTable *changes, gpointer user_data)
632 {
633  GNCLotViewer *lv = user_data;
634 
635  if (changes)
636  {
637  const EventInfo *info = gnc_gui_get_entity_events (changes, &lv->account_id);
638  if (info && (info->event_mask & QOF_EVENT_DESTROY))
639  {
640  gnc_close_gui_component (lv->component_id);
641  return;
642  }
643  }
644 
645  lv_refresh (lv);
646 }
647 
648 static void
649 lv_close_handler (gpointer user_data)
650 {
651  GNCLotViewer *lv = user_data;
652 
653  lv_save_current_lot (lv);
654 
655  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(lv->window));
656  gtk_widget_destroy (lv->window);
657 }
658 
659 /* =========================== Callbacks ============================ */
660 /* ======================================================================== */
661 /* The lot title in the entry widget changed */
662 
663 void
664 lv_title_entry_changed_cb (GtkEntry *ent, gpointer user_data)
665 {
666  GNCLotViewer *lv = user_data;
667  GtkTreeModel *model;
668  GtkTreeIter iter;
669  GtkTreeSelection *selection;
670  const char * title;
671  title = gtk_entry_get_text (lv->title_entry);
672 
673  selection = gtk_tree_view_get_selection (lv->lot_view);
674  if (gtk_tree_selection_get_selected (selection, &model, &iter))
675  {
676  gtk_list_store_set (GTK_LIST_STORE(model), &iter, LOT_COL_TITLE, title, -1);
677  }
678 }
679 
680 /* ======================================================================== */
681 /* Selection in the lot list view changed */
682 
683 static void
684 lv_selection_changed_cb (GtkTreeSelection *selection,
685  GNCLotViewer *lv)
686 {
687  GNCLot *lot;
688  GtkTreeModel *model;
689  GtkTreeIter iter;
690 
691  if (gtk_tree_selection_get_selected (selection, &model, &iter))
692  {
693  gtk_tree_model_get (model, &iter, LOT_COL_PNTR, &lot, -1);
694  lv_select_row (lv, lot);
695  }
696  else
697  {
698  lv_unselect_row (lv);
699  }
700  lv_update_split_buttons (lv);
701 }
702 
703 /* ======================================================================== */
704 /* Lot viewer window closed */
705 
706 void
707 lv_window_destroy_cb (GtkWidget *object, gpointer user_data)
708 {
709  GNCLotViewer *lv = user_data;
710 
711  gnc_unregister_gui_component (lv->component_id);
712 
713  g_free (lv);
714 }
715 
716 static void
717 lv_split_selection_changed_cb (GtkTreeSelection *selection,
718  GNCLotViewer *lv)
719 {
720  lv_update_split_buttons (lv);
721 }
722 
723 static void
724 lv_add_split_to_lot_cb (GtkWidget *widget, GNCLotViewer * lv)
725 {
726  Split *split;
727 
728  if ( NULL == lv->selected_lot ) return;
729  split = lv_get_selected_split (lv, lv->split_free_view);
730  if ( NULL == split ) return;
731 
732  gnc_suspend_gui_refresh ();
733  xaccAccountBeginEdit (lv->account);
734  gnc_lot_add_split (lv->selected_lot, split);
735  xaccAccountCommitEdit (lv->account);
736  gnc_resume_gui_refresh ();
737 
738  lv_refresh (lv);
739 }
740 
741 static void
742 lv_remove_split_from_lot_cb (GtkWidget *widget, GNCLotViewer * lv)
743 {
744  Split *split;
745 
746  if ( NULL == lv->selected_lot ) return;
747  split = lv_get_selected_split (lv, lv->split_in_lot_view);
748  if ( NULL == split ) return;
749 
750  if ( FALSE == lv_can_remove_split_from_lot (split, lv->selected_lot) )
751  return;
752 
753  gnc_suspend_gui_refresh ();
754  xaccAccountBeginEdit (lv->account);
755  gnc_lot_remove_split (lv->selected_lot, split);
756  xaccAccountCommitEdit (lv->account);
757  gnc_resume_gui_refresh ();
758 
759  lv_refresh (lv);
760 }
761 
762 static void
763 lv_only_show_open_lots_changed_cb (GtkWidget *widget, GNCLotViewer * lv)
764 {
765  lv_refresh (lv);
766 }
767 
768 static void
769 lv_show_adjusted_amounts_changed_cb (GtkWidget *widget, GNCLotViewer * lv)
770 {
771  lv_refresh (lv);
772 }
773 
774 /* ======================================================================== */
775 /* Any button was pressed */
776 
777 void
778 lv_response_cb (GtkDialog *dialog, gint response, gpointer data)
779 {
780  GNCLotViewer *lv = data;
781  GNCLot *lot = lv->selected_lot;
782 
783  switch (response)
784  {
785  case GTK_RESPONSE_CLOSE:
786  gnc_close_gui_component_by_data (LOT_VIEWER_CM_CLASS, lv);
787  return;
788 
789  case RESPONSE_VIEW:
790  if (NULL == lot)
791  return;
792  printf ("UNIMPLEMENTED: need to display register showing only this one lot.\n");
793  break;
794 
795  case RESPONSE_DELETE:
796  if (NULL == lot)
797  return;
798  /* Prevent broken invoices */
799  if (NULL != gncInvoiceGetInvoiceFromLot (lot))
800  return;
801  xaccAccountRemoveLot (gnc_lot_get_account (lot), lot);
802  gnc_lot_destroy (lot);
803  lv_unset_lot (lv);
804  gnc_lot_viewer_fill (lv);
805  break;
806 
807  case RESPONSE_SCRUB_LOT:
808  if (NULL == lot)
809  return;
810  if (xaccAccountIsAPARType (xaccAccountGetType (lv->account)))
811  gncScrubBusinessLot (lot);
812  else
813  xaccScrubLot (lot);
814  gnc_lot_viewer_fill (lv);
815  lv_show_splits_in_lot (lv);
816  break;
817 
818  case RESPONSE_SCRUB_ACCOUNT:
819  gnc_suspend_gui_refresh ();
820  if (xaccAccountIsAPARType (xaccAccountGetType (lv->account)))
821  gncScrubBusinessAccountLots (lv->account, gnc_window_show_progress);
822  else
823  xaccAccountScrubLots (lv->account);
824  gnc_resume_gui_refresh ();
825  lv_refresh (lv);
826  break;
827 
828  case RESPONSE_NEW_LOT:
829  lv_save_current_lot (lv);
830  lot = gnc_lot_make_default (lv->account);
831  xaccAccountInsertLot (lv->account, lot);
832  break;
833  }
834 }
835 
836 /* ======================================================================== */
837 
838 static gchar* lot_get_open_date (GNCLot *lot)
839 {
840  g_return_val_if_fail (lot, NULL);
841 
842  if (!gnc_lot_get_split_list (lot))
843  return g_strdup (_("Empty"));
844  else
846 }
847 
848 static gchar* lot_get_closing_date (GNCLot *lot)
849 {
850  g_return_val_if_fail (lot, NULL);
851 
852  if (!gnc_lot_get_split_list (lot))
853  return NULL;
854  else if (!gnc_lot_is_closed (lot))
855  return g_strdup (C_("Adjective", "Open"));
856  else
858 }
859 
860 typedef gchar* (*LotToDateFunc) (GNCLot *lot);
861 
862 static void lot_print_date (GtkTreeViewColumn *tree_column,
863  GtkCellRenderer *cell,
864  GtkTreeModel *tree_model,
865  GtkTreeIter *iter,
866  LotToDateFunc lot_to_date)
867 {
868  GNCLot *lot;
869  gchar *str = NULL;
870 
871  g_return_if_fail (cell && iter && tree_model);
872  gtk_tree_model_get (tree_model, iter, LOT_COL_PNTR, &lot, -1);
873 
874  if (lot)
875  str = lot_to_date (lot);
876 
877  g_object_set (G_OBJECT (cell), "text", str, NULL);
878  g_free (str);
879 }
880 
881 static void print_date (GtkTreeViewColumn *tree_column,
882  GtkCellRenderer *cell,
883  GtkTreeModel *tree_model,
884  GtkTreeIter *iter,
885  gpointer data)
886 {
887  time64 doc_date_time;
888  gchar *doc_date_str;
889  gint col = GPOINTER_TO_INT(data);
890 
891  g_return_if_fail (cell && iter && tree_model);
892 
893  gtk_tree_model_get (tree_model, iter, col, &doc_date_time, -1);
894 
895  doc_date_str = qof_print_date (doc_date_time);
896  g_object_set (G_OBJECT (cell), "text", doc_date_str, NULL);
897  g_free (doc_date_str);
898 }
899 
900 static void
901 configure_number_columns (GtkTreeViewColumn *column,
902  GtkCellRenderer *renderer, gint sort_column)
903 {
904  gtk_tree_view_column_set_sort_column_id (column, sort_column);
905  gtk_cell_renderer_set_alignment (renderer, 1.0, 0.5); // right align amount column
906  gtk_tree_view_column_set_alignment (column, 1.0);
907  gtk_cell_renderer_set_padding (renderer, 5, 0); // add padding so its not close to edge
908 }
909 
910 static void
911 lv_init_lot_view (GNCLotViewer *lv)
912 {
913  GtkTreeView *view;
914  GtkListStore *store;
915  GtkTreeViewColumn *column;
916  GtkTreeSelection *selection;
917  GtkCellRenderer *renderer;
918 
919  g_return_if_fail (GTK_IS_TREE_VIEW(lv->lot_view));
920 
921  view = lv->lot_view;
922  store = gtk_list_store_new (NUM_LOT_COLS, G_TYPE_STRING, G_TYPE_INT64,
923  G_TYPE_INT64, G_TYPE_STRING,
924  G_TYPE_STRING, G_TYPE_DOUBLE,
925  G_TYPE_STRING,G_TYPE_DOUBLE,
926  G_TYPE_POINTER);
927  gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
928  g_object_unref (store);
929  lv->lot_store = store;
930 
931  /* Set up the columns */
932  renderer = gtk_cell_renderer_text_new ();
933  column = gtk_tree_view_column_new_with_attributes (_("Type"), renderer,
934  "text", LOT_COL_TYPE, NULL);
935  gtk_tree_view_column_set_sort_column_id (column, LOT_COL_TYPE);
936  gtk_tree_view_append_column (view, column);
937 
938  renderer = gtk_cell_renderer_text_new ();
939  column = gtk_tree_view_column_new_with_attributes (_("Opened"), renderer,
940  "text", LOT_COL_OPEN, NULL);
941  gtk_tree_view_column_set_sort_column_id (column, LOT_COL_OPEN);
942  tree_view_column_set_default_width (view, column, "31-12-2013");
943  gtk_tree_view_column_set_cell_data_func (column, renderer,
944  (GtkTreeCellDataFunc) lot_print_date,
945  lot_get_open_date, NULL);
946  gtk_tree_view_append_column (view, column);
947 
948  renderer = gtk_cell_renderer_text_new ();
949  column = gtk_tree_view_column_new_with_attributes (_("Closed"), renderer,
950  "text", LOT_COL_CLOSE, NULL);
951  gtk_tree_view_column_set_sort_column_id (column, LOT_COL_CLOSE);
952  tree_view_column_set_default_width (view, column, "31-12-2013");
953  gtk_tree_view_column_set_cell_data_func (column, renderer,
954  (GtkTreeCellDataFunc) lot_print_date,
955  lot_get_closing_date, NULL);
956  gtk_tree_view_append_column (view, column);
957 
958  renderer = gtk_cell_renderer_text_new ();
959  column = gtk_tree_view_column_new_with_attributes (_("Title"), renderer,
960  "text", LOT_COL_TITLE, NULL);
961  gtk_tree_view_column_set_sort_column_id (column, LOT_COL_TITLE);
962  gtk_tree_view_column_set_expand (column, TRUE);
963  gtk_tree_view_append_column (view, column);
964 
965  renderer = gtk_cell_renderer_text_new ();
966  column = gtk_tree_view_column_new_with_attributes (_("Balance"), renderer,
967  "text", LOT_COL_BALN, NULL);
968  configure_number_columns (column, renderer, LOT_COL_BALN_DOUBLE);
969  gtk_tree_view_append_column (view, column);
970 
971  renderer = gtk_cell_renderer_text_new ();
972  column = gtk_tree_view_column_new_with_attributes (_("Gains"), renderer,
973  "text", LOT_COL_GAINS, NULL);
974  configure_number_columns (column, renderer, LOT_COL_GAINS_DOUBLE);
975  gtk_tree_view_append_column (view, column);
976 
977  /* Set up signals */
978  selection = gtk_tree_view_get_selection (view);
979  g_signal_connect (selection, "changed",
980  G_CALLBACK(lv_selection_changed_cb), lv);
981 }
982 
983 /* ======================================================================== */
984 
985 static GtkListStore *
986 lv_init_split_view (GNCLotViewer *lv, GtkTreeView *view)
987 {
988  GtkListStore *store;
989  GtkTreeViewColumn *column;
990  GtkTreeSelection *selection;
991  GtkCellRenderer *renderer;
992 
993  g_return_val_if_fail (GTK_IS_TREE_VIEW(view), NULL);
994 
995  store = gtk_list_store_new (NUM_SPLIT_COLS, G_TYPE_INT64,
996  G_TYPE_STRING, G_TYPE_STRING,
997  G_TYPE_STRING, G_TYPE_DOUBLE,
998  G_TYPE_STRING, G_TYPE_DOUBLE,
999  G_TYPE_STRING, G_TYPE_DOUBLE,
1000  G_TYPE_STRING, G_TYPE_DOUBLE,
1001  G_TYPE_POINTER);
1002  gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
1003  g_object_unref (store);
1004 
1005  /* Set up the columns */
1006  renderer = gtk_cell_renderer_text_new ();
1007  column = gtk_tree_view_column_new_with_attributes (_("Date"), renderer,
1008  "text", SPLIT_COL_DATE, NULL);
1009  gtk_tree_view_column_set_sort_column_id (column, SPLIT_COL_DATE);
1010  tree_view_column_set_default_width (view, column, "31-12-2013");
1011  gtk_tree_view_column_set_cell_data_func (column, renderer,
1012  (GtkTreeCellDataFunc) print_date,
1013  GINT_TO_POINTER (SPLIT_COL_DATE), NULL);
1014  gtk_tree_view_append_column (view, column);
1015 
1016  renderer = gtk_cell_renderer_text_new ();
1017  column = gtk_tree_view_column_new_with_attributes (_("Num"), renderer,
1018  "text", SPLIT_COL_NUM, NULL);
1019  gtk_tree_view_column_set_sort_column_id (column, SPLIT_COL_NUM);
1020  gtk_tree_view_append_column (view, column);
1021 
1022  renderer = gtk_cell_renderer_text_new ();
1023  column = gtk_tree_view_column_new_with_attributes (_("Description"), renderer,
1024  "text", SPLIT_COL_DESCRIPTION, NULL);
1025 
1026  g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1027  /* as this column is the expander column, if ellipsize is set, the column
1028  width would be small, so set a minimum width */
1029  gtk_tree_view_column_set_min_width (column, 200);
1030 
1031  gtk_tree_view_column_set_sort_column_id (column, SPLIT_COL_DESCRIPTION);
1032  gtk_tree_view_column_set_expand (column, TRUE);
1033  gtk_tree_view_column_set_resizable (column, TRUE);
1034  gtk_tree_view_append_column (view, column);
1035 
1036  renderer = gtk_cell_renderer_text_new ();
1037  column = gtk_tree_view_column_new_with_attributes (_("Amount"), renderer,
1038  "text", SPLIT_COL_AMOUNT, NULL);
1039  configure_number_columns (column, renderer, SPLIT_COL_AMOUNT_DOUBLE);
1040  gtk_tree_view_append_column (view, column);
1041 
1042  renderer = gtk_cell_renderer_text_new ();
1043  column = gtk_tree_view_column_new_with_attributes (_("Value"), renderer,
1044  "text", SPLIT_COL_VALUE, NULL);
1045  configure_number_columns (column, renderer, SPLIT_COL_VALUE_DOUBLE);
1046  gtk_tree_view_append_column (view, column);
1047 
1048  renderer = gtk_cell_renderer_text_new ();
1049  column = gtk_tree_view_column_new_with_attributes (_("Gain/Loss"), renderer,
1050  "text", SPLIT_COL_GAIN_LOSS, NULL);
1051  configure_number_columns (column, renderer, SPLIT_COL_GAIN_LOSS_DOUBLE);
1052  gtk_tree_view_append_column (view, column);
1053 
1054  renderer = gtk_cell_renderer_text_new ();
1055  column = gtk_tree_view_column_new_with_attributes (_("Balance"), renderer,
1056  "text", SPLIT_COL_BALANCE, NULL);
1057  configure_number_columns (column, renderer, SPLIT_COL_BALANCE_DOUBLE);
1058  gtk_tree_view_append_column (view, column);
1059 
1060  /* Set up the selection callbacks */
1061  selection = gtk_tree_view_get_selection (view);
1062  g_signal_connect (selection, "changed",
1063  G_CALLBACK(lv_split_selection_changed_cb), lv);
1064 
1065  return store;
1066 }
1067 
1068 static void
1069 lv_init_split_views (GNCLotViewer *lv)
1070 {
1071  lv->split_free_store = lv_init_split_view (lv, lv->split_free_view);
1072  lv->split_in_lot_store = lv_init_split_view (lv, lv->split_in_lot_view);
1073 }
1074 
1075 static void
1076 lv_init_split_buttons (GNCLotViewer *lv)
1077 {
1078  /* Set up the add/remove callbacks */
1079  g_signal_connect (G_OBJECT(lv->add_split_to_lot_button), "clicked",
1080  G_CALLBACK(lv_add_split_to_lot_cb), lv);
1081  g_signal_connect (G_OBJECT(lv->remove_split_from_lot_button), "clicked",
1082  G_CALLBACK(lv_remove_split_from_lot_cb), lv);
1083 }
1084 
1085 /* ======================================================================== */
1086 
1087 static void
1088 window_realize_set_split_paned_position_cb (GtkWidget *widget, gpointer user_data)
1089 {
1090  GNCLotViewer *lv = user_data;
1091  gint width;
1092 
1093  gtk_window_get_size (GTK_WINDOW(lv->window), &width, NULL);
1094  gtk_paned_set_position (GTK_PANED(lv->split_hpaned), width / 2);
1095 }
1096 
1097 static void
1098 lv_create (GNCLotViewer *lv, GtkWindow *parent)
1099 {
1100  GtkBuilder *builder;
1101 
1102  builder = gtk_builder_new ();
1103  gnc_builder_add_from_file (builder, "dialog-lot-viewer.glade", "lot_viewer_dialog");
1104 
1105  lv->window = GTK_WIDGET(gtk_builder_get_object (builder, "lot_viewer_dialog"));
1106 
1107  gtk_window_set_transient_for (GTK_WINDOW (lv->window), parent);
1108 
1109  // Set the name for this dialog so it can be easily manipulated with css
1110  gtk_widget_set_name (GTK_WIDGET(lv->window), "gnc-id-lot-viewer");
1111 
1112 #ifdef LOTS_READY_FOR_SHOWTIME
1113  lv->regview_button = GTK_BUTTON(glade_xml_get_widget (builder, "regview_button"));
1114 #endif
1115  lv->delete_button = GTK_BUTTON(gtk_builder_get_object (builder, "delete_button"));
1116  lv->scrub_lot_button = GTK_BUTTON(gtk_builder_get_object (builder, "scrub_lot_button"));
1117  lv->new_lot_button = GTK_BUTTON(gtk_builder_get_object (builder, "new_lot_button"));
1118 
1119  lv->only_show_open_lots_checkbutton = GTK_TOGGLE_BUTTON(gtk_builder_get_object (builder, "only_show_open_lots_checkbutton"));
1120  g_signal_connect (lv->only_show_open_lots_checkbutton, "toggled", G_CALLBACK(lv_only_show_open_lots_changed_cb), lv);
1121 
1122  lv->show_adjusted_amounts_checkbutton = GTK_TOGGLE_BUTTON(gtk_builder_get_object (builder, "show_adjusted_amounts_checkbutton"));
1123  g_signal_connect (lv->show_adjusted_amounts_checkbutton, "toggled", G_CALLBACK(lv_show_adjusted_amounts_changed_cb), lv);
1124  set_adjusted_ammounts_checkbutton_visibility (lv);
1125 
1126  lv->lot_view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "lot_view"));
1127  lv_init_lot_view (lv);
1128  lv->lot_notes = GTK_TEXT_VIEW(gtk_builder_get_object (builder, "lot_notes_text"));
1129  lv->title_entry = GTK_ENTRY (gtk_builder_get_object (builder, "lot_title_entry"));
1130 
1131  lv->split_in_lot_view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "split_in_lot_view"));
1132  lv->split_free_view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "split_free_view"));
1133  lv->split_hpaned = GTK_WIDGET(gtk_builder_get_object (builder, "split_hpaned"));
1134  lv_init_split_views (lv);
1135 
1136  lv->add_split_to_lot_button = GTK_BUTTON(gtk_builder_get_object (builder, "add_split_to_lot_button"));
1137  lv->remove_split_from_lot_button = GTK_BUTTON(gtk_builder_get_object (builder, "remove_split_from_lot_button"));
1138  lv_init_split_buttons (lv);
1139 
1140  // Set grid lines option to preference
1141  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(lv->lot_view), gnc_tree_view_get_grid_lines_pref ());
1142 
1143  // Set grid lines option to preference
1144  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(lv->split_in_lot_view), gnc_tree_view_get_grid_lines_pref ());
1145 
1146  // Set grid lines option to preference
1147  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(lv->split_free_view), gnc_tree_view_get_grid_lines_pref ());
1148 
1149 
1150  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SAVE_GEOMETRY))
1151  {
1152  GObject *object;
1153  object = gtk_builder_get_object (builder, "lot_vpaned");
1154  gnc_prefs_bind (GNC_PREFS_GROUP, GNC_PREF_VPOS, NULL, object, "position");
1155 
1156  object = gtk_builder_get_object (builder, "lot_hpaned");
1157  gnc_prefs_bind (GNC_PREFS_GROUP, GNC_PREF_HPOS, NULL, object, "position");
1158  }
1159 
1160  lv->selected_lot = NULL;
1161 
1162  /* set the split paned position to be halfway at the start */
1163  g_signal_connect (G_OBJECT(lv->window), "realize",
1164  G_CALLBACK(window_realize_set_split_paned_position_cb), lv);
1165 
1166  /* Setup signals */
1167  gtk_builder_connect_signals (builder, lv);
1168  g_object_unref (G_OBJECT(builder));
1169 
1170  lv_update_split_buttons (lv);
1171 
1172  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(lv->window), parent);
1173  gtk_widget_show_all (lv->window);
1174  gnc_window_adjust_for_screen (GTK_WINDOW(lv->window));
1175 }
1176 
1177 /* ======================================================================== */
1178 
1179 GNCLotViewer *
1180 gnc_lot_viewer_dialog (GtkWindow *parent, Account *account)
1181 {
1182  GNCLotViewer *lv;
1183 
1184  if (!account) return NULL;
1185 
1186  lv = g_new0 (GNCLotViewer, 1);
1187  lv->account = account;
1188  lv_create (lv, parent);
1189  lv_refresh (lv);
1190 
1191  lv->component_id = gnc_register_gui_component (LOT_VIEWER_CM_CLASS, lv_refresh_handler, lv_close_handler, lv);
1192  lv->account_id = *xaccAccountGetGUID (account);
1193 
1194  gnc_gui_component_set_session (lv->component_id, gnc_get_current_session ());
1195  gnc_gui_component_watch_entity_type (lv->component_id, GNC_ID_LOT,
1196  QOF_EVENT_CREATE | QOF_EVENT_ADD | QOF_EVENT_REMOVE | QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
1197  gnc_gui_component_watch_entity (lv->component_id, &lv->account_id,
1198  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY | GNC_EVENT_ITEM_CHANGED);
1199 
1200 
1201  return lv;
1202 }
1203 
1204 /* ============================ END OF FILE =============================== */
High-Level API for imposing Lot constraints.
void tree_view_column_set_default_width(GtkTreeView *view, GtkTreeViewColumn *column, const gchar *sizing_text)
Set default width for a treeview column.
GList LotList
GList of GNCLots.
Definition: gnc-engine.h:205
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:3949
gnc_numeric xaccLotFreeSplitCapGain(Split *split, GNCLot *lot)
The xaccLotFreeSplitCapGain() method returns the value of capital gain (if any) associated with the i...
Definition: cap-gains.cpp:896
utility functions for the GnuCash UI
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3267
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
STRUCTS.
All arguments are required to have the same denominator, that denominator is to be used in the output...
Definition: gnc-numeric.h:206
Functions that are supported by all types of windows.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
Definition: gnc-lot.cpp:579
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2140
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gnc_numeric xaccSplitGetCapGains(Split *split)
The xaccSplitGetCapGains() method returns the value of capital gains (if any) associated with the ind...
Definition: cap-gains.cpp:1038
gboolean xaccAccountHasStockSplit(const Account *acc)
Returns true if the account has a stock split, otherwise false.
Definition: Account.cpp:3507
void xaccAccountScrubLots(Account *acc)
The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot...
Definition: Scrub3.cpp:159
Cleanup functions for business objects.
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
Definition: gnc-lot.cpp:658
void gncScrubBusinessAccountLots(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccountLots() function will call gncScrubBusinessLot() on each lot in the given a...
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
Definition: gncInvoice.c:1272
Split * gnc_lot_get_latest_split(GNCLot *lot)
Convenience routineto identify the date this lot was closed.
Definition: gnc-lot.cpp:670
#define xaccAccountGetGUID(X)
Definition: Account.h:252
gdouble gnc_numeric_to_double(gnc_numeric n)
Convert numeric to floating-point value.
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:610
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
Account handling public routines.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
Definition: gnc-lot.cpp:425
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.cpp:3975
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
void gnc_lot_remove_split(GNCLot *lot, Split *split)
Adds a split from this lot.
Definition: gnc-lot.cpp:631
gboolean xaccSplitIsStockSplit(Split *s)
Returns true if the split is of type stock split.
Definition: Split.cpp:2078
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4527
Additional event handling code.
void gnc_prefs_bind(const gchar *group, const gchar *pref_name, const gchar *pref_value, gpointer object, const gchar *property)
Bind a setting to a g_object property.
Definition: gnc-prefs.cpp:180
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
Generic api to store and retrieve preferences.
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1234
Business Invoice Interface.
GNCLot * gnc_lot_make_default(Account *acc)
Definition: gnc-lot.cpp:765
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition: gnc-lot.cpp:367
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
gboolean gncScrubBusinessLot(GNCLot *lot)
The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties r...
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1475
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
gboolean xaccScrubLot(GNCLot *lot)
The xaccScrubLot() routine makes sure that the indicated lot is self-consistent and properly balanced...
Definition: Scrub3.cpp:85
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3289
gnc_numeric xaccSplitGetAdjustedAmount(const Split *s)
Returns the stock-split adjusted amount of the split in the account&#39;s commodity.
Definition: Split.cpp:1340
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1516
Utilities to Automatically Compute Capital Gains/Losses.
Commodity handling public routines.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition: gnc-lot.cpp:487
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.cpp:1920
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69