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