GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-split-reg.c
1 /********************************************************************\
2  * gnc-split-reg.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  * *
10  * This program is free software; you can redistribute it and/or *
11  * modify it under the terms of the GNU General Public License as *
12  * published by the Free Software Foundation; either version 2 of *
13  * the License, or (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License*
21  * along with this program; if not, contact: *
22  * *
23  * Free Software Foundation Voice: +1-617-542-5942 *
24  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
25  * Boston, MA 02110-1301, USA [email protected] *
26 \********************************************************************/
27 
28 #include "config.h"
29 
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <time.h>
33 
34 #include "gnc-split-reg.h"
35 
36 #include "Account.h"
37 #include "qof.h"
38 #include "SX-book.h"
39 #include "dialog-account.h"
40 #include "dialog-sx-editor.h"
41 #include "dialog-sx-from-trans.h"
42 #include "gnc-component-manager.h"
43 #include "gnc-date-edit.h"
44 #include "gnc-engine.h"
45 #include "gnc-euro.h"
46 #include "gnc-prefs.h"
47 #include "gnc-gui-query.h"
48 #include "gnc-gnome-utils.h"
49 #include "gnc-ledger-display.h"
50 #include "gnc-pricedb.h"
51 #include "gnc-ui-util.h"
52 #include "gnc-ui.h"
53 #include "gnome-utils/gnc-warnings.h"
54 #include "gnucash-sheet.h"
55 #include "table-allgui.h"
56 
57 #include "dialog-utils.h"
58 
59 // static QofLogModule log_module = GNC_MOD_SX;
60 static QofLogModule log_module = GNC_MOD_GUI;
61 
62 #define STATE_SECTION_REG_PREFIX "Register"
63 
64 /***** PROTOTYPES ***************************************************/
65 void gnc_split_reg_raise( GNCSplitReg *gsr );
66 
67 static GtkWidget* add_summary_label( GtkWidget *summarybar,
68  const char *label_str );
69 
70 static void gnc_split_reg_determine_read_only( GNCSplitReg *gsr );
71 
72 static GNCPlaceholderType gnc_split_reg_get_placeholder( GNCSplitReg *gsr );
73 static GtkWidget *gnc_split_reg_get_parent( GNCLedgerDisplay *ledger );
74 
75 static void gsr_create_table( GNCSplitReg *gsr );
76 static void gsr_setup_table( GNCSplitReg *gsr );
77 static void gsr_setup_status_widgets( GNCSplitReg *gsr );
78 
79 static void gsr_update_summary_label( GtkWidget *label,
80  xaccGetBalanceFn getter,
81  Account *leader,
82  GNCPrintAmountInfo print_info,
83  gnc_commodity *cmdty,
84  gboolean reverse,
85  gboolean euroFlag );
86 
87 static void gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data);
88 
89 static void gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger );
90 
91 static Transaction* create_balancing_transaction(QofBook *book, Account *account,
92  time64 statement_date, gnc_numeric balancing_amount);
93 
94 void gsr_default_enter_handler ( GNCSplitReg *w, gpointer ud );
95 void gsr_default_cancel_handler ( GNCSplitReg *w, gpointer ud );
96 void gsr_default_delete_handler ( GNCSplitReg *w, gpointer ud );
97 void gsr_default_reinit_handler ( GNCSplitReg *w, gpointer ud );
98 void gsr_default_dup_handler ( GNCSplitReg *w, gpointer ud );
99 void gsr_default_schedule_handler ( GNCSplitReg *w, gpointer ud );
100 void gsr_default_expand_handler ( GNCSplitReg *w, gpointer ud );
101 void gsr_default_blank_handler ( GNCSplitReg *w, gpointer ud );
102 void gsr_default_jump_handler ( GNCSplitReg *w, gpointer ud );
103 void gsr_default_cut_handler ( GNCSplitReg *w, gpointer ud );
104 void gsr_default_cut_txn_handler ( GNCSplitReg *w, gpointer ud );
105 void gsr_default_copy_handler ( GNCSplitReg *w, gpointer ud );
106 void gsr_default_copy_txn_handler ( GNCSplitReg *w, gpointer ud );
107 void gsr_default_paste_handler ( GNCSplitReg *w, gpointer ud );
108 void gsr_default_paste_txn_handler( GNCSplitReg *w, gpointer ud );
109 void gsr_default_void_txn_handler ( GNCSplitReg *w, gpointer ud );
110 void gsr_default_unvoid_txn_handler ( GNCSplitReg *w, gpointer ud );
111 void gsr_default_reverse_txn_handler ( GNCSplitReg *w, gpointer ud );
112 void gsr_default_associate_handler_file ( GNCSplitReg *w, gpointer ud );
113 void gsr_default_associate_handler_location ( GNCSplitReg *w, gpointer ud );
114 void gsr_default_execassociated_handler ( GNCSplitReg *w, gpointer ud );
115 
116 static void gsr_emit_simple_signal( GNCSplitReg *gsr, const char *sigName );
117 static void gsr_emit_help_changed( GnucashRegister *reg, gpointer user_data );
118 static void gsr_emit_include_date_signal( GNCSplitReg *gsr, time64 date );
119 
120 void gnc_split_reg_cut_cb(GtkWidget *w, gpointer data);
121 void gnc_split_reg_copy_cb(GtkWidget *w, gpointer data);
122 void gnc_split_reg_paste_cb(GtkWidget *w, gpointer data);
123 
124 void gnc_split_reg_cut_trans_cb(GtkWidget *w, gpointer data);
125 void gnc_split_reg_copy_trans_cb(GtkWidget *w, gpointer data);
126 void gnc_split_reg_paste_trans_cb(GtkWidget *w, gpointer data);
127 void gnc_split_reg_void_trans_cb(GtkWidget *w, gpointer data);
128 void gnc_split_reg_unvoid_trans_cb(GtkWidget *w, gpointer data);
129 void gnc_split_reg_reverse_trans_cb(GtkWidget *w, gpointer data);
130 
131 void gnc_split_reg_record_cb (GnucashRegister *reg, gpointer data);
132 void gnc_split_reg_reinitialize_trans_cb(GtkWidget *w, gpointer data);
133 void gnc_split_reg_delete_trans_cb(GtkWidget *w, gpointer data);
134 void gnc_split_reg_duplicate_trans_cb(GtkWidget *w, gpointer data);
135 void gnc_split_reg_recur_cb(GtkWidget *w, gpointer data);
136 void gnc_split_reg_record_trans_cb(GtkWidget *w, gpointer data);
137 void gnc_split_reg_cancel_trans_cb(GtkWidget *w, gpointer data);
138 
139 void gnc_split_reg_expand_trans_menu_cb(GtkWidget *widget, gpointer data);
140 void gnc_split_reg_expand_trans_toolbar_cb(GtkWidget *widget, gpointer data);
141 void gnc_split_reg_new_trans_cb(GtkWidget *widget, gpointer data);
142 void gnc_split_reg_jump_cb(GtkWidget *widget, gpointer data);
143 
144 void gnc_split_reg_style_ledger_cb (GtkWidget *w, gpointer data);
145 void gnc_split_reg_style_auto_ledger_cb (GtkWidget *w, gpointer data);
146 void gnc_split_reg_style_journal_cb (GtkWidget *w, gpointer data);
147 void gnc_split_reg_double_line_cb (GtkWidget *w, gpointer data);
148 
149 void gnc_split_reg_sort_standard_cb (GtkWidget *w, gpointer data);
150 void gnc_split_reg_sort_date_cb (GtkWidget *w, gpointer data);
151 void gnc_split_reg_sort_date_entered_cb (GtkWidget *w, gpointer data);
152 void gnc_split_reg_sort_date_reconciled_cb (GtkWidget *w, gpointer data);
153 void gnc_split_reg_sort_num_cb (GtkWidget *w, gpointer data);
154 void gnc_split_reg_sort_amount_cb (GtkWidget *w, gpointer data);
155 void gnc_split_reg_sort_memo_cb (GtkWidget *w, gpointer data);
156 void gnc_split_reg_sort_desc_cb (GtkWidget *w, gpointer data);
157 void gnc_split_reg_sort_action_cb (GtkWidget *w, gpointer data);
158 void gnc_split_reg_sort_notes_cb (GtkWidget *w, gpointer data);
159 
160 
161 void gnc_split_reg_destroy_cb(GtkWidget *widget, gpointer data);
162 void gnc_split_reg_size_allocate( GtkWidget *widget,
163  GtkAllocation *allocation,
164  gpointer user_data );
165 
166 
167 void gnc_split_reg_handle_exchange_cb (GtkWidget *w, gpointer data);
168 
169 static void gnc_split_reg_class_init( GNCSplitRegClass *klass );
170 static void gnc_split_reg_init( GNCSplitReg *gsr );
171 static void gnc_split_reg_init2( GNCSplitReg *gsr );
172 
173 FROM_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
174 AS_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
175 
176 GType
177 gnc_split_reg_get_type( void )
178 {
179  static GType gnc_split_reg_type = 0;
180 
181  if (!gnc_split_reg_type)
182  {
183  GTypeInfo type_info =
184  {
185  sizeof(GNCSplitRegClass), /* class_size */
186  NULL, /* base_init */
187  NULL, /* base_finalize */
188  (GClassInitFunc)gnc_split_reg_class_init,
189  NULL, /* class_finalize */
190  NULL, /* class_data */
191  sizeof(GNCSplitReg), /* */
192  0, /* n_preallocs */
193  (GInstanceInitFunc)gnc_split_reg_init,
194  };
195 
196  gnc_split_reg_type = g_type_register_static( GTK_TYPE_VBOX,
197  "GNCSplitReg",
198  &type_info, 0 );
199  }
200 
201  return gnc_split_reg_type;
202 }
203 
204 /* SIGNALS */
205 enum gnc_split_reg_signal_enum
206 {
207  ENTER_ENT_SIGNAL,
208  CANCEL_ENT_SIGNAL,
209  DELETE_ENT_SIGNAL,
210  REINIT_ENT_SIGNAL,
211  DUP_ENT_SIGNAL,
212  SCHEDULE_ENT_SIGNAL,
213  EXPAND_ENT_SIGNAL,
214  BLANK_SIGNAL,
215  JUMP_SIGNAL,
216  CUT_SIGNAL,
217  CUT_TXN_SIGNAL,
218  COPY_SIGNAL,
219  COPY_TXN_SIGNAL,
220  PASTE_SIGNAL,
221  PASTE_TXN_SIGNAL,
222  VOID_TXN_SIGNAL,
223  UNVOID_TXN_SIGNAL,
224  REVERSE_TXN_SIGNAL,
225  HELP_CHANGED_SIGNAL,
226  INCLUDE_DATE_SIGNAL,
227  LAST_SIGNAL
228 };
229 
230 static guint gnc_split_reg_signals[LAST_SIGNAL] = { 0 };
231 
232 static void
233 gnc_split_reg_class_init( GNCSplitRegClass *klass )
234 {
235  int i;
236  GtkObjectClass *object_class;
237  static struct similar_signal_info
238  {
239  enum gnc_split_reg_signal_enum s;
240  const char *signal_name;
241  guint defaultOffset;
242  } signals[] =
243  {
244  { ENTER_ENT_SIGNAL, "enter_ent", G_STRUCT_OFFSET( GNCSplitRegClass, enter_ent_cb ) },
245  { CANCEL_ENT_SIGNAL, "cancel_ent", G_STRUCT_OFFSET( GNCSplitRegClass, cancel_ent_cb ) },
246  { DELETE_ENT_SIGNAL, "delete_ent", G_STRUCT_OFFSET( GNCSplitRegClass, delete_ent_cb ) },
247  { REINIT_ENT_SIGNAL, "reinit_ent", G_STRUCT_OFFSET( GNCSplitRegClass, reinit_ent_cb ) },
248  { DUP_ENT_SIGNAL, "dup_ent", G_STRUCT_OFFSET( GNCSplitRegClass, dup_ent_cb ) },
249  { SCHEDULE_ENT_SIGNAL, "schedule_ent", G_STRUCT_OFFSET( GNCSplitRegClass, schedule_ent_cb ) },
250  { EXPAND_ENT_SIGNAL, "expand_ent", G_STRUCT_OFFSET( GNCSplitRegClass, expand_ent_cb ) },
251  { BLANK_SIGNAL, "blank", G_STRUCT_OFFSET( GNCSplitRegClass, blank_cb ) },
252  { JUMP_SIGNAL, "jump", G_STRUCT_OFFSET( GNCSplitRegClass, jump_cb ) },
253  { CUT_SIGNAL, "cut", G_STRUCT_OFFSET( GNCSplitRegClass, cut_cb ) },
254  { CUT_TXN_SIGNAL, "cut_txn", G_STRUCT_OFFSET( GNCSplitRegClass, cut_txn_cb ) },
255  { COPY_SIGNAL, "copy", G_STRUCT_OFFSET( GNCSplitRegClass, copy_cb ) },
256  { COPY_TXN_SIGNAL, "copy_txn", G_STRUCT_OFFSET( GNCSplitRegClass, copy_txn_cb ) },
257  { PASTE_SIGNAL, "paste", G_STRUCT_OFFSET( GNCSplitRegClass, paste_cb ) },
258  { PASTE_TXN_SIGNAL, "paste_txn", G_STRUCT_OFFSET( GNCSplitRegClass, paste_txn_cb ) },
259  { VOID_TXN_SIGNAL, "void_txn", G_STRUCT_OFFSET( GNCSplitRegClass, void_txn_cb ) },
260  { UNVOID_TXN_SIGNAL, "unvoid_txn", G_STRUCT_OFFSET( GNCSplitRegClass, unvoid_txn_cb ) },
261  { REVERSE_TXN_SIGNAL, "reverse_txn", G_STRUCT_OFFSET( GNCSplitRegClass, reverse_txn_cb ) },
262  { HELP_CHANGED_SIGNAL, "help-changed", G_STRUCT_OFFSET( GNCSplitRegClass, help_changed_cb ) },
263  { INCLUDE_DATE_SIGNAL, "include-date", G_STRUCT_OFFSET( GNCSplitRegClass, include_date_cb ) },
264  { LAST_SIGNAL, NULL, 0 }
265  };
266 
267  object_class = (GtkObjectClass*) klass;
268 
269  for ( i = 0; signals[i].s != INCLUDE_DATE_SIGNAL; i++ )
270  {
271  gnc_split_reg_signals[ signals[i].s ] =
272  g_signal_new( signals[i].signal_name,
273  G_TYPE_FROM_CLASS(object_class),
274  G_SIGNAL_RUN_LAST,
275  signals[i].defaultOffset,
276  NULL, NULL,
277  g_cclosure_marshal_VOID__VOID,
278  G_TYPE_NONE, 0 );
279  }
280  /* Setup the non-default-marshalled signals; 'i' is still valid, here. */
281  /* "include-date" */
282  gnc_split_reg_signals[ INCLUDE_DATE_SIGNAL ] =
283  g_signal_new( "include-date",
284  G_TYPE_FROM_CLASS(object_class),
285  G_SIGNAL_RUN_LAST,
286  signals[i++].defaultOffset,
287  NULL, NULL,
288  g_cclosure_marshal_VOID__INT, /* time64 == int */
289  G_TYPE_NONE, 1, G_TYPE_INT );
290 
291  g_assert( i == LAST_SIGNAL );
292 
293  /* Setup the default handlers. */
294  klass->enter_ent_cb = gsr_default_enter_handler;
295  klass->cancel_ent_cb = gsr_default_cancel_handler;
296  klass->delete_ent_cb = gsr_default_delete_handler;
297  klass->reinit_ent_cb = gsr_default_reinit_handler;
298  klass->dup_ent_cb = gsr_default_dup_handler;
299  klass->schedule_ent_cb = gsr_default_schedule_handler;
300  klass->expand_ent_cb = gsr_default_expand_handler;
301  klass->blank_cb = gsr_default_blank_handler;
302  klass->jump_cb = gsr_default_jump_handler;
303  klass->cut_cb = gsr_default_cut_handler;
304  klass->cut_txn_cb = gsr_default_cut_txn_handler;
305  klass->copy_cb = gsr_default_copy_handler;
306  klass->copy_txn_cb = gsr_default_copy_txn_handler;
307  klass->paste_cb = gsr_default_paste_handler;
308  klass->paste_txn_cb = gsr_default_paste_txn_handler;
309  klass->void_txn_cb = gsr_default_void_txn_handler;
310  klass->unvoid_txn_cb = gsr_default_unvoid_txn_handler;
311  klass->reverse_txn_cb = gsr_default_reverse_txn_handler;
312 
313  klass->help_changed_cb = NULL;
314  klass->include_date_cb = NULL;
315 }
316 
317 GtkWidget*
318 gnc_split_reg_new( GNCLedgerDisplay *ld,
319  GtkWindow *parent,
320  gint numberOfLines,
321  gboolean read_only )
322 {
323  GNCSplitReg *gsrToRet;
324 
325  ENTER("ld=%p, parent=%p, numberOfLines=%d, read_only=%s",
326  ld, parent, numberOfLines, read_only ? "TRUE" : "FALSE");
327 
328  gsrToRet = g_object_new( gnc_split_reg_get_type(), NULL );
329 
330  gsrToRet->numRows = numberOfLines;
331  gsrToRet->read_only = read_only;
332 
333  gsrToRet->ledger = ld;
334  gsrToRet->window = GTK_WIDGET(parent);
335 
336  gnc_split_reg_init2( gsrToRet );
337 
338  LEAVE("%p", gsrToRet);
339  return GTK_WIDGET( gsrToRet );
340 }
341 
342 static void
343 gnc_split_reg_init( GNCSplitReg *gsr )
344 {
345  gsr->sort_type = BY_STANDARD;
346  gsr->width = -1;
347  gsr->height = -1;
348  gsr->numRows = 10;
349  gsr->read_only = FALSE;
350 
351  g_signal_connect( gsr, "destroy",
352  G_CALLBACK (gnc_split_reg_destroy_cb), gsr );
353 }
354 
355 static void
356 gnc_split_reg_init2( GNCSplitReg *gsr )
357 {
358  if ( !gsr ) return;
359 
360  gnc_split_reg_determine_read_only( gsr );
361 
362  gsr_setup_status_widgets( gsr );
363  /* ordering is important here... setup_status before create_table */
364  gsr_create_table( gsr );
365  gsr_setup_table( gsr );
366 }
367 
368 static
369 void
370 gsr_setup_table( GNCSplitReg *gsr )
371 {
372  SplitRegister *sr;
373 
374  ENTER("gsr=%p", gsr);
375 
376  sr = gnc_ledger_display_get_split_register( gsr->ledger );
378  /* events should be sufficient to redraw this */
379  /* gnc_ledger_display_refresh( gsr->ledger ); */
380 
381  LEAVE(" ");
382 }
383 
384 static
385 void
386 gsr_create_table( GNCSplitReg *gsr )
387 {
388  GtkWidget *register_widget = NULL;
389  SplitRegister *sr = NULL;
390 
391  Account * account = gnc_ledger_display_leader(gsr->ledger);
392  const GncGUID * guid = xaccAccountGetGUID(account);
393  gchar guidstr[GUID_ENCODING_LENGTH+1];
394  gchar *state_section = NULL;
395  guid_to_string_buff(guid, guidstr);
396  state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr, NULL);
397 
398  ENTER("gsr=%p", gsr);
399 
400  gnc_ledger_display_set_user_data( gsr->ledger, (gpointer)gsr );
401  gnc_ledger_display_set_handlers( gsr->ledger,
402  gnc_split_reg_ld_destroy,
403  gnc_split_reg_get_parent );
404 
405  /* FIXME: We'd really rather pass this down... */
406  sr = gnc_ledger_display_get_split_register( gsr->ledger );
407  register_widget = gnucash_register_new( sr->table );
408  gsr->reg = GNUCASH_REGISTER( register_widget );
409  gnc_table_init_gui( GTK_WIDGET(gsr->reg), state_section);
410  g_free (state_section);
411  gtk_box_pack_start (GTK_BOX (gsr), GTK_WIDGET(gsr->reg), TRUE, TRUE, 0);
412  gnucash_sheet_set_window (gnucash_register_get_sheet (gsr->reg), gsr->window);
413  gtk_widget_show ( GTK_WIDGET(gsr->reg) );
414  g_signal_connect (gsr->reg, "activate_cursor",
415  G_CALLBACK(gnc_split_reg_record_cb), gsr);
416  g_signal_connect (gsr->reg, "redraw_all",
417  G_CALLBACK(gsr_redraw_all_cb), gsr);
418  g_signal_connect (gsr->reg, "redraw_help",
419  G_CALLBACK(gsr_emit_help_changed), gsr);
420 
421  LEAVE(" ");
422 }
423 
424 static
425 void
426 gsr_setup_status_widgets( GNCSplitReg *gsr )
427 {
428  SplitRegister *sr;
429  gboolean use_double_line;
430 
431  sr = gnc_ledger_display_get_split_register( gsr->ledger );
432  use_double_line = gnc_ledger_display_default_double_line( gsr->ledger );
433 
434  /* be sure to initialize the gui elements associated with the cursor */
435  gnc_split_register_config( sr, sr->type, sr->style, use_double_line );
436 }
437 
438 void
439 gnc_split_reg_destroy_cb(GtkWidget *widget, gpointer data)
440 {
441 }
442 
446 void
447 gnc_split_reg_raise( GNCSplitReg *gsr )
448 {
449  if (gsr == NULL)
450  return;
451 
452  if (gsr->window == NULL)
453  return;
454 
455  gtk_window_present( GTK_WINDOW(gsr->window) );
456 }
457 
458 
463 static
464 void
465 gsr_update_summary_label( GtkWidget *label,
466  xaccGetBalanceFn getter,
467  Account *leader,
468  GNCPrintAmountInfo print_info,
469  gnc_commodity *cmdty,
470  gboolean reverse,
471  gboolean euroFlag )
472 {
473  gnc_numeric amount;
474  char string[256];
475 
476  if ( label == NULL )
477  return;
478 
479  amount = (*getter)( leader );
480 
481  if ( reverse )
482  {
483  amount = gnc_numeric_neg( amount );
484  }
485 
486  xaccSPrintAmount( string, amount, print_info );
487 
488  if ( euroFlag )
489  {
490  strcat( string, " / " );
491  xaccSPrintAmount( string + strlen( string ),
492  gnc_convert_to_euro( cmdty, amount ),
493  gnc_commodity_print_info( gnc_get_euro(), TRUE ) );
494  }
495 
496  gnc_set_label_color( label, amount );
497  gtk_label_set_text( GTK_LABEL(label), string );
498 }
499 
500 static GNCPrice *
501 account_latest_price (Account *account)
502 {
503  QofBook *book;
504  GNCPriceDB *pdb;
505  gnc_commodity *commodity;
506  gnc_commodity *currency;
507 
508  if (!account) return NULL;
509  commodity = xaccAccountGetCommodity (account);
510  currency = gnc_default_currency ();
511 
512  book = gnc_account_get_book (account);
513  pdb = gnc_pricedb_get_db (book);
514 
515  return gnc_pricedb_lookup_latest (pdb, commodity, currency);
516 }
517 
518 static GNCPrice *
519 account_latest_price_any_currency (Account *account)
520 {
521  QofBook *book;
522  GNCPriceDB *pdb;
523  gnc_commodity *commodity;
524  GList *price_list;
525  GNCPrice *result;
526 
527  if (!account) return NULL;
528  commodity = xaccAccountGetCommodity (account);
529 
530  book = gnc_account_get_book (account);
531  pdb = gnc_pricedb_get_db (book);
532 
533  price_list = gnc_pricedb_lookup_latest_any_currency (pdb, commodity);
534  if (!price_list) return NULL;
535 
536  result = gnc_price_clone((GNCPrice *)(price_list->data), book);
537 
538  gnc_price_list_destroy(price_list);
539 
540  return result;
541 }
542 
543 static
544 void
545 gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
546 {
547  GNCSplitReg *gsr = data;
548  gnc_commodity * commodity;
549  GNCPrintAmountInfo print_info;
550  gnc_numeric amount;
551  char string[256];
552  Account *leader;
553  gboolean reverse;
554  gboolean euro;
555 
556  if ( gsr->summarybar == NULL )
557  return;
558 
559  leader = gnc_ledger_display_leader( gsr->ledger );
560 
561  commodity = xaccAccountGetCommodity( leader );
562 
563  /* no EURO converson, if account is already EURO or no EURO currency */
564  if (commodity != NULL)
565  euro = (gnc_is_euro_currency( commodity ) &&
566  (strncasecmp(gnc_commodity_get_mnemonic(commodity), "EUR", 3)));
567  else
568  euro = FALSE;
569 
570  print_info = gnc_account_print_info( leader, TRUE );
571  reverse = gnc_reverse_balance( leader );
572 
573  gsr_update_summary_label( gsr->balance_label,
574  xaccAccountGetPresentBalance,
575  leader, print_info, commodity, reverse, euro );
576  gsr_update_summary_label( gsr->cleared_label,
578  leader, print_info, commodity, reverse, euro );
579  gsr_update_summary_label( gsr->reconciled_label,
581  leader, print_info, commodity, reverse, euro );
582  gsr_update_summary_label( gsr->future_label,
584  leader, print_info, commodity, reverse, euro );
585  gsr_update_summary_label( gsr->projectedminimum_label,
586  xaccAccountGetProjectedMinimumBalance,
587  leader, print_info, commodity, reverse, euro );
588 
589  /* Print the summary share amount */
590  if (gsr->shares_label != NULL)
591  {
592  print_info = gnc_account_print_info( leader, TRUE );
593 
594  amount = xaccAccountGetBalance( leader );
595  if (reverse)
596  amount = gnc_numeric_neg( amount );
597 
598  xaccSPrintAmount( string, amount, print_info );
599 
600  gnc_set_label_color( gsr->shares_label, amount );
601  gtk_label_set_text( GTK_LABEL(gsr->shares_label), string );
602  }
603 
604  /* Print the summary share value */
605  if (gsr->value_label != NULL)
606  {
607  GNCPrice *price;
608 
609  amount = xaccAccountGetBalance (leader);
610  if (reverse) amount = gnc_numeric_neg (amount);
611 
612  price = account_latest_price (leader);
613  if (!price)
614  {
615  /* If the balance is zero, then print zero. */
616  if (gnc_numeric_equal(amount, gnc_numeric_zero()))
617  {
618  gnc_commodity *currency = gnc_default_currency ();
619  print_info = gnc_commodity_print_info (currency, TRUE);
620  amount = gnc_numeric_zero ();
621 
622  xaccSPrintAmount (string, amount, print_info);
623 
624  gnc_set_label_color (gsr->value_label, amount);
625  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
626  }
627  else
628  {
629  /* else try to do a double-price-conversion :-( */
630  price = account_latest_price_any_currency (leader);
631  if (!price)
632  {
633  gnc_set_label_color (gsr->value_label, gnc_numeric_zero ());
634  gtk_label_set_text (GTK_LABEL (gsr->value_label),
635  _("<No information>"));
636  }
637  else
638  {
639  gnc_commodity *currency = gnc_price_get_currency (price);
640  gnc_commodity *default_currency = gnc_default_currency ();
641  gnc_numeric currency_amount;
642  gnc_numeric default_currency_amount;
643 
644  print_info = gnc_commodity_print_info (currency, TRUE);
645 
646  currency_amount =
647  xaccAccountConvertBalanceToCurrency(leader, amount,
648  commodity, currency);
649  xaccSPrintAmount (string, currency_amount, print_info);
650 
651  default_currency_amount =
652  xaccAccountConvertBalanceToCurrency(leader, amount,
653  commodity,
654  default_currency);
655  if (!gnc_numeric_zero_p(default_currency_amount))
656  {
657  strcat( string, " / " );
658  print_info = gnc_commodity_print_info (default_currency, TRUE);
659  xaccSPrintAmount( string + strlen( string ), default_currency_amount,
660  print_info);
661  }
662 
663  gnc_set_label_color (gsr->value_label, amount);
664  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
665 
666  gnc_price_unref (price);
667  }
668  }
669  }
670  else
671  {
672  gnc_commodity *currency = gnc_price_get_currency (price);
673 
674  print_info = gnc_commodity_print_info (currency, TRUE);
675 
676  amount = gnc_numeric_mul (amount, gnc_price_get_value (price),
677  gnc_commodity_get_fraction (currency),
679 
680  xaccSPrintAmount (string, amount, print_info);
681 
682  gnc_set_label_color (gsr->value_label, amount);
683  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
684 
685  gnc_price_unref (price);
686  }
687  }
688 }
689 
690 static void
691 gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger )
692 {
693  GNCSplitReg *gsr = gnc_ledger_display_get_user_data( ledger );
694 
695  Account * account = gnc_ledger_display_leader(ledger);
696  const GncGUID * guid = xaccAccountGetGUID(account);
697  gchar guidstr[GUID_ENCODING_LENGTH+1];
698  gchar *state_section;
699 
700  guid_to_string_buff(guid, guidstr);
701 
702  state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr, NULL);
703 
704  if (gsr)
705  {
706  SplitRegister *reg;
707 
708  reg = gnc_ledger_display_get_split_register (ledger);
709 
710  if (reg && reg->table)
711  gnc_table_save_state (reg->table, state_section);
712 
713  /*
714  * Don't destroy the window here any more. The register no longer
715  * owns it.
716  */
717  }
718  g_free (state_section);
719  gnc_ledger_display_set_user_data (ledger, NULL);
720 }
721 
722 void
723 gsr_default_cut_handler( GNCSplitReg *gsr, gpointer data )
724 {
725  gnucash_register_cut_clipboard( gsr->reg );
726 }
727 
731 void
732 gnc_split_reg_cut_cb (GtkWidget *w, gpointer data)
733 {
734  GNCSplitReg *gsr = data;
735  gsr_emit_simple_signal( gsr, "cut" );
736 }
737 
738 void
739 gsr_default_copy_handler( GNCSplitReg *gsr, gpointer data )
740 {
741  gnucash_register_copy_clipboard( gsr->reg );
742 }
743 
747 void
748 gnc_split_reg_copy_cb (GtkWidget *w, gpointer data)
749 {
750  GNCSplitReg *gsr = data;
751  gsr_emit_simple_signal( gsr, "copy" );
752 }
753 
754 void
755 gsr_default_paste_handler( GNCSplitReg *gsr, gpointer data )
756 {
757  gnucash_register_paste_clipboard( gsr->reg );
758 }
759 
763 void
764 gnc_split_reg_paste_cb (GtkWidget *w, gpointer data)
765 {
766  GNCSplitReg *gsr = data;
767  gsr_emit_simple_signal( gsr, "paste" );
768 }
769 
770 void
771 gsr_default_cut_txn_handler( GNCSplitReg *gsr, gpointer data )
772 {
774  (gnc_ledger_display_get_split_register( gsr->ledger ));
775 }
776 
780 void
781 gnc_split_reg_cut_trans_cb (GtkWidget *w, gpointer data)
782 {
783  GNCSplitReg *gsr = data;
784  gsr_emit_simple_signal( gsr, "cut_txn" );
785 }
786 
787 void
788 gsr_default_copy_txn_handler( GNCSplitReg *gsr, gpointer data )
789 {
791  (gnc_ledger_display_get_split_register( gsr->ledger ));
792 }
793 
797 void
798 gnc_split_reg_copy_trans_cb(GtkWidget *w, gpointer data)
799 {
800  GNCSplitReg *gsr = data;
801  gsr_emit_simple_signal( gsr, "copy_txn" );
802 }
803 
804 void
805 gsr_default_paste_txn_handler( GNCSplitReg *gsr, gpointer data )
806 {
808  (gnc_ledger_display_get_split_register( gsr->ledger ));
809 }
810 
814 void
815 gnc_split_reg_paste_trans_cb (GtkWidget *w, gpointer data)
816 {
817  GNCSplitReg *gsr = data;
818  gsr_emit_simple_signal( gsr, "paste_txn" );
819 }
820 
821 /********************************************************************\
822  * gnc_split_reg_void_trans_cb *
823  * *
824  * Args: widget - the widget that called us *
825  * data - the data struct for this register *
826  * Return: none *
827 \********************************************************************/
828 void
829 gsr_default_void_txn_handler (GNCSplitReg *gsr, gpointer data)
830 {
831  // Override this function.
832 }
833 
834 void
835 gnc_split_reg_void_trans_cb (GtkWidget *w, gpointer data)
836 {
837  GNCSplitReg *gsr = data;
838  gsr_emit_simple_signal( gsr, "void_txn" );
839 }
840 
841 /********************************************************************\
842  * gnc_split_reg_unvoid_trans_cb *
843  * *
844  * Args: widget - the widget that called us *
845  * data - the data struct for this register *
846  * Return: none *
847 \********************************************************************/
848 void
849 gsr_default_unvoid_txn_handler (GNCSplitReg *gsr, gpointer data)
850 {
851  // Override this function.
852 }
853 
854 void
855 gnc_split_reg_unvoid_trans_cb (GtkWidget *w, gpointer data)
856 {
857  GNCSplitReg *gsr = data;
858  gsr_emit_simple_signal( gsr, "unvoid_txn" );
859 }
860 
861 /********************************************************************\
862  * gnc_split_reg_reverse_trans_cb *
863  * *
864  * Args: widget - the widget that called us *
865  * data - the data struct for this register *
866  * Return: none *
867 \********************************************************************/
868 void
869 gsr_default_reverse_txn_handler (GNCSplitReg *gsr, gpointer data)
870 {
871  SplitRegister *reg;
872  Transaction *trans, *new_trans;
873 
874  reg = gnc_ledger_display_get_split_register( gsr->ledger );
876  if (trans == NULL)
877  return;
878 
879  if (xaccTransGetReversedBy(trans))
880  {
881  gnc_error_dialog(gsr->window, "%s",
882  _("A reversing entry has already been created for this transaction."));
883  return;
884  }
885 
886  new_trans = xaccTransReverse(trans);
887 
888  /* Clear transaction level info */
890  xaccTransSetDateEnteredSecs(new_trans, gnc_time (NULL));
891 
892  /* Now jump to new trans */
893  gnc_split_reg_jump_to_split(gsr, xaccTransGetSplit(new_trans, 0));
894 }
895 
896 void
897 gnc_split_reg_reverse_trans_cb (GtkWidget *w, gpointer data)
898 {
899  GNCSplitReg *gsr = data;
900  gsr_emit_simple_signal( gsr, "reverse_txn" );
901 }
902 
903 
904 static gboolean
905 is_trans_readonly_and_warn (const Transaction *trans)
906 {
907  GtkWidget *dialog;
908  const gchar *reason;
909  const gchar *title = _("Cannot modify or delete this transaction.");
910  const gchar *message =
911  _("This transaction is marked read-only with the comment: '%s'");
912 
913  if (!trans) return FALSE;
914 
916  {
917  dialog = gtk_message_dialog_new(NULL,
918  0,
919  GTK_MESSAGE_ERROR,
920  GTK_BUTTONS_OK,
921  "%s", title);
922  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
923  "%s", _("The date of this transaction is older than the \"Read-Only Threshold\" set for this book. "
924  "This setting can be changed in File -> Properties -> Accounts."));
925  gtk_dialog_run(GTK_DIALOG(dialog));
926  gtk_widget_destroy(dialog);
927  return TRUE;
928  }
929 
930  reason = xaccTransGetReadOnly (trans);
931  if (reason)
932  {
933  dialog = gtk_message_dialog_new(NULL,
934  0,
935  GTK_MESSAGE_ERROR,
936  GTK_BUTTONS_OK,
937  "%s", title);
938  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
939  message, reason);
940  gtk_dialog_run(GTK_DIALOG(dialog));
941  gtk_widget_destroy(dialog);
942  return TRUE;
943  }
944  return FALSE;
945 }
946 
947 
948 void
949 gsr_default_reinit_handler( GNCSplitReg *gsr, gpointer data )
950 {
951  VirtualCellLocation vcell_loc;
952  SplitRegister *reg;
953  Transaction *trans;
954  Split *split;
955  GtkWidget *dialog;
956  gint response;
957  const gchar *warning;
958 
959  const char *title = _("Remove the splits from this transaction?");
960  const char *recn_warn = _("This transaction contains reconciled splits. "
961  "Modifying it is not a good idea because that will "
962  "cause your reconciled balance to be off.");
963 
964  reg = gnc_ledger_display_get_split_register( gsr->ledger );
965 
967  if (is_trans_readonly_and_warn(trans))
968  return;
969  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
970  GTK_DIALOG_DESTROY_WITH_PARENT,
971  GTK_MESSAGE_WARNING,
972  GTK_BUTTONS_NONE,
973  "%s", title);
974  if (xaccTransHasReconciledSplits (trans))
975  {
976  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
977  "%s", recn_warn);
978  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL_RECD;
979  }
980  else
981  {
982  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL;
983  }
984 
985  gtk_dialog_add_button(GTK_DIALOG(dialog),
986  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
987  gnc_gtk_dialog_add_button(dialog, _("_Remove Splits"),
988  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
989  response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
990  gtk_widget_destroy (dialog);
991  if (response != GTK_RESPONSE_ACCEPT)
992  return;
993 
994  /*
995  * Find the "transaction" split for the current transaction. This is
996  * the split that appears at the top of the transaction in the
997  * register.
998  */
1000  if (!gnc_split_register_get_split_virt_loc(reg, split, &vcell_loc))
1001  return;
1002  split = gnc_split_register_get_current_trans_split (reg, &vcell_loc);
1004 }
1005 
1009 void
1010 gnc_split_reg_reinitialize_trans_cb(GtkWidget *widget, gpointer data)
1011 {
1012  GNCSplitReg *gsr = data;
1013  gsr_emit_simple_signal( gsr, "reinit_ent" );
1014 }
1015 
1019 void
1020 gsr_default_associate_handler_file( GNCSplitReg *gsr, gpointer data )
1021 {
1022  CursorClass cursor_class;
1023  SplitRegister *reg;
1024  Transaction *trans;
1025  Split *split;
1026  GtkWidget *dialog;
1027 
1028  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1029 
1030  /* get the current split based on cursor position */
1032  if (split == NULL)
1033  {
1035  return;
1036  }
1037 
1038  trans = xaccSplitGetParent(split);
1039  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1040 
1041  if (cursor_class == CURSOR_CLASS_NONE)
1042  return;
1043 
1044  if (is_trans_readonly_and_warn(trans))
1045  return;
1046 
1047  dialog = gtk_file_chooser_dialog_new ("Associate File with Transaction",
1048  GTK_WINDOW(gsr->window),
1049  GTK_FILE_CHOOSER_ACTION_OPEN,
1050  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1051  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1052  NULL);
1053 
1054  gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(dialog), 0);
1055  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1056  {
1057  char *uri;
1058 
1059  uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
1060  DEBUG("File URI: %s\n", uri);
1061  xaccTransSetAssociation(trans, uri);
1062  }
1063 
1064  gtk_widget_destroy (dialog);
1065 
1066 }
1067 
1071 void
1072 gsr_default_associate_handler_location( GNCSplitReg *gsr, gpointer data )
1073 {
1074  CursorClass cursor_class;
1075  SplitRegister *reg;
1076  Transaction *trans;
1077  Split *split;
1078  GtkWidget *dialog, *entry, *label, *content_area;
1079 
1080  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1081 
1082  /* get the current split based on cursor position */
1084  if (split == NULL)
1085  {
1087  return;
1088  }
1089 
1090  trans = xaccSplitGetParent(split);
1091  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1092 
1093  if (cursor_class == CURSOR_CLASS_NONE)
1094  return;
1095 
1096  if (is_trans_readonly_and_warn(trans))
1097  return;
1098 
1099  dialog = gtk_dialog_new_with_buttons ("Associate Location with Transaction",
1100  GTK_WINDOW(gsr->window),
1101  GTK_DIALOG_MODAL,
1102  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1103  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1104  NULL);
1105 
1106  content_area = GTK_DIALOG (dialog)->vbox;
1107 
1108  // add a label
1109  label = gtk_label_new ("Please enter URL:");
1110  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
1111  gtk_container_add (GTK_CONTAINER (content_area), label);
1112 
1113  // add the entry text
1114  entry = gtk_entry_new ();
1115  gtk_entry_set_width_chars(GTK_ENTRY (entry), 80);
1116  gtk_entry_set_activates_default(GTK_ENTRY (entry), TRUE);
1117  gtk_container_add (GTK_CONTAINER (content_area), entry);
1118 
1119  // set spacings
1120  gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
1121  gtk_container_set_border_width (GTK_CONTAINER (label), 5);
1122  gtk_container_set_border_width (GTK_CONTAINER (content_area), 5);
1123 
1124  // set the default response
1125  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1126 
1127  // run the dialog
1128  gtk_widget_show_all (dialog);
1129 
1130  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1131  {
1132  const char *uri;
1133 
1134  uri = gtk_entry_get_text (GTK_ENTRY (entry));
1135  DEBUG("Location URI: %s\n", uri);
1136  xaccTransSetAssociation(trans, uri);
1137  }
1138 
1139  gtk_widget_destroy (dialog);
1140 
1141 }
1145 void
1146 gsr_default_execassociated_handler( GNCSplitReg *gsr, gpointer data )
1147 {
1148  CursorClass cursor_class;
1149  SplitRegister *reg;
1150  Transaction *trans;
1151  Split *split;
1152  GtkWidget *dialog;
1153  const char *uri;
1154 
1155  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1156 
1157  /* get the current split based on cursor position */
1159  if (split == NULL)
1160  {
1162  return;
1163  }
1164 
1165  trans = xaccSplitGetParent(split);
1166  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1167 
1168  if (cursor_class == CURSOR_CLASS_NONE)
1169  return;
1170 
1171 #ifdef DUMP_FUNCTIONS
1172  if (qof_log_check (log_module, QOF_LOG_DEBUG))
1173  xaccTransDump (trans, "ExecAssociated");
1174 #endif
1175 
1176  uri = xaccTransGetAssociation(trans);
1177  if (!uri)
1178  {
1179  const gchar *message =
1180  _("This transaction is not associated with a URI.");
1181  gnc_error_dialog(NULL, "%s", message);
1182  return;
1183  }
1184  else
1185  {
1186  gnc_launch_assoc(uri);
1187  }
1188 
1189  return;
1190 }
1191 
1192 void
1193 gsr_default_delete_handler( GNCSplitReg *gsr, gpointer data )
1194 {
1195  CursorClass cursor_class;
1196  SplitRegister *reg;
1197  Transaction *trans;
1198  Split *split;
1199  GtkWidget *dialog;
1200  gint response;
1201  const gchar *warning;
1202 
1203  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1204 
1205  /* get the current split based on cursor position */
1207  if (split == NULL)
1208  {
1210  return;
1211  }
1212 
1213  trans = xaccSplitGetParent(split);
1214  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1215 
1216  /* Deleting the blank split just cancels */
1217  {
1218  Split *blank_split = gnc_split_register_get_blank_split (reg);
1219 
1220  if (split == blank_split)
1221  {
1223  return;
1224  }
1225  }
1226 
1227  if (cursor_class == CURSOR_CLASS_NONE)
1228  return;
1229 
1230  if (is_trans_readonly_and_warn(trans))
1231  return;
1232 
1233  /* On a split cursor, just delete the one split. */
1234  if (cursor_class == CURSOR_CLASS_SPLIT)
1235  {
1236  const char *format = _("Delete the split '%s' from the transaction '%s'?");
1237  const char *recn_warn = _("You would be deleting a reconciled split! "
1238  "This is not a good idea as it will cause your "
1239  "reconciled balance to be off.");
1240  const char *anchor_error = _("You cannot delete this split.");
1241  const char *anchor_split = _("This is the split anchoring this transaction "
1242  "to the register. You may not delete it from "
1243  "this register window. You may delete the "
1244  "entire transaction from this window, or you "
1245  "may navigate to a register that shows "
1246  "another side of this same transaction and "
1247  "delete the split from that register.");
1248  char *buf = NULL;
1249  const char *memo;
1250  const char *desc;
1251  char recn;
1252 
1253  if (split == gnc_split_register_get_current_trans_split (reg, NULL))
1254  {
1255  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1256  GTK_DIALOG_MODAL
1257  | GTK_DIALOG_DESTROY_WITH_PARENT,
1258  GTK_MESSAGE_ERROR,
1259  GTK_BUTTONS_OK,
1260  "%s", anchor_error);
1261  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1262  "%s", anchor_split);
1263  gtk_dialog_run(GTK_DIALOG(dialog));
1264  gtk_widget_destroy (dialog);
1265  return;
1266  }
1267 
1268  memo = xaccSplitGetMemo (split);
1269  memo = (memo && *memo) ? memo : _("(no memo)");
1270 
1271  desc = xaccTransGetDescription (trans);
1272  desc = (desc && *desc) ? desc : _("(no description)");
1273 
1274  /* ask for user confirmation before performing permanent damage */
1275  buf = g_strdup_printf (format, memo, desc);
1276  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1277  GTK_DIALOG_MODAL
1278  | GTK_DIALOG_DESTROY_WITH_PARENT,
1279  GTK_MESSAGE_QUESTION,
1280  GTK_BUTTONS_NONE,
1281  "%s", buf);
1282  g_free(buf);
1283  recn = xaccSplitGetReconcile (split);
1284  if (recn == YREC || recn == FREC)
1285  {
1286  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1287  "%s", recn_warn);
1288  warning = GNC_PREF_WARN_REG_SPLIT_DEL_RECD;
1289  }
1290  else
1291  {
1292  warning = GNC_PREF_WARN_REG_SPLIT_DEL;
1293  }
1294 
1295  gtk_dialog_add_button(GTK_DIALOG(dialog),
1296  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1297  gnc_gtk_dialog_add_button(dialog, _("_Delete Split"),
1298  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
1299  response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
1300  gtk_widget_destroy (dialog);
1301  if (response != GTK_RESPONSE_ACCEPT)
1302  return;
1303 
1305  return;
1306  }
1307 
1308  g_return_if_fail(cursor_class == CURSOR_CLASS_TRANS);
1309 
1310  /* On a transaction cursor with 2 or fewer splits in single or double
1311  * mode, we just delete the whole transaction, kerblooie */
1312  {
1313  const char *title = _("Delete the current transaction?");
1314  const char *recn_warn = _("You would be deleting a transaction "
1315  "with reconciled splits! "
1316  "This is not a good idea as it will cause your "
1317  "reconciled balance to be off.");
1318 
1319  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1320  GTK_DIALOG_MODAL
1321  | GTK_DIALOG_DESTROY_WITH_PARENT,
1322  GTK_MESSAGE_WARNING,
1323  GTK_BUTTONS_NONE,
1324  "%s", title);
1325  if (xaccTransHasReconciledSplits (trans))
1326  {
1327  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1328  "%s", recn_warn);
1329  warning = GNC_PREF_WARN_REG_TRANS_DEL_RECD;
1330  }
1331  else
1332  {
1333  warning = GNC_PREF_WARN_REG_TRANS_DEL;
1334  }
1335  gtk_dialog_add_button(GTK_DIALOG(dialog),
1336  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1337  gnc_gtk_dialog_add_button(dialog, _("_Delete Transaction"),
1338  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
1339  response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
1340  gtk_widget_destroy (dialog);
1341  if (response != GTK_RESPONSE_ACCEPT)
1342  return;
1343 
1345  return;
1346  }
1347 }
1348 
1352 void
1353 gnc_split_reg_delete_trans_cb(GtkWidget *widget, gpointer data)
1354 {
1355  GNCSplitReg *gsr = data;
1356  gsr_emit_simple_signal( gsr, "delete_ent" );
1357 }
1358 
1359 void
1360 gsr_default_dup_handler( GNCSplitReg *gsr, gpointer data )
1361 {
1363  (gnc_ledger_display_get_split_register( gsr->ledger ));
1364 }
1365 
1369 void
1370 gnc_split_reg_duplicate_trans_cb(GtkWidget *w, gpointer data)
1371 {
1372  GNCSplitReg *gsr = data;
1373  gsr_emit_simple_signal( gsr, "dup_ent" );
1374 }
1375 
1381 void
1382 gsr_default_schedule_handler( GNCSplitReg *gsr, gpointer data )
1383 {
1384  SplitRegister *reg = gnc_ledger_display_get_split_register( gsr->ledger );
1385  Transaction *pending_trans = gnc_split_register_get_current_trans (reg);
1386 
1387  /* If the transaction has a sched-xact KVP frame, then go to the editor
1388  * for the existing SX; otherwise, do the sx-from-trans dialog. */
1389  {
1390  GncGUID *fromSXId = NULL;
1391  SchedXaction *theSX = NULL;
1392  GList *sxElts;
1393  qof_instance_get (QOF_INSTANCE (pending_trans),
1394  "from-sched-xaction", &fromSXId,
1395  NULL);
1396 
1397  /* Get the correct SX */
1398  for ( sxElts = gnc_book_get_schedxactions (gnc_get_current_book())->sx_list;
1399  (!theSX) && sxElts;
1400  sxElts = sxElts->next )
1401  {
1402  SchedXaction *sx = (SchedXaction*)sxElts->data;
1403  theSX =
1404  ((guid_equal (xaccSchedXactionGetGUID (sx), fromSXId))
1405  ? sx : NULL);
1406  }
1407 
1408  if ( theSX )
1409  {
1410  gnc_ui_scheduled_xaction_editor_dialog_create(theSX, FALSE);
1411  return;
1412  }
1413  }
1414 
1415  gnc_sx_create_from_trans(pending_trans);
1416 }
1417 
1418 void
1419 gnc_split_reg_recur_cb(GtkWidget *w, gpointer data)
1420 {
1421  GNCSplitReg *gsr = data;
1422  gsr_emit_simple_signal( gsr, "schedule_ent" );
1423 }
1424 
1428 void
1429 gnc_split_reg_record_trans_cb (GtkWidget *w, gpointer data)
1430 {
1431  GNCSplitReg *gsr = data;
1432  gsr_emit_simple_signal( gsr, "enter_ent" );
1433 }
1434 
1435 void
1436 gsr_default_cancel_handler( GNCSplitReg *gsr, gpointer data )
1437 {
1439  (gnc_ledger_display_get_split_register( gsr->ledger ));
1440 }
1441 
1445 void
1446 gnc_split_reg_cancel_trans_cb(GtkWidget *w, gpointer data)
1447 {
1448  GNCSplitReg *gsr = data;
1449  gsr_emit_simple_signal( gsr, "cancel_ent" );
1450 }
1451 
1452 void
1453 gsr_default_expand_handler( GNCSplitReg *gsr, gpointer data )
1454 {
1455  gint activeCount;
1456  gboolean expand;
1457  SplitRegister *reg;
1458 
1459  if (!gsr)
1460  return;
1461 
1462  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1463 
1464  /* These should all be in agreement. */
1465  activeCount =
1466  ( ( GTK_CHECK_MENU_ITEM(gsr->split_menu_check)->active ? 1 : -1 )
1467  + ( GTK_CHECK_MENU_ITEM(gsr->split_popup_check)->active ? 1 : -1 )
1468  + ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(gsr->split_button) )
1469  ? 1 : -1 ) );
1470 
1471  /* If activeCount > 0, then there's more active than inactive; otherwise,
1472  * more inactive than active. Both determine which state the user is
1473  * attempting to get to. */
1474  expand = ( activeCount < 0 );
1475 
1476  /* The ledger's invocation of 'redraw_all' will force the agreement in the
1477  * other split state widgets, so we neglect doing it here. */
1479 }
1480 
1481 void
1482 gnc_split_reg_expand_trans_menu_cb (GtkWidget *widget, gpointer data)
1483 {
1484  GNCSplitReg *gsr = data;
1485  gsr_emit_simple_signal( gsr, "expand_ent" );
1486 }
1487 
1488 void
1489 gnc_split_reg_expand_trans_toolbar_cb (GtkWidget *widget, gpointer data)
1490 {
1491  GNCSplitReg *gsr = data;
1492  gsr_emit_simple_signal( gsr, "expand_ent" );
1493 }
1494 
1498 void
1499 gnc_split_reg_jump_to_split(GNCSplitReg *gsr, Split *split)
1500 {
1501  Transaction *trans;
1502  VirtualCellLocation vcell_loc;
1503  SplitRegister *reg;
1504 
1505  if (!gsr) return;
1506 
1507  trans = xaccSplitGetParent(split);
1508 
1509  gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
1510 
1511  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1512 
1513  if (gnc_split_register_get_split_virt_loc(reg, split, &vcell_loc))
1514  gnucash_register_goto_virt_cell( gsr->reg, vcell_loc );
1515 
1516  gnc_ledger_display_refresh( gsr->ledger );
1517 }
1518 
1519 
1523 void
1524 gnc_split_reg_jump_to_split_amount(GNCSplitReg *gsr, Split *split)
1525 {
1526  VirtualLocation virt_loc;
1527  SplitRegister *reg;
1528  Transaction *trans;
1529 
1530  if (!gsr) return;
1531 
1532  trans = xaccSplitGetParent(split);
1533  gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
1534 
1535  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1536 
1537  if (gnc_split_register_get_split_amount_virt_loc (reg, split, &virt_loc))
1538  gnucash_register_goto_virt_loc (gsr->reg, virt_loc);
1539 
1540  gnc_ledger_display_refresh (gsr->ledger);
1541 }
1542 
1543 void
1544 gnc_split_reg_jump_to_blank (GNCSplitReg *gsr)
1545 {
1546  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1547  VirtualCellLocation vcell_loc;
1548  Split *blank;
1549 
1550  ENTER("gsr=%p", gsr);
1551 
1552  blank = gnc_split_register_get_blank_split (reg);
1553  if (blank == NULL)
1554  {
1555  LEAVE("no blank split");
1556  return;
1557  }
1558 
1559  if (gnc_split_register_get_split_virt_loc (reg, blank, &vcell_loc))
1560  gnucash_register_goto_virt_cell (gsr->reg, vcell_loc);
1561 
1562  gnc_ledger_display_refresh (gsr->ledger);
1563  LEAVE(" ");
1564 }
1565 
1566 void
1567 gnc_split_reg_balancing_entry(GNCSplitReg *gsr, Account *account,
1568  time64 statement_date, gnc_numeric balancing_amount)
1569 {
1570 
1571  Transaction *transaction;
1572  Split *split;
1573 
1574  // create transaction
1575  transaction = create_balancing_transaction(gnc_get_current_book(),
1576  account, statement_date, balancing_amount);
1577 
1578  // jump to transaction
1579  split = xaccTransFindSplitByAccount(transaction, account);
1580  if (split == NULL)
1581  {
1582  // default behaviour: jump to blank split
1583  g_warning("create_balancing_transaction failed");
1584  gnc_split_reg_jump_to_blank(gsr);
1585  }
1586  else
1587  {
1588  // goto balancing transaction
1589  gnc_split_reg_jump_to_split(gsr, split );
1590  }
1591 }
1592 
1593 static Transaction*
1594 create_balancing_transaction(QofBook *book, Account *account,
1595  time64 statement_date, gnc_numeric balancing_amount)
1596 {
1597 
1598  Transaction *trans;
1599  Split *split;
1600 
1601  if (!account)
1602  return NULL;
1603  if (gnc_numeric_zero_p(balancing_amount))
1604  return NULL;
1605 
1606  xaccAccountBeginEdit(account);
1607 
1608  trans = xaccMallocTransaction(book);
1609 
1610  xaccTransBeginEdit(trans);
1611 
1612  // fill Transaction
1614  xaccTransSetDatePostedSecsNormalized(trans, statement_date);
1615  xaccTransSetDescription(trans, _("Balancing entry from reconcilation"));
1616  /* We also must set a new DateEntered on the new entry
1617  * because otherwise the ordering is not deterministic */
1618  xaccTransSetDateEnteredSecs(trans, gnc_time(NULL));
1619 
1620  // 1. Split
1621  split = xaccMallocSplit(book);
1622  xaccTransAppendSplit(trans, split);
1623  xaccAccountInsertSplit(account, split);
1624  xaccSplitSetAmount(split, balancing_amount);
1625  xaccSplitSetValue(split, balancing_amount);
1626 
1627  // 2. Split (no account is defined: split goes to orphan account)
1628  split = xaccMallocSplit(book);
1629  xaccTransAppendSplit(trans, split);
1630 
1631  balancing_amount = gnc_numeric_neg(balancing_amount);
1632  xaccSplitSetAmount(split, balancing_amount);
1633  xaccSplitSetValue(split, balancing_amount);
1634 
1635  xaccTransCommitEdit(trans);
1636  xaccAccountCommitEdit(account);
1637  return trans;
1638 }
1639 
1640 void
1641 gsr_default_blank_handler( GNCSplitReg *gsr, gpointer data )
1642 {
1643  SplitRegister *reg;
1644 
1645  ENTER("gsr=%p, gpointer=%p", gsr, data);
1646 
1647  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1648 
1649  if (gnc_split_register_save (reg, TRUE))
1651 
1652  gnc_split_reg_jump_to_blank (gsr);
1653  LEAVE(" ");
1654 }
1655 
1656 void
1657 gnc_split_reg_new_trans_cb (GtkWidget *widget, gpointer data)
1658 {
1659  GNCSplitReg *gsr = data;
1660  gsr_emit_simple_signal( gsr, "blank" );
1661 }
1662 
1663 void
1664 gsr_default_jump_handler( GNCSplitReg *gsr, gpointer data )
1665 {
1666  g_assert_not_reached();
1667 }
1668 
1669 void
1670 gnc_split_reg_jump_cb( GtkWidget *widget, gpointer data )
1671 {
1672  GNCSplitReg *gsr = data;
1673  gsr_emit_simple_signal( gsr, "jump" );
1674 }
1675 
1676 void
1677 gnc_split_reg_change_style (GNCSplitReg *gsr, SplitRegisterStyle style)
1678 {
1679  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1680 
1681  if (style == reg->style)
1682  return;
1683 
1684  gnc_split_register_config (reg, reg->type, style, reg->use_double_line);
1685  gnc_ledger_display_refresh (gsr->ledger);
1686 }
1687 
1688 void
1689 gnc_split_reg_style_ledger_cb (GtkWidget *w, gpointer data)
1690 {
1691  GNCSplitReg *gsr = data;
1692 
1693  if (!GTK_CHECK_MENU_ITEM(w)->active)
1694  return;
1695 
1696  gnc_split_reg_change_style (gsr, REG_STYLE_LEDGER);
1697 }
1698 
1699 void
1700 gnc_split_reg_style_auto_ledger_cb (GtkWidget *w, gpointer data)
1701 {
1702  GNCSplitReg *gsr = data;
1703 
1704  if (!GTK_CHECK_MENU_ITEM(w)->active)
1705  return;
1706 
1707  gnc_split_reg_change_style (gsr, REG_STYLE_AUTO_LEDGER);
1708 }
1709 
1710 void
1711 gnc_split_reg_style_journal_cb (GtkWidget *w, gpointer data)
1712 {
1713  GNCSplitReg *gsr = data;
1714 
1715  if (!GTK_CHECK_MENU_ITEM(w)->active)
1716  return;
1717 
1718  gnc_split_reg_change_style (gsr, REG_STYLE_JOURNAL);
1719 }
1720 
1721 void
1722 gnc_split_reg_double_line_cb (GtkWidget *w, gpointer data)
1723 {
1724  GNCSplitReg *gsr = data;
1725  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1726  gboolean use_double_line;
1727 
1728  use_double_line = GTK_CHECK_MENU_ITEM(w)->active;
1729  if ( use_double_line == reg->use_double_line )
1730  return;
1731 
1732  gnc_split_register_config( reg, reg->type, reg->style, use_double_line );
1733  gnc_ledger_display_refresh( gsr->ledger );
1734 }
1735 
1736 static void
1737 gnc_split_reg_sort_force( GNCSplitReg *gsr, SortType sort_code, gboolean force )
1738 {
1739  Query *query = gnc_ledger_display_get_query( gsr->ledger );
1740  gboolean show_present_divider = FALSE;
1741  GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
1742  SplitRegister *reg;
1743 
1744  if ((gsr->sort_type == sort_code) && !force)
1745  return;
1746 
1747  standard = g_slist_prepend( NULL, QUERY_DEFAULT_SORT );
1748 
1749  switch (sort_code)
1750  {
1751  case BY_STANDARD:
1752  p1 = standard;
1753  show_present_divider = TRUE;
1754  break;
1755  case BY_DATE:
1756  p1 = g_slist_prepend (p1, TRANS_DATE_POSTED);
1757  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1758  p2 = standard;
1759  show_present_divider = TRUE;
1760  break;
1761  case BY_DATE_ENTERED:
1762  p1 = g_slist_prepend (p1, TRANS_DATE_ENTERED);
1763  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1764  p2 = standard;
1765  break;
1766  case BY_DATE_RECONCILED:
1767  p1 = g_slist_prepend (p1, SPLIT_RECONCILE);
1768  p2 = g_slist_prepend (p2, SPLIT_DATE_RECONCILED);
1769  p3 = standard;
1770  break;
1771  case BY_NUM:
1772  p1 = g_slist_prepend (p1, TRANS_NUM);
1773  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1774  p2 = standard;
1775  break;
1776  case BY_AMOUNT:
1777  p1 = g_slist_prepend (p1, SPLIT_VALUE);
1778  p2 = standard;
1779  break;
1780  case BY_MEMO:
1781  p1 = g_slist_prepend (p1, SPLIT_MEMO);
1782  p2 = standard;
1783  break;
1784  case BY_DESC:
1785  p1 = g_slist_prepend (p1, TRANS_DESCRIPTION);
1786  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1787  p2 = standard;
1788  break;
1789  case BY_ACTION:
1790  p1 = g_slist_prepend (p1, SPLIT_ACTION);
1791  p2 = standard;
1792  break;
1793  case BY_NOTES:
1794  p1 = g_slist_prepend (p1, TRANS_NOTES);
1795  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1796  p2 = standard;
1797  break;
1798  default:
1799  g_slist_free (standard);
1800  g_return_if_fail (FALSE);
1801  break;
1802  }
1803 
1804  qof_query_set_sort_order( query, p1, p2, p3 );
1805  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1806  gnc_split_register_show_present_divider( reg, show_present_divider );
1807  gsr->sort_type = sort_code;
1808  gnc_ledger_display_refresh( gsr->ledger );
1809 }
1810 
1811 static void
1812 gnc_split_reg_sort( GNCSplitReg *gsr, SortType sort_code )
1813 {
1814  gnc_split_reg_sort_force( gsr, sort_code, FALSE );
1815 }
1816 
1817 void
1818 gnc_split_reg_sort_standard_cb(GtkWidget *w, gpointer data)
1819 {
1820  GNCSplitReg *gsr = data;
1821  gnc_split_reg_sort(gsr, BY_STANDARD);
1822 }
1823 
1824 void
1825 gnc_split_reg_sort_date_cb(GtkWidget *w, gpointer data)
1826 {
1827  GNCSplitReg *gsr = data;
1828  gnc_split_reg_sort(gsr, BY_DATE);
1829 }
1830 
1831 void
1832 gnc_split_reg_sort_date_entered_cb(GtkWidget *w, gpointer data)
1833 {
1834  GNCSplitReg *gsr = data;
1835  gnc_split_reg_sort(gsr, BY_DATE_ENTERED);
1836 }
1837 
1838 void
1839 gnc_split_reg_sort_date_reconciled_cb(GtkWidget *w, gpointer data)
1840 {
1841  GNCSplitReg *gsr = data;
1842  gnc_split_reg_sort(gsr, BY_DATE_RECONCILED);
1843 }
1844 
1845 void
1846 gnc_split_reg_sort_num_cb(GtkWidget *w, gpointer data)
1847 {
1848  GNCSplitReg *gsr = data;
1849  gnc_split_reg_sort(gsr, BY_NUM);
1850 }
1851 
1852 void
1853 gnc_split_reg_sort_amount_cb(GtkWidget *w, gpointer data)
1854 {
1855  GNCSplitReg *gsr = data;
1856  gnc_split_reg_sort(gsr, BY_AMOUNT);
1857 }
1858 
1859 void
1860 gnc_split_reg_sort_memo_cb(GtkWidget *w, gpointer data)
1861 {
1862  GNCSplitReg *gsr = data;
1863  gnc_split_reg_sort(gsr, BY_MEMO);
1864 }
1865 
1866 void
1867 gnc_split_reg_sort_desc_cb(GtkWidget *w, gpointer data)
1868 {
1869  GNCSplitReg *gsr = data;
1870  gnc_split_reg_sort(gsr, BY_DESC);
1871 }
1872 
1873 void
1874 gnc_split_reg_sort_action_cb(GtkWidget *w, gpointer data)
1875 {
1876  GNCSplitReg *gsr = data;
1877  gnc_split_reg_sort(gsr, BY_ACTION);
1878 }
1879 
1880 void
1881 gnc_split_reg_sort_notes_cb(GtkWidget *w, gpointer data)
1882 {
1883  GNCSplitReg *gsr = data;
1884  gnc_split_reg_sort(gsr, BY_NOTES);
1885 }
1886 
1887 
1888 void
1889 gnc_split_reg_set_sort_reversed(GNCSplitReg *gsr, gboolean rev)
1890 {
1891  Query *query = gnc_ledger_display_get_query( gsr->ledger );
1892  qof_query_set_sort_increasing (query, rev, rev, rev);
1893  gnc_ledger_display_refresh( gsr->ledger );
1894 }
1895 
1896 void
1897 gnc_split_reg_handle_exchange_cb (GtkWidget *w, gpointer data)
1898 {
1899  GNCSplitReg *gsr = data;
1900  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1901 
1902  /* XXX Ignore the return value -- we don't care if this succeeds */
1903  (void)gnc_split_register_handle_exchange (reg, TRUE);
1904 }
1905 
1906 static void
1907 gnc_split_reg_record (GNCSplitReg *gsr)
1908 {
1909  SplitRegister *reg;
1910  Transaction *trans;
1911 
1912  ENTER("gsr=%p", gsr);
1913 
1914  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1916 
1917  if (!gnc_split_register_save (reg, TRUE))
1918  {
1919  LEAVE("no save");
1920  return;
1921  }
1922 
1923  gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
1924 
1925  /* Explicit redraw shouldn't be needed,
1926  * since gui_refresh events should handle this. */
1927  /* gnc_split_register_redraw (reg); */
1928  LEAVE(" ");
1929 }
1930 
1931 static gboolean
1932 gnc_split_reg_match_trans_row( VirtualLocation virt_loc,
1933  gpointer user_data )
1934 {
1935  GNCSplitReg *gsr = user_data;
1936  CursorClass cursor_class;
1937  SplitRegister *sr;
1938 
1939  sr = gnc_ledger_display_get_split_register (gsr->ledger);
1940  cursor_class = gnc_split_register_get_cursor_class (sr, virt_loc.vcell_loc);
1941 
1942  return (cursor_class == CURSOR_CLASS_TRANS);
1943 }
1944 
1945 static void
1946 gnc_split_reg_goto_next_trans_row (GNCSplitReg *gsr)
1947 {
1948  ENTER("gsr=%p", gsr);
1949  gnucash_register_goto_next_matching_row( gsr->reg,
1950  gnc_split_reg_match_trans_row,
1951  gsr );
1952  LEAVE(" ");
1953 }
1954 
1955 void
1956 gnc_split_reg_enter( GNCSplitReg *gsr, gboolean next_transaction )
1957 {
1958  SplitRegister *sr = gnc_ledger_display_get_split_register( gsr->ledger );
1959  gboolean goto_blank;
1960 
1961  ENTER("gsr=%p, next_transaction=%s", gsr, next_transaction ? "TRUE" : "FALSE");
1962 
1963  goto_blank = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER,
1964  GNC_PREF_ENTER_MOVES_TO_END);
1965 
1966  /* If we are in single or double line mode and we hit enter
1967  * on the blank split, go to the blank split instead of the
1968  * next row. This prevents the cursor from jumping around
1969  * when you are entering transactions. */
1970  if ( !goto_blank && !next_transaction )
1971  {
1972  SplitRegisterStyle style = sr->style;
1973 
1974  if (style == REG_STYLE_LEDGER)
1975  {
1976  Split *blank_split;
1977 
1978  blank_split = gnc_split_register_get_blank_split(sr);
1979  if (blank_split != NULL)
1980  {
1981  Split *current_split;
1982 
1983  current_split = gnc_split_register_get_current_split(sr);
1984 
1985  if (blank_split == current_split)
1986  goto_blank = TRUE;
1987  }
1988  }
1989  }
1990 
1991  /* First record the transaction. This will perform a refresh. */
1992  gnc_split_reg_record( gsr );
1993 
1994  if (!goto_blank && next_transaction)
1996 
1997  /* Now move. */
1998  if (goto_blank)
1999  gnc_split_reg_jump_to_blank( gsr );
2000  else if (next_transaction)
2001  gnc_split_reg_goto_next_trans_row( gsr );
2002  else
2003  gnucash_register_goto_next_virt_row( gsr->reg );
2004  LEAVE(" ");
2005 }
2006 
2007 void
2008 gsr_default_enter_handler( GNCSplitReg *gsr, gpointer data )
2009 {
2010  gnc_split_reg_enter( gsr, FALSE );
2011 }
2012 
2013 void
2014 gnc_split_reg_record_cb (GnucashRegister *reg, gpointer data)
2015 {
2016  gsr_emit_simple_signal( (GNCSplitReg*)data, "enter_ent" );
2017 }
2018 
2019 void
2020 gnc_split_reg_size_allocate (GtkWidget *widget,
2021  GtkAllocation *allocation,
2022  gpointer user_data)
2023 {
2024  GNCSplitReg *gsr = user_data;
2025  gsr->width = allocation->width;
2026  gtk_window_set_default_size( GTK_WINDOW(gsr->window), gsr->width, 0 );
2027 }
2028 
2029 static
2030 GtkWidget*
2031 add_summary_label (GtkWidget *summarybar, const char *label_str)
2032 {
2033  GtkWidget *hbox;
2034  GtkWidget *label;
2035 
2036  hbox = gtk_hbox_new(FALSE, 2);
2037  gtk_box_pack_start( GTK_BOX(summarybar), hbox, FALSE, FALSE, 5 );
2038 
2039  label = gtk_label_new( label_str );
2040  gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
2041  gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, FALSE, 0 );
2042 
2043  label = gtk_label_new( "" );
2044  gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
2045  gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, FALSE, 0 );
2046 
2047  return label;
2048 }
2049 
2050 GtkWidget *
2051 gsr_create_summary_bar( GNCSplitReg *gsr )
2052 {
2053  GtkWidget *summarybar;
2054 
2055  gsr->cleared_label = NULL;
2056  gsr->balance_label = NULL;
2057  gsr->reconciled_label = NULL;
2058  gsr->future_label = NULL;
2059  gsr->projectedminimum_label = NULL;
2060  gsr->shares_label = NULL;
2061  gsr->value_label = NULL;
2062 
2063  if ( gnc_ledger_display_type(gsr->ledger) >= LD_SUBACCOUNT )
2064  {
2065  gsr->summarybar = NULL;
2066  return NULL;
2067  }
2068 
2069  summarybar = gtk_hbox_new (FALSE, 4);
2070 
2071  if (!xaccAccountIsPriced(gnc_ledger_display_leader(gsr->ledger)))
2072  {
2073  gsr->balance_label = add_summary_label (summarybar, _("Present:"));
2074  gsr->future_label = add_summary_label (summarybar, _("Future:"));
2075  gsr->cleared_label = add_summary_label (summarybar, _("Cleared:"));
2076  gsr->reconciled_label = add_summary_label (summarybar, _("Reconciled:"));
2077  gsr->projectedminimum_label = add_summary_label (summarybar, _("Projected Minimum:"));
2078  }
2079  else
2080  {
2081  gsr->shares_label = add_summary_label (summarybar, _("Shares:"));
2082  gsr->value_label = add_summary_label (summarybar, _("Current Value:"));
2083  }
2084 
2085  gsr->summarybar = summarybar;
2086 
2087  /* Force the first update */
2088  gsr_redraw_all_cb(NULL, gsr);
2089  return gsr->summarybar;
2090 }
2091 
2098 static
2100 gnc_split_reg_get_placeholder( GNCSplitReg *gsr )
2101 {
2102  Account *leader;
2103  SplitRegister *reg;
2104  gboolean single_account;
2105 
2106  if (gsr == NULL)
2107  return PLACEHOLDER_NONE;
2108 
2109  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2110 
2111  switch (reg->type)
2112  {
2113  case GENERAL_LEDGER:
2114  case INCOME_LEDGER:
2115  case PORTFOLIO_LEDGER:
2116  case SEARCH_LEDGER:
2117  single_account = FALSE;
2118  break;
2119  default:
2120  single_account = TRUE;
2121  break;
2122  }
2123 
2124  leader = gnc_ledger_display_leader( gsr->ledger );
2125 
2126  if (leader == NULL)
2127  return PLACEHOLDER_NONE;
2128  if (single_account)
2129  {
2130  if (xaccAccountGetPlaceholder( leader ))
2131  return PLACEHOLDER_THIS;
2132  return PLACEHOLDER_NONE;
2133  }
2134  return xaccAccountGetDescendantPlaceholder( leader );
2135 }
2136 
2140 typedef struct dialog_args
2141 {
2142  GNCSplitReg *gsr;
2143  gchar *string;
2144 } dialog_args;
2145 
2151 static
2152 gboolean
2153 gtk_callback_bug_workaround (gpointer argp)
2154 {
2155  dialog_args *args = argp;
2156  const gchar *read_only = _("This account register is read-only.");
2157  GtkWidget *dialog;
2158 
2159  dialog = gtk_message_dialog_new(GTK_WINDOW(args->gsr->window),
2160  GTK_DIALOG_DESTROY_WITH_PARENT,
2161  GTK_MESSAGE_WARNING,
2162  GTK_BUTTONS_CLOSE,
2163  "%s", read_only);
2164  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
2165  "%s", args->string);
2166  gnc_dialog_run(GTK_DIALOG(dialog), GNC_PREF_WARN_REG_IS_READ_ONLY);
2167  gtk_widget_destroy(dialog);
2168  g_free(args);
2169  return FALSE;
2170 }
2171 
2175 static
2176 void
2177 gnc_split_reg_determine_read_only( GNCSplitReg *gsr )
2178 {
2179  dialog_args *args = g_malloc(sizeof(dialog_args));
2180  SplitRegister *reg;
2181 
2182  if (qof_book_is_readonly(gnc_get_current_book()))
2183  {
2184  /* Is the book read-only? Then for sure also make this register
2185  read-only. */
2186  gsr->read_only = TRUE;
2187  }
2188 
2189  if ( !gsr->read_only )
2190  {
2191 
2192  switch (gnc_split_reg_get_placeholder(gsr))
2193  {
2194  case PLACEHOLDER_NONE:
2195  /* stay as false. */
2196  return;
2197 
2198  case PLACEHOLDER_THIS:
2199  args->string = _("This account may not be edited. If you want "
2200  "to edit transactions in this register, please "
2201  "open the account options and turn off the "
2202  "placeholder checkbox.");
2203  break;
2204 
2205  default:
2206  args->string = _("One of the sub-accounts selected may not be "
2207  "edited. If you want to edit transactions in "
2208  "this register, please open the sub-account "
2209  "options and turn off the placeholder checkbox. "
2210  "You may also open an individual account instead "
2211  "of a set of accounts.");
2212  break;
2213  }
2214  gsr->read_only = TRUE;
2215  /* Put up a warning dialog */
2216  args->gsr = gsr;
2217  g_timeout_add (250, gtk_callback_bug_workaround, args); /* 0.25 seconds */
2218  }
2219 
2220  /* Make the contents immutable */
2221  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2222  gnc_split_register_set_read_only( reg, TRUE );
2223 
2224 }
2225 
2226 static
2227 GtkWidget *
2228 gnc_split_reg_get_parent( GNCLedgerDisplay *ledger )
2229 {
2230  GNCSplitReg *gsr =
2231  GNC_SPLIT_REG(gnc_ledger_display_get_user_data( ledger ));
2232 
2233  if (gsr == NULL)
2234  return NULL;
2235 
2236  return gsr->window;
2237 }
2238 
2239 static
2240 void
2241 gsr_emit_help_changed( GnucashRegister *reg, gpointer user_data )
2242 {
2243  gsr_emit_simple_signal( (GNCSplitReg*)user_data, "help-changed" );
2244 }
2245 
2246 static
2247 void
2248 gsr_emit_include_date_signal( GNCSplitReg *gsr, time64 date )
2249 {
2250  g_signal_emit_by_name( gsr, "include-date", date, NULL );
2251 }
2252 
2253 static
2254 void
2255 gsr_emit_simple_signal( GNCSplitReg *gsr, const char *sigName )
2256 {
2257  g_signal_emit_by_name( gsr, sigName, NULL );
2258 }
2259 
2261 gnc_split_reg_get_register( GNCSplitReg *gsr )
2262 {
2263  if ( !gsr )
2264  return NULL;
2265 
2266  return gsr->reg;
2267 }
2268 
2269 SortType
2270 gnc_split_reg_get_sort_type( GNCSplitReg *gsr )
2271 {
2272  g_assert( gsr );
2273  return gsr->sort_type;
2274 }
2275 
2276 void
2277 gnc_split_reg_set_sort_type( GNCSplitReg *gsr, SortType t )
2278 {
2279  gnc_split_reg_sort( gsr, t );
2280 }
2281 
2282 void
2283 gnc_split_reg_set_sort_type_force( GNCSplitReg *gsr, SortType t, gboolean force )
2284 {
2285  gnc_split_reg_sort_force( gsr, t, force );
2286 }
2287 
2288 
2289 GtkWidget*
2290 gnc_split_reg_get_summarybar( GNCSplitReg *gsr )
2291 {
2292  if ( !gsr ) return NULL;
2293  return gsr->summarybar;
2294 }
2295 
2296 gboolean
2297 gnc_split_reg_get_read_only( GNCSplitReg *gsr )
2298 {
2299  g_assert( gsr );
2300  return gsr->read_only;
2301 }
2302 
2303 void
2304 gnc_split_reg_set_moved_cb( GNCSplitReg *gsr, GFunc cb, gpointer cb_data )
2305 {
2306  gnucash_register_set_moved_cb (gsr->reg, cb, cb_data);
2307 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
void gnc_price_list_destroy(PriceList *prices)
Definition: gnc-pricedb.c:701
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
Definition: Transaction.c:2433
#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)
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Definition: Transaction.c:2144
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2215
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Definition: Transaction.c:2345
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Dialog for create/edit an account.
gboolean xaccAccountIsPriced(const Account *acc)
Definition: Account.c:4249
a simple price database for gnucash
utility functions for the GnuCash UI
void gnc_split_register_copy_current(SplitRegister *reg)
The type, style and table for the register.
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *primary_sort_params, QofQueryParamList *secondary_sort_params, QofQueryParamList *tertiary_sort_params)
const char * xaccTransGetAssociation(const Transaction *trans)
Definition: Transaction.c:2190
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Split * gnc_split_register_get_current_split(SplitRegister *reg)
void gnc_split_register_delete_current_split(SplitRegister *reg)
void gnc_price_unref(GNCPrice *p)
Definition: gnc-pricedb.c:272
#define DEBUG(format, args...)
Definition: qoflog.h:255
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
char xaccSplitGetReconcile(const Split *split)
Definition: Split.c:1980
void xaccTransSetDescription(Transaction *trans, const char *desc)
Definition: Transaction.c:2085
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
gboolean gnc_numeric_zero_p(gnc_numeric a)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
void gnc_split_register_expand_current_trans(SplitRegister *reg, gboolean expand)
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
#define ENTER(format, args...)
Definition: qoflog.h:261
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
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level)
void gnc_split_register_redraw(SplitRegister *reg)
gboolean use_double_line
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
#define xaccAccountGetGUID(X)
Definition: Account.h:239
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
void xaccTransSetAssociation(Transaction *trans, const char *assoc)
Definition: Transaction.c:2096
void gnc_split_register_paste_current(SplitRegister *reg)
Account handling public routines.
#define YREC
Definition: Split.h:68
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
#define FREC
Definition: Split.h:69
GNCPlaceholderType xaccAccountGetDescendantPlaceholder(const Account *acc)
Definition: Account.c:3935
GnucashRegister * reg
Definition: gnc-split-reg.h:81
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
void gnc_table_save_state(Table *table, gchar *state_section)
Definition: table-gnome.c:68
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
PriceList * gnc_pricedb_lookup_latest_any_currency(GNCPriceDB *db, const gnc_commodity *commodity)
Definition: gnc-pricedb.c:1373
Gnome specific utility functions.
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
#define xaccSchedXactionGetGUID(X)
Definition: SchedXaction.h:321
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_numeric xaccAccountGetReconciledBalance(const Account *acc)
Definition: Account.c:3243
void gnc_table_init_gui(GtkWidget *widget, gchar *state_section)
Definition: table-gnome.c:157
const char * xaccTransGetReadOnly(const Transaction *trans)
Definition: Transaction.c:2313
All type declarations for the whole Gnucash engine.
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
void gnc_split_register_empty_current_trans_except_split(SplitRegister *reg, Split *split)
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
Generic api to store and retrieve preferences.
void gnc_split_register_set_read_only(SplitRegister *reg, gboolean read_only)
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
CursorClass
Transaction * xaccTransReverse(Transaction *orig)
Definition: Transaction.c:2579
void gnc_launch_assoc(const char *uri)
gboolean qof_book_is_readonly(const QofBook *book)
gboolean gnc_split_register_handle_exchange(SplitRegister *reg, gboolean force_dialog)
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
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
#define xaccAccountInsertSplit(acc, s)
Definition: Account.h:972
GNCLedgerDisplay * ledger
Definition: gnc-split-reg.h:79
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Declarations for the Table object.
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Definition: Transaction.c:2606
#define LEAVE(format, args...)
Definition: qoflog.h:271
void gnc_split_register_delete_current_trans(SplitRegister *reg)
gboolean gnc_split_register_get_split_amount_virt_loc(SplitRegister *reg, Split *split, VirtualLocation *virt_loc)
Split * gnc_split_register_duplicate_current(SplitRegister *reg)
#define QUERY_DEFAULT_SORT
Definition: qofquery.h:106
time64 gnc_time(time64 *tbuf)
get the current local time
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
void gnc_split_register_show_present_divider(SplitRegister *reg, gboolean show_present)
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 xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Definition: Transaction.c:1951
void gnc_split_register_cut_current(SplitRegister *reg)
SplitRegisterStyle
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void gnc_split_register_cancel_cursor_trans_changes(SplitRegister *reg)
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_split_register_config(SplitRegister *reg, SplitRegisterType newtype, SplitRegisterStyle newstyle, gboolean use_double_line)