GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-split-reg2.c
1 /********************************************************************\
2  * gnc-split-reg2.c -- A widget for the common register look-n-feel *
3  * Copyright (C) 1997 Robin D. Clark *
4  * Copyright (C) 1997-1998 Linas Vepstas <[email protected]> *
5  * Copyright (C) 1998 Rob Browning <[email protected]> *
6  * Copyright (C) 1999-2000 Dave Peticolas <[email protected]> *
7  * Copyright (C) 2001 Gnumatic, Inc. *
8  * Copyright (C) 2002,2006 Joshua Sled <[email protected]> *
9  * Copyright (C) 2012 Robert Fewell *
10  * *
11  * This program is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public License as *
13  * published by the Free Software Foundation; either version 2 of *
14  * the License, or (at your option) any later version. *
15  * *
16  * This program is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19  * GNU General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU General Public License*
22  * along with this program; if not, contact: *
23  * *
24  * Free Software Foundation Voice: +1-617-542-5942 *
25  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
26  * Boston, MA 02110-1301, USA [email protected] *
27 \********************************************************************/
28 
29 #include "config.h"
30 
31 #include <gtk/gtk.h>
32 #include <glib.h>
33 #include <glib/gi18n.h>
34 
35 #include "gnc-split-reg2.h"
36 #include "gnc-tree-view-split-reg.h"
37 #include "gnc-tree-control-split-reg.h"
38 #include "gnc-ledger-display2.h"
39 
40 #include "gnc-euro.h"
41 #include "gnc-state.h"
42 #include "gnome-utils/gnc-warnings.h"
43 #include "dialog-utils.h"
44 
45 #define STATE_SECTION_REG_PREFIX "Register"
46 #define STATE_SECTION_GEN_LEDGER "General Ledger"
47 
48 static QofLogModule log_module = GNC_MOD_GUI;
49 
50 /***** PROTOTYPES ***************************************************/
51 void gnc_split_reg2_raise (GNCSplitReg2 *gsr);
52 
53 static GtkWidget* add_summary_label (GtkWidget *summarybar,
54  const char *label_str);
55 
56 static void gnc_split_reg2_determine_read_only (GNCSplitReg2 *gsr);
57 
58 static void gnc_split_reg2_determine_account_pr (GNCSplitReg2 *gsr);
59 
60 static GNCPlaceholderType gnc_split_reg2_get_placeholder (GNCSplitReg2 *gsr);
61 static GtkWidget *gnc_split_reg2_get_parent (GNCLedgerDisplay2 *ledger);
62 
63 static void gsr2_create_table (GNCSplitReg2 *gsr);
64 static void gsr2_setup_table (GNCSplitReg2 *gsr);
65 
66 static void gsr2_setup_status_widgets (GNCSplitReg2 *gsr);
67 
68 static void gsr2_update_summary_label (GtkWidget *label,
69  xaccGetBalanceFn getter,
70  Account *leader,
71  GNCPrintAmountInfo print_info,
72  gnc_commodity *cmdty,
73  gboolean reverse,
74  gboolean euroFlag );
75 
76 static void gsr2_redraw_all_cb (GncTreeViewSplitReg *view, gpointer data);
77 
78 static void gnc_split_reg2_ld_destroy (GNCLedgerDisplay2 *ledger);
79 
80 static Transaction* gsr2_create_balancing_transaction (QofBook *book, Account *account,
81  time64 statement_date, gnc_numeric balancing_amount);
82 
83 static void gsr2_emit_simple_signal (GNCSplitReg2 *gsr, const char *sigName);
84 static void gsr2_emit_help_changed (GncTreeViewSplitReg *view, gpointer user_data);
85 static void gsr2_scroll_value_changed_cb (GtkAdjustment *adj, gpointer user_data);
86 static gboolean gsr2_scroll_button_event_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data);
87 static void gsr2_scroll_sync_cb (GncTreeModelSplitReg *model, gpointer user_data);
88 
89 void gnc_split_reg2_style_ledger_cb (GtkWidget *w, gpointer data);
90 void gnc_split_reg2_style_auto_ledger_cb (GtkWidget *w, gpointer data);
91 void gnc_split_reg2_style_journal_cb (GtkWidget *w, gpointer data);
92 void gnc_split_reg2_double_line_cb (GtkWidget *w, gpointer data);
93 
94 void gnc_split_reg2_destroy_cb (GtkWidget *widget, gpointer data);
95 
96 static void gnc_split_reg2_class_init (GNCSplitReg2Class *klass);
97 static void gnc_split_reg2_init (GNCSplitReg2 *gsr);
98 static void gnc_split_reg2_init2 (GNCSplitReg2 *gsr);
99 
100 static void gnc_split_reg2_sort_changed_cb (GtkTreeSortable *sortable, gpointer user_data);
101 
102 
103 GType
104 gnc_split_reg2_get_type (void)
105 {
106  static GType gnc_split_reg2_type = 0;
107 
108  if (!gnc_split_reg2_type)
109  {
110  GTypeInfo type_info =
111  {
112  sizeof(GNCSplitReg2Class), /* class_size */
113  NULL, /* base_init */
114  NULL, /* base_finalize */
115  (GClassInitFunc)gnc_split_reg2_class_init,
116  NULL, /* class_finalize */
117  NULL, /* class_data */
118  sizeof(GNCSplitReg2), /* */
119  0, /* n_preallocs */
120  (GInstanceInitFunc)gnc_split_reg2_init,
121  };
122 
123  gnc_split_reg2_type = g_type_register_static (GTK_TYPE_VBOX,
124  "GNCSplitReg2",
125  &type_info, 0 );
126  }
127 
128  return gnc_split_reg2_type;
129 }
130 
131 /* SIGNALS */
132 enum
133 {
134  HELP_CHANGED,
135  LAST_SIGNAL
136 };
137 
138 static guint gnc_split_reg2_signals[LAST_SIGNAL] = { 0 };
139 
140 static void
141 gnc_split_reg2_class_init (GNCSplitReg2Class *klass)
142 {
143  GtkObjectClass *object_class;
144 
145  object_class = (GtkObjectClass*) klass;
146 
147  gnc_split_reg2_signals[HELP_CHANGED] =
148  g_signal_new("help-changed",
149  G_TYPE_FROM_CLASS (object_class),
150  G_SIGNAL_RUN_LAST,
151  G_STRUCT_OFFSET (GNCSplitReg2Class, help_changed),
152  NULL, NULL,
153  g_cclosure_marshal_VOID__VOID,
154  G_TYPE_NONE, 0);
155 
156  /* Setup the default handlers. */
157  klass->help_changed = NULL;
158 
159 }
160 
161 GtkWidget*
162 gnc_split_reg2_new (GNCLedgerDisplay2 *ld,
163  GtkWindow *parent,
164  gint numberOfLines,
165  gboolean read_only )
166 {
167  GNCSplitReg2 *gsrToRet;
168 
169  ENTER("ld=%p, parent=%p, numberOfLines=%d, read_only=%s",
170  ld, parent, numberOfLines, read_only ? "TRUE" : "FALSE");
171 
172  gsrToRet = g_object_new (gnc_split_reg2_get_type(), NULL);
173 
174  gsrToRet->numRows = numberOfLines;
175  gsrToRet->read_only = read_only;
176 
177  gsrToRet->ledger = ld;
178  gsrToRet->window = GTK_WIDGET (parent);
179 
180  gnc_split_reg2_init2 (gsrToRet);
181 
182  LEAVE("%p", gsrToRet);
183  return GTK_WIDGET (gsrToRet);
184 }
185 
186 static void
187 gnc_split_reg2_init (GNCSplitReg2 *gsr)
188 {
189  gsr->numRows = 10;
190  gsr->read_only = FALSE;
191 
192  g_signal_connect (gsr, "destroy",
193  G_CALLBACK (gnc_split_reg2_destroy_cb), gsr );
194 }
195 
196 static void
197 gnc_split_reg2_init2 (GNCSplitReg2 *gsr)
198 {
199  if (!gsr) return;
200 
201  gnc_split_reg2_determine_read_only (gsr);
202 
203  gnc_split_reg2_determine_account_pr (gsr);
204 
205  gsr2_setup_status_widgets (gsr);
206  /* ordering is important here... setup_status before create_table */
207 
208  gsr2_create_table (gsr);
209  gsr2_setup_table (gsr);
210 
211 }
212 
213 static
214 void
215 gsr2_setup_table (GNCSplitReg2 *gsr)
216 {
217  GncTreeModelSplitReg *model;
218 
219  ENTER("gsr=%p", gsr);
220 
221  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
222 
223  LEAVE(" ");
224 }
225 
226 static
227 void
228 gsr2_create_table (GNCSplitReg2 *gsr)
229 {
230  GtkWidget *register_widget;
231  GncTreeViewSplitReg *view;
232  GncTreeModelSplitReg *model;
233  GtkTreeModel *s_model;
234  GtkWidget *scrolled_window;
235  GtkTreeViewColumn *col;
236  GNCLedgerDisplay2Type ledger_type;
237  GtkWidget *hbox;
238  gdouble num_of_trans;
239 
240  gchar *state_section;
241  GKeyFile *state_file = gnc_state_get_current();
242  const GncGUID * guid;
243  Account * account;
244  const gchar *sort_string;
245 
246  account = gnc_ledger_display2_leader (gsr->ledger);
247  guid = xaccAccountGetGUID (account);
248 
249  ENTER("create table gsr=%p", gsr);
250 
251  gnc_ledger_display2_set_user_data (gsr->ledger, (gpointer)gsr);
252  gnc_ledger_display2_set_handlers (gsr->ledger,
253  gnc_split_reg2_ld_destroy,
254  gnc_split_reg2_get_parent);
255 
256  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
257  view = gnc_tree_view_split_reg_new_with_model (model);
258  g_object_unref (G_OBJECT (model));
259 
260  /* State_section is used to store per register state: column widths, sort order,... */
261  ledger_type = gnc_ledger_display2_type (gsr->ledger);
262  if (ledger_type == LD2_GL && model->type == GENERAL_LEDGER2)
263  state_section = g_strdup (STATE_SECTION_GEN_LEDGER);
264  else if (ledger_type == LD2_SUBACCOUNT)
265  {
266  gchar guidstr[GUID_ENCODING_LENGTH+1];
267  guid_to_string_buff (guid, guidstr);
268  state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr, " w/subaccounts", NULL);
269  }
270  else
271  {
272  gchar guidstr[GUID_ENCODING_LENGTH+1];
273  guid_to_string_buff (guid, guidstr);
274  state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr, NULL);
275  }
276  g_object_set (G_OBJECT (view), "state-section", state_section,
277  "show-column-menu", FALSE, NULL);
278 
279  // Create a hbox for treeview and scrollbar.
280  hbox = gtk_hbox_new (FALSE, 0);
281  gtk_widget_show (hbox);
282 
283  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
284  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
285  GTK_POLICY_AUTOMATIC,
286  GTK_POLICY_AUTOMATIC);
287 
288  gtk_widget_show (scrolled_window);
289 
290  gtk_box_pack_start (GTK_BOX (gsr), hbox, TRUE, TRUE, 0);
291 
292  num_of_trans = model->number_of_trans_in_full_tlist - 1;
293 
294  gsr->scroll_adj = GTK_ADJUSTMENT (gtk_adjustment_new (model->position_of_trans_in_full_tlist, 0.0, num_of_trans + 10, 1.0, 10.0, 10.0));
295 
296  gsr->scroll_bar = gtk_vscrollbar_new (GTK_ADJUSTMENT (gsr->scroll_adj));
297  gtk_widget_show (gsr->scroll_bar);
298 
299  gtk_box_pack_start (GTK_BOX (hbox), gsr->scroll_bar, FALSE, FALSE, 2);
300  gtk_box_pack_start (GTK_BOX (hbox), scrolled_window, TRUE, TRUE, 0);
301 
302  gnc_ledger_display2_set_split_view_register (gsr->ledger, view);
303 
304  /* Synchronize model state with view state
305  * (needed to properly set up the internal query) */
306 
307  /* Restore the sort depth from saved state */
308  model->sort_depth = g_key_file_get_integer (state_file, state_section, "sort_depth", NULL);
309 
310  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
311  if (s_model)
312  {
313  gint sort_col;
314  GtkSortType type;
315 
316  if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (s_model), &sort_col, &type))
317  {
318  model->sort_col = sort_col;
319  model->sort_direction = type;
320  }
321  }
322 
323  gnc_tree_view_configure_columns (GNC_TREE_VIEW (view));
324 
325  if (ledger_type == LD2_GL && model->type == GENERAL_LEDGER2)
326  gnc_tree_view_set_show_column_menu (GNC_TREE_VIEW (view), TRUE);
327  else
328  gnc_tree_view_set_show_column_menu (GNC_TREE_VIEW (view), FALSE);
329 
330  /* This column gets all the free space */
331  gnc_tree_view_expand_columns (GNC_TREE_VIEW (view), "descnotes", NULL);
332 
333  /* This sets the status color column, 4 is the minimum */
334  col = gnc_tree_view_find_column_by_name (GNC_TREE_VIEW (view), "status");
335  if (col != NULL)
336  g_object_set (G_OBJECT(col),
337  "resizable", FALSE,
338  "sizing", GTK_TREE_VIEW_COLUMN_FIXED,
339  "fixed-width", 4,
340  NULL);
341 
342  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), TRUE);
343  gtk_widget_show (GTK_WIDGET (view));
344 
345  gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (view));
346  gtk_widget_show (GTK_WIDGET (gsr));
347 
348  /* Should this be read only */
349  gnc_tree_view_split_reg_set_read_only (view, gsr->read_only);
350 
351  /* This tells the ledger that we have a valid tree view */
352  gnc_ledger_display2_set_split_view_refresh (gsr->ledger, TRUE);
353 
354  /* This triggers the update of the summary bar */
355  g_signal_connect_after (model, "refresh_status_bar",
356  G_CALLBACK (gsr2_redraw_all_cb), gsr); //this works
357 
358  // This will keep scrollbar in sync.
359  g_signal_connect (model, "scroll_sync",
360  G_CALLBACK (gsr2_scroll_sync_cb), gsr);
361 
362  /* This triggers the update of the help text */
363  g_signal_connect (view, "help_signal",
364  G_CALLBACK (gsr2_emit_help_changed), gsr); // this works
365 
366  gsr2_scroll_value_changed_cb (GTK_ADJUSTMENT (gsr->scroll_adj), gsr);
367 
368  /* This triggers the tooltip to change when scrolling */
369  g_signal_connect (gsr->scroll_adj, "value-changed",
370  G_CALLBACK (gsr2_scroll_value_changed_cb), gsr); // this works
371 
372  /* This triggers the model update when mouse button released */
373  g_signal_connect (gsr->scroll_bar, "button-release-event",
374  G_CALLBACK (gsr2_scroll_button_event_cb), gsr);
375 
376  // Connect a call back to update the sort settings.
377  g_signal_connect (GTK_TREE_SORTABLE (s_model), "sort-column-changed",
378  G_CALLBACK (gnc_split_reg2_sort_changed_cb), gsr);
379 
380  LEAVE(" ");
381 }
382 
383 static
384 void
385 gsr2_setup_status_widgets (GNCSplitReg2 *gsr)
386 {
387  GncTreeModelSplitReg *model;
388  gboolean use_double_line;
389 
390  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
391  use_double_line = gnc_ledger_display2_default_double_line (gsr->ledger);
392 
393  /* be sure to initialize the gui elements */
394  gnc_tree_model_split_reg_config (model, model->type, model->style, use_double_line);
395 }
396 
397 void
398 gnc_split_reg2_destroy_cb (GtkWidget *widget, gpointer data)
399 {
400 }
401 
405 void
406 gnc_split_reg2_jump_to_split (GNCSplitReg2 *gsr, Split *split)
407 {
408  GncTreeViewSplitReg *view;
409 
410  if (gsr == NULL)
411  return;
412 
413  if (split == NULL)
414  return;
415 
416  view = gnc_ledger_display2_get_split_view_register (gsr->ledger);
417 
418  gnc_tree_control_split_reg_jump_to (view, NULL, split, FALSE);
419 }
420 
421 
425 void
426 gnc_split_reg2_jump_to_split_amount (GNCSplitReg2 *gsr, Split *split)
427 {
428  GncTreeViewSplitReg *view;
429 
430  if (gsr == NULL)
431  return;
432 
433  if (split == NULL)
434  return;
435 
436  view = gnc_ledger_display2_get_split_view_register (gsr->ledger);
437 
438  gnc_tree_control_split_reg_jump_to (view, NULL, split, TRUE);
439 }
440 
444 void
445 gnc_split_reg2_raise (GNCSplitReg2 *gsr)
446 {
447  if (gsr == NULL)
448  return;
449 
450  if (gsr->window == NULL)
451  return;
452 
453  gtk_window_present (GTK_WINDOW (gsr->window));
454 }
455 
456 
461 static
462 void
463 gsr2_update_summary_label (GtkWidget *label,
464  xaccGetBalanceFn getter,
465  Account *leader,
466  GNCPrintAmountInfo print_info,
467  gnc_commodity *cmdty,
468  gboolean reverse,
469  gboolean euroFlag)
470 {
471  gnc_numeric amount;
472  char string[256];
473 
474  if ( label == NULL )
475  return;
476 
477  amount = (*getter)( leader );
478 
479  if ( reverse )
480  {
481  amount = gnc_numeric_neg( amount );
482  }
483 
484  xaccSPrintAmount( string, amount, print_info );
485 
486  if ( euroFlag )
487  {
488  strcat( string, " / " );
489  xaccSPrintAmount( string + strlen( string ),
490  gnc_convert_to_euro( cmdty, amount ),
491  gnc_commodity_print_info( gnc_get_euro(), TRUE ) );
492  }
493 
494  gnc_set_label_color( label, amount );
495  gtk_label_set_text( GTK_LABEL(label), string );
496 }
497 
498 static GNCPrice *
499 account_latest_price (Account *account)
500 {
501  QofBook *book;
502  GNCPriceDB *pdb;
503  gnc_commodity *commodity;
504  gnc_commodity *currency;
505 
506  if (!account) return NULL;
507  commodity = xaccAccountGetCommodity (account);
508  currency = gnc_default_currency ();
509 
510  book = gnc_account_get_book (account);
511  pdb = gnc_pricedb_get_db (book);
512 
513  return gnc_pricedb_lookup_latest (pdb, commodity, currency);
514 }
515 
516 static GNCPrice *
517 account_latest_price_any_currency (Account *account)
518 {
519  QofBook *book;
520  GNCPriceDB *pdb;
521  gnc_commodity *commodity;
522  GList *price_list;
523  GNCPrice *result;
524 
525  if (!account) return NULL;
526  commodity = xaccAccountGetCommodity (account);
527 
528  book = gnc_account_get_book (account);
529  pdb = gnc_pricedb_get_db (book);
530 
531  price_list = gnc_pricedb_lookup_latest_any_currency (pdb, commodity);
532  if (!price_list) return NULL;
533 
534  result = gnc_price_clone ((GNCPrice *)(price_list->data), book);
535 
536  gnc_price_list_destroy (price_list);
537 
538  return result;
539 }
540 
541 static
542 void
543 gsr2_redraw_all_cb (GncTreeViewSplitReg *view, gpointer user_data)
544 {
545  GNCSplitReg2 *gsr = user_data;
546  gnc_commodity * commodity;
547  GNCPrintAmountInfo print_info;
548  gnc_numeric amount;
549  char string[256];
550  Account *leader;
551  gboolean reverse;
552  gboolean euro;
553 
554  if ( gsr->summarybar == NULL )
555  return;
556 
557  leader = gnc_ledger_display2_leader( gsr->ledger );
558 
559  commodity = xaccAccountGetCommodity( leader );
560 
561  /* no EURO converson, if account is already EURO or no EURO currency */
562  if (commodity != NULL)
563  euro = (gnc_is_euro_currency( commodity ) &&
564  (strncasecmp(gnc_commodity_get_mnemonic(commodity), "EUR", 3)));
565  else
566  euro = FALSE;
567 
568  print_info = gnc_account_print_info( leader, TRUE );
569  reverse = gnc_reverse_balance( leader );
570 
571  gsr2_update_summary_label( gsr->balance_label,
572  xaccAccountGetPresentBalance,
573  leader, print_info, commodity, reverse, euro );
574  gsr2_update_summary_label( gsr->cleared_label,
576  leader, print_info, commodity, reverse, euro );
577  gsr2_update_summary_label( gsr->reconciled_label,
579  leader, print_info, commodity, reverse, euro );
580  gsr2_update_summary_label( gsr->future_label,
582  leader, print_info, commodity, reverse, euro );
583  gsr2_update_summary_label( gsr->projectedminimum_label,
584  xaccAccountGetProjectedMinimumBalance,
585  leader, print_info, commodity, reverse, euro );
586 
587  /* Print the summary share amount */
588  if (gsr->shares_label != NULL)
589  {
590  print_info = gnc_account_print_info( leader, TRUE );
591 
592  amount = xaccAccountGetBalance( leader );
593  if (reverse)
594  amount = gnc_numeric_neg( amount );
595 
596  xaccSPrintAmount( string, amount, print_info );
597 
598  gnc_set_label_color( gsr->shares_label, amount );
599  gtk_label_set_text( GTK_LABEL(gsr->shares_label), string );
600  }
601 
602  /* Print the summary share value */
603  if (gsr->value_label != NULL)
604  {
605  GNCPrice *price;
606 
607  amount = xaccAccountGetBalance (leader);
608  if (reverse) amount = gnc_numeric_neg (amount);
609 
610  price = account_latest_price (leader);
611  if (!price)
612  {
613  /* If the balance is zero, then print zero. */
614  if (gnc_numeric_equal(amount, gnc_numeric_zero()))
615  {
616  gnc_commodity *currency = gnc_default_currency ();
617  print_info = gnc_commodity_print_info (currency, TRUE);
618  amount = gnc_numeric_zero ();
619 
620  xaccSPrintAmount (string, amount, print_info);
621 
622  gnc_set_label_color (gsr->value_label, amount);
623  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
624  }
625  else
626  {
627  /* else try to do a double-price-conversion :-( */
628  price = account_latest_price_any_currency (leader);
629  if (!price)
630  {
631  gnc_set_label_color (gsr->value_label, gnc_numeric_zero ());
632  gtk_label_set_text (GTK_LABEL (gsr->value_label),
633  _("<No information>"));
634  }
635  else
636  {
637  gnc_commodity *currency = gnc_price_get_currency (price);
638  gnc_commodity *default_currency = gnc_default_currency ();
639  gnc_numeric currency_amount;
640  gnc_numeric default_currency_amount;
641 
642  print_info = gnc_commodity_print_info (currency, TRUE);
643 
644  currency_amount =
645  xaccAccountConvertBalanceToCurrency(leader, amount,
646  commodity, currency);
647  xaccSPrintAmount (string, currency_amount, print_info);
648 
649  default_currency_amount =
650  xaccAccountConvertBalanceToCurrency(leader, amount,
651  commodity,
652  default_currency);
653  if (!gnc_numeric_zero_p(default_currency_amount))
654  {
655  strcat( string, " / " );
656  print_info = gnc_commodity_print_info (default_currency, TRUE);
657  xaccSPrintAmount( string + strlen( string ), default_currency_amount,
658  print_info);
659  }
660 
661  gnc_set_label_color (gsr->value_label, amount);
662  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
663 
664  gnc_price_unref (price);
665  }
666  }
667  }
668  else
669  {
670  gnc_commodity *currency = gnc_price_get_currency (price);
671 
672  print_info = gnc_commodity_print_info (currency, TRUE);
673 
674  amount = gnc_numeric_mul (amount, gnc_price_get_value (price),
675  gnc_commodity_get_fraction (currency),
677 
678  xaccSPrintAmount (string, amount, print_info);
679 
680  gnc_set_label_color (gsr->value_label, amount);
681  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
682 
683  gnc_price_unref (price);
684  }
685  }
686 }
687 
688 static void
689 gnc_split_reg2_ld_destroy (GNCLedgerDisplay2 *ledger)
690 {
691  gnc_ledger_display2_set_user_data (ledger, NULL);
692 }
693 
694 
695 /* ########################### Handlers ############################### */
696 
697 void
698 gnc_split_reg2_balancing_entry (GNCSplitReg2 *gsr, Account *account,
699  time64 statement_date, gnc_numeric balancing_amount) // this works
700 {
701  GncTreeViewSplitReg *view;
702  Transaction *transaction;
703  Split *split;
704 
705  view = gnc_ledger_display2_get_split_view_register (gsr->ledger);
706 
707  // create transaction
708  transaction = gsr2_create_balancing_transaction (gnc_get_current_book(),
709  account, statement_date, balancing_amount);
710 
711  // jump to transaction
712  split = xaccTransFindSplitByAccount (transaction, account);
713  if (split == NULL)
714  {
715  // default behaviour: jump to blank split
716  g_warning("gsr2_create_balancing_transaction failed");
717  gnc_tree_control_split_reg_jump_to_blank (view);
718  }
719  else
720  {
721  // goto balancing transaction
722  gnc_tree_control_split_reg_jump_to (view, NULL, split, FALSE);
723  }
724 }
725 
726 static Transaction*
727 gsr2_create_balancing_transaction (QofBook *book, Account *account,
728  time64 statement_date, gnc_numeric balancing_amount)
729 {
730  Transaction *trans;
731  Split *split;
732 
733  if (!account)
734  return NULL;
735  if (gnc_numeric_zero_p (balancing_amount))
736  return NULL;
737 
738  xaccAccountBeginEdit (account);
739 
740  trans = xaccMallocTransaction (book);
741 
742  xaccTransBeginEdit (trans);
743 
744  // fill Transaction
745  xaccTransSetCurrency (trans, gnc_account_or_default_currency (account, NULL));
746  xaccTransSetDatePostedSecsNormalized (trans, statement_date);
747  xaccTransSetDescription (trans, _("Balancing entry from reconcilation"));
748 
749  // 1. Split
750  split = xaccMallocSplit (book);
751  xaccTransAppendSplit (trans, split);
752  xaccAccountInsertSplit (account, split);
753  xaccSplitSetAmount (split, balancing_amount);
754  xaccSplitSetValue (split, balancing_amount);
755 
756  // 2. Split (no account is defined: split goes to orphan account)
757  split = xaccMallocSplit (book);
758  xaccTransAppendSplit (trans, split);
759 
760  balancing_amount = gnc_numeric_neg (balancing_amount);
761  xaccSplitSetAmount (split, balancing_amount);
762  xaccSplitSetValue (split, balancing_amount);
763 
764  xaccTransCommitEdit (trans);
765  xaccAccountCommitEdit (account);
766  return trans;
767 }
768 
769 
770 /* Sort changed callback */
771 static void
772 gnc_split_reg2_sort_changed_cb (GtkTreeSortable *sortable, gpointer user_data)
773 {
774  Query *query;
775  GNCSplitReg2 *gsr = user_data;
776  GncTreeViewSplitReg *view;
777  GncTreeModelSplitReg *model;
778  GtkSortType type;
779  gint sortcol;
780  gint sort_depth;
781  const gchar *state_section;
782  GKeyFile *state_file = gnc_state_get_current();
783 
784  gtk_tree_sortable_get_sort_column_id (sortable, &sortcol, &type);
785  ENTER("sortcol is %d", sortcol);
786 
787  view = gnc_ledger_display2_get_split_view_register (gsr->ledger);
788  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
789 
790  query = gnc_ledger_display2_get_query (gsr->ledger);
791 
792  sort_depth = gnc_tree_view_reg_get_selected_row_depth (view);
793  if (sort_depth != 0)
794  model->sort_depth = sort_depth;
795 
796  model->sort_col = sortcol;
797  model->sort_direction = type;
798 
799  /* Save the sort depth state */
800  state_section = gnc_tree_view_get_state_section (GNC_TREE_VIEW (view));
801  g_key_file_set_integer (state_file, state_section, "sort_depth", model->sort_depth);
802 
803  LEAVE("m_sort_col %d, m_sort_direction is %d m_sort_depth is %d", model->sort_col, model->sort_direction, model->sort_depth);
804 
805  if (sortcol != -1)
806  gnc_ledger_display2_refresh (gsr->ledger);
807 }
808 /* ############################## End Handlers ############################ */
809 
810 void
811 gnc_split_reg2_change_style (GNCSplitReg2 *gsr, SplitRegisterStyle2 style)
812 {
813  GncTreeModelSplitReg *model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
814 
815  if (style == model->style)
816  return;
817 
818  gnc_tree_model_split_reg_config (model, model->type, style, model->use_double_line);
819 
820  // This will re-display the view.
821  gnc_tree_view_split_reg_set_format (gnc_ledger_display2_get_split_view_register (gsr->ledger));
822 }
823 
824 void
825 gnc_split_reg2_style_ledger_cb (GtkWidget *w, gpointer data)
826 {
827  GNCSplitReg2 *gsr = data;
828 
829  if (!GTK_CHECK_MENU_ITEM (w)->active)
830  return;
831 
832  gnc_split_reg2_change_style (gsr, REG2_STYLE_LEDGER);
833 }
834 
835 void
836 gnc_split_reg2_style_auto_ledger_cb (GtkWidget *w, gpointer data)
837 {
838  GNCSplitReg2 *gsr = data;
839 
840  if (!GTK_CHECK_MENU_ITEM (w)->active)
841  return;
842 
843  gnc_split_reg2_change_style (gsr, REG2_STYLE_AUTO_LEDGER);
844 }
845 
846 void
847 gnc_split_reg2_style_journal_cb (GtkWidget *w, gpointer data)
848 {
849  GNCSplitReg2 *gsr = data;
850 
851  if (!GTK_CHECK_MENU_ITEM (w)->active)
852  return;
853 
854  gnc_split_reg2_change_style (gsr, REG2_STYLE_JOURNAL);
855 }
856 
857 void
858 gnc_split_reg2_double_line_cb (GtkWidget *w, gpointer data)
859 {
860  GNCSplitReg2 *gsr = data;
861  GncTreeModelSplitReg *model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
862  gboolean use_double_line;
863 
864  use_double_line = GTK_CHECK_MENU_ITEM (w)->active;
865  if (use_double_line == model->use_double_line)
866  return;
867 
868  gnc_tree_model_split_reg_config (model, model->type, model->style, use_double_line);
869 
870  // This will re-display the view.
871  gnc_tree_view_split_reg_set_format (gnc_ledger_display2_get_split_view_register (gsr->ledger));
872 }
873 
874 static
875 GtkWidget*
876 add_summary_label (GtkWidget *summarybar, const char *label_str)
877 {
878  GtkWidget *hbox;
879  GtkWidget *label;
880 
881  hbox = gtk_hbox_new (FALSE, 2);
882  gtk_box_pack_start (GTK_BOX (summarybar), hbox, FALSE, FALSE, 5);
883 
884  label = gtk_label_new (label_str);
885  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
886  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
887 
888  label = gtk_label_new ("");
889  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
890  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
891 
892  return label;
893 }
894 
895 GtkWidget *
896 gnc_split_reg2_create_summary_bar (GNCSplitReg2 *gsr)
897 {
898  GtkWidget *summarybar;
899 
900  gsr->cleared_label = NULL;
901  gsr->balance_label = NULL;
902  gsr->reconciled_label = NULL;
903  gsr->future_label = NULL;
904  gsr->projectedminimum_label = NULL;
905  gsr->shares_label = NULL;
906  gsr->value_label = NULL;
907 
908  if (gnc_ledger_display2_type (gsr->ledger) >= LD2_SUBACCOUNT)
909  {
910  gsr->summarybar = NULL;
911  return NULL;
912  }
913 
914  summarybar = gtk_hbox_new (FALSE, 4);
915 
916  if (!xaccAccountIsPriced(gnc_ledger_display2_leader(gsr->ledger)))
917  {
918  gsr->balance_label = add_summary_label (summarybar, _("Present:"));
919  gsr->future_label = add_summary_label (summarybar, _("Future:"));
920  gsr->cleared_label = add_summary_label (summarybar, _("Cleared:"));
921  gsr->reconciled_label = add_summary_label (summarybar, _("Reconciled:"));
922  gsr->projectedminimum_label = add_summary_label (summarybar, _("Projected Minimum:"));
923  }
924  else
925  {
926  gsr->shares_label = add_summary_label (summarybar, _("Shares:"));
927  gsr->value_label = add_summary_label (summarybar, _("Current Value:"));
928  }
929 
930  gsr->summarybar = summarybar;
931 
932  /* Force the first update */
933  gsr2_redraw_all_cb (NULL, gsr);
934  return gsr->summarybar;
935 }
936 
943 static
945 gnc_split_reg2_get_placeholder (GNCSplitReg2 *gsr)
946 {
947  Account *leader;
948  GncTreeModelSplitReg *model;
949  gboolean single_account;
950 
951  if (gsr == NULL)
952  return PLACEHOLDER_NONE;
953 
954  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
955 
956  switch (model->type)
957  {
958  case GENERAL_LEDGER2:
959  case INCOME_LEDGER2:
960  case PORTFOLIO_LEDGER2:
961  case SEARCH_LEDGER2:
962  single_account = FALSE;
963  break;
964  default:
965  single_account = TRUE;
966  break;
967  }
968 
969  leader = gnc_ledger_display2_leader (gsr->ledger);
970 
971  if (leader == NULL)
972  return PLACEHOLDER_NONE;
973  if (single_account)
974  {
975  if (xaccAccountGetPlaceholder (leader))
976  return PLACEHOLDER_THIS;
977  return PLACEHOLDER_NONE;
978  }
979  return xaccAccountGetDescendantPlaceholder (leader);
980 }
981 
982 
983 
987 typedef struct dialog_args
988 {
989  GNCSplitReg2 *gsr;
990  gchar *string;
991 } dialog_args;
992 
993 
994 /* This Register is an Account Payable / Receivable one */
995 static
996 gboolean
997 gsr2_determine_account_pr_dialog (gpointer argp)
998 {
999  dialog_args *args = argp;
1000  GtkWidget *dialog;
1001 
1002  const char *title = _("Account Payable / Receivable Register");
1003  const char *message =
1004  _("The register displayed is for Account Payable or Account Receivable. "
1005  "Changing the entries may cause harm, please use the business "
1006  "options to change the entries.");
1007 
1008  dialog = gtk_message_dialog_new (GTK_WINDOW (args->gsr->window),
1009  GTK_DIALOG_DESTROY_WITH_PARENT,
1010  GTK_MESSAGE_WARNING,
1011  GTK_BUTTONS_CLOSE,
1012  "%s", title);
1013  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1014  "%s", message);
1015 
1016  gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_IS_ACCT_PAY_REC);
1017  gtk_widget_destroy (dialog);
1018  g_free (args);
1019  return FALSE;
1020 }
1021 
1022 
1023 /* This Register is an Account Payable / Receivable one */
1024 static void
1025 gnc_split_reg2_determine_account_pr (GNCSplitReg2 *gsr)
1026 {
1027  dialog_args *args = g_malloc (sizeof (dialog_args));
1028  GncTreeModelSplitReg *model;
1029 
1030  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
1031 
1032  if (model->type != PAYABLE_REGISTER2 && model->type != RECEIVABLE_REGISTER2)
1033  return;
1034 
1035  /* Put up a warning dialog */
1036  args->gsr = gsr;
1037  g_timeout_add (250, gsr2_determine_account_pr_dialog, args); /* 0.25 seconds */
1038 }
1039 
1040 
1046 static
1047 gboolean
1048 gtk_callback_bug_workaround (gpointer argp)
1049 {
1050  dialog_args *args = argp;
1051  const gchar *read_only = _("This account register is read-only.");
1052  GtkWidget *dialog;
1053 
1054  dialog = gtk_message_dialog_new (GTK_WINDOW(args->gsr->window),
1055  GTK_DIALOG_DESTROY_WITH_PARENT,
1056  GTK_MESSAGE_WARNING,
1057  GTK_BUTTONS_CLOSE,
1058  "%s", read_only);
1059  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1060  "%s", args->string);
1061  gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_IS_READ_ONLY);
1062  gtk_widget_destroy (dialog);
1063  g_free (args);
1064  return FALSE;
1065 }
1066 
1070 static
1071 void
1072 gnc_split_reg2_determine_read_only (GNCSplitReg2 *gsr) //this works
1073 {
1074  dialog_args *args = g_malloc (sizeof (dialog_args));
1075  GncTreeViewSplitReg *view;
1076 
1077  if (qof_book_is_readonly (gnc_get_current_book()))
1078  {
1079  /* Is the book read-only? Then for sure also make this register
1080  read-only. */
1081  gsr->read_only = TRUE;
1082  }
1083 
1084  if (!gsr->read_only)
1085  {
1086 
1087  switch (gnc_split_reg2_get_placeholder (gsr))
1088  {
1089  case PLACEHOLDER_NONE:
1090  /* stay as false. */
1091  return;
1092 
1093  case PLACEHOLDER_THIS:
1094  args->string = _("This account may not be edited. If you want "
1095  "to edit transactions in this register, please "
1096  "open the account options and turn off the "
1097  "placeholder checkbox.");
1098  break;
1099 
1100  default:
1101  args->string = _("One of the sub-accounts selected may not be "
1102  "edited. If you want to edit transactions in "
1103  "this register, please open the sub-account "
1104  "options and turn off the placeholder checkbox. "
1105  "You may also open an individual account instead "
1106  "of a set of accounts.");
1107  break;
1108  }
1109  gsr->read_only = TRUE;
1110  /* Put up a warning dialog */
1111  args->gsr = gsr;
1112  g_timeout_add (250, gtk_callback_bug_workaround, args); /* 0.25 seconds */
1113  }
1114 }
1115 
1116 static
1117 GtkWidget *
1118 gnc_split_reg2_get_parent (GNCLedgerDisplay2 *ledger)
1119 {
1120  GNCSplitReg2 *gsr =
1121  GNC_SPLIT_REG2 (gnc_ledger_display2_get_user_data (ledger));
1122 
1123  if (gsr == NULL)
1124  return NULL;
1125 
1126  return gsr->window;
1127 }
1128 
1129 static void
1130 gsr2_emit_help_changed (GncTreeViewSplitReg *view, gpointer user_data)
1131 {
1132  gsr2_emit_simple_signal ((GNCSplitReg2*)user_data, "help-changed" );
1133 }
1134 
1135 /* Callback to keep vertical scroll bar in sync */
1136 static void
1137 gsr2_scroll_sync_cb (GncTreeModelSplitReg *model, gpointer user_data)
1138 {
1139  GNCSplitReg2 *gsr = user_data;
1140  gint trans_position;
1141 
1142  trans_position = model->position_of_trans_in_full_tlist;
1143 
1144  gtk_adjustment_set_value (gsr->scroll_adj, trans_position);
1145 
1146  gtk_adjustment_set_upper (gsr->scroll_adj, model->number_of_trans_in_full_tlist + 9);
1147 }
1148 
1149 static void
1150 gsr2_scroll_value_changed_cb (GtkAdjustment *adj, gpointer user_data)
1151 {
1152  GNCSplitReg2 *gsr = user_data;
1153  GncTreeModelSplitReg *model;
1154  gchar *text;
1155  gint trans_position;
1156 
1157  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
1158 
1159  trans_position = gtk_adjustment_get_value (adj);
1160 
1161  text = gnc_tree_model_split_reg_get_tooltip (model, trans_position);
1162 
1163  g_object_set (gtk_widget_get_settings (gsr->scroll_bar), "gtk-tooltip-timeout", 2, NULL);
1164 
1165  gtk_widget_set_tooltip_text (gsr->scroll_bar, text);
1166 
1167  g_free (text);
1168 }
1169 
1170 static
1171 gboolean
1172 gsr2_scroll_button_event_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1173 {
1174  GNCSplitReg2 *gsr = user_data;
1175  GncTreeModelSplitReg *model;
1176  gint trans_position;
1177 
1178  model = gnc_ledger_display2_get_split_model_register (gsr->ledger);
1179 
1180  trans_position = gtk_adjustment_get_value (gsr->scroll_adj);
1181 
1182  gnc_tree_model_split_reg_set_current_trans_by_position (model, trans_position);
1183 
1184 //FIXME should we store what it was...
1185  g_object_set (gtk_widget_get_settings (gsr->scroll_bar), "gtk-tooltip-timeout", 500, NULL);
1186 
1187  g_signal_emit_by_name (model, "refresh_trans");
1188 
1189  return FALSE;
1190 }
1191 
1192 static
1193 void
1194 gsr2_emit_simple_signal (GNCSplitReg2 *gsr, const char *sigName)
1195 {
1196  g_signal_emit_by_name( gsr, sigName, NULL );
1197 }
1198 
1200 gnc_split_reg2_get_register (GNCSplitReg2 *gsr )
1201 {
1202  if ( !gsr )
1203  return NULL;
1204 
1205  return gnc_ledger_display2_get_split_view_register (gsr->ledger);
1206 }
1207 
1208 GtkWidget*
1209 gnc_split_reg2_get_summarybar (GNCSplitReg2 *gsr)
1210 {
1211  if (!gsr) return NULL;
1212  return gsr->summarybar;
1213 }
1214 
1215 gboolean
1216 gnc_split_reg2_get_read_only (GNCSplitReg2 *gsr)
1217 {
1218  g_assert (gsr);
1219  return gsr->read_only;
1220 }
1221 
1222 void
1223 gnc_split_reg2_set_moved_cb (GNCSplitReg2 *gsr, GFunc cb, gpointer cb_data ) //this works
1224 {
1225  gnc_tree_view_split_reg_set_uiupdate_cb (gnc_ledger_display2_get_split_view_register (gsr->ledger), cb, cb_data);
1226 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
void gnc_price_list_destroy(PriceList *prices)
Definition: gnc-pricedb.c:701
Functions to load, save and get gui state.
void gnc_tree_view_expand_columns(GncTreeView *view, gchar *first_column_name,...)
#define xaccTransAppendSplit(t, s)
Definition: Transaction.h:357
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
Definition: Transaction.c:1920
int gnc_commodity_get_fraction(const gnc_commodity *cm)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
gboolean xaccAccountIsPriced(const Account *acc)
Definition: Account.c:4249
gnc_numeric gnc_numeric_neg(gnc_numeric a)
void gnc_price_unref(GNCPrice *p)
Definition: gnc-pricedb.c:272
GNCLedgerDisplay2 * ledger
void xaccTransSetDescription(Transaction *trans, const char *desc)
Definition: Transaction.c:2085
gboolean gnc_numeric_zero_p(gnc_numeric a)
void gnc_tree_view_set_show_column_menu(GncTreeView *view, gboolean visible)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
GtkTreeViewColumn * gnc_tree_view_find_column_by_name(GncTreeView *view, const gchar *wanted)
#define ENTER(format, args...)
Definition: qoflog.h:261
GKeyFile * gnc_state_get_current(void)
Definition: gnc-state.c:252
gnc_numeric xaccAccountGetClearedBalance(const Account *acc)
Definition: Account.c:3236
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Definition: gnc-pricedb.c:872
Definition: guid.h:65
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
gnc_commodity * gnc_default_currency(void)
Definition: gnc-ui-util.c:939
#define xaccAccountGetGUID(X)
Definition: Account.h:239
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
GNCPlaceholderType xaccAccountGetDescendantPlaceholder(const Account *acc)
Definition: Account.c:3935
void gnc_tree_view_configure_columns(GncTreeView *view)
PriceList * gnc_pricedb_lookup_latest_any_currency(GNCPriceDB *db, const gnc_commodity *commodity)
Definition: gnc-pricedb.c:1373
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_numeric xaccAccountGetReconciledBalance(const Account *acc)
Definition: Account.c:3243
gnc_numeric xaccAccountGetBalance(const Account *acc)
Definition: Account.c:3229
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Definition: gnc-ui-util.c:1437
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
const gchar * gnc_tree_view_get_state_section(GncTreeView *view)
GNCPlaceholderType
Definition: Account.h:1125
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Definition: gnc-ui-util.c:944
gboolean qof_book_is_readonly(const QofBook *book)
GNCPrice * gnc_price_clone(GNCPrice *p, QofBook *book)
Definition: gnc-pricedb.c:295
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
#define xaccAccountInsertSplit(acc, s)
Definition: Account.h:972
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
#define LEAVE(format, args...)
Definition: qoflog.h:271
gint64 time64
Definition: gnc-date.h:83
GNCPrice * gnc_pricedb_lookup_latest(GNCPriceDB *db, const gnc_commodity *commodity, const gnc_commodity *currency)
Definition: gnc-pricedb.c:1309
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
const gchar * QofLogModule
Definition: qofid.h:89