GnuCash  4.12-11-g8193d7f23a+
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 <linas@linas.org> *
5  * Copyright (C) 1998 Rob Browning <rlb@cs.utexas.edu> *
6  * Copyright (C) 1999-2000 Dave Peticolas <dave@krondo.com> *
7  * Copyright (C) 2001 Gnumatic, Inc. *
8  * Copyright (C) 2002,2006 Joshua Sled <jsled@asynchronous.org> *
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 gnu@gnu.org *
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-doclink.h"
41 #include "dialog-doclink-utils.h"
42 #include "dialog-sx-editor.h"
43 #include "dialog-sx-from-trans.h"
44 #include "gnc-component-manager.h"
45 #include "gnc-date-edit.h"
46 #include "gnc-engine.h"
47 #include "gnc-euro.h"
48 #include "gnc-prefs.h"
49 #include "gnc-gui-query.h"
50 #include "gnc-gnome-utils.h"
51 #include "gnc-ledger-display.h"
52 #include "gnc-pricedb.h"
53 #include "gnc-ui-util.h"
54 #include "gnc-ui.h"
55 #include "gnc-uri-utils.h"
56 #include "gnc-filepath-utils.h"
57 #include "gnc-warnings.h"
58 #include "gnucash-sheet.h"
59 #include "gnucash-register.h"
60 #include "table-allgui.h"
61 #include "gnc-state.h"
62 
63 #include "dialog-utils.h"
64 
65 // static QofLogModule log_module = GNC_MOD_SX;
66 static QofLogModule log_module = GNC_MOD_GUI;
67 
68 /***** PROTOTYPES ***************************************************/
69 void gnc_split_reg_raise( GNCSplitReg *gsr );
70 
71 static GtkWidget* add_summary_label( GtkWidget *summarybar, gboolean pack_start,
72  const char *label_str, GtkWidget *extra );
73 
74 static void gsr_summarybar_set_arrow_draw (GNCSplitReg *gsr);
75 
76 static void gnc_split_reg_determine_read_only( GNCSplitReg *gsr, gboolean show_dialog );
77 static gboolean is_trans_readonly_and_warn (GtkWindow *parent, Transaction *trans);
78 
79 static GNCPlaceholderType gnc_split_reg_get_placeholder( GNCSplitReg *gsr );
80 static GtkWidget *gnc_split_reg_get_parent( GNCLedgerDisplay *ledger );
81 
82 static void gsr_create_table( GNCSplitReg *gsr );
83 static void gsr_setup_table( GNCSplitReg *gsr );
84 static void gsr_setup_status_widgets( GNCSplitReg *gsr );
85 
86 static void gsr_update_summary_label( GtkWidget *label,
87  xaccGetBalanceFn getter,
88  Account *leader,
89  GNCPrintAmountInfo print_info,
90  gnc_commodity *cmdty,
91  gboolean reverse,
92  gboolean euroFlag );
93 
94 static void gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data);
95 
96 static void gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger );
97 
98 static Transaction* create_balancing_transaction(QofBook *book, Account *account,
99  time64 statement_date, gnc_numeric balancing_amount);
100 
101 void gsr_default_enter_handler ( GNCSplitReg *w, gpointer ud );
102 void gsr_default_cancel_handler ( GNCSplitReg *w, gpointer ud );
103 void gsr_default_delete_handler ( GNCSplitReg *w, gpointer ud );
104 void gsr_default_reinit_handler ( GNCSplitReg *w, gpointer ud );
105 void gsr_default_dup_handler ( GNCSplitReg *w, gpointer ud );
106 void gsr_default_schedule_handler ( GNCSplitReg *w, gpointer ud );
107 void gsr_default_expand_handler ( GNCSplitReg *w, gpointer ud );
108 void gsr_default_blank_handler ( GNCSplitReg *w, gpointer ud );
109 void gsr_default_jump_handler ( GNCSplitReg *w, gpointer ud );
110 void gsr_default_cut_handler ( GNCSplitReg *w, gpointer ud );
111 void gsr_default_cut_txn_handler ( GNCSplitReg *w, gpointer ud );
112 void gsr_default_copy_handler ( GNCSplitReg *w, gpointer ud );
113 void gsr_default_copy_txn_handler ( GNCSplitReg *w, gpointer ud );
114 void gsr_default_paste_handler ( GNCSplitReg *w, gpointer ud );
115 void gsr_default_paste_txn_handler( GNCSplitReg *w, gpointer ud );
116 void gsr_default_void_txn_handler ( GNCSplitReg *w, gpointer ud );
117 void gsr_default_unvoid_txn_handler ( GNCSplitReg *w, gpointer ud );
118 void gsr_default_reverse_txn_handler ( GNCSplitReg *w, gpointer ud );
119 void gsr_default_doclink_handler ( GNCSplitReg *w );
120 void gsr_default_doclink_open_handler ( GNCSplitReg *w );
121 void gsr_default_doclink_remove_handler ( GNCSplitReg *w );
122 static void gsr_default_doclink_from_sheet_handler ( GNCSplitReg *w );
123 
124 static void gsr_emit_simple_signal ( GNCSplitReg *gsr, const char *sigName );
125 static void gsr_emit_help_changed ( GnucashRegister *reg, gpointer user_data );
126 static void gsr_emit_show_popup_menu ( GnucashRegister *reg, gpointer user_data );
127 static void gsr_emit_include_date_signal ( GNCSplitReg *gsr, time64 date );
128 
129 void gnc_split_reg_cut_cb(GtkWidget *w, gpointer data);
130 void gnc_split_reg_copy_cb(GtkWidget *w, gpointer data);
131 void gnc_split_reg_paste_cb(GtkWidget *w, gpointer data);
132 
133 void gnc_split_reg_cut_trans_cb(GtkWidget *w, gpointer data);
134 void gnc_split_reg_copy_trans_cb(GtkWidget *w, gpointer data);
135 void gnc_split_reg_paste_trans_cb(GtkWidget *w, gpointer data);
136 void gnc_split_reg_void_trans_cb(GtkWidget *w, gpointer data);
137 void gnc_split_reg_unvoid_trans_cb(GtkWidget *w, gpointer data);
138 void gnc_split_reg_reverse_trans_cb(GtkWidget *w, gpointer data);
139 
140 void gnc_split_reg_record_cb (GnucashRegister *reg, gpointer data);
141 void gnc_split_reg_reinitialize_trans_cb(GtkWidget *w, gpointer data);
142 void gnc_split_reg_delete_trans_cb(GtkWidget *w, gpointer data);
143 void gnc_split_reg_duplicate_trans_cb(GtkWidget *w, gpointer data);
144 void gnc_split_reg_recur_cb(GtkWidget *w, gpointer data);
145 void gnc_split_reg_record_trans_cb(GtkWidget *w, gpointer data);
146 void gnc_split_reg_cancel_trans_cb(GtkWidget *w, gpointer data);
147 
148 void gnc_split_reg_expand_trans_menu_cb(GtkWidget *widget, gpointer data);
149 void gnc_split_reg_expand_trans_toolbar_cb(GtkWidget *widget, gpointer data);
150 void gnc_split_reg_new_trans_cb(GtkWidget *widget, gpointer data);
151 void gnc_split_reg_jump_cb(GtkWidget *widget, gpointer data);
152 
153 void gnc_split_reg_style_ledger_cb (GtkWidget *w, gpointer data);
154 void gnc_split_reg_style_auto_ledger_cb (GtkWidget *w, gpointer data);
155 void gnc_split_reg_style_journal_cb (GtkWidget *w, gpointer data);
156 void gnc_split_reg_double_line_cb (GtkWidget *w, gpointer data);
157 
158 void gnc_split_reg_sort_standard_cb (GtkWidget *w, gpointer data);
159 void gnc_split_reg_sort_date_cb (GtkWidget *w, gpointer data);
160 void gnc_split_reg_sort_date_entered_cb (GtkWidget *w, gpointer data);
161 void gnc_split_reg_sort_date_reconciled_cb (GtkWidget *w, gpointer data);
162 void gnc_split_reg_sort_num_cb (GtkWidget *w, gpointer data);
163 void gnc_split_reg_sort_amount_cb (GtkWidget *w, gpointer data);
164 void gnc_split_reg_sort_memo_cb (GtkWidget *w, gpointer data);
165 void gnc_split_reg_sort_desc_cb (GtkWidget *w, gpointer data);
166 void gnc_split_reg_sort_action_cb (GtkWidget *w, gpointer data);
167 void gnc_split_reg_sort_notes_cb (GtkWidget *w, gpointer data);
168 
169 
170 void gnc_split_reg_size_allocate( GtkWidget *widget,
171  GtkAllocation *allocation,
172  gpointer user_data );
173 
174 
175 static void gnc_split_reg_class_init( GNCSplitRegClass *klass );
176 static void gnc_split_reg_init( GNCSplitReg *gsr );
177 static void gnc_split_reg_init2( GNCSplitReg *gsr );
178 void gnc_split_reg_dispose(GObject *obj);
179 
180 FROM_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
181 AS_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
182 
183 GType
184 gnc_split_reg_get_type( void )
185 {
186  static GType gnc_split_reg_type = 0;
187 
188  if (!gnc_split_reg_type)
189  {
190  GTypeInfo type_info =
191  {
192  sizeof(GNCSplitRegClass), /* class_size */
193  NULL, /* base_init */
194  NULL, /* base_finalize */
195  (GClassInitFunc)gnc_split_reg_class_init,
196  NULL, /* class_finalize */
197  NULL, /* class_data */
198  sizeof(GNCSplitReg), /* */
199  0, /* n_preallocs */
200  (GInstanceInitFunc)gnc_split_reg_init,
201  };
202 
203  gnc_split_reg_type = g_type_register_static( GTK_TYPE_BOX,
204  "GNCSplitReg",
205  &type_info, 0 );
206  }
207 
208  return gnc_split_reg_type;
209 }
210 
211 /* SIGNALS */
212 enum gnc_split_reg_signal_enum
213 {
214  ENTER_ENT_SIGNAL,
215  CANCEL_ENT_SIGNAL,
216  DELETE_ENT_SIGNAL,
217  REINIT_ENT_SIGNAL,
218  DUP_ENT_SIGNAL,
219  SCHEDULE_ENT_SIGNAL,
220  EXPAND_ENT_SIGNAL,
221  BLANK_SIGNAL,
222  JUMP_SIGNAL,
223  CUT_SIGNAL,
224  CUT_TXN_SIGNAL,
225  COPY_SIGNAL,
226  COPY_TXN_SIGNAL,
227  PASTE_SIGNAL,
228  PASTE_TXN_SIGNAL,
229  VOID_TXN_SIGNAL,
230  UNVOID_TXN_SIGNAL,
231  REVERSE_TXN_SIGNAL,
232  HELP_CHANGED_SIGNAL,
233  SHOW_POPUP_MENU_SIGNAL,
234  INCLUDE_DATE_SIGNAL,
235  LAST_SIGNAL
236 };
237 
238 static guint gnc_split_reg_signals[LAST_SIGNAL] = { 0 };
239 
240 static void
241 gnc_split_reg_class_init( GNCSplitRegClass *klass )
242 {
243  int i;
244  GObjectClass *object_class;
245  static struct similar_signal_info
246  {
247  enum gnc_split_reg_signal_enum s;
248  const char *signal_name;
249  guint defaultOffset;
250  } signals[] =
251  {
252  { ENTER_ENT_SIGNAL, "enter_ent", G_STRUCT_OFFSET( GNCSplitRegClass, enter_ent_cb ) },
253  { CANCEL_ENT_SIGNAL, "cancel_ent", G_STRUCT_OFFSET( GNCSplitRegClass, cancel_ent_cb ) },
254  { DELETE_ENT_SIGNAL, "delete_ent", G_STRUCT_OFFSET( GNCSplitRegClass, delete_ent_cb ) },
255  { REINIT_ENT_SIGNAL, "reinit_ent", G_STRUCT_OFFSET( GNCSplitRegClass, reinit_ent_cb ) },
256  { DUP_ENT_SIGNAL, "dup_ent", G_STRUCT_OFFSET( GNCSplitRegClass, dup_ent_cb ) },
257  { SCHEDULE_ENT_SIGNAL, "schedule_ent", G_STRUCT_OFFSET( GNCSplitRegClass, schedule_ent_cb ) },
258  { EXPAND_ENT_SIGNAL, "expand_ent", G_STRUCT_OFFSET( GNCSplitRegClass, expand_ent_cb ) },
259  { BLANK_SIGNAL, "blank", G_STRUCT_OFFSET( GNCSplitRegClass, blank_cb ) },
260  { JUMP_SIGNAL, "jump", G_STRUCT_OFFSET( GNCSplitRegClass, jump_cb ) },
261  { CUT_SIGNAL, "cut", G_STRUCT_OFFSET( GNCSplitRegClass, cut_cb ) },
262  { CUT_TXN_SIGNAL, "cut_txn", G_STRUCT_OFFSET( GNCSplitRegClass, cut_txn_cb ) },
263  { COPY_SIGNAL, "copy", G_STRUCT_OFFSET( GNCSplitRegClass, copy_cb ) },
264  { COPY_TXN_SIGNAL, "copy_txn", G_STRUCT_OFFSET( GNCSplitRegClass, copy_txn_cb ) },
265  { PASTE_SIGNAL, "paste", G_STRUCT_OFFSET( GNCSplitRegClass, paste_cb ) },
266  { PASTE_TXN_SIGNAL, "paste_txn", G_STRUCT_OFFSET( GNCSplitRegClass, paste_txn_cb ) },
267  { VOID_TXN_SIGNAL, "void_txn", G_STRUCT_OFFSET( GNCSplitRegClass, void_txn_cb ) },
268  { UNVOID_TXN_SIGNAL, "unvoid_txn", G_STRUCT_OFFSET( GNCSplitRegClass, unvoid_txn_cb ) },
269  { REVERSE_TXN_SIGNAL, "reverse_txn", G_STRUCT_OFFSET( GNCSplitRegClass, reverse_txn_cb ) },
270  { HELP_CHANGED_SIGNAL, "help-changed", G_STRUCT_OFFSET( GNCSplitRegClass, help_changed_cb ) },
271  { SHOW_POPUP_MENU_SIGNAL, "show-popup-menu", G_STRUCT_OFFSET( GNCSplitRegClass, show_popup_menu_cb ) },
272  { INCLUDE_DATE_SIGNAL, "include-date", G_STRUCT_OFFSET( GNCSplitRegClass, include_date_cb ) },
273  { LAST_SIGNAL, NULL, 0 }
274  };
275 
276  object_class = (GObjectClass*) klass;
277 
278  for ( i = 0; signals[i].s != INCLUDE_DATE_SIGNAL; i++ )
279  {
280  gnc_split_reg_signals[ signals[i].s ] =
281  g_signal_new( signals[i].signal_name,
282  G_TYPE_FROM_CLASS(object_class),
283  G_SIGNAL_RUN_LAST,
284  signals[i].defaultOffset,
285  NULL, NULL,
286  g_cclosure_marshal_VOID__VOID,
287  G_TYPE_NONE, 0 );
288  }
289  /* Setup the non-default-marshalled signals; 'i' is still valid, here. */
290  /* "include-date" */
291  gnc_split_reg_signals[ INCLUDE_DATE_SIGNAL ] =
292  g_signal_new( "include-date",
293  G_TYPE_FROM_CLASS(object_class),
294  G_SIGNAL_RUN_LAST,
295  signals[i++].defaultOffset,
296  NULL, NULL,
297  g_cclosure_marshal_VOID__INT, /* time64 == int */
298  G_TYPE_NONE, 1, G_TYPE_INT );
299 
300  g_assert( i == LAST_SIGNAL );
301 
302  /* Setup the default handlers. */
303  klass->enter_ent_cb = gsr_default_enter_handler;
304  klass->cancel_ent_cb = gsr_default_cancel_handler;
305  klass->delete_ent_cb = gsr_default_delete_handler;
306  klass->reinit_ent_cb = gsr_default_reinit_handler;
307  klass->dup_ent_cb = gsr_default_dup_handler;
308  klass->schedule_ent_cb = gsr_default_schedule_handler;
309  klass->expand_ent_cb = gsr_default_expand_handler;
310  klass->blank_cb = gsr_default_blank_handler;
311  klass->jump_cb = gsr_default_jump_handler;
312  klass->cut_cb = gsr_default_cut_handler;
313  klass->cut_txn_cb = gsr_default_cut_txn_handler;
314  klass->copy_cb = gsr_default_copy_handler;
315  klass->copy_txn_cb = gsr_default_copy_txn_handler;
316  klass->paste_cb = gsr_default_paste_handler;
317  klass->paste_txn_cb = gsr_default_paste_txn_handler;
318  klass->void_txn_cb = gsr_default_void_txn_handler;
319  klass->unvoid_txn_cb = gsr_default_unvoid_txn_handler;
320  klass->reverse_txn_cb = gsr_default_reverse_txn_handler;
321 
322  klass->help_changed_cb = NULL;
323  klass->show_popup_menu_cb = NULL;
324  klass->include_date_cb = NULL;
325 
326  object_class->dispose = gnc_split_reg_dispose;
327 }
328 
329 GtkWidget*
330 gnc_split_reg_new( GNCLedgerDisplay *ld,
331  GtkWindow *parent,
332  gint numberOfLines,
333  gboolean read_only )
334 {
335  GNCSplitReg *gsrToRet;
336 
337  ENTER("ld=%p, parent=%p, numberOfLines=%d, read_only=%s",
338  ld, parent, numberOfLines, read_only ? "TRUE" : "FALSE");
339 
340  gsrToRet = g_object_new( gnc_split_reg_get_type(), NULL );
341 
342  gsrToRet->numRows = numberOfLines;
343  gsrToRet->read_only = read_only;
344 
345  gsrToRet->ledger = ld;
346  gsrToRet->window = GTK_WIDGET(parent);
347 
348  gnc_split_reg_init2( gsrToRet );
349 
350  LEAVE("%p", gsrToRet);
351  return GTK_WIDGET( gsrToRet );
352 }
353 
354 static void
355 gnc_split_reg_init( GNCSplitReg *gsr )
356 {
357  gtk_orientable_set_orientation (GTK_ORIENTABLE(gsr), GTK_ORIENTATION_VERTICAL);
358 
359  gsr->sort_type = BY_STANDARD;
360  gsr->sort_rev = FALSE;
361  gsr->sort_arrow_handler_id = 0;
362  gsr->filter_text = NULL;
363  gsr->width = -1;
364  gsr->height = -1;
365  gsr->numRows = 10;
366  gsr->read_only = FALSE;
367 }
368 
369 static void
370 gnc_split_reg_pref_acc_labels (gpointer prefs, gchar *pref, gpointer user_data)
371 {
372  GNCSplitReg *gsr = user_data;
373  gnucash_register_refresh_from_prefs (gsr->reg);
374 }
375 
376 static void
377 gnc_split_reg_init2( GNCSplitReg *gsr )
378 {
379  if ( !gsr ) return;
380 
381  gnc_split_reg_determine_read_only( gsr, TRUE );
382 
383  gsr_setup_status_widgets( gsr );
384  /* ordering is important here... setup_status before create_table */
385  gsr_create_table( gsr );
386  gsr_setup_table( gsr );
387 
388  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
389  GNC_PREF_ACCOUNTING_LABELS,
390  gnc_split_reg_pref_acc_labels,
391  gsr);
392 }
393 
394 static
395 void
396 gsr_setup_table( GNCSplitReg *gsr )
397 {
398  SplitRegister *sr;
399 
400  ENTER("gsr=%p", gsr);
401 
402  sr = gnc_ledger_display_get_split_register( gsr->ledger );
404  /* events should be sufficient to redraw this */
405  /* gnc_ledger_display_refresh( gsr->ledger ); */
406 
407  LEAVE(" ");
408 }
409 
410 static void
411 gsr_move_sort_and_filter_to_state_file (GNCSplitReg *gsr, GKeyFile* state_file, const gchar *state_section)
412 {
413  GNCLedgerDisplayType ledger_type;
414  GNCLedgerDisplay* ld;
415 
416  // Look for any old kvp entries and add them to .gcm file
417  ledger_type = gnc_ledger_display_type (gsr->ledger);
418 
419  // General ledger should already be using .gcm file
420  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
421  {
422  Account *leader = gnc_ledger_display_leader (gsr->ledger);
423  const char* kvp_filter = NULL;
424  const char* kvp_sort_order = NULL;
425  gboolean kvp_sort_reversed = FALSE;
426 
427  kvp_filter = xaccAccountGetFilter (leader);
428  if (kvp_filter)
429  {
430  gchar *temp_filter_text = g_strdup (kvp_filter);
431  // make it conform to .gcm file list
432  g_strdelimit (temp_filter_text, ",", ';');
433  g_key_file_set_string (state_file, state_section, KEY_PAGE_FILTER,
434  temp_filter_text);
435  g_free (temp_filter_text);
436  xaccAccountSetFilter (leader, NULL);
437  }
438 
439  kvp_sort_order = xaccAccountGetSortOrder (leader);
440  if (kvp_sort_order)
441  {
442  g_key_file_set_string (state_file, state_section,
443  KEY_PAGE_SORT, kvp_sort_order);
444  xaccAccountSetSortOrder (leader, NULL);
445  }
446 
447  kvp_sort_reversed = xaccAccountGetSortReversed (leader);
448  if (kvp_sort_reversed)
449  {
450  g_key_file_set_boolean (state_file, state_section,
451  KEY_PAGE_SORT_REV, kvp_sort_reversed);
452  xaccAccountSetSortReversed (leader, FALSE);
453  }
454  }
455 }
456 
457 static
458 void
459 gsr_create_table( GNCSplitReg *gsr )
460 {
461  GtkWidget *register_widget = NULL;
462  SplitRegister *sr = NULL;
463 
464  Account * account = gnc_ledger_display_leader(gsr->ledger);
465  const GncGUID * guid = xaccAccountGetGUID(account);
466  gchar guidstr[GUID_ENCODING_LENGTH+1];
467  GKeyFile* state_file = gnc_state_get_current();
468  gchar *register_state_section;
469 
470  guid_to_string_buff (guid, guidstr);
471 
472  register_state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr, NULL);
473 
474  ENTER("gsr=%p", gsr);
475 
476  sr = gnc_ledger_display_get_split_register (gsr->ledger);
477 
478  gnc_ledger_display_set_user_data( gsr->ledger, (gpointer)gsr );
479  gnc_ledger_display_set_handlers( gsr->ledger,
480  gnc_split_reg_ld_destroy,
481  gnc_split_reg_get_parent );
482 
483  /* FIXME: We'd really rather pass this down... */
484  sr = gnc_ledger_display_get_split_register( gsr->ledger );
485  register_widget = gnucash_register_new( sr->table, register_state_section );
486  gsr->reg = GNUCASH_REGISTER( register_widget );
487 
488  gtk_box_pack_start (GTK_BOX (gsr), GTK_WIDGET(gsr->reg), TRUE, TRUE, 0);
489  gnucash_sheet_set_window (gnucash_register_get_sheet (gsr->reg), gsr->window);
490 
491  // setup the callback for when the doclink cell clicked on
492  gnucash_register_set_open_doclink_cb (gsr->reg,
493  (GFunc)gsr_default_doclink_from_sheet_handler, gsr);
494 
495  gtk_widget_show ( GTK_WIDGET(gsr->reg) );
496  g_signal_connect (gsr->reg, "activate_cursor",
497  G_CALLBACK(gnc_split_reg_record_cb), gsr);
498  g_signal_connect (gsr->reg, "redraw_all",
499  G_CALLBACK(gsr_redraw_all_cb), gsr);
500  g_signal_connect (gsr->reg, "redraw_help",
501  G_CALLBACK(gsr_emit_help_changed), gsr);
502  g_signal_connect (gsr->reg, "show_popup_menu",
503  G_CALLBACK(gsr_emit_show_popup_menu), gsr);
504 
505  gsr_move_sort_and_filter_to_state_file (gsr, state_file, register_state_section);
506 
507  g_free (register_state_section);
508  LEAVE(" ");
509 }
510 
511 static
512 void
513 gsr_setup_status_widgets( GNCSplitReg *gsr )
514 {
515  SplitRegister *sr;
516  gboolean use_double_line;
517 
518  sr = gnc_ledger_display_get_split_register( gsr->ledger );
519  use_double_line = gnc_ledger_display_default_double_line( gsr->ledger );
520 
521  /* be sure to initialize the gui elements associated with the cursor */
522  gnc_split_register_config( sr, sr->type, sr->style, use_double_line );
523 }
524 
525 void
526 gnc_split_reg_dispose(GObject *obj)
527 {
528  GNCSplitReg *gsr = GNC_SPLIT_REG(obj);
529 
530  if (gsr->filter_text)
531  g_free (gsr->filter_text);
532  gsr->filter_text = NULL;
533 
534  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
535  GNC_PREF_ACCOUNTING_LABELS,
536  gnc_split_reg_pref_acc_labels,
537  gsr);
538 
539  if (gsr->reg)
540  {
541  g_signal_handlers_disconnect_by_data (gsr->reg, gsr);
542  gtk_widget_destroy (GTK_WIDGET (gsr->reg));
543  }
544  gsr->reg = NULL;
545 }
546 
550 void
551 gnc_split_reg_raise( GNCSplitReg *gsr )
552 {
553  if (gsr == NULL)
554  return;
555 
556  if (gsr->window == NULL)
557  return;
558 
559  gtk_window_present( GTK_WINDOW(gsr->window) );
560 }
561 
562 
567 static
568 void
569 gsr_update_summary_label( GtkWidget *label,
570  xaccGetBalanceFn getter,
571  Account *leader,
572  GNCPrintAmountInfo print_info,
573  gnc_commodity *cmdty,
574  gboolean reverse,
575  gboolean euroFlag )
576 {
577  gnc_numeric amount;
578  char string[256];
579  const gchar *label_str = NULL;
580  GtkWidget *text_label, *hbox;
581  gchar *bidi_string;
582 
583  if ( label == NULL )
584  return;
585 
586  hbox = g_object_get_data (G_OBJECT(label), "text_box");
587  text_label = g_object_get_data (G_OBJECT(label), "text_label");
588  label_str = gtk_label_get_text (GTK_LABEL(text_label));
589 
590  amount = (*getter)( leader );
591 
592  if ( reverse )
593  {
594  amount = gnc_numeric_neg( amount );
595  }
596 
597  xaccSPrintAmount( string, amount, print_info );
598 
599  if ( euroFlag )
600  {
601  strcat( string, " / " );
602  xaccSPrintAmount( string + strlen( string ),
603  gnc_convert_to_euro( cmdty, amount ),
604  gnc_commodity_print_info( gnc_get_euro(), TRUE ) );
605  }
606 
607  gnc_set_label_color( label, amount );
608  bidi_string = gnc_wrap_text_with_bidi_ltr_isolate (string);
609  gtk_label_set_text( GTK_LABEL(label), bidi_string );
610  g_free (bidi_string);
611 
612  if (label_str)
613  {
614  gchar *tooltip = g_strdup_printf ("%s %s", label_str, string);
615  gtk_widget_set_tooltip_text (GTK_WIDGET(hbox), tooltip);
616  g_free (tooltip);
617  }
618 }
619 
620 static
621 void
622 gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data)
623 {
624  GNCSplitReg *gsr = data;
625  gnc_commodity * commodity;
626  GNCPrintAmountInfo print_info;
627  gnc_numeric amount;
628  Account *leader;
629  gboolean reverse;
630  gboolean euro;
631 
632  if ( gsr->summarybar == NULL )
633  return;
634 
635  leader = gnc_ledger_display_leader( gsr->ledger );
636 
637  commodity = xaccAccountGetCommodity( leader );
638 
639  /* no EURO conversion, if account is already EURO or no EURO currency */
640  if (commodity != NULL)
641  euro = (gnc_is_euro_currency( commodity ) &&
642  (strncasecmp(gnc_commodity_get_mnemonic(commodity), "EUR", 3)));
643  else
644  euro = FALSE;
645 
646  print_info = gnc_account_print_info( leader, TRUE );
647  reverse = gnc_reverse_balance( leader );
648 
649  if (gsr->balance_label != NULL) // only test the first as they are a group
650  {
651  gsr_update_summary_label( gsr->balance_label,
652  xaccAccountGetPresentBalance,
653  leader, print_info, commodity, reverse, euro );
654  gsr_update_summary_label( gsr->cleared_label,
656  leader, print_info, commodity, reverse, euro );
657  gsr_update_summary_label( gsr->reconciled_label,
659  leader, print_info, commodity, reverse, euro );
660  gsr_update_summary_label( gsr->future_label,
662  leader, print_info, commodity, reverse, euro );
663  gsr_update_summary_label( gsr->projectedminimum_label,
664  xaccAccountGetProjectedMinimumBalance,
665  leader, print_info, commodity, reverse, euro );
666  }
667 
668  // Sort label
669  if (gsr->sort_label != NULL)
670  {
671  gchar *old_tt_text = gtk_widget_get_tooltip_text (GTK_WIDGET(gsr->sort_label));
672  gchar *new_tt_text;
673  gchar *text = NULL;
674 
675  switch (gsr->sort_type)
676  {
677  case (0):
678  text = _("None");
679  break;
680  case (1):
681  text = _("Standard Order");
682  break;
683  case (2):
684  text = _("Date");
685  break;
686  case (3):
687  text = _("Date of Entry");
688  break;
689  case (4):
690  text = _("Statement Date");
691  break;
692  case (5):
693  text = _("Number");
694  break;
695  case (6):
696  text = _("Amount");
697  break;
698  case (7):
699  text = _("Memo");
700  break;
701  case (8):
702  text = _("Description");
703  break;
704  case (9):
705  text = _("Action");
706  break;
707  case (10):
708  text = _("Notes");
709  break;
710  }
711 
712  if (gsr->sort_rev)
713  gtk_widget_set_tooltip_text (GTK_WIDGET(gsr->sort_label), _("Descending"));
714  else
715  gtk_widget_set_tooltip_text (GTK_WIDGET(gsr->sort_label), _("Ascending"));
716 
717  new_tt_text = gtk_widget_get_tooltip_text (GTK_WIDGET(gsr->sort_label));
718 
719  // does the arrow need changing
720  if (g_strcmp0 (old_tt_text, new_tt_text) != 0)
721  gsr_summarybar_set_arrow_draw (gsr);
722 
723  if (old_tt_text)
724  g_free (old_tt_text);
725 
726  if (new_tt_text)
727  g_free (new_tt_text);
728 
729  gtk_label_set_text (GTK_LABEL(gsr->sort_label), text);
730  }
731 
732  // Filter label
733  if (gsr->filter_label != NULL)
734  {
735  gchar *old_tt_text = gtk_widget_get_tooltip_text (GTK_WIDGET(gsr->filter_label));
736 
737  // check for a change in text
738  if (g_strcmp0 (old_tt_text, gsr->filter_text) != 0)
739  {
740  if (gsr->filter_text != NULL)
741  gtk_label_set_text (GTK_LABEL(gsr->filter_label), _("Filtered"));
742  else
743  gtk_label_set_text (GTK_LABEL(gsr->filter_label), "");
744 
745  gtk_widget_set_tooltip_text (GTK_WIDGET(gsr->filter_label), gsr->filter_text);
746 
747  }
748  g_free (old_tt_text);
749  }
750 
751  if (gsr->shares_label == NULL && gsr->value_label == NULL)
752  return;
753  amount = xaccAccountGetBalance( leader );
754  if (reverse)
755  amount = gnc_numeric_neg( amount );
756 
757  /* Print the summary share amount */
758  if (gsr->shares_label != NULL)
759  {
760  char string[256];
761  print_info = gnc_account_print_info( leader, TRUE );
762  xaccSPrintAmount( string, amount, print_info );
763  gnc_set_label_color( gsr->shares_label, amount );
764  gtk_label_set_text( GTK_LABEL(gsr->shares_label), string );
765  }
766 
767  /* Print the summary share value */
768  if (gsr->value_label != NULL)
769  {
770  char string[256];
771  QofBook *book = gnc_account_get_book (leader);
772  GNCPriceDB *pricedb = gnc_pricedb_get_db (book);
773  gnc_commodity *currency = gnc_default_currency ();
774  gnc_numeric value =
776  commodity, currency);
777  print_info = gnc_commodity_print_info (currency, TRUE);
778  xaccSPrintAmount (string, value, print_info);
779  gnc_set_label_color (gsr->value_label, amount);
780  gtk_label_set_text (GTK_LABEL (gsr->value_label), string);
781 
782  }
783 }
784 
785 static void
786 gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger )
787 {
788  GNCSplitReg *gsr = gnc_ledger_display_get_user_data( ledger );
789  Account * account = gnc_ledger_display_leader(ledger);
790  const GncGUID * guid = xaccAccountGetGUID(account);
791  gchar guidstr[GUID_ENCODING_LENGTH+1];
792  gchar *state_section;
793  guid_to_string_buff(guid, guidstr);
794 
795  state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr, NULL);
796 
797  if (gsr)
798  {
799  SplitRegister *reg;
800 
802 
803  if (reg && reg->table)
804  gnc_table_save_state (reg->table, state_section);
805 
806  /*
807  * Don't destroy the window here any more. The register no longer
808  * owns it.
809  */
810  }
811  g_free (state_section);
812 
813  gnc_ledger_display_set_user_data (ledger, NULL);
814  g_object_unref (gsr);
815 }
816 
817 void
818 gsr_default_cut_handler( GNCSplitReg *gsr, gpointer data )
819 {
820  gnucash_register_cut_clipboard( gsr->reg );
821 }
822 
826 void
827 gnc_split_reg_cut_cb (GtkWidget *w, gpointer data)
828 {
829  GNCSplitReg *gsr = data;
830  gsr_emit_simple_signal( gsr, "cut" );
831 }
832 
833 void
834 gsr_default_copy_handler( GNCSplitReg *gsr, gpointer data )
835 {
836  gnucash_register_copy_clipboard( gsr->reg );
837 }
838 
842 void
843 gnc_split_reg_copy_cb (GtkWidget *w, gpointer data)
844 {
845  GNCSplitReg *gsr = data;
846  gsr_emit_simple_signal( gsr, "copy" );
847 }
848 
849 void
850 gsr_default_paste_handler( GNCSplitReg *gsr, gpointer data )
851 {
852  gnucash_register_paste_clipboard( gsr->reg );
853 }
854 
858 void
859 gnc_split_reg_paste_cb (GtkWidget *w, gpointer data)
860 {
861  GNCSplitReg *gsr = data;
862  gsr_emit_simple_signal( gsr, "paste" );
863 }
864 
865 void
866 gsr_default_cut_txn_handler (GNCSplitReg *gsr, gpointer data)
867 {
868  CursorClass cursor_class;
869  SplitRegister *reg;
870  Transaction *trans;
871  Split *split;
872  GtkWidget *dialog;
873  gint response;
874  const gchar *warning;
875 
876  reg = gnc_ledger_display_get_split_register (gsr->ledger);
877 
878  /* get the current split based on cursor position */
880  if (split == NULL)
881  {
883  return;
884  }
885 
886  trans = xaccSplitGetParent (split);
887  cursor_class = gnc_split_register_get_current_cursor_class (reg);
888 
889  /* test for blank_split reference pointing to split */
890  if (gnc_split_register_is_blank_split (reg, split))
892 
893  /* Cutting the blank split just cancels */
894  {
895  Split *blank_split = gnc_split_register_get_blank_split (reg);
896 
897  if (split == blank_split)
898  {
900  return;
901  }
902  }
903 
904  if (cursor_class == CURSOR_CLASS_NONE)
905  return;
906 
907  /* this is probably not required but leave as a double check */
908  if (is_trans_readonly_and_warn (GTK_WINDOW(gsr->window), trans))
909  return;
910 
911  /* On a split cursor, just delete the one split. */
912  if (cursor_class == CURSOR_CLASS_SPLIT)
913  {
914  const char *format = _("Cut the split '%s' from the transaction '%s'?");
915  const char *recn_warn = _("You would be removing a reconciled split! "
916  "This is not a good idea as it will cause your "
917  "reconciled balance to be off.");
918  const char *anchor_error = _("You cannot cut this split.");
919  const char *anchor_split = _("This is the split anchoring this transaction "
920  "to the register. You may not remove it from "
921  "this register window. You may remove the "
922  "entire transaction from this window, or you "
923  "may navigate to a register that shows "
924  "another side of this same transaction and "
925  "remove the split from that register.");
926  char *buf = NULL;
927  const char *memo;
928  const char *desc;
929  char recn;
930 
931  if (reg->type != GENERAL_JOURNAL) // no anchoring split
932  {
933  if (split == gnc_split_register_get_current_trans_split (reg, NULL))
934  {
935  dialog = gtk_message_dialog_new (GTK_WINDOW(gsr->window),
936  GTK_DIALOG_MODAL
937  | GTK_DIALOG_DESTROY_WITH_PARENT,
938  GTK_MESSAGE_ERROR,
939  GTK_BUTTONS_OK,
940  "%s", anchor_error);
941  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
942  "%s", anchor_split);
943  gtk_dialog_run (GTK_DIALOG(dialog));
944  gtk_widget_destroy (dialog);
945  return;
946  }
947  }
948  memo = xaccSplitGetMemo (split);
949  memo = (memo && *memo) ? memo : _("(no memo)");
950 
951  desc = xaccTransGetDescription (trans);
952  desc = (desc && *desc) ? desc : _("(no description)");
953 
954  /* ask for user confirmation before performing permanent damage */
955  buf = g_strdup_printf (format, memo, desc);
956  dialog = gtk_message_dialog_new (GTK_WINDOW(gsr->window),
957  GTK_DIALOG_MODAL
958  | GTK_DIALOG_DESTROY_WITH_PARENT,
959  GTK_MESSAGE_QUESTION,
960  GTK_BUTTONS_NONE,
961  "%s", buf);
962  g_free (buf);
963  recn = xaccSplitGetReconcile (split);
964  if (recn == YREC || recn == FREC)
965  {
966  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
967  "%s", recn_warn);
968  warning = GNC_PREF_WARN_REG_SPLIT_CUT_RECD;
969  }
970  else
971  {
972  warning = GNC_PREF_WARN_REG_SPLIT_CUT;
973  }
974 
975  gtk_dialog_add_button (GTK_DIALOG(dialog),
976  _("_Cancel"), GTK_RESPONSE_CANCEL);
977  gnc_gtk_dialog_add_button (dialog, _("_Cut Split"),
978  "edit-delete", GTK_RESPONSE_ACCEPT);
979  response = gnc_dialog_run (GTK_DIALOG(dialog), warning);
980  gtk_widget_destroy (dialog);
981  if (response != GTK_RESPONSE_ACCEPT)
982  return;
983 
985  return;
986  }
987 
988  /* On a transaction cursor with 2 or fewer splits in single or double
989  * mode, we just delete the whole transaction, kerblooie */
990  {
991  const char *title = _("Cut the current transaction?");
992  const char *recn_warn = _("You would be removing a transaction "
993  "with reconciled splits! "
994  "This is not a good idea as it will cause your "
995  "reconciled balance to be off.");
996 
997  dialog = gtk_message_dialog_new (GTK_WINDOW(gsr->window),
998  GTK_DIALOG_MODAL
999  | GTK_DIALOG_DESTROY_WITH_PARENT,
1000  GTK_MESSAGE_WARNING,
1001  GTK_BUTTONS_NONE,
1002  "%s", title);
1003  if (xaccTransHasReconciledSplits (trans))
1004  {
1005  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1006  "%s", recn_warn);
1007  warning = GNC_PREF_WARN_REG_TRANS_CUT_RECD;
1008  }
1009  else
1010  {
1011  warning = GNC_PREF_WARN_REG_TRANS_CUT;
1012  }
1013  gtk_dialog_add_button (GTK_DIALOG(dialog),
1014  _("_Cancel"), GTK_RESPONSE_CANCEL);
1015  gnc_gtk_dialog_add_button (dialog, _("_Cut Transaction"),
1016  "edit-delete", GTK_RESPONSE_ACCEPT);
1017  response = gnc_dialog_run (GTK_DIALOG(dialog), warning);
1018  gtk_widget_destroy (dialog);
1019  if (response != GTK_RESPONSE_ACCEPT)
1020  return;
1021 
1023  return;
1024  }
1025 }
1026 
1030 void
1031 gnc_split_reg_cut_trans_cb (GtkWidget *w, gpointer data)
1032 {
1033  GNCSplitReg *gsr = data;
1034  gsr_emit_simple_signal( gsr, "cut_txn" );
1035 }
1036 
1037 void
1038 gsr_default_copy_txn_handler( GNCSplitReg *gsr, gpointer data )
1039 {
1041  (gnc_ledger_display_get_split_register( gsr->ledger ));
1042 }
1043 
1047 void
1048 gnc_split_reg_copy_trans_cb(GtkWidget *w, gpointer data)
1049 {
1050  GNCSplitReg *gsr = data;
1051  gsr_emit_simple_signal( gsr, "copy_txn" );
1052 }
1053 
1054 void
1055 gsr_default_paste_txn_handler( GNCSplitReg *gsr, gpointer data )
1056 {
1058  (gnc_ledger_display_get_split_register( gsr->ledger ));
1059 }
1060 
1064 void
1065 gnc_split_reg_paste_trans_cb (GtkWidget *w, gpointer data)
1066 {
1067  GNCSplitReg *gsr = data;
1068  gsr_emit_simple_signal( gsr, "paste_txn" );
1069 }
1070 
1071 /********************************************************************\
1072  * gnc_split_reg_void_trans_cb *
1073  * *
1074  * Args: widget - the widget that called us *
1075  * data - the data struct for this register *
1076  * Return: none *
1077 \********************************************************************/
1078 void
1079 gsr_default_void_txn_handler (GNCSplitReg *gsr, gpointer data)
1080 {
1081  // Override this function.
1082 }
1083 
1084 void
1085 gnc_split_reg_void_trans_cb (GtkWidget *w, gpointer data)
1086 {
1087  GNCSplitReg *gsr = data;
1088  gsr_emit_simple_signal( gsr, "void_txn" );
1089 }
1090 
1091 /********************************************************************\
1092  * gnc_split_reg_unvoid_trans_cb *
1093  * *
1094  * Args: widget - the widget that called us *
1095  * data - the data struct for this register *
1096  * Return: none *
1097 \********************************************************************/
1098 void
1099 gsr_default_unvoid_txn_handler (GNCSplitReg *gsr, gpointer data)
1100 {
1101  // Override this function.
1102 }
1103 
1104 void
1105 gnc_split_reg_unvoid_trans_cb (GtkWidget *w, gpointer data)
1106 {
1107  GNCSplitReg *gsr = data;
1108  gsr_emit_simple_signal( gsr, "unvoid_txn" );
1109 }
1110 
1111 /********************************************************************\
1112  * gnc_split_reg_reverse_trans_cb *
1113  * *
1114  * Args: widget - the widget that called us *
1115  * data - the data struct for this register *
1116  * Return: none *
1117 \********************************************************************/
1118 void
1119 gsr_default_reverse_txn_handler (GNCSplitReg *gsr, gpointer data)
1120 {
1121  SplitRegister *reg;
1122  Transaction *trans, *new_trans;
1123 
1124  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1126  if (trans == NULL)
1127  return;
1128 
1129  if (xaccTransGetReversedBy(trans))
1130  {
1131  gnc_error_dialog (GTK_WINDOW (gsr->window), "%s",
1132  _("A reversing entry has already been created for this transaction."));
1133  return;
1134  }
1135 
1136  new_trans = xaccTransReverse(trans);
1137 
1138  /* Clear transaction level info */
1140  xaccTransSetDateEnteredSecs(new_trans, gnc_time (NULL));
1141 
1142  /* Now jump to new trans */
1143  gnc_split_reg_jump_to_split(gsr, xaccTransGetSplit(new_trans, 0));
1144 }
1145 
1146 void
1147 gnc_split_reg_reverse_trans_cb (GtkWidget *w, gpointer data)
1148 {
1149  GNCSplitReg *gsr = data;
1150  gsr_emit_simple_signal( gsr, "reverse_txn" );
1151 }
1152 
1153 
1154 static gboolean
1155 is_trans_readonly_and_warn (GtkWindow *parent, Transaction *trans)
1156 {
1157  GtkWidget *dialog;
1158  const gchar *reason;
1159  const gchar *title = _("Cannot modify or delete this transaction.");
1160  const gchar *message =
1161  _("This transaction is marked read-only with the comment: '%s'");
1162 
1163  if (!trans) return FALSE;
1164 
1165  if (xaccTransIsReadonlyByPostedDate (trans))
1166  {
1167  dialog = gtk_message_dialog_new(parent,
1168  0,
1169  GTK_MESSAGE_ERROR,
1170  GTK_BUTTONS_OK,
1171  "%s", title);
1172  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1173  "%s", _("The date of this transaction is older than the \"Read-Only Threshold\" set for this book. "
1174  "This setting can be changed in File->Properties->Accounts."));
1175  gtk_dialog_run(GTK_DIALOG(dialog));
1176  gtk_widget_destroy(dialog);
1177  return TRUE;
1178  }
1179 
1180  reason = xaccTransGetReadOnly (trans);
1181  if (reason)
1182  {
1183  dialog = gtk_message_dialog_new(parent,
1184  0,
1185  GTK_MESSAGE_ERROR,
1186  GTK_BUTTONS_OK,
1187  "%s", title);
1188  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1189  message, reason);
1190  gtk_dialog_run(GTK_DIALOG(dialog));
1191  gtk_widget_destroy(dialog);
1192  return TRUE;
1193  }
1194  return FALSE;
1195 }
1196 
1197 
1198 void
1199 gsr_default_reinit_handler( GNCSplitReg *gsr, gpointer data )
1200 {
1201  VirtualCellLocation vcell_loc;
1202  SplitRegister *reg;
1203  Transaction *trans;
1204  Split *split;
1205  GtkWidget *dialog;
1206  gint response;
1207  const gchar *warning;
1208 
1209  const char *title = _("Remove the splits from this transaction?");
1210  const char *recn_warn = _("This transaction contains reconciled splits. "
1211  "Modifying it is not a good idea because that will "
1212  "cause your reconciled balance to be off.");
1213 
1214  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1215 
1217  if (is_trans_readonly_and_warn(GTK_WINDOW(gsr->window), trans))
1218  return;
1219  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1220  GTK_DIALOG_DESTROY_WITH_PARENT,
1221  GTK_MESSAGE_WARNING,
1222  GTK_BUTTONS_NONE,
1223  "%s", title);
1224  if (xaccTransHasReconciledSplits (trans))
1225  {
1226  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1227  "%s", recn_warn);
1228  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL_RECD;
1229  }
1230  else
1231  {
1232  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL;
1233  }
1234 
1235  gtk_dialog_add_button(GTK_DIALOG(dialog),
1236  _("_Cancel"), GTK_RESPONSE_CANCEL);
1237  gnc_gtk_dialog_add_button(dialog,
1238  /* Translators: This is the confirmation button in a warning dialog */
1239  _("_Remove Splits"),
1240  "edit-delete", GTK_RESPONSE_ACCEPT);
1241  response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
1242  gtk_widget_destroy (dialog);
1243  if (response != GTK_RESPONSE_ACCEPT)
1244  return;
1245 
1246  /*
1247  * Find the "transaction" split for the current transaction. This is
1248  * the split that appears at the top of the transaction in the
1249  * register.
1250  */
1252  if (!gnc_split_register_get_split_virt_loc(reg, split, &vcell_loc))
1253  return;
1254  split = gnc_split_register_get_current_trans_split (reg, &vcell_loc);
1256 }
1257 
1261 void
1262 gnc_split_reg_reinitialize_trans_cb(GtkWidget *widget, gpointer data)
1263 {
1264  GNCSplitReg *gsr = data;
1265  gsr_emit_simple_signal( gsr, "reinit_ent" );
1266 }
1267 
1268 /* Edit the document link for the current transaction. */
1269 void
1270 gsr_default_doclink_handler (GNCSplitReg *gsr)
1271 {
1272  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1273  Split *split = gnc_split_register_get_current_split (reg);
1274  Transaction *trans;
1275  CursorClass cursor_class;
1276  gchar *uri;
1277  gchar *ret_uri;
1278 
1279  /* get the current split based on cursor position */
1280  if (!split)
1281  {
1283  return;
1284  }
1285 
1286  trans = xaccSplitGetParent (split);
1287  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1288 
1289  if (cursor_class == CURSOR_CLASS_NONE)
1290  return;
1291 
1292  if (is_trans_readonly_and_warn (GTK_WINDOW(gsr->window), trans))
1293  return;
1294 
1295  // fix an earlier error when storing relative paths before version 3.5
1296  uri = gnc_doclink_convert_trans_link_uri (trans, gsr->read_only);
1297 
1298  ret_uri =
1299  gnc_doclink_get_uri_dialog (GTK_WINDOW (gsr->window),
1300  _("Change a Transaction Linked Document"),
1301  uri);
1302 
1303  if (ret_uri && g_strcmp0 (uri, ret_uri) != 0)
1304  xaccTransSetDocLink (trans, ret_uri);
1305 
1306  g_free (ret_uri);
1307  g_free (uri);
1308 }
1309 
1310 /* Opens the document link for the current transaction. */
1311 void
1312 gsr_default_doclink_open_handler (GNCSplitReg *gsr)
1313 {
1314  CursorClass cursor_class;
1315  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1316  Transaction *trans;
1317  Split *split = gnc_split_register_get_current_split (reg);
1318  gchar *uri;
1319 
1320  /* get the current split based on cursor position */
1321  if (!split)
1322  {
1324  return;
1325  }
1326 
1327  trans = xaccSplitGetParent (split);
1328  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1329 
1330  if (cursor_class == CURSOR_CLASS_NONE)
1331  return;
1332 
1333  // fix an earlier error when storing relative paths before version 3.5
1334  uri = gnc_doclink_convert_trans_link_uri (trans, gsr->read_only);
1335 
1336  gnc_doclink_open_uri (GTK_WINDOW (gsr->window), uri);
1337  g_free (uri);
1338 }
1339 
1340 /* Removes the document link for the current transaction. */
1341 void
1342 gsr_default_doclink_remove_handler (GNCSplitReg *gsr)
1343 {
1344  CursorClass cursor_class;
1345  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1346  Transaction *trans;
1347  Split *split = gnc_split_register_get_current_split (reg);
1348 
1349  /* get the current split based on cursor position */
1350  if (!split)
1351  {
1353  return;
1354  }
1355 
1356  trans = xaccSplitGetParent (split);
1357  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1358 
1359  if (cursor_class == CURSOR_CLASS_NONE)
1360  return;
1361 
1362  if (is_trans_readonly_and_warn (GTK_WINDOW(gsr->window), trans))
1363  return;
1364 
1365  xaccTransSetDocLink (trans, "");
1366 }
1367 
1368 static void
1369 gsr_default_doclink_from_sheet_handler (GNCSplitReg *gsr)
1370 {
1371  CursorClass cursor_class;
1372  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1373  Transaction *trans;
1374  Split *split;
1375  gchar *uri = NULL;
1376 
1377  /* get the current split based on cursor position */
1379  if (!split)
1380  return;
1381 
1382  trans = xaccSplitGetParent (split);
1383 
1384  // fix an earlier error when storing relative paths before version 3.5
1385  uri = gnc_doclink_convert_trans_link_uri (trans, gsr->read_only);
1386 
1387  if (uri)
1388  gnc_doclink_open_uri (GTK_WINDOW (gsr->window), uri);
1389 
1390  g_free (uri);
1391 }
1392 
1393 void
1394 gsr_default_delete_handler( GNCSplitReg *gsr, gpointer data )
1395 {
1396  CursorClass cursor_class;
1397  SplitRegister *reg;
1398  Transaction *trans;
1399  Split *split;
1400  GtkWidget *dialog;
1401  gint response;
1402  const gchar *warning;
1403 
1404  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1405 
1406  /* get the current split based on cursor position */
1408  if (split == NULL)
1409  {
1411  return;
1412  }
1413 
1414  trans = xaccSplitGetParent(split);
1415  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1416 
1417  /* test for blank_split reference pointing to split */
1418  if (gnc_split_register_is_blank_split (reg, split))
1420 
1421  /* Deleting the blank split just cancels */
1422  {
1423  Split *blank_split = gnc_split_register_get_blank_split (reg);
1424 
1425  if (split == blank_split)
1426  {
1428  return;
1429  }
1430  }
1431 
1432  if (cursor_class == CURSOR_CLASS_NONE)
1433  return;
1434 
1435  if (is_trans_readonly_and_warn(GTK_WINDOW(gsr->window), trans))
1436  return;
1437 
1438  /* On a split cursor, just delete the one split. */
1439  if (cursor_class == CURSOR_CLASS_SPLIT)
1440  {
1441  const char *format = _("Delete the split '%s' from the transaction '%s'?");
1442  const char *recn_warn = _("You would be deleting a reconciled split! "
1443  "This is not a good idea as it will cause your "
1444  "reconciled balance to be off.");
1445  const char *anchor_error = _("You cannot delete this split.");
1446  const char *anchor_split = _("This is the split anchoring this transaction "
1447  "to the register. You may not delete it from "
1448  "this register window. You may delete the "
1449  "entire transaction from this window, or you "
1450  "may navigate to a register that shows "
1451  "another side of this same transaction and "
1452  "delete the split from that register.");
1453  char *buf = NULL;
1454  const char *memo;
1455  const char *desc;
1456  char recn;
1457 
1458  if (reg->type != GENERAL_JOURNAL) // no anchoring split
1459  {
1460  if (split == gnc_split_register_get_current_trans_split (reg, NULL))
1461  {
1462  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1463  GTK_DIALOG_MODAL
1464  | GTK_DIALOG_DESTROY_WITH_PARENT,
1465  GTK_MESSAGE_ERROR,
1466  GTK_BUTTONS_OK,
1467  "%s", anchor_error);
1468  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1469  "%s", anchor_split);
1470  gtk_dialog_run(GTK_DIALOG(dialog));
1471  gtk_widget_destroy (dialog);
1472  return;
1473  }
1474  }
1475 
1476  memo = xaccSplitGetMemo (split);
1477  memo = (memo && *memo) ? memo : _("(no memo)");
1478 
1479  desc = xaccTransGetDescription (trans);
1480  desc = (desc && *desc) ? desc : _("(no description)");
1481 
1482  /* ask for user confirmation before performing permanent damage */
1483  buf = g_strdup_printf (format, memo, desc);
1484  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1485  GTK_DIALOG_MODAL
1486  | GTK_DIALOG_DESTROY_WITH_PARENT,
1487  GTK_MESSAGE_QUESTION,
1488  GTK_BUTTONS_NONE,
1489  "%s", buf);
1490  g_free(buf);
1491  recn = xaccSplitGetReconcile (split);
1492  if (recn == YREC || recn == FREC)
1493  {
1494  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1495  "%s", recn_warn);
1496  warning = GNC_PREF_WARN_REG_SPLIT_DEL_RECD;
1497  }
1498  else
1499  {
1500  warning = GNC_PREF_WARN_REG_SPLIT_DEL;
1501  }
1502 
1503  gtk_dialog_add_button(GTK_DIALOG(dialog),
1504  _("_Cancel"), GTK_RESPONSE_CANCEL);
1505  gnc_gtk_dialog_add_button(dialog, _("_Delete Split"),
1506  "edit-delete", GTK_RESPONSE_ACCEPT);
1507  response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
1508  gtk_widget_destroy (dialog);
1509  if (response != GTK_RESPONSE_ACCEPT)
1510  return;
1511 
1513  return;
1514  }
1515 
1516  g_return_if_fail(cursor_class == CURSOR_CLASS_TRANS);
1517 
1518  /* On a transaction cursor with 2 or fewer splits in single or double
1519  * mode, we just delete the whole transaction, kerblooie */
1520  {
1521  const char *title = _("Delete the current transaction?");
1522  const char *recn_warn = _("You would be deleting a transaction "
1523  "with reconciled splits! "
1524  "This is not a good idea as it will cause your "
1525  "reconciled balance to be off.");
1526 
1527  dialog = gtk_message_dialog_new(GTK_WINDOW(gsr->window),
1528  GTK_DIALOG_MODAL
1529  | GTK_DIALOG_DESTROY_WITH_PARENT,
1530  GTK_MESSAGE_WARNING,
1531  GTK_BUTTONS_NONE,
1532  "%s", title);
1533  if (xaccTransHasReconciledSplits (trans))
1534  {
1535  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1536  "%s", recn_warn);
1537  warning = GNC_PREF_WARN_REG_TRANS_DEL_RECD;
1538  }
1539  else
1540  {
1541  warning = GNC_PREF_WARN_REG_TRANS_DEL;
1542  }
1543  gtk_dialog_add_button(GTK_DIALOG(dialog),
1544  _("_Cancel"), GTK_RESPONSE_CANCEL);
1545  gnc_gtk_dialog_add_button(dialog, _("_Delete Transaction"),
1546  "edit-delete", GTK_RESPONSE_ACCEPT);
1547  response = gnc_dialog_run(GTK_DIALOG(dialog), warning);
1548  gtk_widget_destroy (dialog);
1549  if (response != GTK_RESPONSE_ACCEPT)
1550  return;
1551 
1553  return;
1554  }
1555 }
1556 
1560 void
1561 gnc_split_reg_delete_trans_cb(GtkWidget *widget, gpointer data)
1562 {
1563  GNCSplitReg *gsr = data;
1564  gsr_emit_simple_signal( gsr, "delete_ent" );
1565 }
1566 
1567 void
1568 gsr_default_dup_handler( GNCSplitReg *gsr, gpointer data )
1569 {
1571  (gnc_ledger_display_get_split_register( gsr->ledger ));
1572 }
1573 
1577 void
1578 gnc_split_reg_duplicate_trans_cb(GtkWidget *w, gpointer data)
1579 {
1580  GNCSplitReg *gsr = data;
1581  gsr_emit_simple_signal( gsr, "dup_ent" );
1582 }
1583 
1589 void
1590 gsr_default_schedule_handler( GNCSplitReg *gsr, gpointer data )
1591 {
1592  GncGUID *fromSXId = NULL;
1593  SchedXaction *theSX = NULL;
1594  GList *sxElts;
1595  SplitRegister *reg = gnc_ledger_display_get_split_register( gsr->ledger );
1596  Transaction *pending_trans = gnc_split_register_get_current_trans (reg);
1597 
1598  /* If the transaction has a sched-xact KVP frame, then go to the editor
1599  * for the existing SX; otherwise, do the sx-from-trans dialog. */
1600 
1601  qof_instance_get (QOF_INSTANCE (pending_trans),
1602  "from-sched-xaction", &fromSXId,
1603  NULL);
1604 
1605  /* Get the correct SX */
1606  for ( sxElts = gnc_book_get_schedxactions (gnc_get_current_book())->sx_list;
1607  (!theSX) && sxElts;
1608  sxElts = sxElts->next )
1609  {
1610  SchedXaction *sx = (SchedXaction*)sxElts->data;
1611  theSX =
1612  ((guid_equal (xaccSchedXactionGetGUID (sx), fromSXId))
1613  ? sx : NULL);
1614  }
1615  guid_free (fromSXId);
1616 
1617  if ( theSX )
1618  {
1619  gnc_ui_scheduled_xaction_editor_dialog_create(GTK_WINDOW(data), theSX, FALSE);
1620  return;
1621  }
1622  gnc_sx_create_from_trans(GTK_WINDOW(data), pending_trans);
1623 }
1624 
1625 void
1626 gnc_split_reg_recur_cb(GtkWidget *w, gpointer data)
1627 {
1628  GNCSplitReg *gsr = data;
1629  gsr_emit_simple_signal( gsr, "schedule_ent" );
1630 }
1631 
1635 void
1636 gnc_split_reg_record_trans_cb (GtkWidget *w, gpointer data)
1637 {
1638  GNCSplitReg *gsr = data;
1639  gsr_emit_simple_signal( gsr, "enter_ent" );
1640 }
1641 
1642 void
1643 gsr_default_cancel_handler( GNCSplitReg *gsr, gpointer data )
1644 {
1646  (gnc_ledger_display_get_split_register( gsr->ledger ));
1647 }
1648 
1652 void
1653 gnc_split_reg_cancel_trans_cb(GtkWidget *w, gpointer data)
1654 {
1655  GNCSplitReg *gsr = data;
1656  gsr_emit_simple_signal( gsr, "cancel_ent" );
1657 }
1658 
1659 void
1660 gsr_default_expand_handler( GNCSplitReg *gsr, gpointer data )
1661 {
1662  gint activeCount;
1663  gboolean expand;
1664  SplitRegister *reg;
1665 
1666  if (!gsr)
1667  return;
1668 
1669  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1670 
1671  /* These should all be in agreement. */
1672  activeCount =
1673  ( ( gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(gsr->split_menu_check)) ? 1 : -1 )
1674  + ( gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(gsr->split_popup_check)) ? 1 : -1 )
1675  + ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(gsr->split_button) )
1676  ? 1 : -1 ) );
1677 
1678  /* If activeCount > 0, then there's more active than inactive; otherwise,
1679  * more inactive than active. Both determine which state the user is
1680  * attempting to get to. */
1681  expand = ( activeCount < 0 );
1682 
1683  /* The ledger's invocation of 'redraw_all' will force the agreement in the
1684  * other split state widgets, so we neglect doing it here. */
1686 }
1687 
1688 void
1689 gnc_split_reg_expand_trans_menu_cb (GtkWidget *widget, gpointer data)
1690 {
1691  GNCSplitReg *gsr = data;
1692  gsr_emit_simple_signal( gsr, "expand_ent" );
1693 }
1694 
1695 void
1696 gnc_split_reg_expand_trans_toolbar_cb (GtkWidget *widget, gpointer data)
1697 {
1698  GNCSplitReg *gsr = data;
1699  gsr_emit_simple_signal( gsr, "expand_ent" );
1700 }
1701 
1702 gboolean
1703 gnc_split_reg_clear_filter_for_split (GNCSplitReg *gsr, Split *split)
1704 {
1705  VirtualCellLocation vcell_loc;
1706  SplitRegister *reg;
1707 
1708  if (!gsr)
1709  return FALSE;
1710 
1711  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1712 
1713  if (!gnc_split_register_get_split_virt_loc (reg, split, &vcell_loc))
1714  {
1715  gint response = gnc_ok_cancel_dialog (GTK_WINDOW(gsr->window),
1716  GTK_RESPONSE_CANCEL,
1717  (_("Target split is currently hidden in this register.\n\n%s\n\n"
1718  "Select OK to temporarily clear filter and proceed,\n"
1719  "otherwise the last active cell will be selected.")),
1720  gsr->filter_text);
1721 
1722  if (response == GTK_RESPONSE_OK)
1723  return TRUE;
1724  }
1725  return FALSE;
1726 }
1727 
1731 void
1732 gnc_split_reg_jump_to_split(GNCSplitReg *gsr, Split *split)
1733 {
1734  Transaction *trans;
1735  VirtualCellLocation vcell_loc;
1736  SplitRegister *reg;
1737 
1738  if (!gsr) return;
1739 
1740  trans = xaccSplitGetParent(split);
1741 
1742  gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
1743 
1744  reg = gnc_ledger_display_get_split_register( gsr->ledger );
1745 
1746  if (gnc_split_register_get_split_virt_loc(reg, split, &vcell_loc))
1747  gnucash_register_goto_virt_cell( gsr->reg, vcell_loc );
1748 
1749  gnc_ledger_display_refresh( gsr->ledger );
1750 }
1751 
1755 void
1756 gnc_split_reg_jump_to_split_amount(GNCSplitReg *gsr, Split *split)
1757 {
1758  VirtualLocation virt_loc;
1759  SplitRegister *reg;
1760  Transaction *trans;
1761 
1762  if (!gsr) return;
1763 
1764  trans = xaccSplitGetParent(split);
1765  gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
1766 
1767  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1768 
1769  if (gnc_split_register_get_split_amount_virt_loc (reg, split, &virt_loc))
1770  gnucash_register_goto_virt_loc (gsr->reg, virt_loc);
1771 
1772  gnc_ledger_display_refresh (gsr->ledger);
1773 }
1774 
1775 void
1776 gnc_split_reg_jump_to_blank (GNCSplitReg *gsr)
1777 {
1778  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1779  VirtualCellLocation vcell_loc;
1780  Split *blank;
1781 
1782  ENTER("gsr=%p", gsr);
1783 
1784  blank = gnc_split_register_get_blank_split (reg);
1785  if (blank == NULL)
1786  {
1787  LEAVE("no blank split");
1788  return;
1789  }
1790 
1791  if (gnc_split_register_get_split_virt_loc (reg, blank, &vcell_loc))
1792  gnucash_register_goto_virt_cell (gsr->reg, vcell_loc);
1793 
1794  gnc_ledger_display_refresh (gsr->ledger);
1795  LEAVE(" ");
1796 }
1797 
1798 void
1799 gnc_split_reg_focus_on_sheet (GNCSplitReg *gsr)
1800 {
1801  GnucashRegister *reg = gsr->reg;
1802  GnucashSheet *sheet = gnucash_register_get_sheet (reg);
1803 
1804  // Make sure the sheet is the focus only when it is realized
1805  if (!gtk_widget_has_focus(GTK_WIDGET(sheet)) && gtk_widget_get_realized (GTK_WIDGET(sheet)))
1806  gtk_widget_grab_focus (GTK_WIDGET(sheet));
1807 }
1808 
1809 void
1810 gnc_split_reg_set_sheet_focus (GNCSplitReg *gsr, gboolean has_focus)
1811 {
1812  GnucashRegister *reg = gsr->reg;
1813  GnucashSheet *sheet = gnucash_register_get_sheet (reg);
1814  gnucash_sheet_set_has_focus (sheet, has_focus);
1815 }
1816 
1817 void
1818 gnc_split_reg_balancing_entry(GNCSplitReg *gsr, Account *account,
1819  time64 statement_date, gnc_numeric balancing_amount)
1820 {
1821 
1822  Transaction *transaction;
1823  Split *split;
1824 
1825  // create transaction
1826  transaction = create_balancing_transaction(gnc_get_current_book(),
1827  account, statement_date, balancing_amount);
1828 
1829  // jump to transaction
1830  split = xaccTransFindSplitByAccount(transaction, account);
1831  if (split == NULL)
1832  {
1833  // default behaviour: jump to blank split
1834  g_warning("create_balancing_transaction failed");
1835  gnc_split_reg_jump_to_blank(gsr);
1836  }
1837  else
1838  {
1839  // goto balancing transaction
1840  gnc_split_reg_jump_to_split(gsr, split );
1841  }
1842 }
1843 
1844 static Transaction*
1845 create_balancing_transaction(QofBook *book, Account *account,
1846  time64 statement_date, gnc_numeric balancing_amount)
1847 {
1848 
1849  Transaction *trans;
1850  Split *split;
1851 
1852  if (!account)
1853  return NULL;
1854  if (gnc_numeric_zero_p(balancing_amount))
1855  return NULL;
1856 
1857  xaccAccountBeginEdit(account);
1858 
1859  trans = xaccMallocTransaction(book);
1860 
1861  xaccTransBeginEdit(trans);
1862 
1863  // fill Transaction
1865  xaccTransSetDatePostedSecsNormalized(trans, statement_date);
1866  xaccTransSetDescription(trans, _("Balancing entry from reconciliation"));
1867  /* We also must set a new DateEntered on the new entry
1868  * because otherwise the ordering is not deterministic */
1869  xaccTransSetDateEnteredSecs(trans, gnc_time(NULL));
1870 
1871  // 1. Split
1872  split = xaccMallocSplit(book);
1873  xaccTransAppendSplit(trans, split);
1874  xaccAccountInsertSplit(account, split);
1875  xaccSplitSetAmount(split, balancing_amount);
1876  xaccSplitSetValue(split, balancing_amount);
1877 
1878  // 2. Split (no account is defined: split goes to orphan account)
1879  split = xaccMallocSplit(book);
1880  xaccTransAppendSplit(trans, split);
1881 
1882  balancing_amount = gnc_numeric_neg(balancing_amount);
1883  xaccSplitSetAmount(split, balancing_amount);
1884  xaccSplitSetValue(split, balancing_amount);
1885 
1886  xaccTransCommitEdit(trans);
1887  xaccAccountCommitEdit(account);
1888  return trans;
1889 }
1890 
1891 void
1892 gsr_default_blank_handler( GNCSplitReg *gsr, gpointer data )
1893 {
1894  SplitRegister *reg;
1895 
1896  ENTER("gsr=%p, gpointer=%p", gsr, data);
1897 
1898  reg = gnc_ledger_display_get_split_register (gsr->ledger);
1899 
1900  if (gnc_split_register_save (reg, TRUE))
1902 
1903  gnc_split_reg_jump_to_blank (gsr);
1904  LEAVE(" ");
1905 }
1906 
1907 void
1908 gnc_split_reg_new_trans_cb (GtkWidget *widget, gpointer data)
1909 {
1910  GNCSplitReg *gsr = data;
1911  gsr_emit_simple_signal( gsr, "blank" );
1912 }
1913 
1914 void
1915 gsr_default_jump_handler( GNCSplitReg *gsr, gpointer data )
1916 {
1917  g_assert_not_reached();
1918 }
1919 
1920 void
1921 gnc_split_reg_jump_cb( GtkWidget *widget, gpointer data )
1922 {
1923  GNCSplitReg *gsr = data;
1924  gsr_emit_simple_signal( gsr, "jump" );
1925 }
1926 
1927 void
1928 gnc_split_reg_change_style (GNCSplitReg *gsr, SplitRegisterStyle style, gboolean refresh)
1929 {
1930  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1931 
1932  if (style == reg->style)
1933  return;
1934 
1935  gnc_split_register_config (reg, reg->type, style, reg->use_double_line);
1936  if (refresh)
1937  gnc_ledger_display_refresh (gsr->ledger);
1938 }
1939 
1940 void
1941 gnc_split_reg_style_ledger_cb (GtkWidget *w, gpointer data)
1942 {
1943  GNCSplitReg *gsr = data;
1944 
1945  if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(w)))
1946  return;
1947 
1948  gnc_split_reg_change_style (gsr, REG_STYLE_LEDGER, TRUE);
1949 }
1950 
1951 void
1952 gnc_split_reg_style_auto_ledger_cb (GtkWidget *w, gpointer data)
1953 {
1954  GNCSplitReg *gsr = data;
1955 
1956  if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(w)))
1957  return;
1958 
1959  gnc_split_reg_change_style (gsr, REG_STYLE_AUTO_LEDGER, TRUE);
1960 }
1961 
1962 void
1963 gnc_split_reg_style_journal_cb (GtkWidget *w, gpointer data)
1964 {
1965  GNCSplitReg *gsr = data;
1966 
1967  if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(w)))
1968  return;
1969 
1970  gnc_split_reg_change_style (gsr, REG_STYLE_JOURNAL, TRUE);
1971 }
1972 
1973 void
1974 gnc_split_reg_double_line_cb (GtkWidget *w, gpointer data)
1975 {
1976  GNCSplitReg *gsr = data;
1977  SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
1978  gboolean use_double_line;
1979 
1980  use_double_line = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(w));
1981  if ( use_double_line == reg->use_double_line )
1982  return;
1983 
1984  gnc_split_register_config( reg, reg->type, reg->style, use_double_line );
1985  gnc_ledger_display_refresh( gsr->ledger );
1986 }
1987 
1988 static void
1989 gnc_split_reg_sort_force( GNCSplitReg *gsr, SortType sort_code, gboolean force )
1990 {
1991  Query *query = gnc_ledger_display_get_query( gsr->ledger );
1992  gboolean show_present_divider = FALSE;
1993  GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
1994  SplitRegister *reg;
1995 
1996  if ((gsr->sort_type == sort_code) && !force)
1997  return;
1998 
1999  standard = g_slist_prepend( NULL, QUERY_DEFAULT_SORT );
2000 
2001  switch (sort_code)
2002  {
2003  case BY_STANDARD:
2004  p1 = standard;
2005  show_present_divider = TRUE;
2006  break;
2007  case BY_DATE:
2008  p1 = g_slist_prepend (p1, TRANS_DATE_POSTED);
2009  p1 = g_slist_prepend (p1, SPLIT_TRANS);
2010  p2 = standard;
2011  show_present_divider = TRUE;
2012  break;
2013  case BY_DATE_ENTERED:
2014  p1 = g_slist_prepend (p1, TRANS_DATE_ENTERED);
2015  p1 = g_slist_prepend (p1, SPLIT_TRANS);
2016  p2 = standard;
2017  break;
2018  case BY_DATE_RECONCILED:
2019  p1 = g_slist_prepend (p1, SPLIT_RECONCILE);
2020  p2 = g_slist_prepend (p2, SPLIT_DATE_RECONCILED);
2021  p3 = standard;
2022  break;
2023  case BY_NUM:
2024  p1 = g_slist_prepend (p1, TRANS_NUM);
2025  p1 = g_slist_prepend (p1, SPLIT_TRANS);
2026  p2 = standard;
2027  break;
2028  case BY_AMOUNT:
2029  p1 = g_slist_prepend (p1, SPLIT_VALUE);
2030  p2 = standard;
2031  break;
2032  case BY_MEMO:
2033  p1 = g_slist_prepend (p1, SPLIT_MEMO);
2034  p2 = standard;
2035  break;
2036  case BY_DESC:
2037  p1 = g_slist_prepend (p1, TRANS_DESCRIPTION);
2038  p1 = g_slist_prepend (p1, SPLIT_TRANS);
2039  p2 = standard;
2040  break;
2041  case BY_ACTION:
2042  p1 = g_slist_prepend (p1, SPLIT_ACTION);
2043  p2 = standard;
2044  break;
2045  case BY_NOTES:
2046  p1 = g_slist_prepend (p1, TRANS_NOTES);
2047  p1 = g_slist_prepend (p1, SPLIT_TRANS);
2048  p2 = standard;
2049  break;
2050  default:
2051  g_slist_free (standard);
2052  g_return_if_fail (FALSE);
2053  break;
2054  }
2055 
2056  qof_query_set_sort_order( query, p1, p2, p3 );
2057  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2058  gnc_split_register_show_present_divider( reg, show_present_divider );
2059  gsr->sort_type = sort_code;
2060  gnc_ledger_display_refresh( gsr->ledger );
2061 }
2062 
2063 static void
2064 gnc_split_reg_sort( GNCSplitReg *gsr, SortType sort_code )
2065 {
2066  gnc_split_reg_sort_force( gsr, sort_code, FALSE );
2067 }
2068 
2069 void
2070 gnc_split_reg_sort_standard_cb(GtkWidget *w, gpointer data)
2071 {
2072  GNCSplitReg *gsr = data;
2073  gnc_split_reg_sort(gsr, BY_STANDARD);
2074 }
2075 
2076 void
2077 gnc_split_reg_sort_date_cb(GtkWidget *w, gpointer data)
2078 {
2079  GNCSplitReg *gsr = data;
2080  gnc_split_reg_sort(gsr, BY_DATE);
2081 }
2082 
2083 void
2084 gnc_split_reg_sort_date_entered_cb(GtkWidget *w, gpointer data)
2085 {
2086  GNCSplitReg *gsr = data;
2087  gnc_split_reg_sort(gsr, BY_DATE_ENTERED);
2088 }
2089 
2090 void
2091 gnc_split_reg_sort_date_reconciled_cb(GtkWidget *w, gpointer data)
2092 {
2093  GNCSplitReg *gsr = data;
2094  gnc_split_reg_sort(gsr, BY_DATE_RECONCILED);
2095 }
2096 
2097 void
2098 gnc_split_reg_sort_num_cb(GtkWidget *w, gpointer data)
2099 {
2100  GNCSplitReg *gsr = data;
2101  gnc_split_reg_sort(gsr, BY_NUM);
2102 }
2103 
2104 void
2105 gnc_split_reg_sort_amount_cb(GtkWidget *w, gpointer data)
2106 {
2107  GNCSplitReg *gsr = data;
2108  gnc_split_reg_sort(gsr, BY_AMOUNT);
2109 }
2110 
2111 void
2112 gnc_split_reg_sort_memo_cb(GtkWidget *w, gpointer data)
2113 {
2114  GNCSplitReg *gsr = data;
2115  gnc_split_reg_sort(gsr, BY_MEMO);
2116 }
2117 
2118 void
2119 gnc_split_reg_sort_desc_cb(GtkWidget *w, gpointer data)
2120 {
2121  GNCSplitReg *gsr = data;
2122  gnc_split_reg_sort(gsr, BY_DESC);
2123 }
2124 
2125 void
2126 gnc_split_reg_sort_action_cb(GtkWidget *w, gpointer data)
2127 {
2128  GNCSplitReg *gsr = data;
2129  gnc_split_reg_sort(gsr, BY_ACTION);
2130 }
2131 
2132 void
2133 gnc_split_reg_sort_notes_cb(GtkWidget *w, gpointer data)
2134 {
2135  GNCSplitReg *gsr = data;
2136  gnc_split_reg_sort(gsr, BY_NOTES);
2137 }
2138 
2139 
2140 void
2141 gnc_split_reg_set_sort_reversed(GNCSplitReg *gsr, gboolean rev, gboolean refresh)
2142 {
2143  /* Note: sort_reversed is the boolean opposite of sort_increasing
2144  * so when rev == true, we're sorting decreasing
2145  * In other words, qof_query_set_sort_increasing should
2146  * always use the inverse of rev.
2147  */
2148  Query *query = gnc_ledger_display_get_query( gsr->ledger );
2149  qof_query_set_sort_increasing (query, !rev, !rev, !rev);
2150  gsr->sort_rev = rev;
2151  if (refresh)
2152  gnc_ledger_display_refresh( gsr->ledger );
2153 }
2154 
2155 static gboolean
2156 gnc_split_reg_record (GNCSplitReg *gsr)
2157 {
2158  SplitRegister *reg;
2159  Transaction *trans;
2160 
2161  ENTER("gsr=%p", gsr);
2162 
2163  reg = gnc_ledger_display_get_split_register (gsr->ledger);
2165 
2166  if (!gnc_split_register_save (reg, TRUE))
2167  {
2168  LEAVE("no save");
2169  return FALSE;
2170  }
2171 
2172  gsr_emit_include_date_signal( gsr, xaccTransGetDate(trans) );
2173 
2174  /* Explicit redraw shouldn't be needed,
2175  * since gui_refresh events should handle this. */
2176  /* gnc_split_register_redraw (reg); */
2177  LEAVE(" ");
2178  return TRUE;
2179 }
2180 
2181 static gboolean
2182 gnc_split_reg_match_trans_row( VirtualLocation virt_loc,
2183  gpointer user_data )
2184 {
2185  GNCSplitReg *gsr = user_data;
2186  CursorClass cursor_class;
2187  SplitRegister *sr;
2188 
2189  sr = gnc_ledger_display_get_split_register (gsr->ledger);
2190  cursor_class = gnc_split_register_get_cursor_class (sr, virt_loc.vcell_loc);
2191 
2192  return (cursor_class == CURSOR_CLASS_TRANS);
2193 }
2194 
2195 static void
2196 gnc_split_reg_goto_next_trans_row (GNCSplitReg *gsr)
2197 {
2198  ENTER("gsr=%p", gsr);
2199  gnucash_register_goto_next_matching_row( gsr->reg,
2200  gnc_split_reg_match_trans_row,
2201  gsr );
2202  LEAVE(" ");
2203 }
2204 
2205 void
2206 gnc_split_reg_enter( GNCSplitReg *gsr, gboolean next_transaction )
2207 {
2208  SplitRegister *sr = gnc_ledger_display_get_split_register( gsr->ledger );
2209  gboolean goto_blank;
2210 
2211  ENTER("gsr=%p, next_transaction=%s", gsr, next_transaction ? "TRUE" : "FALSE");
2212 
2213  goto_blank = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER,
2214  GNC_PREF_ENTER_MOVES_TO_END);
2215 
2216  /* If we are in single or double line mode and we hit enter
2217  * on the blank split, go to the blank split instead of the
2218  * next row. This prevents the cursor from jumping around
2219  * when you are entering transactions. */
2220  if ( !goto_blank && !next_transaction )
2221  {
2222  SplitRegisterStyle style = sr->style;
2223 
2224  if (style == REG_STYLE_LEDGER)
2225  {
2226  Split *blank_split;
2227 
2228  blank_split = gnc_split_register_get_blank_split(sr);
2229  if (blank_split != NULL)
2230  {
2231  Split *current_split;
2232 
2233  current_split = gnc_split_register_get_current_split(sr);
2234 
2235  if (blank_split == current_split)
2236  goto_blank = TRUE;
2237  }
2238  }
2239  }
2240  /* First record the transaction. This will perform a refresh. */
2241  if (!gnc_split_reg_record (gsr))
2242  {
2243  /* we may come here from the transfer cell if we decline to create a
2244  * new account, make sure the sheet has the focus if the record is FALSE
2245  * which results in no cursor movement. */
2246  gnc_split_reg_focus_on_sheet (gsr);
2247 
2248  /* if there are no changes, just enter was pressed, proceed to move
2249  * other wise lets not move. */
2250  if (gnc_table_current_cursor_changed (sr->table, FALSE))
2251  {
2252  LEAVE(" ");
2253  return;
2254  }
2255  }
2256 
2257  if (!goto_blank && next_transaction)
2259 
2260  /* Now move. */
2261  if (goto_blank)
2262  gnc_split_reg_jump_to_blank( gsr );
2263  else if (next_transaction)
2264  gnc_split_reg_goto_next_trans_row( gsr );
2265  else
2266  gnucash_register_goto_next_virt_row( gsr->reg );
2267  LEAVE(" ");
2268 }
2269 
2270 void
2271 gsr_default_enter_handler( GNCSplitReg *gsr, gpointer data )
2272 {
2273  gnc_split_reg_enter( gsr, FALSE );
2274 }
2275 
2276 void
2277 gnc_split_reg_record_cb (GnucashRegister *reg, gpointer data)
2278 {
2279  gsr_emit_simple_signal( (GNCSplitReg*)data, "enter_ent" );
2280 }
2281 
2282 void
2283 gnc_split_reg_size_allocate (GtkWidget *widget,
2284  GtkAllocation *allocation,
2285  gpointer user_data)
2286 {
2287  GNCSplitReg *gsr = user_data;
2288  gsr->width = allocation->width;
2289  gtk_window_set_default_size( GTK_WINDOW(gsr->window), gsr->width, 0 );
2290 }
2291 
2292 static
2293 GtkWidget*
2294 add_summary_label (GtkWidget *summarybar, gboolean pack_start, const char *label_str, GtkWidget *extra)
2295 {
2296  GtkWidget *hbox;
2297  GtkWidget *text_label, *secondary_label;
2298 
2299  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
2300  gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
2301  if (pack_start)
2302  gtk_box_pack_start( GTK_BOX(summarybar), hbox, FALSE, FALSE, 5 );
2303  else
2304  gtk_box_pack_end( GTK_BOX(summarybar), hbox, FALSE, FALSE, 5 );
2305 
2306  text_label = gtk_label_new (label_str);
2307  gnc_label_set_alignment (text_label, 1.0, 0.5 );
2308  gtk_label_set_ellipsize (GTK_LABEL(text_label), PANGO_ELLIPSIZE_END);
2309  gtk_box_pack_start (GTK_BOX(hbox), text_label, FALSE, FALSE, 0);
2310 
2311  secondary_label = gtk_label_new ( "" );
2312  g_object_set_data (G_OBJECT(secondary_label), "text_label", text_label);
2313  g_object_set_data (G_OBJECT(secondary_label), "text_box", hbox);
2314  gnc_label_set_alignment (secondary_label, 1.0, 0.5 );
2315  gtk_box_pack_start (GTK_BOX(hbox), secondary_label, FALSE, FALSE, 0);
2316 
2317  if (extra != NULL)
2318  gtk_box_pack_start( GTK_BOX(hbox), extra, FALSE, FALSE, 0 );
2319 
2320  return secondary_label;
2321 }
2322 
2323 static void
2324 gsr_summarybar_set_arrow_draw (GNCSplitReg *gsr)
2325 {
2326  if (gsr->sort_arrow_handler_id > 0)
2327  g_signal_handler_disconnect (G_OBJECT(gsr->sort_arrow), gsr->sort_arrow_handler_id);
2328 
2329  gsr->sort_arrow_handler_id = g_signal_connect (G_OBJECT (gsr->sort_arrow), "draw",
2330  G_CALLBACK (gnc_draw_arrow_cb), GINT_TO_POINTER(gsr->sort_rev));
2331 
2332  gtk_widget_queue_draw (gsr->sort_arrow);
2333 }
2334 
2335 GtkWidget *
2336 gsr_create_summary_bar( GNCSplitReg *gsr )
2337 {
2338  GtkWidget *summarybar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
2339  gtk_box_set_homogeneous (GTK_BOX (summarybar), FALSE);
2340  gtk_widget_set_name (summarybar, "gnc-id-summarybar");
2341 
2342  gsr->cleared_label = NULL;
2343  gsr->balance_label = NULL;
2344  gsr->reconciled_label = NULL;
2345  gsr->future_label = NULL;
2346  gsr->projectedminimum_label = NULL;
2347  gsr->sort_label = NULL;
2348  gsr->sort_arrow = NULL;
2349  gsr->filter_label = NULL;
2350  gsr->shares_label = NULL;
2351  gsr->value_label = NULL;
2352 
2353  if (gnc_ledger_display_type(gsr->ledger) == LD_SINGLE)
2354  {
2356  {
2357  gsr->balance_label = add_summary_label (summarybar, TRUE, _("Present:"), NULL);
2358  gsr->future_label = add_summary_label (summarybar, TRUE, _("Future:"), NULL);
2359  gsr->cleared_label = add_summary_label (summarybar, TRUE, _("Cleared:"), NULL);
2360  gsr->reconciled_label = add_summary_label (summarybar, TRUE, _("Reconciled:"), NULL);
2361  gsr->projectedminimum_label = add_summary_label (summarybar, TRUE, _("Projected Minimum:"), NULL);
2362  }
2363  else
2364  {
2365  gsr->shares_label = add_summary_label (summarybar, TRUE, _("Shares:"), NULL);
2366  gsr->value_label = add_summary_label (summarybar, TRUE, _("Current Value:"), NULL);
2367  }
2368  }
2369 
2370  gsr->filter_label = add_summary_label (summarybar, FALSE, "", NULL);
2371  gsr->sort_arrow = gtk_image_new_from_icon_name ("image-missing", GTK_ICON_SIZE_SMALL_TOOLBAR);
2372  gsr->sort_label = add_summary_label (summarybar, FALSE, _("Sort By:"), gsr->sort_arrow);
2373 
2374  gnc_widget_style_context_add_class (GTK_WIDGET(gsr->filter_label), "gnc-class-highlight");
2375  gnc_widget_style_context_add_class (GTK_WIDGET(gsr->sort_arrow), "gnc-class-highlight");
2376 
2377  gsr->summarybar = summarybar;
2378 
2379  /* Force the first update */
2380  gsr_redraw_all_cb(NULL, gsr);
2381  return gsr->summarybar;
2382 }
2383 
2390 static
2392 gnc_split_reg_get_placeholder( GNCSplitReg *gsr )
2393 {
2394  Account *leader;
2395  SplitRegister *reg;
2396  gboolean single_account;
2397 
2398  if (gsr == NULL)
2399  return PLACEHOLDER_NONE;
2400 
2401  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2402 
2403  switch (reg->type)
2404  {
2405  case GENERAL_JOURNAL:
2406  case INCOME_LEDGER:
2407  case PORTFOLIO_LEDGER:
2408  case SEARCH_LEDGER:
2409  single_account = FALSE;
2410  break;
2411  default:
2412  single_account = TRUE;
2413  break;
2414  }
2415 
2416  leader = gnc_ledger_display_leader( gsr->ledger );
2417 
2418  if (leader == NULL)
2419  return PLACEHOLDER_NONE;
2420  if (single_account)
2421  {
2422  if (xaccAccountGetPlaceholder( leader ))
2423  return PLACEHOLDER_THIS;
2424  return PLACEHOLDER_NONE;
2425  }
2426  return xaccAccountGetDescendantPlaceholder( leader );
2427 }
2428 
2432 typedef struct dialog_args
2433 {
2434  GNCSplitReg *gsr;
2435  gchar *string;
2436 } dialog_args;
2437 
2443 static
2444 gboolean
2445 gtk_callback_bug_workaround (gpointer argp)
2446 {
2447  dialog_args *args = argp;
2448  const gchar *read_only_this = _("This account register is read-only.");
2449  const gchar *read_only_acc = _("The '%s' account register is read-only.");
2450  gchar *read_only = NULL;
2451  GtkWidget *dialog;
2452  GNCLedgerDisplayType ledger_type = gnc_ledger_display_type (args->gsr->ledger);
2453  Account *acc = gnc_ledger_display_leader (args->gsr->ledger);
2454  const gchar *acc_name = NULL;
2455  gchar *tmp = NULL;
2456 
2457  if (acc)
2458  {
2459  acc_name = xaccAccountGetName (acc);
2460 
2461  if (ledger_type == LD_SINGLE)
2462  read_only = g_strdup_printf (read_only_acc, acc_name);
2463  else
2464  {
2465  gchar *tmp = g_strconcat (acc_name, "+", NULL);
2466  read_only = g_strdup_printf (read_only_acc, tmp);
2467  g_free (tmp);
2468  }
2469  }
2470  else
2471  read_only = g_strdup (read_only_this);
2472 
2473  dialog = gtk_message_dialog_new(GTK_WINDOW(args->gsr->window),
2474  GTK_DIALOG_DESTROY_WITH_PARENT,
2475  GTK_MESSAGE_WARNING,
2476  GTK_BUTTONS_CLOSE,
2477  "%s", read_only);
2478  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
2479  "%s", args->string);
2480  gnc_dialog_run(GTK_DIALOG(dialog), GNC_PREF_WARN_REG_IS_READ_ONLY);
2481  gtk_widget_destroy(dialog);
2482  g_free(read_only);
2483  g_free(args);
2484  return FALSE;
2485 }
2486 
2490 static
2491 void
2492 gnc_split_reg_determine_read_only( GNCSplitReg *gsr, gboolean show_dialog )
2493 {
2494  SplitRegister *reg;
2495 
2496  if (qof_book_is_readonly(gnc_get_current_book()))
2497  {
2498  /* Is the book read-only? Then for sure also make this register
2499  read-only. */
2500  gsr->read_only = TRUE;
2501  }
2502 
2503  if ( !gsr->read_only )
2504  {
2505  dialog_args *args;
2506  char *string = NULL;
2507  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2508  if(reg->mismatched_commodities)
2509  {
2510  string = _("The transactions of this account may not be edited "
2511  "because its subaccounts have mismatched commodities "
2512  "or currencies.\n"
2513  "You need to open each account individually to edit "
2514  "transactions.");
2515  }
2516  else
2517  {
2518  switch (gnc_split_reg_get_placeholder(gsr))
2519  {
2520  case PLACEHOLDER_NONE:
2521  /* stay as false. */
2522  return;
2523 
2524  case PLACEHOLDER_THIS:
2525  string = _("The transactions of this account may not be edited.\n"
2526  "If you want to edit transactions in this register, "
2527  "please open the account options and turn off the "
2528  "placeholder checkbox.");
2529  break;
2530 
2531  default:
2532  string = _("The transactions in one of the selected "
2533  "sub-accounts may not be edited.\n"
2534  "If you want to edit transactions in this register, please open "
2535  "the sub-account options and turn off the placeholder checkbox.\n"
2536  "You may also open an individual account instead "
2537  "of a set of accounts.");
2538  break;
2539  }
2540  }
2541  gsr->read_only = TRUE;
2542  /* Put up a warning dialog */
2543  args = g_malloc(sizeof(dialog_args));
2544  args->string = string;
2545  args->gsr = gsr;
2546  if (show_dialog)
2547  g_timeout_add (250, gtk_callback_bug_workaround, args); /* 0.25 seconds */
2548  }
2549 
2550  /* Make the contents immutable */
2551  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2552  gnc_split_register_set_read_only( reg, TRUE );
2553 
2554 }
2555 
2556 static
2557 GtkWidget *
2558 gnc_split_reg_get_parent( GNCLedgerDisplay *ledger )
2559 {
2560  GNCSplitReg *gsr =
2561  GNC_SPLIT_REG(gnc_ledger_display_get_user_data( ledger ));
2562 
2563  if (gsr == NULL)
2564  return NULL;
2565 
2566  return gsr->window;
2567 }
2568 
2569 static
2570 void
2571 gsr_emit_help_changed( GnucashRegister *reg, gpointer user_data )
2572 {
2573  gsr_emit_simple_signal( (GNCSplitReg*)user_data, "help-changed" );
2574 }
2575 
2576 static
2577 void
2578 gsr_emit_show_popup_menu( GnucashRegister *reg, gpointer user_data )
2579 {
2580  gsr_emit_simple_signal( (GNCSplitReg*)user_data, "show-popup-menu" );
2581 }
2582 
2583 static
2584 void
2585 gsr_emit_include_date_signal( GNCSplitReg *gsr, time64 date )
2586 {
2587  g_signal_emit_by_name( gsr, "include-date", date, NULL );
2588 }
2589 
2590 static
2591 void
2592 gsr_emit_simple_signal( GNCSplitReg *gsr, const char *sigName )
2593 {
2594  g_signal_emit_by_name( gsr, sigName, NULL );
2595 }
2596 
2597 GnucashRegister*
2598 gnc_split_reg_get_register( GNCSplitReg *gsr )
2599 {
2600  if ( !gsr )
2601  return NULL;
2602 
2603  return gsr->reg;
2604 }
2605 
2606 SortType
2607 gnc_split_reg_get_sort_type( GNCSplitReg *gsr )
2608 {
2609  g_assert( gsr );
2610  return gsr->sort_type;
2611 }
2612 
2613 void
2614 gnc_split_reg_set_sort_type( GNCSplitReg *gsr, SortType t )
2615 {
2616  gnc_split_reg_sort( gsr, t );
2617 }
2618 
2619 void
2620 gnc_split_reg_set_sort_type_force( GNCSplitReg *gsr, SortType t, gboolean force )
2621 {
2622  gnc_split_reg_sort_force( gsr, t, force );
2623 }
2624 
2625 
2626 GtkWidget*
2627 gnc_split_reg_get_summarybar( GNCSplitReg *gsr )
2628 {
2629  if ( !gsr ) return NULL;
2630  return gsr->summarybar;
2631 }
2632 
2633 gboolean
2634 gnc_split_reg_get_read_only( GNCSplitReg *gsr )
2635 {
2636  SplitRegister *reg;
2637 
2638  g_assert( gsr );
2639 
2640  // reset read_only flag
2641  gsr->read_only = FALSE;
2642  gnc_split_reg_determine_read_only (gsr, FALSE);
2643 
2644  reg = gnc_ledger_display_get_split_register( gsr->ledger );
2645  gnc_split_register_set_read_only( reg, gsr->read_only );
2646  return gsr->read_only;
2647 }
2648 
2649 void
2650 gnc_split_reg_set_moved_cb( GNCSplitReg *gsr, GFunc cb, gpointer cb_data )
2651 {
2652  gnucash_register_set_moved_cb (gsr->reg, cb, cb_data);
2653 }
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;s current cursor.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
void xaccAccountSetFilter(Account *acc, const char *str)
Set the account&#39;s Filter.
Definition: Account.cpp:2576
void xaccAccountSetSortOrder(Account *acc, const char *str)
Set the account&#39;s Sort Order.
Definition: Account.cpp:2586
Public declarations for GncLedgerDisplay class.
Functions to load, save and get gui state.
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
Definition: Transaction.c:2723
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:370
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:511
void gnc_ledger_display_refresh(GNCLedgerDisplay *ld)
redisplay/redraw only the indicated window.
gboolean gnc_ledger_display_default_double_line(GNCLedgerDisplay *gld)
Returns a boolean of whether this display should be single or double lined mode by default...
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
gboolean xaccAccountGetSortReversed(const Account *acc)
Get the account&#39;s Sort Order direction.
Definition: Account.cpp:3400
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
Definition: Transaction.c:2635
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
This file contains the functions to present a gui to the user for creating a new account or editing a...
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4712
a simple price database for gnucash
void gnc_split_register_expand_current_trans(SplitRegister *reg, gboolean expand)
Expand the current transaction if it is collapsed.
utility functions for the GnuCash UI
const char * xaccAccountGetFilter(const Account *acc)
Get the account&#39;s filter.
Definition: Account.cpp:3380
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *params1, QofQueryParamList *params2, QofQueryParamList *params3)
When a query is run, the results are sorted before being returned.
Definition: qofquery.cpp:1232
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void gnc_split_register_delete_current_split(SplitRegister *reg)
Deletes the split associated with the current cursor, if both are non-NULL.
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
Definition: Transaction.c:2596
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
Account * gnc_ledger_display_leader(GNCLedgerDisplay *ld)
Implementations.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:174
void gnc_split_register_delete_current_trans(SplitRegister *reg)
Deletes the transaction associated with the current cursor, if both are non-NULL. ...
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
When a query is run, the results are sorted before being returned.
Definition: qofquery.cpp:1263
void gnc_split_register_set_read_only(SplitRegister *reg, gboolean read_only)
Sets whether a register window is "read only".
GtkWidget * gnucash_register_new(Table *table, const gchar *state_section)
this already has scrollbars attached
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
gnc_numeric xaccAccountGetClearedBalance(const Account *acc)
Get the current balance of the account, only including cleared transactions.
Definition: Account.cpp:3536
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
Definition: gnc-pricedb.c:967
Query * gnc_ledger_display_get_query(GNCLedgerDisplay *ld)
return the query associated with a ledger
gnc_numeric gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency)
Convert a balance from one currency to another using the most recent price between the two...
Definition: gnc-pricedb.c:2659
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1426
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Definition: gnc-ui-util.c:1197
#define xaccAccountGetGUID(X)
Definition: Account.h:248
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
Account handling public routines.
void gnc_ledger_display_set_handlers(GNCLedgerDisplay *ld, GNCLedgerDisplayDestroy destroy, GNCLedgerDisplayGetParent get_parent)
set the handlers used by the ledger display
CursorClass
Types of cursors.
#define YREC
The Split has been reconciled.
Definition: Split.h:72
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition: guid.cpp:204
void gnc_split_register_cut_current(SplitRegister *reg)
Equivalent to copying the current entity and the deleting it with the appropriate delete method...
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
#define FREC
frozen into accounting period
Definition: Split.h:73
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
GNCPlaceholderType xaccAccountGetDescendantPlaceholder(const Account *acc)
Returns PLACEHOLDER_NONE if account is NULL or neither account nor any descendant of account is a pla...
Definition: Account.cpp:4312
Anchor Scheduled Transaction info in a book.
void gnc_split_register_config(SplitRegister *reg, SplitRegisterType newtype, SplitRegisterStyle newstyle, gboolean use_double_line)
Sets a split register&#39;s type, style or line use.
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Gnome specific utility functions.
Public declarations of GnucashRegister class.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gboolean gnc_split_register_get_split_amount_virt_loc(SplitRegister *reg, Split *split, VirtualLocation *virt_loc)
Searches the split register for the given split and determines the location of either its credit (if ...
#define xaccSchedXactionGetGUID(X)
Definition: SchedXaction.h:323
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_numeric xaccAccountGetReconciledBalance(const Account *acc)
Get the current balance of the account, only including reconciled transactions.
Definition: Account.cpp:3543
All type declarations for the whole Gnucash engine.
gnc_numeric xaccAccountGetBalance(const Account *acc)
Get the current balance of the account, which may include future splits.
Definition: Account.cpp:3529
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
Definition: gnc-ui-util.c:1728
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
gboolean gnc_split_register_is_blank_split(SplitRegister *reg, Split *split)
Return TRUE if split is the blank_split.
Generic api to store and retrieve preferences.
Split * gnc_split_register_duplicate_current(SplitRegister *reg)
Duplicates either the current transaction or the current split depending on the register mode and cur...
void gnc_split_register_cancel_cursor_trans_changes(SplitRegister *reg)
Cancels any changes made to the current pending transaction, reloads the table from the engine...
GNCPlaceholderType
DOCUMENT ME!
Definition: Account.h:1193
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: gnc-ui-util.c:1202
void gnc_split_register_paste_current(SplitRegister *reg)
Pastes a previous copied entity onto the current entity, but only if the copied and current entity ha...
Transaction * xaccTransReverse(Transaction *orig)
xaccTransReverse creates a Transaction that reverses the given transaction by inverting all the numer...
Definition: Transaction.c:2897
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:580
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
Searches the split register for a given split.
gchar * gnc_wrap_text_with_bidi_ltr_isolate(const char *text)
This function helps with GTK&#39;s use of &#39;Unicode Bidirectional Text Algorithm&#39;.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1449
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
void gnc_split_register_empty_current_trans_except_split(SplitRegister *reg, Split *split)
Deletes the non-transaction splits associated with the current cursor, if both are non-NULL...
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4262
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Definition: Transaction.c:2211
Declarations for the Table object.
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Returns the transaction that reversed the given transaction.
Definition: Transaction.c:2937
void xaccAccountSetSortReversed(Account *acc, gboolean sortreversed)
Set the account&#39;s Sort Order direction.
Definition: Account.cpp:2596
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition: qofquery.h:106
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
Utility functions for convert uri in separate components and back.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
void gnc_table_save_state(Table *table, const gchar *state_section)
Implementation.
Definition: table-gnome.c:71
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
void gnc_split_register_change_blank_split_ref(SplitRegister *reg, Split *split)
Change the blank_split reference from pointing to split to another split of the transaction.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2054
File path resolution utility functions.
SplitRegister * gnc_ledger_display_get_split_register(GNCLedgerDisplay *ld)
return the split register associated with a ledger display
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3301
void gnc_split_register_show_present_divider(SplitRegister *reg, gboolean show_present)
If TRUE, visually indicate the demarcation between splits with post dates prior to the present...
const char * xaccAccountGetSortOrder(const Account *acc)
Get the account&#39;s Sort Order.
Definition: Account.cpp:3390
The type used to store guids in C.
Definition: guid.h:75
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1490
void gnc_ledger_display_set_user_data(GNCLedgerDisplay *ld, gpointer user_data)
get and set the user data associated with the ledger
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
SplitRegisterStyle
Register styles.
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143
void gnc_split_register_copy_current(SplitRegister *reg)
Makes a copy of the current entity, either a split or a transaction, so that it can be pasted later...